[Scummvm-git-logs] scummvm master -> 3e61864ad8f007c36c3e568361a422baf2666a9c

sev- sev at scummvm.org
Sat Jun 1 22:44:44 CEST 2019


This automated email contains information about 87 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
97397bdaff STREAM: add read/write functions for double LE/BE
531aa8392e CRYOMNI3D: Add engine for Versailles 1685
8d770af865 CRYOMNI3D: Fix compilation error with -std=c++11
c7205da58b CRYOMNI3D: Fix use after free when playing dialog
a055268a08 CRYOMNI3D: remove debug define which skipped videos
ba6506d8d3 CRYOMNI3D: Fix struct declarations
6ef4fba3d1 CRYOMNI3D: Fix type of return to match prototype
db85320bcc CRYOMNI3D: Remove DATAS_V folder level for searching files
acb8349a91 CRYOMNI3D: Add Macintosh support to Versailles
f50d89841d CRYOMNI3D: Fix fonts for MacOS version
92a306e56e CRYOMNI3D: Remove long delayMillis as they lower the framerate
769f8d46ef CRYOMNI3D: Fix cursor not shown in some events
01234cd773 CRYOMNI3D: Fix cursor shown in transitions
84b60b92bd CRYOMNI3D: Fix appending of files extensions
2860d5caac CRYOMNI3D: Apply sound settings at startup
4ceb3e4b07 CRYOMNI3D: Let user type spaces in save names
49c90c74a6 CRYOMNI3D: Add a function to deselect object
cd9aefc425 CRYOMNI3D: Add a function to disable a zone in fixed images
f4d274c41e CRYOMNI3D: Add missing actions masks
9e31e4dfb9 CRYOMNI3D: Mark clearly missing parts for next levels
28702028a2 CRYOMNI3D: Add a function to not look for end of conversations
d655fb5530 CRYOMNI3D: Add function to change sprite color
812d75e4e4 CRYOMNI3D: Make objects functions names more consistent
6e692195c8 CRYOMNI3D: Let change individual color in main palette
0619120f3a CRYOMNI3D: Add a function to collect an Object *
3a12d53ffc CRYOMNI3D: Implement level 2
c83f86a245 CRYOMNI3D: Fix file names for Macintosh version
6d36bc3cca CRYOMNI3D: Fix style
9bfc24eee3 CRYOMNI3D: Deselect object when removing from inventory
7d6c3ee12b CRYOMNI3D: Fix some comments and order of callback
47908def70 CRYOMNI3D: Fix palette not applied when loading frame
7cbf7095fc CRYOMNI3D: Fix messages
9496c796bc CRYOMNI3D: Implement missing objects callbacks
c427cd9dca CRYOMNI3D: Implement level 3
5a0d511ebd CRYOMNI3D: Use typedef instead of repeating
349201ba15 CRYOMNI3D: Let callback modify displayed fixed image
ac5d392a76 CRYOMNI3D: Add a function to load a set of BMP files
5eb8b19a9c CRYOMNI3D: If save name can't be read don't add it
75e5339246 CRYOMNI3D: Fix comments
36405f483f CRYOMNI3D: Make placeStates array always the same size
17887c713e CRYOMNI3D: Reset key pressed
91d0f43cbf CRYOMNI3D: Add ability to choose ZON file
c18f209c90 CRYOMNI3D: Implement level 4
adf6ab006c CRYOMNI3D: Use fabs instead of abs
bdc6969ea4 CRYOMNI3D: Remove unused private members
96978b2079 CRYOMNI3D: Avoid LLVM warnings on the logic
807c4c5247 CRYOMNI3D: Save savegames list offset in settings
995b10e71e CRYOMNI3D: Fix surface not reloaded after finished with safe
67e76c3b56 CRYOMNI3D: Forgot to deselect object after talking to Bontemps
07011e4fc7 CRYOMNI3D: Remove almost dumb images
bf123ad630 CRYOMNI3D: Implement level 5
8ad730260b CRYOMNI3D: Remove TODO as it's not needed anymore
2ed2d617c0 CRYOMNI3D: Fix errors in strings
6e0e3bb6b1 CRYOMNI3D: Don't abort when there is no transition defined
c6999b091e CRYOMNI3D: Number objects to help mangling of saves
3413768f8e CRYOMNI3D: Don't skip videos (debug leftover)
93bc6cf02b CRYOMNI3D: Fix incorrect dialog shows
cba0ee7296 CRYOMNI3D: Implement level 6
1c4d0d87ec CRYOMNI3D: Use existing palette to init video one
edf2fdb128 CRYOMNI3D: Add hook to video playing
01f6e2db12 CRYOMNI3D: Implement countdown
48ad952e50 CRYOMNI3D: Save some space
f7c7707d15 CRYOMNI3D: Fix objects order to keep savegame compat
e791122c59 CRYOMNI3D: Implement (final) level 7
4e955c4776 CRYOMNI3D: Remove outdated TODOs
0e0cdbee24 CRYOMNI3D: Fix cursor shown too soon in transitions
dae772f496 CRYOMNI3D: Make sure toolbar is displayed on colored screen
57074300ca CRYOMNI3D: Remove superflous header
222f6b0e4c CRYOMNI3D: Add assert where needed
ff197718c2 CRYOMNI3D: Rename unsigned int to uint
28206dd554 CRYOMNI3D: Fix include paths
8dceff30ea CRYOMNI3D: Fix indentation of preproc blocks
257a788e08 CRYOMNI3D: Cleanup
d3c33364d7 CRYOMNI3D: Sort files
bd8698897d CRYOMNI3D: Better check of sprites magic
5ed893bb6a CRYOMNI3D: Move break to be clear it's not a fall through
d5a6c1c9cb CRYOMNI3D: Fix abort constants names
b81f477ac1 CRYOMNI3D: Convert short to int16
2d82abdaf5 CRYOMNI3D: Add a comment to clarify
7ae6e1af1e CRYOMNI3D: Use byte instead of char
f20d33f130 CRYOMNI3D: Make ignored reads explicit
e07844e06b CRYOMNI3D: Fix constants names
f25102ac76 CRYOMNI3D: Put delayMillis out of pollEvents
b72fdaf8a2 CRYOMNI3D: Fix search path of files
e707e312da CRYOMNI3D: Handle cursor moves during fading
475f9ea293 CRYOMNI3D: Fix missed clicks when occuring beteen two pollEvent
3e61864ad8 CRYOMNI3D: Fix places documentation


Commit: 97397bdaffed7f7bdf97ccde20bbcd41df4e63fb
    https://github.com/scummvm/scummvm/commit/97397bdaffed7f7bdf97ccde20bbcd41df4e63fb
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
STREAM: add read/write functions for double LE/BE

Changed paths:
    common/stream.h


diff --git a/common/stream.h b/common/stream.h
index dfb7d6c..16264a7 100644
--- a/common/stream.h
+++ b/common/stream.h
@@ -204,6 +204,31 @@ public:
 	}
 
 	/**
+	 * Write the given 64-bit floating point value stored
+	 * in little endian(LSB first) order into the stream.
+	 */
+	FORCEINLINE void writeDoubleLE(double value) {
+		uint64 n;
+
+		memcpy(&n, &value, 8);
+
+		writeUint64LE(n);
+	}
+
+
+	/**
+	 * Write the given 64-bit floating point value stored
+	 * in big endian order into the stream.
+	 */
+	FORCEINLINE void writeDoubleBE(double value) {
+		uint64 n;
+
+		memcpy(&n, &value, 8);
+
+		writeUint64BE(n);
+	}
+
+	/**
 	 * Write the given string to the stream.
 	 * This writes str.size() characters, but no terminating zero byte.
 	 */
@@ -474,6 +499,39 @@ public:
 		return f;
 	}
 
+
+	/**
+	 * Read a 64-bit floating point value stored in little endian (LSB first)
+	 * order from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE double readDoubleLE() {
+		uint64 n = readUint64LE();
+		double d;
+
+		memcpy(&d, &n, 8);
+
+		return d;
+	}
+
+	/**
+	 * Read a 64-bit floating point value stored in big endian
+	 * order from the stream and return it.
+	 * Performs no error checking. The return value is undefined
+	 * if a read error occurred (for which client code can check by
+	 * calling err() and eos() ).
+	 */
+	FORCEINLINE double readDoubleBE() {
+		uint64 n = readUint64BE();
+		double d;
+
+		memcpy(&d, &n, 8);
+
+		return d;
+	}
+
 	/**
 	 * Read the specified amount of data into a malloc'ed buffer
 	 * which then is wrapped into a MemoryReadStream.


Commit: 531aa8392e40458d52f22edef71abf3506ca63da
    https://github.com/scummvm/scummvm/commit/531aa8392e40458d52f22edef71abf3506ca63da
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add engine for Versailles 1685

Changed paths:
  A engines/cryomni3d/configure.engine
  A engines/cryomni3d/cryomni3d.cpp
  A engines/cryomni3d/cryomni3d.h
  A engines/cryomni3d/detection.cpp
  A engines/cryomni3d/detection_tables.h
  A engines/cryomni3d/dialogs_manager.cpp
  A engines/cryomni3d/dialogs_manager.h
  A engines/cryomni3d/fixed_image.cpp
  A engines/cryomni3d/fixed_image.h
  A engines/cryomni3d/font_manager.cpp
  A engines/cryomni3d/font_manager.h
  A engines/cryomni3d/image/codecs/hlz.cpp
  A engines/cryomni3d/image/codecs/hlz.h
  A engines/cryomni3d/image/hlz.cpp
  A engines/cryomni3d/image/hlz.h
  A engines/cryomni3d/module.mk
  A engines/cryomni3d/mouse_boxes.cpp
  A engines/cryomni3d/mouse_boxes.h
  A engines/cryomni3d/objects.cpp
  A engines/cryomni3d/objects.h
  A engines/cryomni3d/omni3d.cpp
  A engines/cryomni3d/omni3d.h
  A engines/cryomni3d/sprites.cpp
  A engines/cryomni3d/sprites.h
  A engines/cryomni3d/versailles/data.cpp
  A engines/cryomni3d/versailles/dialogs.cpp
  A engines/cryomni3d/versailles/dialogs_manager.cpp
  A engines/cryomni3d/versailles/dialogs_manager.h
  A engines/cryomni3d/versailles/documentation.cpp
  A engines/cryomni3d/versailles/documentation.h
  A engines/cryomni3d/versailles/engine.cpp
  A engines/cryomni3d/versailles/engine.h
  A engines/cryomni3d/versailles/logic.cpp
  A engines/cryomni3d/versailles/menus.cpp
  A engines/cryomni3d/versailles/music.cpp
  A engines/cryomni3d/versailles/saveload.cpp
  A engines/cryomni3d/versailles/toolbar.cpp
  A engines/cryomni3d/versailles/toolbar.h
  A engines/cryomni3d/video/hnm_decoder.cpp
  A engines/cryomni3d/video/hnm_decoder.h
  A engines/cryomni3d/wam_parser.cpp
  A engines/cryomni3d/wam_parser.h


diff --git a/engines/cryomni3d/configure.engine b/engines/cryomni3d/configure.engine
new file mode 100644
index 0000000..eac62b6
--- /dev/null
+++ b/engines/cryomni3d/configure.engine
@@ -0,0 +1,4 @@
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine cryomni3d "Cryo Omni3D games" no "versailles" "" "highres"
+add_engine versailles "Versailles 1685" no
+
diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
new file mode 100644
index 0000000..49347a2
--- /dev/null
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -0,0 +1,411 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/error.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "common/translation.h"
+#include "common/debug-channels.h"
+
+#include "common/events.h"
+#include "common/file.h"
+
+#include "audio/mixer.h"
+#include "graphics/palette.h"
+
+#include "cryomni3d/cryomni3d.h"
+
+#include "cryomni3d/image/hlz.h"
+#include "cryomni3d/video/hnm_decoder.h"
+
+#include <stdarg.h> // For va_list etc.
+
+namespace CryOmni3D {
+
+CryOmni3DEngine::CryOmni3DEngine(OSystem *syst,
+                                 const CryOmni3DGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc),
+	_fontManager(), _sprites(), _dragStatus(kDragStatus_NoDrag), _autoRepeatNextEvent(-1u) {
+	if (!_mixer->isReady()) {
+		error("Sound initialization failed");
+	}
+
+	// Setup mixer
+	syncSoundSettings();
+
+	unlockPalette();
+
+	DebugMan.addDebugChannel(kDebugFile, "File", "Track File Accesses");
+	DebugMan.addDebugChannel(kDebugVariable, "Variable", "Track Variable Accesses");
+	DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function");
+}
+
+CryOmni3DEngine::~CryOmni3DEngine() {
+	DebugMan.clearAllDebugChannels();
+}
+
+Common::Error CryOmni3DEngine::run() {
+	return Common::kNoError;
+}
+
+void CryOmni3DEngine::pauseEngineIntern(bool pause) {
+	Engine::pauseEngineIntern(pause);
+
+	/*
+	if (pause) {
+	    _video->pauseVideos();
+	} else {
+	    _video->resumeVideos();
+	    _system->updateScreen();
+	}
+	*/
+}
+
+void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::SoundType soundType) {
+	Common::String fname(filename);
+
+	Video::VideoDecoder *videoDecoder = new Video::HNMDecoder();
+	videoDecoder->setSoundType(soundType);
+
+	int lastDotPos = fname.size() - 1;
+	for (; lastDotPos >= 0; --lastDotPos) {
+		if (fname[lastDotPos] == '.') {
+			break;
+		}
+	}
+	if (lastDotPos > -1) {
+		fname.erase(lastDotPos);
+	} else {
+		lastDotPos = fname.size();
+	}
+	fname += ".hnm";
+
+	if (!Common::File::exists(fname)) {
+		fname.erase(lastDotPos);
+		fname += ".hns";
+	}
+
+	if (!videoDecoder->loadFile(fname)) {
+		warning("Failed to open movie file %s/%s", filename.c_str(), fname.c_str());
+		delete videoDecoder;
+		return;
+	}
+
+	videoDecoder->start();
+
+	uint16 width = videoDecoder->getWidth();
+	uint16 height = videoDecoder->getHeight();
+
+	bool skipVideo = false;
+	while (!g_engine->shouldQuit() && !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);
+				}
+
+				// TODO: beforeDraw
+				g_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, width, height);
+				// TODO: afterDraw
+
+			}
+		}
+		g_system->updateScreen();
+
+		if (pollEvents() && checkKeysPressed()) {
+			skipVideo = true;
+		}
+	}
+
+	delete videoDecoder;
+}
+
+Image::ImageDecoder *CryOmni3DEngine::loadHLZ(const Common::String &filename) {
+	Common::String fname(filename);
+
+	Image::ImageDecoder *imageDecoder = new Image::HLZFileDecoder();
+
+	Common::File file;
+
+	int lastDotPos = fname.size() - 1;
+	for (; lastDotPos >= 0; --lastDotPos) {
+		if (fname[lastDotPos] == '.') {
+			break;
+		}
+	}
+	if (lastDotPos > -1) {
+		fname.erase(lastDotPos);
+	}
+	fname += ".hlz";
+
+	if (!file.open(fname)) {
+		warning("Failed to open hlz file %s/%s", filename.c_str(), fname.c_str());
+		return nullptr;
+	}
+
+	if (!imageDecoder->loadStream(file)) {
+		warning("Failed to open hlz file %s", fname.c_str());
+		delete imageDecoder;
+		imageDecoder = 0;
+		return nullptr;
+	}
+
+	return imageDecoder;
+}
+
+void CryOmni3DEngine::displayHLZ(const Common::String &filename) {
+	Image::ImageDecoder *imageDecoder = loadHLZ(filename);
+
+	if (!imageDecoder) {
+		return;
+	}
+
+	if (imageDecoder->hasPalette()) {
+		const byte *palette = imageDecoder->getPalette();
+		setPalette(palette, imageDecoder->getPaletteStartIndex(), imageDecoder->getPaletteColorCount());
+	}
+
+	const Graphics::Surface *frame = imageDecoder->getSurface();
+	g_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+	g_system->updateScreen();
+
+	bool exitImg = false;
+	while (!g_engine->shouldQuit() && !exitImg) {
+		if (pollEvents()) {
+			if (checkKeysPressed(1, Common::KEYCODE_ESCAPE) || getCurrentMouseButton() == 1) {
+				exitImg = true;
+			}
+		}
+		g_system->updateScreen();
+	}
+
+	delete imageDecoder;
+}
+
+void CryOmni3DEngine::setCursor(const Graphics::Cursor &cursor) const {
+	g_system->setMouseCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(),
+	                         cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor());
+}
+
+void CryOmni3DEngine::setCursor(unsigned int cursorId) const {
+	const Graphics::Cursor &cursor = _sprites.getCursor(cursorId);
+	g_system->setMouseCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(),
+	                         cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor());
+}
+
+bool CryOmni3DEngine::pollEvents() {
+	Common::Event event;
+	bool hasEvents = false;
+
+	unsigned int oldMouseButton = getCurrentMouseButton();
+
+	while (g_system->getEventManager()->pollEvent(event)) {
+		if (event.type == Common::EVENT_KEYDOWN) {
+			_keysPressed.push(event.kbd);
+		}
+		hasEvents = true;
+	}
+	g_system->delayMillis(10);
+
+	_dragStatus = kDragStatus_NoDrag;
+	unsigned int 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 != -1u) {
+				// 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 = -1;
+		}
+	}
+	// Else we weren't dragging and still aren't
+
+	return hasEvents;
+}
+
+void CryOmni3DEngine::setAutoRepeatClick(unsigned int millis) {
+	_autoRepeatNextEvent = g_system->getMillis() + millis;
+}
+
+unsigned int CryOmni3DEngine::getCurrentMouseButton() {
+	int mask = g_system->getEventManager()->getButtonState();
+	if (mask & 0x1) {
+		return 1;
+	} else if (mask & 0x2) {
+		return 2;
+	} else {
+		return 0;
+	}
+}
+
+void CryOmni3DEngine::waitMouseRelease() {
+	while (g_system->getEventManager()->getButtonState() != 0 && !g_engine->shouldQuit()) {
+		pollEvents();
+	}
+}
+
+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(unsigned int numKeys, ...) {
+	bool found = false;
+	Common::KeyCode kc = getNextKey().keycode;
+	while (!found && kc != Common::KEYCODE_INVALID) {
+		va_list va;
+		va_start(va, numKeys);
+		for (unsigned int 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) {
+	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 (unsigned int i = 0; i < 256 * 3; i++) {
+		palWork[i] = palOut[i] << 8;
+		delta[i] = palWork[i] / 25;
+	}
+
+	for (unsigned int step = 0; step < 25 && !g_engine->shouldQuit(); step++) {
+		for (unsigned int i = 0; i < 256 * 3; i++) {
+			palWork[i] -= delta[i];
+			palOut[i] = palWork[i] >> 8;
+		}
+		setPalette(palOut, 0, 256);
+		g_system->updateScreen();
+		g_system->delayMillis(50);
+	}
+	setBlackPalette();
+}
+
+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 (unsigned int i = 0; i < 256 * 3; i++) {
+		delta[i] = (palette[i] << 8) / 25;
+	}
+
+	setBlackPalette();
+	for (unsigned int step = 0; step < 25 && !g_engine->shouldQuit(); step++) {
+		for (unsigned int i = 0; i < 256 * 3; i++) {
+			palWork[i] += delta[i];
+			palOut[i] = palWork[i] >> 8;
+		}
+		setPalette(palOut, 0, 256);
+		g_system->updateScreen();
+		g_system->delayMillis(50);
+	}
+	setPalette(palette, 0, 256);
+	g_system->updateScreen();
+}
+
+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();
+}
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
new file mode 100644
index 0000000..0220001
--- /dev/null
+++ b/engines/cryomni3d/cryomni3d.h
@@ -0,0 +1,164 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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 "font_manager.h"
+#include "objects.h"
+#include "sprites.h"
+
+class OSystem;
+
+namespace Common {
+class 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 {
+
+enum CryOmni3DGameType {
+	GType_VERSAILLES
+};
+
+struct CryOmni3DGameDescription;
+
+// Engine Debug Flags
+enum {
+	kDebugFile     = (1 << 0),
+	kDebugVariable = (1 << 1),
+	kDebugSaveLoad = (1 << 2)
+};
+
+enum DragStatus {
+	kDragStatus_NoDrag = 0,
+	kDragStatus_Pressed,
+	kDragStatus_Finished,
+	kDragStatus_Dragging
+};
+
+class CryOmni3DEngine : public ::Engine {
+protected:
+	virtual Common::Error run();
+
+public:
+	CryOmni3DEngine(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
+	virtual ~CryOmni3DEngine();
+
+	// Detection related functions
+	const CryOmni3DGameDescription *_gameDescription;
+	const char *getGameId() const;
+	uint32 getFeatures() const;
+	const char *getAppName() const;
+	uint16 getVersion() const;
+	Common::Platform getPlatform() const;
+	uint8 getGameType() const;
+	Common::Language getLanguage() const;
+
+	bool hasFeature(EngineFeature f) const;
+
+private:
+	void pauseEngineIntern(bool);
+
+public:
+	Image::ImageDecoder *loadHLZ(const Common::String &filename);
+
+	void fillSurface(byte color);
+	void setCursor(const Graphics::Cursor &cursor) const;
+	void setCursor(unsigned int cursorId) const;
+	void playHNM(const Common::String &filename,
+	             Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
+	void displayHLZ(const Common::String &filename);
+
+	bool pollEvents();
+	Common::Point getMousePos();
+	void setMousePos(const Common::Point &point);
+	unsigned int getCurrentMouseButton();
+	Common::KeyState getNextKey();
+	bool checkKeysPressed();
+	bool checkKeysPressed(unsigned int numKeys, ...);
+	void clearKeys() { _keysPressed.clear(); }
+	void waitMouseRelease();
+	void setAutoRepeatClick(unsigned int millis);
+	DragStatus getDragStatus() { return _dragStatus; }
+
+	virtual bool displayToolbar(const Graphics::Surface *original) = 0;
+	virtual bool hasPlaceDocumentation() = 0;
+	virtual bool displayPlaceDocumentation() = 0;
+	virtual unsigned int 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:
+	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();
+
+protected:
+	FontManager _fontManager;
+	Sprites _sprites;
+	Objects _objects;
+	Inventory _inventory;
+
+	Common::Queue<Common::KeyState> _keysPressed;
+
+	DragStatus _dragStatus;
+	Common::Point _dragStart;
+	unsigned int _autoRepeatNextEvent;
+
+private:
+	unsigned int _lockPaletteStartRW;
+	unsigned int _lockPaletteEndRW;
+};
+
+} // End of namespace CryOmni3D
+
+#endif
diff --git a/engines/cryomni3d/detection.cpp b/engines/cryomni3d/detection.cpp
new file mode 100644
index 0000000..62bdebd
--- /dev/null
+++ b/engines/cryomni3d/detection.cpp
@@ -0,0 +1,255 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "base/plugins.h"
+
+#include "engines/advancedDetector.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
+
+namespace CryOmni3D {
+
+struct CryOmni3DGameDescription {
+	ADGameDescription desc;
+
+	uint8 gameType;
+	uint32 features;
+	const char *appName;
+};
+
+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;
+}
+
+const char *CryOmni3DEngine::getAppName() const {
+	return _gameDescription->appName;
+}
+
+uint8 CryOmni3DEngine::getGameType() const {
+	return _gameDescription->gameType;
+}
+
+Common::Language CryOmni3DEngine::getLanguage() const {
+	return _gameDescription->desc.language;
+}
+
+bool CryOmni3DEngine::hasFeature(EngineFeature f) const {
+	return false;
+//		(f == kSupportsRTL);
+}
+
+/*
+#ifdef ENABLE_MYST
+
+bool MohawkEngine_Myst::hasFeature(EngineFeature f) const {
+    return
+        MohawkEngine::hasFeature(f)
+        || (f == kSupportsLoadingDuringRuntime)
+        || (f == kSupportsSavingDuringRuntime);
+}
+
+#endif
+*/
+
+} // End of Namespace CryOmni3D
+
+static const PlainGameDescriptor cryomni3DGames[] = {
+	{"versailles", "Versailles 1685"},
+	{0, 0}
+};
+
+#include "cryomni3d/detection_tables.h"
+
+/*
+static const char *directoryGlobs[] = {
+    "all",
+    "assets1",
+    "data",
+    "program",
+    "95instal",
+    "Rugrats Adventure Game",
+    0
+};
+*/
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+	/*{
+	        GAMEOPTION_PLAY_MYST_FLYBY,
+	        {
+	                _s("Play the Myst fly by movie"),
+	                _s("The Myst fly by movie was not played by the original engine."),
+	                "playmystflyby",
+	                false
+	        }
+	},*/
+
+	AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+class CryOmni3DMetaEngine : public AdvancedMetaEngine {
+public:
+	CryOmni3DMetaEngine() : AdvancedMetaEngine(CryOmni3D::gameDescriptions,
+		        sizeof(CryOmni3D::CryOmni3DGameDescription), cryomni3DGames, optionsList) {
+		//_singleId = "cryomni3d";
+		_maxScanDepth = 2;
+		//_directoryGlobs = directoryGlobs;
+	}
+
+	ADDetectedGame fallbackDetect(const FileMap &allFiles,
+	                              const Common::FSList &fslist) const override {
+		return detectGameFilebased(allFiles, fslist, CryOmni3D::fileBased);
+	}
+
+	virtual const char *getName() const {
+		return "Cryo Omni3D";
+	}
+
+	virtual const char *getOriginalCopyright() const {
+		return "Cryo game Engine (C) 1997-2002 Cryo Interactive";
+	}
+
+	virtual bool hasFeature(MetaEngineFeature f) const;
+	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+	virtual SaveStateList listSaves(const char *target) const;
+	SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const;
+	virtual int getMaximumSaveSlot() const { return 999; }
+	virtual void removeSaveState(const char *target, int slot) const;
+	virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool CryOmni3DMetaEngine::hasFeature(MetaEngineFeature f) const {
+	return
+	    (f == kSupportsListSaves)
+	    || (f == kSupportsLoadingDuringStartup)
+	    || (f == kSupportsDeleteSave)
+	    || (f == kSavesSupportMetaInfo)
+	    || (f == kSavesSupportThumbnail)
+	    || (f == kSavesSupportCreationDate)
+	    || (f == kSavesSupportPlayTime);
+}
+
+SaveStateList CryOmni3DMetaEngine::listSavesForPrefix(const char *prefix,
+        const char *extension) const {
+	Common::String pattern = Common::String::format("%s-###.%s", prefix, extension);
+	Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
+	size_t prefixLen = strlen(prefix);
+
+	SaveStateList saveList;
+	for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end();
+	        ++filename) {
+		// Extract the slot number from the filename
+		char slot[4];
+		slot[0] = (*filename)[prefixLen + 1];
+		slot[1] = (*filename)[prefixLen + 2];
+		slot[2] = (*filename)[prefixLen + 3];
+		slot[3] = '\0';
+
+		int slotNum = atoi(slot);
+
+		saveList.push_back(SaveStateDescriptor(slotNum, ""));
+	}
+
+	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+
+	return saveList;
+}
+
+SaveStateList CryOmni3DMetaEngine::listSaves(const char *target) const {
+	SaveStateList saveList;
+
+	/*
+	// Loading games is only supported in Myst/Riven currently.
+	saveList = listSavesForPrefix("myst", "mys");
+
+	for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+	    // Read the description from the save
+	    int slot = save->getSaveSlot();
+	    Common::String description = Mohawk::MystGameState::querySaveDescription(slot);
+	    save->setDescription(description);
+	}
+	*/
+
+	return saveList;
+}
+
+void CryOmni3DMetaEngine::removeSaveState(const char *target, int slot) const {
+
+	/*
+	// Removing saved games is only supported in Myst/Riven currently.
+	if (strstr(target, "myst")) {
+	    Mohawk::MystGameState::deleteSave(slot);
+	}
+	*/
+}
+
+SaveStateDescriptor CryOmni3DMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+	/*
+	if (strstr(target, "myst")) {
+	    return Mohawk::MystGameState::querySaveMetaInfos(slot);
+	}
+	*/
+	return SaveStateDescriptor();
+}
+
+bool CryOmni3DMetaEngine::createInstance(OSystem *syst, Engine **engine,
+        const ADGameDescription *desc) const {
+	const CryOmni3D::CryOmni3DGameDescription *gd = (const CryOmni3D::CryOmni3DGameDescription *)desc;
+
+	if (gd) {
+		switch (gd->gameType) {
+		case CryOmni3D::GType_VERSAILLES:
+#ifdef ENABLE_VERSAILLES
+			*engine = new CryOmni3D::Versailles::CryOmni3DEngine_Versailles(syst, gd);
+			break;
+#else
+			warning("Versailles support not compiled in");
+			return false;
+#endif
+		default:
+			error("Unknown Cryo Omni3D Engine");
+		}
+	}
+
+	return (gd != 0);
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(CRYOMNI3D)
+	REGISTER_PLUGIN_DYNAMIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
+#else
+	REGISTER_PLUGIN_STATIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
+#endif
diff --git a/engines/cryomni3d/detection_tables.h b/engines/cryomni3d/detection_tables.h
new file mode 100644
index 0000000..49a7cb0
--- /dev/null
+++ b/engines/cryomni3d/detection_tables.h
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+namespace CryOmni3D {
+
+//#define GAMEOPTION_PLAY_MYST_FLYBY         GUIO_GAMEOPTIONS1
+
+//#define GUI_OPTIONS_MYST                   GUIO3(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI)
+
+static const CryOmni3DGameDescription gameDescriptions[] = {
+	// Versailles 1685
+	// French Windows 95
+	// From lePhilousophe
+	{
+		{
+			"versailles",
+			"",
+			AD_ENTRY1s("VERSAILL.EXE", "3775004b96f056716ce615b458b1f394", 372736),
+			Common::FR_FRA,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE,
+			GUIO1(GUIO_NOASPECT)
+		},
+		GType_VERSAILLES,
+		0,
+		0,
+	},
+
+	// Versailles 1685
+	// French Windows 95 compressed
+	// From lePhilousophe
+	{
+		{
+			"versailles",
+			"",
+			AD_ENTRY1s("PROGRAM.Z", "a07b5d86af5f3a8883ba97db2bade87d", 293223),
+			Common::FR_FRA,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE,
+			GUIO1(GUIO_NOASPECT)
+		},
+		GType_VERSAILLES,
+		0,
+		0,
+	},
+
+	// Versailles 1685
+	// French DOS
+	// From lePhilousophe
+	{
+		{
+			"versailles",
+			"",
+			AD_ENTRY1s("VERSAILL.PGM", "1c992f034f43418a5da2e8ebd0b92620", 630431),
+			Common::FR_FRA,
+			Common::kPlatformDOS,
+			ADGF_UNSTABLE,
+			GUIO1(GUIO_NOASPECT)
+		},
+		GType_VERSAILLES,
+		0,
+		0,
+	},
+
+	{ AD_TABLE_END_MARKER, 0, 0, 0 }
+};
+
+//////////////////////////////
+//Fallback detection
+//////////////////////////////
+
+static const CryOmni3DGameDescription fallbackDescs[] = {
+	{
+		{
+			"versailles",
+			"unknown",
+			AD_ENTRY1(0, 0),
+			Common::UNK_LANG,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE,
+			GUIO1(GUIO_NOASPECT)
+		},
+		GType_VERSAILLES,
+		0,
+		0
+	},
+};
+
+static const ADFileBasedFallback fileBased[] = {
+	{ &fallbackDescs[0].desc,  { "VERSAILL.EXE", 0 } },
+	{ &fallbackDescs[0].desc,  { "VERSAILL.PGM", 0 } },
+	{ 0, { 0 } }
+};
+
+} // End of Namespace CryOmni3D
diff --git a/engines/cryomni3d/dialogs_manager.cpp b/engines/cryomni3d/dialogs_manager.cpp
new file mode 100644
index 0000000..6c1c2ac
--- /dev/null
+++ b/engines/cryomni3d/dialogs_manager.cpp
@@ -0,0 +1,555 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cryomni3d/dialogs_manager.h"
+
+#include "common/debug.h"
+#include "common/file.h"
+
+namespace CryOmni3D {
+
+DialogsManager::~DialogsManager() {
+	delete[] _gtoBuffer;
+}
+
+void DialogsManager::loadGTO(const Common::String &gtoFileName) {
+	Common::File gtoFile;
+	if (!gtoFile.open(gtoFileName)) {
+		error("Can't open GTO file '%s'", gtoFileName.c_str());
+	}
+
+	_labels.clear();
+	_gtoEnd = nullptr;
+	delete[] _gtoBuffer;
+	_gtoBuffer = nullptr;
+
+	unsigned int 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 */
+	unsigned int 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 {
+	unsigned int 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 {
+	unsigned int 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 nullptr;
+	}
+
+	// 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;
+	}
+
+	unsigned int 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;
+	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);
+		}
+		Common::Array<DialogsManager::Goto> 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));
+		}
+		unsigned int eocInserted = -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
+			unsigned int playerChoice = askPlayerQuestions(video, questions);
+			didSomething = true;
+			// -1 when shouldQuit
+			if (playerChoice == -1u || 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
diff --git a/engines/cryomni3d/dialogs_manager.h b/engines/cryomni3d/dialogs_manager.h
new file mode 100644
index 0000000..ce84dcd
--- /dev/null
+++ b/engines/cryomni3d/dialogs_manager.h
@@ -0,0 +1,132 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_DIALOGS_MANAGER_H
+#define CRYOMNI3D_DIALOGS_MANAGER_H
+
+#include "common/array.h"
+#include "common/hash-str.h"
+#include "common/hashmap.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(unsigned int size, const Common::String &endOfConversationText) { _dialogsVariables.resize(size); _endOfConversationText = endOfConversationText; }
+	void loadGTO(const Common::String &gtoFile);
+
+	void setupVariable(unsigned int id, const Common::String &variable) { _dialogsVariables[id] = DialogVariable(variable, 'N'); }
+	void reinitVariables();
+	unsigned int size() const { return _dialogsVariables.size(); }
+	byte &operator[](unsigned int idx) { return _dialogsVariables[idx].value; }
+	const byte &operator[](unsigned int 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);
+
+	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 unsigned int 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
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
new file mode 100644
index 0000000..fa2b4a2
--- /dev/null
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -0,0 +1,308 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/cryomni3d/fixed_image.h"
+
+#include "common/file.h"
+#include "common/system.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) {
+}
+
+ZonFixedImage::~ZonFixedImage() {
+	delete _imageDecoder;
+}
+
+void ZonFixedImage::run(const Common::Functor1<ZonFixedImage *, void> *callback) {
+	_exit = false;
+	_zonesMode = kZonesMode_None;
+
+	_callback = callback;
+
+	g_system->showMouse(true);
+	while (!_exit) {
+		(*_callback)(this);
+	}
+	_engine.waitMouseRelease();
+	g_system->showMouse(false);
+
+	// Deselect object
+	_inventory.setSelectedObject(nullptr);
+
+	delete _callback;
+	_callback = nullptr;
+}
+
+void ZonFixedImage::load(const Common::String &image) {
+	_imageSurface = nullptr;
+	delete _imageDecoder;
+	_imageDecoder = nullptr;
+
+	_imageDecoder = _engine.loadHLZ(image);
+	if (!_imageDecoder) {
+		error("Can't display fixed image");
+	}
+	_imageSurface = _imageDecoder->getSurface();
+
+	loadZones(image);
+#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
+	g_system->showMouse(false);
+	g_system->updateScreen();
+	_engine.waitMouseRelease();
+	g_system->showMouse(true);
+}
+
+void ZonFixedImage::display() const {
+	_engine.setupPalette(_imageDecoder->getPalette(), _imageDecoder->getPaletteStartIndex(),
+	                     _imageDecoder->getPaletteColorCount());
+
+	g_system->copyRectToScreen(_imageSurface->getPixels(), _imageSurface->pitch, 0, 0,
+	                           _imageSurface->w, _imageSurface->h);
+	g_system->updateScreen();
+}
+
+void ZonFixedImage::loadZones(const Common::String &image) {
+	_zones.clear();
+
+	Common::String fname(image);
+
+	int lastDotPos = fname.size() - 1;
+	for (; lastDotPos >= 0; --lastDotPos) {
+		if (fname[lastDotPos] == '.') {
+			break;
+		}
+	}
+	if (lastDotPos > -1) {
+		fname.erase(lastDotPos);
+		fname += ".zon";
+	}
+
+	Common::File zonFile;
+	if (!zonFile.open(fname)) {
+		error("Can't open ZON file '%s'", fname.c_str());
+	}
+
+	int32 zonesNumber = zonFile.size() / 26;
+	_zones.reserve(zonesNumber);
+
+	_highLeftId = -1;
+	_highRightId = -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(unsigned int 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 = -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;
+
+	// Force poll events even when we must refresh the cursor
+	if (!_engine.pollEvents() && !_refreshCursor) {
+		g_system->updateScreen();
+		// TODO: countdown even when no events
+		return;
+	}
+	_refreshCursor = false;
+
+	// Feed the key for the caller
+	_key = _engine.getNextKey();
+	Common::Point mousePos = _engine.getMousePos();
+
+	if (_key == Common::KEYCODE_ESCAPE) {
+		_exit = true;
+		return;
+	} else if (_engine.shouldAbort()) {
+		_exit = true;
+		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;
+		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 = -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());
+		}
+
+	}
+
+	// TODO: handle countdown
+	g_system->updateScreen();
+}
+
+void ZonFixedImage::handleMouseZones(const Common::Array<Zone>::const_iterator &currentZone) {
+	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);
+	}
+}
+
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
new file mode 100644
index 0000000..5690788
--- /dev/null
+++ b/engines/cryomni3d/fixed_image.h
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_FIXED_IMAGE_H
+#define CRYOMNI3D_FIXED_IMAGE_H
+
+#include "common/func.h"
+
+#include "engines/cryomni3d/cryomni3d.h"
+#include "engines/cryomni3d/objects.h"
+
+namespace Graphics {
+class Surface;
+}
+
+namespace CryOmni3D {
+
+struct FixedImageConfiguration {
+	unsigned int spriteNothing;
+	unsigned int spriteLow;
+	unsigned int spriteHigh;
+	unsigned int spriteLeft;
+	unsigned int spriteRight;
+	unsigned int spriteQuestion;
+	unsigned int spriteListen;
+	unsigned int spriteSee;
+	unsigned int spriteUse;
+	unsigned int 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::String &image);
+	void manage();
+	const Graphics::Surface *surface() const { return _imageSurface; }
+	void changeCallback(CallbackFunctor *callback) { delete _callback; _callback = callback; }
+	Common::Point getZoneCenter(unsigned int zoneId) const;
+
+	ZonesMode _zonesMode;
+
+	/* These attributes are read by the image handler to check what action player did */
+	unsigned int _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 Common::Functor1<ZonFixedImage *, void> *_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::String &image);
+	void handleMouseZones(const Common::Array<Zone>::const_iterator &currentZone);
+
+	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
diff --git a/engines/cryomni3d/font_manager.cpp b/engines/cryomni3d/font_manager.cpp
new file mode 100644
index 0000000..0b3b1a5
--- /dev/null
+++ b/engines/cryomni3d/font_manager.cpp
@@ -0,0 +1,340 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "graphics/managed_surface.h"
+
+#include "engines/cryomni3d/font_manager.h"
+
+namespace CryOmni3D {
+
+FontManager::FontManager() : _currentFont(nullptr), _transparentBackground(false),
+	_spaceWidth(0), _charSpacing(0), _lineHeight(30), _foreColor(0), _blockTextRemaining(nullptr) {
+}
+
+FontManager::~FontManager() {
+	for (Common::Array<Font *>::iterator it = _fonts.begin(); it != _fonts.end(); it++) {
+		delete *it;
+	}
+}
+
+void FontManager::loadFonts(const Common::Array<Common::String> &fontFiles) {
+	_fonts.reserve(_fonts.size() + fontFiles.size());
+
+	for (Common::Array<Common::String>::const_iterator it = fontFiles.begin(); it != fontFiles.end();
+	        it++) {
+		Common::File font_fl;
+		//debug("Open font file %s", it->c_str());
+		if (!font_fl.open(*it)) {
+			error("Can't open file %s", it->c_str());
+		}
+		loadFont(font_fl);
+	}
+}
+
+void FontManager::loadFont(Common::ReadStream &font_fl) {
+	byte magic[8];
+
+	font_fl.read(magic, sizeof(magic));
+	if (memcmp(magic, "CRYOFONT", 8)) {
+		error("Invalid font magic");
+	}
+
+	// 3 unknown uint16
+	font_fl.readUint16BE();
+	font_fl.readUint16BE();
+	font_fl.readUint16BE();
+
+	Font *font = new Font();
+
+	font->maxHeight = font_fl.readSint16BE();
+	//debug("Max char height %d", font.maxHeight);
+
+	font_fl.read(font->comment, sizeof(font->comment));
+	//debug("Comment %s", font.comment);
+
+	for (unsigned int i = 0; i < Font::kCharactersCount; i++) {
+		uint16 h = font_fl.readUint16BE();
+		uint16 w = font_fl.readUint16BE();
+		unsigned int sz = font->chars[i].setup(w, h);
+		//debug("Char %d sz %dx%d %d", i, w, h, sz);
+		font->chars[i].offX = font_fl.readSint16BE();
+		font->chars[i].offY = font_fl.readSint16BE();
+		font->chars[i].printedWidth = font_fl.readUint16BE();
+		//debug("Char %d offX %d offY %d PW %d", i, font.chars[i].offX, font.chars[i].offY, font.chars[i].printedWidth);
+
+		font_fl.read(font->chars[i].data, sz);
+		//debug("Char %d read %d", i, v);
+	}
+
+	_fonts.push_back(font);
+}
+
+void FontManager::setCurrentFont(int currentFont) {
+	if (currentFont == -1) {
+		currentFont = 0;
+	}
+	_currentFontId = currentFont;
+	_currentFont = _fonts[currentFont];
+
+	setSpaceWidth(0);
+}
+
+void FontManager::setSpaceWidth(unsigned int additionalSpace) {
+	if (_currentFont) {
+		_spaceWidth = additionalSpace + _currentFont->chars[0].printedWidth;
+	} else {
+		_spaceWidth = 0;
+	}
+}
+
+unsigned int FontManager::displayStr_(unsigned int x, unsigned int y,
+                                      const Common::String &text) const {
+	unsigned int offset = 0;
+	for (Common::String::const_iterator it = text.begin(); it != text.end(); it++) {
+		offset += displayChar(x + offset, y, *it);
+	}
+	return offset;
+}
+
+unsigned int FontManager::displayChar(unsigned int x, unsigned int y, unsigned char c) const {
+	if (!_currentFont) {
+		error("There is no current font");
+	}
+	if (!_currentSurface) {
+		error("There is no current surface");
+	}
+
+	if (c < ' ' || c >= 255) {
+		c = '?';
+	}
+	c -= 32;
+
+	const Character &char_ = _currentFont->chars[c];
+	int realX = x + char_.offX;
+	int realY = y + char_.offY + _currentFont->maxHeight - 2;
+
+	if (!_transparentBackground) {
+		_currentSurface->fillRect(Common::Rect(realX, realY, realX + char_.w, realY + char_.h), 0xff);
+	}
+	Graphics::Surface src;
+	src.init(char_.w, char_.h, char_.w, char_.data, Graphics::PixelFormat::createFormatCLUT8());
+	_currentSurface->transBlitFrom(src, Common::Point(realX, realY), 0, false, _foreColor);
+
+	// WORKAROUND: in Versailles game the space width is calculated differently in this function and in the getStrWidth one, let's try to be consistent
+#define KEEP_SPACE_BUG
+#ifndef KEEP_SPACE_BUG
+	if (c == 0) {
+		return _spaceWidth;
+	} else {
+		return _charSpacing + char_.printedWidth;
+	}
+#else
+	return _charSpacing + char_.printedWidth;
+#endif
+}
+
+unsigned int FontManager::getStrWidth(const Common::String &text) const {
+	unsigned int width = 0;
+	for (Common::String::const_iterator it = text.begin(); it != text.end(); it++) {
+		unsigned char c = *it;
+		if (c == ' ') {
+			width += _spaceWidth;
+		} else {
+			if (c < ' ' || c >= 255) {
+				c = '?';
+			}
+			c -= 32;
+			width += _charSpacing;
+			width += _currentFont->chars[c].printedWidth;
+		}
+	}
+	return width;
+}
+
+bool FontManager::displayBlockText(const Common::String &text,
+                                   Common::String::const_iterator begin) {
+	bool notEnoughSpace = false;
+	Common::String::const_iterator ptr = begin;
+	Common::Array<Common::String> words;
+
+	if (begin != text.end()) {
+		_blockTextRemaining = nullptr;
+		while (ptr != text.end() && !notEnoughSpace) {
+			unsigned int finalPos;
+			bool has_cr;
+			calculateWordWrap(text, &ptr, &finalPos, &has_cr, words);
+			unsigned int spacesWidth = (words.size() - 1) * _spaceWidth;
+			unsigned int remainingSpace = (_blockRect.right - finalPos);
+			unsigned int spaceConsumed = 0;
+			double spaceWidthPerWord;
+			if (words.size() == 1) {
+				spaceWidthPerWord = _spaceWidth;
+			} else {
+				spaceWidthPerWord = (double)spacesWidth / (double)words.size();
+			}
+			Common::Array<Common::String>::const_iterator word;
+			unsigned int 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 += sp;
+					spaceConsumed += sp;
+					remainingSpace -= sp;
+				}
+			}
+			if (_blockPos.y + _lineHeight + getFontMaxHeight() >= _blockRect.bottom) {
+				notEnoughSpace = true;
+				_blockTextRemaining = ptr;
+			} else {
+				_blockPos.x = _blockRect.left;
+				_blockPos.y += _lineHeight;
+			}
+		}
+	}
+	return notEnoughSpace;
+}
+
+unsigned int FontManager::getLinesCount(const Common::String &text, unsigned int 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;
+	}
+
+	unsigned int lineCount = 0;
+	Common::String::const_iterator textP = text.begin();
+	unsigned int len = text.size();
+
+	while (len > 0) {
+		Common::String buffer;
+		unsigned int 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
+			while (buffer.size()) {
+				if (buffer[buffer.size() - 1] == ' ') {
+					break;
+				}
+				buffer.deleteLastChar();
+				textP--;
+				len++;
+			}
+			if (!buffer.size()) {
+				// Word was too long: fail
+				return 0;
+			}
+			if (*textP == ' ') {
+				textP++;
+			}
+			// 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::String &text,
+                                    Common::String::const_iterator *position, unsigned int *finalPos, bool *hasCr,
+                                    Common::Array<Common::String> &words) const {
+	*hasCr = false;
+	unsigned int offset = 0;
+	bool wordWrap = false;
+	unsigned int lineWidth = _blockRect.right - _blockRect.left;
+	Common::String::const_iterator ptr = *position;
+
+	words.clear();
+
+	if (ptr == text.end() || *ptr == '\r') {
+		ptr++;
+		*hasCr = true;
+		*position = ptr;
+		*finalPos = offset;
+		return;
+	}
+
+	while (!wordWrap) {
+		Common::String::const_iterator begin = ptr;
+		for (; ptr != text.end() && *ptr != '\r' && *ptr != ' '; ptr++) { }
+		Common::String word(begin, ptr);
+		unsigned int width = getStrWidth(word);
+		if (width + offset >= lineWidth) {
+			wordWrap = true;
+			// word is too long: just put pointer back at begining
+			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;
+	}
+	*finalPos = offset;
+	*position = ptr;
+}
+
+FontManager::Character::Character() : h(0), w(0), offX(0), offY(0), printedWidth(0), data(0) {
+}
+
+FontManager::Character::~Character() {
+	delete[] data;
+}
+
+unsigned int FontManager::Character::setup(uint16 width, uint16 height) {
+	w = width;
+	h = height;
+	unsigned int sz = w * h;
+	data = new byte[sz];
+	return sz;
+}
+
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/font_manager.h b/engines/cryomni3d/font_manager.h
new file mode 100644
index 0000000..24b45f5
--- /dev/null
+++ b/engines/cryomni3d/font_manager.h
@@ -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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_FONT_MANAGER_H
+#define CRYOMNI3D_FONT_MANAGER_H
+
+#include "common/array.h"
+#include "common/str.h"
+#include "common/rect.h"
+
+namespace Common {
+class ReadStream;
+}
+
+namespace Graphics {
+class ManagedSurface;
+}
+
+namespace CryOmni3D {
+
+class FontManager {
+public:
+	FontManager();
+	virtual ~FontManager();
+
+	void loadFonts(const Common::Array<Common::String> &fontFiles);
+	void setCurrentFont(int currentFont);
+	unsigned int getCurrentFont() { return _currentFontId; }
+	void setTransparentBackground(bool transparent) { _transparentBackground = transparent; }
+	void setSpaceWidth(unsigned int additionalSpace);
+	void setForeColor(byte color) { _foreColor = color; }
+	void setLineHeight(int h) { _lineHeight = h; }
+	int lineHeight() { return _lineHeight; }
+	void setCharSpacing(unsigned int w) { _charSpacing = w; }
+	void setSurface(Graphics::ManagedSurface *surface) { _currentSurface = surface; }
+
+	int getFontMaxHeight() { return _currentFont->maxHeight; }
+
+	void displayInt(unsigned int x, unsigned int y, int value) const { displayStr_(x, y, Common::String::format("%d", value)); }
+	void displayStr(unsigned int x, unsigned int y, const Common::String &text) const { displayStr_(x, y, text); }
+	unsigned int getStrWidth(const Common::String &text) const;
+
+	unsigned int getLinesCount(const Common::String &text, unsigned int 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) { return displayBlockText(text, text.begin()); }
+	bool displayBlockText(const Common::String &text, Common::String::const_iterator begin);
+	Common::String::const_iterator blockTextRemaining() { return _blockTextRemaining; }
+	Common::Point blockTextLastPos() { return _blockPos; }
+
+private:
+	void loadFont(Common::ReadStream &font_fl);
+	unsigned int displayStr_(unsigned int x, unsigned int y, const Common::String &text) const;
+	unsigned int displayChar(unsigned int x, unsigned int y, unsigned char c) const;
+	void calculateWordWrap(const Common::String &text, Common::String::const_iterator *position,
+	                       unsigned int *finalPos, bool *has_br, Common::Array<Common::String> &words) const;
+
+	struct Character {
+		uint16 h;
+		uint16 w;
+		int16 offX;
+		int16 offY;
+		uint16 printedWidth;
+
+		byte *data;
+
+		Character();
+		~Character();
+
+		unsigned int setup(uint16 width, uint16 height);
+	};
+
+	struct Font {
+		static const int kCharactersCount = 223;
+
+		uint16 maxHeight;
+		byte comment[32];
+		Character chars[kCharactersCount];
+	};
+
+	Common::Array<Font *> _fonts;
+	const Font *_currentFont;
+	unsigned int _currentFontId;
+	bool _transparentBackground;
+	unsigned int _spaceWidth;
+	unsigned int _charSpacing;
+
+	byte _foreColor;
+
+	Graphics::ManagedSurface *_currentSurface;
+
+	Common::Rect _blockRect;
+	Common::Point _blockPos;
+	int _lineHeight;
+	bool _justifyText;
+	Common::String::const_iterator _blockTextRemaining;
+};
+
+} // End of namespace CryOmni3D
+
+#endif
diff --git a/engines/cryomni3d/image/codecs/hlz.cpp b/engines/cryomni3d/image/codecs/hlz.cpp
new file mode 100644
index 0000000..146336e
--- /dev/null
+++ b/engines/cryomni3d/image/codecs/hlz.cpp
@@ -0,0 +1,140 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cryomni3d/image/codecs/hlz.h"
+
+#include "common/stream.h"
+#include "common/textconsole.h"
+#include "graphics/surface.h"
+
+namespace Image {
+
+HLZDecoder::HLZDecoder(int width, int height) : Codec(),
+	_width(width), _height(height), _surface(nullptr) {
+}
+
+HLZDecoder::~HLZDecoder() {
+	if (_surface) {
+		_surface->free();
+		delete _surface;
+	}
+}
+
+const Graphics::Surface *HLZDecoder::decodeFrame(Common::SeekableReadStream &stream) {
+	if (!_surface) {
+		_surface = new Graphics::Surface();
+	}
+
+	_surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+
+	byte *dst = (byte *)_surface->getPixels();
+	decodeFrameInPlace(stream, -1, dst);
+
+	return _surface;
+}
+
+Graphics::PixelFormat HLZDecoder::getPixelFormat() const {
+	return Graphics::PixelFormat::createFormatCLUT8();
+}
+
+static inline bool getReg(Common::SeekableReadStream &stream, uint32 *size, uint32 *reg,
+                          int *regBits) {
+	if (*regBits == 0) {
+		if (*size < 4) {
+			error("Can't feed register: not enough data");
+		}
+		*reg = stream.readUint32LE();
+		*size -= 4;
+		*regBits = 32;
+	}
+	bool ret = (*reg >> 31) != 0;
+	*reg <<= 1;
+	(*regBits)--;
+	return ret;
+}
+
+void HLZDecoder::decodeFrameInPlace(Common::SeekableReadStream &stream, uint32 size, byte *dst) {
+	bool eof = false;
+	bool checkSize = (size != (uint32) - 1);
+	byte *orig = dst;
+	uint32 reg;
+	int regBits = 0;
+#define GETREG() getReg(stream, &size, &reg, &regBits)
+
+	while (!eof) {
+		if (GETREG()) {
+			if (size < 1) {
+				error("Can't read pixel byte");
+			}
+			byte c = stream.readByte();
+			*(dst++) = c;
+			size--;
+		} else {
+			int offset, repeat_count;
+			if (GETREG()) {
+				// Long repeat
+				if (size < 2) {
+					error("Can't read repeat count/offset");
+				}
+				uint16 tmp = stream.readUint16LE();
+				size -= 2;
+				repeat_count = tmp & 0x7;
+				offset = (tmp >> 3) - 0x2000;
+				if (repeat_count == 0) {
+					if (size < 1) {
+						error("Can't read long repeat count");
+					}
+					repeat_count = stream.readByte();
+					size--;
+					if (repeat_count == 0) {
+						eof = true;
+						continue;
+					}
+				}
+			} else {
+				// Short repeat
+				repeat_count = GETREG() << 1;
+				repeat_count |= GETREG();
+				if (size < 1) {
+					error("Can't read offset byte");
+				}
+				offset = stream.readByte() - 0x100;
+				size--;
+			}
+			repeat_count += 2;
+			if (dst + offset < orig) {
+				error("Invalid offset %d, dst is %d", offset, (int)(dst - orig));
+			}
+			for (; repeat_count > 0; repeat_count--) {
+				// offset is always < 0
+				*dst = *(dst + offset);
+				dst++;
+			}
+		}
+	}
+	if (checkSize && size != 0) {
+		stream.skip(size);
+	}
+#undef GETREG
+}
+
+} // End of namespace Image
diff --git a/engines/cryomni3d/image/codecs/hlz.h b/engines/cryomni3d/image/codecs/hlz.h
new file mode 100644
index 0000000..4ec8d3e
--- /dev/null
+++ b/engines/cryomni3d/image/codecs/hlz.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_IMAGE_CODECS_HLZ_H
+#define CRYOMNI3D_IMAGE_CODECS_HLZ_H
+
+#include "image/codecs/codec.h"
+
+namespace Image {
+
+/**
+ * HLZ image decoder.
+ *
+ * Used by HLZ image format and HNM video format.
+ */
+class HLZDecoder : public Codec {
+public:
+	HLZDecoder(int width, int height);
+	~HLZDecoder();
+
+	const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
+	Graphics::PixelFormat getPixelFormat() const;
+
+	static void decodeFrameInPlace(Common::SeekableReadStream &stream, uint32 size, byte *dst);
+
+private:
+	Graphics::Surface *_surface;
+	int _width, _height;
+	int _bitsPerPixel;
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/engines/cryomni3d/image/hlz.cpp b/engines/cryomni3d/image/hlz.cpp
new file mode 100644
index 0000000..dd545c5
--- /dev/null
+++ b/engines/cryomni3d/image/hlz.cpp
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "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 "cryomni3d/image/codecs/hlz.h"
+
+namespace Image {
+
+HLZFileDecoder::HLZFileDecoder() {
+	_surface = 0;
+	_codec = 0;
+}
+
+HLZFileDecoder::~HLZFileDecoder() {
+	destroy();
+}
+
+void HLZFileDecoder::destroy() {
+	delete _codec;
+	_codec = 0;
+	_surface = 0;
+}
+
+bool HLZFileDecoder::loadStream(Common::SeekableReadStream &stream) {
+	destroy();
+
+	stream.read(_palette, sizeof(_palette));
+	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
diff --git a/engines/cryomni3d/image/hlz.h b/engines/cryomni3d/image/hlz.h
new file mode 100644
index 0000000..831632f
--- /dev/null
+++ b/engines/cryomni3d/image/hlz.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file
+ * Image decoder used in engines:
+ *  - hugo
+ *  - mohawk
+ *  - wintermute
+ */
+
+#ifndef CRYOMNI3D_IMAGE_HLZ_H
+#define CRYOMNI3D_IMAGE_HLZ_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "image/image_decoder.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Image {
+class HLZDecoder;
+
+class HLZFileDecoder : public ImageDecoder {
+public:
+	HLZFileDecoder();
+	virtual ~HLZFileDecoder();
+
+	// ImageDecoder API
+	void destroy();
+	virtual bool loadStream(Common::SeekableReadStream &stream);
+	virtual const Graphics::Surface *getSurface() const { return _surface; }
+	const byte *getPalette() const { return _palette; }
+	uint16 getPaletteColorCount() const { return 256; }
+
+private:
+	HLZDecoder *_codec;
+	const Graphics::Surface *_surface;
+	byte _palette[256 * 3];
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/engines/cryomni3d/module.mk b/engines/cryomni3d/module.mk
new file mode 100644
index 0000000..637cf34
--- /dev/null
+++ b/engines/cryomni3d/module.mk
@@ -0,0 +1,38 @@
+MODULE := engines/cryomni3d
+
+MODULE_OBJS = \
+	cryomni3d.o \
+	omni3d.o \
+	detection.o \
+	mouse_boxes.o \
+	dialogs_manager.o \
+	fixed_image.o \
+	font_manager.o \
+	objects.o \
+	sprites.o \
+	wam_parser.o \
+	video/hnm_decoder.o \
+	image/hlz.o \
+	image/codecs/hlz.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
diff --git a/engines/cryomni3d/mouse_boxes.cpp b/engines/cryomni3d/mouse_boxes.cpp
new file mode 100644
index 0000000..6e8887d
--- /dev/null
+++ b/engines/cryomni3d/mouse_boxes.cpp
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cryomni3d/mouse_boxes.h"
+
+#include "common/rect.h"
+
+#include "cryomni3d/font_manager.h"
+
+namespace CryOmni3D {
+
+MouseBoxes::MouseBoxes(unsigned int size) {
+	_boxes.resize(size);
+}
+
+MouseBoxes::~MouseBoxes() {
+}
+
+void MouseBoxes::reset() {
+	unsigned int 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);
+		}
+	}
+}
+
+}
diff --git a/engines/cryomni3d/mouse_boxes.h b/engines/cryomni3d/mouse_boxes.h
new file mode 100644
index 0000000..5e4d496
--- /dev/null
+++ b/engines/cryomni3d/mouse_boxes.h
@@ -0,0 +1,73 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_MOUSE_BOXES_H
+#define CRYOMNI3D_MOUSE_BOXES_H
+
+#include "common/array.h"
+#include "common/str.h"
+
+namespace Common {
+class Point;
+class Rect;
+}
+
+namespace CryOmni3D {
+
+class FontManager;
+
+class MouseBoxes {
+public:
+	MouseBoxes(unsigned int 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
diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
new file mode 100644
index 0000000..5963a1d
--- /dev/null
+++ b/engines/cryomni3d/objects.cpp
@@ -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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "engines/cryomni3d/objects.h"
+
+namespace CryOmni3D {
+
+Object *Objects::findObjectByNameID(unsigned int nameID) {
+	for (iterator it = begin(); it != end(); it++) {
+		if (it->valid() && it->idOBJ() == nameID) {
+			return it;
+		}
+	}
+	// TODO: check if 111 and 112 are called and should be filtered out or not
+	error("nameID not found %u", nameID);
+}
+
+Object *Objects::findObjectByIconID(unsigned int 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(unsigned int position) {
+	(*this)[position] = nullptr;
+	(*_changeCallback)(-1u);
+}
+
+void Inventory::removeByCursorId(unsigned int cursorId) {
+	for (iterator it = begin(); it != end(); it++) {
+		if ((*it) && (*it)->idCA() == cursorId) {
+			remove(it - begin());
+			return;
+		}
+	}
+	// Don't bail out
+}
+
+void Inventory::removeByNameId(unsigned int nameId) {
+	for (iterator it = begin(); it != end(); it++) {
+		if ((*it) && (*it)->idOBJ() == nameId) {
+			remove(it - begin());
+			return;
+		}
+	}
+	// Don't bail out
+}
+
+bool Inventory::inInventoryByCursorId(unsigned int cursorId) const {
+	for (const_iterator it = begin(); it != end(); it++) {
+		if ((*it) && (*it)->idCA() == cursorId) {
+			return true;
+		}
+	}
+	return false;
+}
+
+bool Inventory::inInventoryByNameId(unsigned int nameId) const {
+	for (const_iterator it = begin(); it != end(); it++) {
+		if ((*it) && (*it)->idOBJ() == nameId) {
+			return true;
+		}
+	}
+	return false;
+}
+
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/objects.h b/engines/cryomni3d/objects.h
new file mode 100644
index 0000000..917233c
--- /dev/null
+++ b/engines/cryomni3d/objects.h
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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(-1), _idCl(-1), _idSA(-1), _idSl(-1), _idOBJ(-1),
+		_viewCallback(nullptr) {}
+
+	Object(const Sprites &sprites, unsigned int idCA, unsigned int idOBJ) : _idCA(idCA),
+		_idCl(sprites.calculateSpriteId(idCA, 1)), _idSA(sprites.calculateSpriteId(idCA, 2)),
+		_idSl(sprites.calculateSpriteId(idCA, 3)),
+		_valid(true), _idOBJ(idOBJ), _viewCallback(nullptr) {}
+
+	~Object() { delete _viewCallback; }
+
+	unsigned int valid() const { return _valid; }
+	unsigned int idCA() const { return _idCA; }
+	unsigned int idCl() const { return _idCl; }
+	unsigned int idSA() const { return _idSA; }
+	unsigned int idSl() const { return _idSl; }
+	unsigned int idOBJ() const { return _idOBJ; }
+	ViewCallback viewCallback() const { return _viewCallback; }
+	// Takes ownership of the pointer
+	void setViewCallback(ViewCallback callback) { _viewCallback = callback; }
+
+	void rename(unsigned int newIdOBJ) { _idOBJ = newIdOBJ; }
+
+private:
+	unsigned int _idOBJ;
+	unsigned int _idCA;
+	unsigned int _idCl;
+	unsigned int _idSA;
+	unsigned int _idSl;
+	bool _valid;
+	ViewCallback _viewCallback;
+};
+
+class Objects : public Common::Array<Object> {
+public:
+	Object *findObjectByNameID(unsigned int nameID);
+	Object *findObjectByIconID(unsigned int iconID);
+private:
+};
+
+class Inventory : public Common::Array<Object *> {
+public:
+	Inventory() : _selectedObject(nullptr), _changeCallback(nullptr) { }
+	~Inventory() { delete _changeCallback; }
+	void init(unsigned int count, Common::Functor1<unsigned int, void> *changeCallback) { _changeCallback = changeCallback; resize(count); }
+
+	void clear();
+	void add(Object *);
+	void remove(unsigned int position);
+	void removeByCursorId(unsigned int cursorId);
+	void removeByNameId(unsigned int nameId);
+	bool inInventoryByCursorId(unsigned int cursorId) const;
+	bool inInventoryByNameId(unsigned int nameId) const;
+
+	Object *selectedObject() const { return _selectedObject; }
+	void setSelectedObject(Object *obj) { _selectedObject = obj; }
+
+private:
+	Object *_selectedObject;
+	Common::Functor1<unsigned int, void> *_changeCallback;
+};
+
+} // End of namespace CryOmni3D
+
+#endif
+
diff --git a/engines/cryomni3d/omni3d.cpp b/engines/cryomni3d/omni3d.cpp
new file mode 100644
index 0000000..5c6d6db
--- /dev/null
+++ b/engines/cryomni3d/omni3d.cpp
@@ -0,0 +1,275 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "engines/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 (abs(_xSpeed) < 0.001) {
+			_xSpeed = 0.;
+		}
+		if (abs(_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;
+
+	unsigned int k = 0;
+	for (unsigned int i = 0; i < 31; i++) {
+		double v11 = _anglesH[i] + _beta;
+		double v26 = sin(v11);
+		double v25 = cos(v11) * _hypothenusesH[i];
+
+		unsigned int offset = 80;
+		unsigned int 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) {
+		unsigned int off = 2;
+		byte *dst = (byte *)_surface.getBasePtr(0, 0);
+		const byte *src = (const byte *)_sourceSurface->getBasePtr(0, 0);
+
+		for (unsigned int i = 0; i < 30; i++) {
+			for (unsigned int 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 (unsigned int y = 0; y < 16; y++) {
+					unsigned int px = (x2 * 2 + x1) * 16;
+					unsigned int py = (y2 * 2 + y1) / 2;
+					unsigned int deltaX = x1 * 32;
+					unsigned int deltaY = y1;
+
+					for (unsigned int x = 0; x < 16; x++) {
+						unsigned int 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;
+
+	unsigned int 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
diff --git a/engines/cryomni3d/omni3d.h b/engines/cryomni3d/omni3d.h
new file mode 100644
index 0000000..e7d9e08
--- /dev/null
+++ b/engines/cryomni3d/omni3d.h
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CRYOMNI3D_OMNI3D_H
+#define CRYOMNI3D_OMNI3D_H
+
+#include "graphics/surface.h"
+
+namespace CryOmni3D {
+
+class Omni3DManager {
+public:
+	Omni3DManager() {}
+	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
diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
new file mode 100644
index 0000000..b1c5f95
--- /dev/null
+++ b/engines/cryomni3d/sprites.cpp
@@ -0,0 +1,218 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "graphics/surface.h"
+
+#include "engines/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) {
+	byte magic[4];
+
+	while (true) {
+		if (spr_fl.read(magic, sizeof(magic)) == 0) {
+			break;
+		}
+		if (memcmp(magic, "SPRI", sizeof(magic))) {
+			error("Invalid sprite magic");
+		}
+
+		// 2 unknown uint32
+		spr_fl.readUint32BE();
+		spr_fl.readUint32BE();
+
+		CryoCursor *cursor = new CryoCursor();
+
+		uint16 w = spr_fl.readUint16BE();
+		uint16 h = spr_fl.readUint16BE();
+		unsigned int 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 unsigned int *table, unsigned int size) {
+	delete _map;
+	_map = nullptr;
+	// Reset the reverse mapping
+	for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
+		(*it)->_constantId = -1;
+	}
+	if (table) {
+		_map = new Common::Array<unsigned int>(table, size);
+
+		// Sweep all the mapping and set its reverse values
+		unsigned int i = 0;
+		for (Common::Array<unsigned int>::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
+		unsigned int 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 indexes
+			_map->reserve(_map->size() + unswept);
+
+			// Set new indexes 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(unsigned int spriteId, unsigned int x, unsigned int y) {
+	MAP_ID(spriteId);
+	_cursors[spriteId]->_offX = x;
+	_cursors[spriteId]->_offY = y;
+}
+
+void Sprites::replaceSprite(unsigned int oldSpriteId, unsigned int 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++;
+}
+
+unsigned int Sprites::getSpritesCount() const {
+	if (_map) {
+		return _map->size();
+	} else {
+		return _cursors.size();
+	}
+}
+
+unsigned int Sprites::revMapSpriteId(unsigned int 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;
+}
+
+unsigned int Sprites::calculateSpriteId(unsigned int baseId, unsigned int 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());
+		}
+		unsigned int spriteId = _cursors[baseId]->_constantId;
+		if (spriteId == -1u) {
+			error("Sprite %d is unreachable", baseId);
+		}
+		return spriteId;
+	} else {
+		return baseId + offset;
+	}
+}
+
+const Graphics::Surface &Sprites::getSurface(unsigned int 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(unsigned int spriteId) const {
+	MAP_ID(spriteId);
+
+	return *_cursors[spriteId];
+}
+
+Sprites::CryoCursor::CryoCursor() : _width(0), _height(0), _offX(0), _offY(0), _data(nullptr),
+	refCnt(1) {
+}
+
+Sprites::CryoCursor::~CryoCursor() {
+	assert(refCnt == 1);
+	delete[] _data;
+}
+
+unsigned int Sprites::CryoCursor::setup(uint16 width, uint16 height) {
+	_width = width;
+	_height = height;
+	unsigned int sz = _width * _height;
+	_data = new byte[sz];
+	return sz;
+}
+
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/sprites.h b/engines/cryomni3d/sprites.h
new file mode 100644
index 0000000..eac4be3
--- /dev/null
+++ b/engines/cryomni3d/sprites.h
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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 {
+class Surface;
+}
+
+namespace CryOmni3D {
+
+class Sprites {
+public:
+	Sprites();
+	virtual ~Sprites();
+
+	void loadSprites(Common::ReadStream &spr_fl);
+	void setupMapTable(const unsigned int *table, unsigned int size);
+
+	void setSpriteHotspot(unsigned int spriteId, unsigned int x, unsigned int y);
+
+	void replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId);
+
+	unsigned int getSpritesCount() const;
+
+	const Graphics::Surface &getSurface(unsigned int spriteId) const;
+	const Graphics::Cursor &getCursor(unsigned int spriteId) const;
+
+	unsigned int revMapSpriteId(unsigned int id) const;
+	unsigned int calculateSpriteId(unsigned int baseId, unsigned int offset) const;
+
+	byte getKeyColor(unsigned int spriteId) const { return 0; }
+
+private:
+	class CryoCursor : public Graphics::Cursor {
+	public:
+		virtual uint16 getWidth() const override { return _width; }
+		virtual uint16 getHeight() const override { return _height; }
+		virtual uint16 getHotspotX() const override { return _offX; }
+		virtual uint16 getHotspotY() const override { return _offY; }
+		virtual byte getKeyColor() const override { return 0; }
+
+		virtual const byte *getSurface() const override { return _data; }
+
+		virtual const byte *getPalette() const override { return nullptr; }
+		virtual byte getPaletteStartIndex() const override { return 0; }
+		virtual uint16 getPaletteCount() const override { return 0; }
+
+		unsigned int setup(uint16 width, uint16 height);
+
+		uint16 _width;
+		uint16 _height;
+		int16 _offX;
+		int16 _offY;
+		unsigned int _constantId;
+
+		byte *_data;
+
+		unsigned int refCnt;
+
+		CryoCursor();
+		virtual ~CryoCursor();
+	};
+
+	// Pointer to avoid to mutate Sprites when asking for a cursor
+	Graphics::Surface *_surface;
+	Common::Array<CryoCursor *> _cursors;
+	Common::Array<unsigned int> *_map;
+};
+
+} // End of namespace CryOmni3D
+
+#endif
diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
new file mode 100644
index 0000000..7439f4d
--- /dev/null
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -0,0 +1,1018 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cryomni3d/versailles/engine.h"
+
+namespace CryOmni3D {
+namespace Versailles {
+
+const unsigned int 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 unsigned int 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
+};
+
+void CryOmni3DEngine_Versailles::setupMessages() {
+	_messages.resize(146);
+#define SET_MESSAGE(id, str) _messages[id] = str
+	SET_MESSAGE(0, "Il est interdit d'ouvrir cette porte pour l'instant.");
+	SET_MESSAGE(1, "Cette porte est ferm" "\x8e" "e " "\x88" " clef.");
+	SET_MESSAGE(2, "Cette porte est ferm" "\x8e" "e.");
+	SET_MESSAGE(3, "Ce tiroir est vide.");
+	SET_MESSAGE(4, "Vous ne pouvez pas atteindre la b" "\x89" "che.");
+	SET_MESSAGE(5, "Il n'y a rien dans cet oranger");
+	SET_MESSAGE(6, "Ceci n'est pas un oranger!");
+	SET_MESSAGE(7, "Il fait trop sombre. ");
+	SET_MESSAGE(8, "Le coffre est ferm" "\x8e" ". ");
+	SET_MESSAGE(9, "Vous pouvez ouvrir la porte");
+	SET_MESSAGE(10, "Il faudrait quelque chose pour atteindre la bombe.");
+	SET_MESSAGE(11, "Ce vase est vide.");
+	SET_MESSAGE(12, "Maintenant, vous pouvez y aller.");
+	SET_MESSAGE(13, "Vous niavez plus le temps de vous renseigner sur la Cour!");
+	SET_MESSAGE(14, "Il est trop tard pour regarder les tableaux!");
+	SET_MESSAGE(16, "Vous ne pouvez pas atteindre le papier.");
+	SET_MESSAGE(15, "Attendez ! Transmettez donc vos indices " "\x88" " l'huissier.");
+	SET_MESSAGE(17, "Vers l'apothicairerie");
+	SET_MESSAGE(
+	    18,
+	    "Attention : Vous allez pouvoir terminer ce niveau, mais vous n'avez pas effectu" "\x8e"
+	    " toutes les actions necessaires pour la suite. "
+	    "Il est conseill" "\x8e" " de SAUVEGARDER votre partie maintenant.");
+	SET_MESSAGE(
+	    19,
+	    "Attention : Vous allez pouvoir terminer ce niveau, mais vous n'avez peut-" "\x89" "tre"
+	    " pas effectu" "\x8e" " toutes les actions necessaires pour la suite. "
+	    "Il est conseill" "\x8e" " de SAUVEGARDER votre partie maintenant.");
+	SET_MESSAGE(20, "Vous ne pouvez pas vous d" "\x8e" "placer en portant une " "\x8e" "chelle!");
+	SET_MESSAGE(21, "Il n'y a plus rien ici");
+	SET_MESSAGE(22, "Au revoir ...");
+	SET_MESSAGE(23, "VERSAILLES,");
+	SET_MESSAGE(24, "Complot " "\x88" " la Cour du Roi Soleil");
+	SET_MESSAGE(27, "           Commencer une nouvelle partie");
+	SET_MESSAGE(26, "           Reprendre la partie en cours");
+	SET_MESSAGE(44, "           Reprendre la visite en cours");
+	SET_MESSAGE(28, "           Charger une partie");
+	SET_MESSAGE(46, "           Charger une visite");
+	SET_MESSAGE(29, "           Sauver la partie");
+	SET_MESSAGE(45, "           Sauver la visite");
+	SET_MESSAGE(25, "Consulter l'espace documentaire");
+	SET_MESSAGE(42, "Visiter le ch" "\x89" "teau");
+	SET_MESSAGE(48, "           Omni3D : normal");
+	SET_MESSAGE(51, "           Omni3D : rapide");
+	SET_MESSAGE(52, "           Omni3D : tr" "\x8f" "s rapide");
+	SET_MESSAGE(49, "           Omni3D : lent");
+	SET_MESSAGE(50, "           Omni3D : tr" "\x8f" "s lent");
+	SET_MESSAGE(30, "           Afficher les sous-titres : OUI");
+	SET_MESSAGE(31, "           Afficher les sous-titres : NON");
+	SET_MESSAGE(32, "           Musique : OUI");
+	SET_MESSAGE(33, "           Musique : NON");
+	SET_MESSAGE(35, "           Toutes les musiques sur disque dur (92 Mo)");
+	SET_MESSAGE(34, "           Une seule musique sur disque dur (20 Mo)");
+	SET_MESSAGE(36, "           Aucune musique sur disque dur (lecture CD)");
+	SET_MESSAGE(43, "Cr" "\x8e" "dits");
+	SET_MESSAGE(39, "Volume");
+	SET_MESSAGE(41, "");
+	SET_MESSAGE(40, "Quitter le jeu");
+	SET_MESSAGE(53, "Confirmer");
+	SET_MESSAGE(54, "Annuler");
+	SET_MESSAGE(55, "libre");
+	SET_MESSAGE(56, "sans nom");
+	SET_MESSAGE(57, "Attention : la partie en cours va " "\x89" "tre abandonn" "\x8e" "e.");
+	SET_MESSAGE(58, "Retour");
+	SET_MESSAGE(59, "Le chateau");
+	SET_MESSAGE(60, "Retour Menu Principal");
+	SET_MESSAGE(61, "Sommaire Espace documentaire");
+	SET_MESSAGE(62, "Plan du ch" "\x89" "teau et des jardins");
+	SET_MESSAGE(63, "Plan des int" "\x8e" "rieurs du ch" "\x89" "teau");
+	SET_MESSAGE(64, "Probl" "\x8f" "me d'" "\x8e" "criture sur dique dur : disque plein ");
+	SET_MESSAGE(66, "Veuillez ins" "\x8e" "rer le CD ");
+	SET_MESSAGE(67, "Veuillez ins" "\x8e" "rer le CD %d et presser une touche");
+	SET_MESSAGE(68, "Les arts");
+	SET_MESSAGE(69, "Le r" "\x8f" "gne");
+	SET_MESSAGE(70, "La Cour");
+	SET_MESSAGE(71, "Vie de Ch" "\x89" "teau");
+	SET_MESSAGE(72, "Le ch" "\x89" "teau et les jardins");
+	SET_MESSAGE(73, "Chronologie");
+	SET_MESSAGE(74, "Bassin d'Apollon");
+	SET_MESSAGE(75, "Le Ch" "\x89" "teau");
+	SET_MESSAGE(76, "Colonnade");
+	SET_MESSAGE(77, "Labyrinthe");
+	SET_MESSAGE(78, "Latone");
+	SET_MESSAGE(79, "Orangerie");
+	SET_MESSAGE(80, "Parterre d'eau");
+	SET_MESSAGE(81, "Tapis vert");
+	SET_MESSAGE(86, "Grand Canal");
+	SET_MESSAGE(87, "Parterre du Midi");
+	SET_MESSAGE(88, "Parterre du nord");
+	SET_MESSAGE(89, "Potager du Roi");
+	SET_MESSAGE(90, "Salle de bal");
+	SET_MESSAGE(91, "Bassin de Neptune");
+	SET_MESSAGE(92, "Pi" "\x8f" "ce d'eau des suisses");
+	SET_MESSAGE(82, "Grandes Ecuries");
+	SET_MESSAGE(83, "Petites Ecuries");
+	SET_MESSAGE(84, "Les jardins");
+	SET_MESSAGE(85, "Avant cour");
+	SET_MESSAGE(93, "Aiguilles (Inutile!)");
+	SET_MESSAGE(94, "Ciseaux");
+	SET_MESSAGE(95, "Papier");
+	SET_MESSAGE(96, "Pamphlet sur les arts");
+	SET_MESSAGE(97, "Petite clef 1");
+	SET_MESSAGE(98, "Papier r" "\x8e" "v" "\x8e" "l" "\x8e" "");
+	SET_MESSAGE(99, "Papier t" "\x89" "ch" "\x8e" "");
+	SET_MESSAGE(100, "Papier du coffre");
+	SET_MESSAGE(101, "Pamphlet sur la lign" "\x8e" "e royale");
+	SET_MESSAGE(102, "Bougie allum" "\x8e" "e");
+	SET_MESSAGE(103, "Bougie");
+	SET_MESSAGE(104, "Clef ");
+	SET_MESSAGE(105, "Carton " "\x88" " dessin");
+	SET_MESSAGE(106, "Carton " "\x88" " dessin");
+	SET_MESSAGE(107, "Fausse esquisse");
+	SET_MESSAGE(108, "Echelle");
+	SET_MESSAGE(109, "Esquisse d" "\x8e" "truite");
+	SET_MESSAGE(110, "pinceau");
+	SET_MESSAGE(111, "pinceau Or");
+	SET_MESSAGE(112, "pinceau Rouge");
+	SET_MESSAGE(113, "Fusain");
+	SET_MESSAGE(114, "Papier");
+	SET_MESSAGE(115, "Pamphlet sur liarchitecture");
+	SET_MESSAGE(116, "Petite clef 2");
+	SET_MESSAGE(117, "Archer(inutile!)");
+	SET_MESSAGE(118, "Partition");
+	SET_MESSAGE(119, "Queue de billard");
+	SET_MESSAGE(120, "Autorisation");
+	SET_MESSAGE(121, "Reproduction des m" "\x8e" "dailles");
+	SET_MESSAGE(122, "Tiroir " "\x88" " m" "\x8e" "dailles");
+	SET_MESSAGE(123, "Clef de la petite porte diApollon");
+	SET_MESSAGE(124, "Nourriture");
+	SET_MESSAGE(125, "Pamphlet sur la religion");
+	SET_MESSAGE(126, "Epigraphe");
+	SET_MESSAGE(127, "Pamphlet sur le gouvernement");
+	SET_MESSAGE(128, "Plume");
+	SET_MESSAGE(129, "Pense-b" "\x89" "te");
+	SET_MESSAGE(130, "Lunette");
+	SET_MESSAGE(131, "Plan Vauban");
+	SET_MESSAGE(132, "Plan Vauban");
+	SET_MESSAGE(133, "Cordon");
+	SET_MESSAGE(134, "Gravure");
+	SET_MESSAGE(135, "Petite clef 3");
+	SET_MESSAGE(136, "Petite clef 4");
+	SET_MESSAGE(137, "M" "\x8e" "morandum");
+	SET_MESSAGE(138, "Plans du chateau");
+	SET_MESSAGE(139, "Plans du chateau");
+	SET_MESSAGE(140, "Clef des combles");
+	SET_MESSAGE(141, "Fables");
+	SET_MESSAGE(142, "Plan du Labyrinthe");
+	SET_MESSAGE(143, "Outil");
+	SET_MESSAGE(144, "M" "\x8e" "dicament");
+	SET_MESSAGE(145, "Eteignoir");
+#undef SET_MESSAGE
+}
+
+void CryOmni3DEngine_Versailles::setupPaintingsTitles() {
+	_paintingsTitles.reserve(48);
+#define SET_PAINTING_TITLE(str) _paintingsTitles.push_back(str)
+	SET_PAINTING_TITLE("\"Entr" "\x8e" "e des animaux dans l'arche\"\rGerolamo Bassano"); // 0: 41201
+	SET_PAINTING_TITLE("\"Le repas d'Emma" "\x9f" "s\"\rJacopo Bassano"); // 1: 41202
+	SET_PAINTING_TITLE("\"La Madeleine aux pieds de J\x8esus Christ\"\rSustris"); // 2: 41203
+	SET_PAINTING_TITLE("\"La sortie de l'arche\"\rGerolamo Bassano"); // 3: 41204
+	SET_PAINTING_TITLE("\"Le frappement du rocher\"\rJacopo Bassano"); // 4: 41205
+	SET_PAINTING_TITLE("\"La Bataille d'Arbelles\"\rJoseph Parrocel"); // 5: 41301
+	SET_PAINTING_TITLE("\"Alexandre Le Grand vainqueur de Darius " "\x88"
+	                   " la bataille d'Arbelles\"\rLe Bourguignon"); // 6: 41302
+	SET_PAINTING_TITLE("\"Le Combat de Leuze\"\rJoseph Parrocel"); // 7: 42401
+	SET_PAINTING_TITLE("\"Sainte C" "\x8e"
+	                   "cile avec un ange tenant une partition musicale\"\rDominiquin"); // 8: 42901
+	SET_PAINTING_TITLE("\"Don Francisco du Moncada \"\rVan Dyck"); // 9: 42902
+	SET_PAINTING_TITLE("\"Le Petit Saint Jean Baptiste\"\rLe Carrache"); // 10: 42903
+	SET_PAINTING_TITLE("\"Saint Mathieu\"\rValentin"); // 11: 42904
+	SET_PAINTING_TITLE("\"Le Denier de C" "\x8e" "sar \"\rValentin"); // 12: 42905
+	SET_PAINTING_TITLE("\"Saint Luc\"\rValentin"); // 13: 42906
+	SET_PAINTING_TITLE("\"Le mariage mystique de Sainte Catherine\"\r Alessandro Turchi"); // 14: 42907
+	SET_PAINTING_TITLE("\"R" "\x8e" "union de buveurs\"\rNicolas Tournier"); // 15: 42908
+	SET_PAINTING_TITLE("\"La diseuse de Bonne aventure \"\rValentin"); // 16: 42909
+	SET_PAINTING_TITLE("\"le roi David jouant de la harpe \"\rDominiquin"); // 17: 42910
+	SET_PAINTING_TITLE("\"Sainte Madeleine\"\rDominiquin"); // 18: 42911
+	SET_PAINTING_TITLE("\"Autoportrait \"\rVan Dyck"); // 19: 42912
+	SET_PAINTING_TITLE("\"Saint Jean l'" "\x8e" "vang" "\x8e" "liste\"\r Valentin"); // 20: 42913
+	SET_PAINTING_TITLE("\"Agar secouru par un ange \"\rGiovanni Lanfranco"); // 21: 42914
+	SET_PAINTING_TITLE("\"Saint Marc \"\rValentin"); // 22: 42915
+	SET_PAINTING_TITLE("\"M" "\x8e" "l" "\x8e" "agre ayant " "\x88"
+	                   " ses pieds la hure du sanglier de Calydon\"\r Jacques Rousseau"); // 23: 43090
+	SET_PAINTING_TITLE("\"Le Roi en costume romain\"\rJean Warin"); // 24: 43091
+	SET_PAINTING_TITLE("\"attalante\"\rJacques Rousseau"); // 25: 43092
+	SET_PAINTING_TITLE("\"En" "\x8e" "e portant Anchise\"\rSpada"); // 26: 43100
+	SET_PAINTING_TITLE("\"David et Bethsab" "\x8e" "e\"\rV" "\x8e" "ron" "\x8f" "se"); // 27: 43101
+	SET_PAINTING_TITLE("\"La fuite en Egypte\"\rGuido R" "\x8e" "ni "); // 28: 43102
+	SET_PAINTING_TITLE("\"Louis XIV " "\x88" " cheval\"\rPierre Mignard"); // 29: 43103
+	SET_PAINTING_TITLE("\"La magnificience royale & le progr" "\x8f"
+	                   "s des beaux arts\"\rHouasse"); // 30: 43104
+	SET_PAINTING_TITLE("\"Le Sacrifice d'Iphig" "\x8e" "nie\"\rCharles de la Fosse"); // 31: 43130
+	SET_PAINTING_TITLE("\"Buste de Louis XIV\"\rsculpt" "\x8e"
+	                   " par le Chevalier Bernin "); // 32: 43131
+	SET_PAINTING_TITLE("\"Diane d" "\x8e" "couvrant son berger Endymion endormi dans les bras de Morph"
+	                   "\x8e" "e\"\rGabriel Blanchard"); // 33: 43132
+	SET_PAINTING_TITLE("\"La vierge & Saint Pierre\"\rGuerchin"); // 34: 43140
+	SET_PAINTING_TITLE("\"Les P" "\x8e" "lerins d'Emma" "\x9f" "s\"\rV" "\x8e" "ron" "\x8f"
+	                   "se"); // 35: 43141
+	SET_PAINTING_TITLE("\"La sainte Famille\"\rV" "\x8e" "ron" "\x8f" "se"); // 36: 43142
+	SET_PAINTING_TITLE("\"La famille de Darius aux pieds d'Alexandre\"\rCharles LeBrun"); // 37: 43143
+	SET_PAINTING_TITLE("\"Saint Jean-Baptiste\"\rRapha" "\x91" "l"); // 38: 43144
+	SET_PAINTING_TITLE("\"Marie de m" "\x8e" "dicis\"\rVan Dyck"); // 39: 43150
+	SET_PAINTING_TITLE("\"Hercule luttant contre Achelous\"\rGuido R" "\x8e" "ni"); // 40: 43151
+	SET_PAINTING_TITLE("\"Le Centaure Nessus porte Dejanire\"\rGuido R" "\x8e" "ni"); // 41: 43152
+	SET_PAINTING_TITLE("\"Saint Franìois d'Assise r" "\x8e" "confort" "\x8e" " apr" "\x8f"
+	                   "s sa stigmatisation\"\rSeghers"); // 42: 43153
+	SET_PAINTING_TITLE("\"Thomiris faisant tremper la t" "\x90"
+	                   "te de Cyrus dans le sang\"\rRubens"); // 43: 43154
+	SET_PAINTING_TITLE("\"Hercule tuant l'Hydre\"\rGuido R" "\x8e" "ni"); // 44: 43155
+	SET_PAINTING_TITLE("\"Hercule sur le b" "\x9e" "cher\"\rGuido R" "\x8e" "ni"); // 45: 43156
+	SET_PAINTING_TITLE("\"Portrait du Prince Palatin & de son fr" "\x8f"
+	                   "re le Prince Robert\"\rVan Dyck"); // 46: 43157
+	SET_PAINTING_TITLE("\"La descente de Croix \"\rCharles Lebrun"); // 47: 45260
+#undef SET_PAINTING_TITLE
+}
+
+struct VideoSubSetting {
+	const char *videoName;
+	int16 textLeft;
+	int16 textTop;
+	int16 textRight;
+	int16 textBottom;
+	int16 drawLeft;
+	int16 drawTop;
+	int16 drawRight;
+	int16 drawBottom;
+};
+
+static const VideoSubSetting videoSubSettings[] = {
+	{"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 (unsigned int i = 0; i < ARRAYSIZE(videoSubSettings); i++) {
+		const VideoSubSetting &vss = videoSubSettings[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() {
+#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) {
+		_placeStates.resize(15);
+		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
+		SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
+		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) {
+		_placeStates.resize(15);
+		SET_PLACE_STATE(1, nullptr, nullptr, "VS22");
+		SET_PLACE_STATE(2, nullptr, nullptr, "VS20");
+		SET_PLACE_STATE(3, nullptr, nullptr, "VS19");
+		SET_PLACE_STATE(4, nullptr, nullptr, "VS18");
+		SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(6, nullptr, nullptr, "VS19");
+		SET_PLACE_STATE(7, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(9, nullptr, nullptr, "VS23");
+		SET_PLACE_STATE(10, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(11, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(12, nullptr, nullptr, "VS24");
+		SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(14, nullptr, nullptr, nullptr);
+	} else if (_currentLevel == 3) {
+		_placeStates.resize(25);
+		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, "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, nullptr, "VS28");
+		SET_PLACE_STATE(11, nullptr, nullptr, "VS28");
+		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, "VS25");
+		SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(19, nullptr, nullptr, "VS26");
+		SET_PLACE_STATE(20, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(21, nullptr, nullptr, "VS28");
+		SET_PLACE_STATE(22, nullptr, nullptr, "VS26");
+		SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
+	} else if (_currentLevel == 4) {
+		_placeStates.resize(18);
+		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, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(10, nullptr, nullptr, "VS18");
+		SET_PLACE_STATE(11, nullptr, nullptr, "VS20");
+		SET_PLACE_STATE(12, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(14, nullptr, nullptr, "VS31");
+		SET_PLACE_STATE(15, nullptr, nullptr, "VS36");
+		SET_PLACE_STATE(16, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
+	} else if (_currentLevel == 5) {
+		_placeStates.resize(35);
+		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, 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, "VS25");
+		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, "VS28");
+		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, "VS16");
+		SET_PLACE_STATE(27, nullptr, nullptr, "VS16");
+		SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(29, nullptr, nullptr, "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, nullptr, nullptr);
+		SET_PLACE_STATE(34, nullptr, nullptr, nullptr);
+	} else if (_currentLevel == 6) {
+		_placeStates.resize(45);
+		SET_PLACE_STATE(1, nullptr, nullptr, "VS34");
+		SET_PLACE_STATE(2, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(3, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(4, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(5, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(6, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(7, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(8, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(9, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(10, nullptr, nullptr, "VS22");
+		SET_PLACE_STATE(11, nullptr, nullptr, "VS12");
+		SET_PLACE_STATE(12, nullptr, nullptr, "VS32");
+		SET_PLACE_STATE(13, nullptr, nullptr, "VS33");
+		SET_PLACE_STATE(14, nullptr, nullptr, "VS33");
+		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, nullptr, "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) {
+		_placeStates.resize(30);
+		SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(2, nullptr, nullptr, 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);
+		SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(9, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(10, nullptr, nullptr, "VS33");
+		SET_PLACE_STATE(11, nullptr, nullptr, "VS33");
+		SET_PLACE_STATE(12, nullptr, nullptr, nullptr);
+		SET_PLACE_STATE(13, nullptr, nullptr, "VS33");
+		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, 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, 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) {
+		_placeStates.resize(50);
+		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, "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");
+		SET_PLACE_STATE(39, nullptr, nullptr, nullptr);
+		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, "VS19");
+	}
+#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, 1);
+	} 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) {
+		// TODO: finish the boring job
+		error("TODO:");
+	} else if (_currentLevel == 5) {
+		error("TODO:");
+	} else if (_currentLevel == 6) {
+		error("TODO:");
+	} 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::kDiscussedLabyrOrder] == 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
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
new file mode 100644
index 0000000..ff5a9ff
--- /dev/null
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -0,0 +1,318 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "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) {
+		playInGameVideo("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::kGotMedaillesSolution] == 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::kUsedPlanVauban1] == 0 ||
+	         _gameVariables[GameVariables::kUsedPlanVauban2] == 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::kUsedPlanVauban1] == 0 ||
+	         _gameVariables[GameVariables::kUsedPlanVauban2] == 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::kGotMedaillesSolution] &&
+		        _dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
+			playInGameVideo("32M_MR2");
+			_gameVariables[GameVariables::kGotMedaillesSolution] = 1;
+		}
+		if (!_gameVariables[GameVariables::kCollectePartition] &&
+		        _dialogsMan["LULLY-DIT-CHAT-PENDU-JOUEUR"] == 'Y') {
+			_gameVariables[GameVariables::kCollectePartition] = 1;
+			collectObject(118);
+			setGameTime(3, 3);
+		}
+		if (currentGameTime() == 1 && _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::kStatePamphletReligion] != 3 &&
+		        _dialogsMan["LACHAIZE-DIT-REFORME"] == 'Y' && _dialogsMan["LACHAIZE-DIT-DRAGONNADES"] == 'Y' &&
+		        _dialogsMan["LACHAIZE-TROUVE-ECROUELLES"] == 'Y') {
+			_inventory.removeByNameId(125);
+			_gameVariables[GameVariables::kStatePamphletReligion] = 3;
+			collectObject(125);
+			_inventory.setSelectedObject(nullptr);
+		}
+	}
+}
+
+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("(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.setSelectedObject(nullptr);
+}
+
+void CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts() {
+	_inventory.removeByNameId(105);
+	collectObject(106);
+	_gameVariables[GameVariables::kEsquissePainted] = 2;
+	_inventory.setSelectedObject(nullptr);
+	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.setSelectedObject(nullptr);
+}
+
+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.setSelectedObject(nullptr);
+}
+
+void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
+	playInGameVideo("62S_DUC1");
+	_inventory.removeByNameId(144);
+	_inventory.setSelectedObject(nullptr);
+	setPlaceState(19, 1);
+}
+
+void CryOmni3DEngine_Versailles::dialogShowTransitionScene() {
+}
+
+void CryOmni3DEngine_Versailles::dialogShowEndOfGame() {
+	playTransitionEndLevel(6);
+}
+
+void CryOmni3DEngine_Versailles::dialogShowLeBrunGives() {
+	collectObject(107);
+	_inventory.setSelectedObject(nullptr);
+}
+
+void CryOmni3DEngine_Versailles::dialogShowLeBrunLeave() {
+	playInGameVideo("11D_LEB3");
+	setGameTime(2, 1);
+}
+
+} // End of namespace Versailles
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
new file mode 100644
index 0000000..4180a65
--- /dev/null
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -0,0 +1,379 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "audio/decoders/wave.h"
+#include "common/file.h"
+#include "common/system.h"
+
+#include "cryomni3d/video/hnm_decoder.h"
+
+#include "cryomni3d/versailles/dialogs_manager.h"
+#include "cryomni3d/versailles/engine.h"
+
+namespace CryOmni3D {
+namespace Versailles {
+
+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 = g_system->showMouse(true);
+
+	bool slowStop = false;
+	bool didSth = DialogsManager::play(sequence, slowStop);
+
+	g_system->showMouse(cursorWasVisible);
+
+	if (didSth && slowStop) {
+		if (_engine->showSubtitles()) {
+			bool skip = false;
+			unsigned int end = g_system->getMillis() + 2000;
+			while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skip) {
+				g_system->updateScreen();
+				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 videoFName(video);
+	Common::String soundFName(sound);
+
+	videoFName += ".hnm";
+	// Don't look for HNS file here
+
+	while (soundFName.size() < 8) {
+		soundFName += '_';
+	}
+	soundFName += ".wav";
+
+	Video::HNMDecoder *videoDecoder = new Video::HNMDecoder(true);
+
+	if (!videoDecoder->loadFile(videoFName)) {
+		warning("Failed to open movie file %s/%s", video.c_str(), videoFName.c_str());
+		delete videoDecoder;
+		return;
+	}
+
+	Common::File *audioFile = new Common::File();
+	if (!audioFile->open(soundFName)) {
+		warning("Failed to open sound file %s/%s", sound.c_str(), soundFName.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;
+	}
+
+	g_system->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;
+
+		unsigned int lines = fontManager.getLinesCount(text, block.width() - 8);
+		if (lines == 0) {
+			lines = 5;
+		}
+		unsigned int 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;
+
+		unsigned int duration = 100 * text.size();
+		if (duration < 1000) {
+			duration = 1000;
+		}
+
+		bool skipWait = false;
+		unsigned int end = g_system->getMillis() + duration;
+		while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skipWait) {
+			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 (!g_engine->shouldQuit() && _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();
+		}
+		_engine->_mixer->stopHandle(audioHandle);
+	}
+
+	// It's intentional that _lastImage is set with the first video image
+
+	delete videoDecoder;
+	g_system->showMouse(true);
+}
+
+void Versailles_DialogsManager::displayMessage(const Common::String &text) {
+	_engine->displayMessageBoxWarp(text);
+}
+
+unsigned int Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
+        const Common::StringArray &questions) {
+	if (_lastImage.empty()) {
+		loadFrame(video);
+	}
+
+	if (questions.size() == 0 || questions.size() > 5) {
+		return -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;
+	unsigned int questionId = 0;
+	for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
+	        it++, questionId++) {
+		tops[questionId] = currentHeight;
+		unsigned int 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;
+	unsigned int selectedQuestion = -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();
+
+		if (_engine->pollEvents()) {
+			_engine->clearKeys();
+			if (g_engine->shouldQuit()) {
+				finished = true;
+				selectedQuestion = -1;
+				break;
+			}
+			Common::Point mousePos = _engine->getMousePos();
+			if (_engine->getDragStatus() == kDragStatus_Finished && selectedQuestion != -1u) {
+				finished = true;
+			} else if (mousePos.x >= 608 || mousePos.y < offsetY) {
+				if (selectedQuestion != -1u) {
+					selectedQuestion = -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 = -1;
+					update = true;
+				}
+			}
+		}
+	}
+
+	return selectedQuestion;
+}
+
+void Versailles_DialogsManager::loadFrame(const Common::String &video) {
+	Common::String videoFName(video);
+	int lastDotPos = videoFName.size() - 1;
+	for (; lastDotPos >= 0; --lastDotPos) {
+		if (videoFName[lastDotPos] == '.') {
+			break;
+		}
+	}
+	if (lastDotPos > -1) {
+		videoFName.erase(lastDotPos);
+		videoFName += ".hnm";
+	}
+
+	Video::HNMDecoder *videoDecoder = new Video::HNMDecoder();
+
+	if (!videoDecoder->loadFile(videoFName)) {
+		warning("Failed to open movie file %s/%s", video.c_str(), videoFName.c_str());
+		delete videoDecoder;
+		return;
+	}
+
+	if (videoDecoder->hasDirtyPalette()) {
+		const byte *palette = videoDecoder->getPalette();
+		_engine->setupPalette(palette, 0, 256);
+	}
+
+	// Preload first frame to draw subtitles from it
+	const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
+	_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
+	_lastImage.blitFrom(*firstFrame);
+}
+
+} // End of namespace Versailles
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/dialogs_manager.h b/engines/cryomni3d/versailles/dialogs_manager.h
new file mode 100644
index 0000000..3c5028f
--- /dev/null
+++ b/engines/cryomni3d/versailles/dialogs_manager.h
@@ -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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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;
+
+class Versailles_DialogsManager : public DialogsManager {
+public:
+	Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine) : _engine(engine) { }
+
+	// This overload will hide the base one and this is what we want
+	bool play(const Common::String &sequence);
+
+	typedef void (CryOmni3DEngine_Versailles::*ShowCallback)();
+	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;
+	unsigned int askPlayerQuestions(const Common::String &video,
+	                                const Common::StringArray &questions) override;
+
+private:
+	CryOmni3DEngine_Versailles *_engine;
+	Common::HashMap<Common::String, ShowCallback> _shows;
+
+	void loadFrame(const Common::String &video);
+
+	Graphics::ManagedSurface _lastImage;
+};
+
+} // End of namespace Versailles
+} // End of namespace CryOmni3D
+
+#endif
diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
new file mode 100644
index 0000000..bbc9242
--- /dev/null
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -0,0 +1,2070 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/file.h"
+#include "common/system.h"
+#include "graphics/managed_surface.h"
+#include "image/bmp.h"
+
+#include "cryomni3d/font_manager.h"
+#include "cryomni3d/mouse_boxes.h"
+#include "cryomni3d/sprites.h"
+
+#include "cryomni3d/versailles/documentation.h"
+#include "cryomni3d/versailles/engine.h"
+
+namespace CryOmni3D {
+namespace Versailles {
+
+const char *Versailles_Documentation::kAllDocsFile = "tous_doc.txt";
+const char *Versailles_Documentation::kLinksDocsFile = "lien_doc.txt";
+const Versailles_Documentation::TimelineEntry Versailles_Documentation::kTimelineEntries[] = {
+	{ "1638", 340,  15 },
+	{ "1643", 470,  30 },
+	{ "1648", 380,  45 },
+	{ "1649", 500,  60 },
+	{ "1650", 420,  75 },
+	{ "1651", 520,  90 },
+	{ "1652", 450, 105 },
+	{ "1654", 540, 120 },
+	{ "1658", 470, 135 },
+	{ "1659", 550, 150 },
+	{ "1660", 480, 165 },
+	{ "1661", 560, 180 },
+	{ "1662", 490, 195 },
+	{ "1663", 560, 210 },
+	{ "1664", 490, 225 },
+	{ "1665", 560, 240 },
+	{ "1666", 490, 255 },
+	{ "1667", 560, 270 },
+	{ "1668", 490, 285 },
+	{ "1670", 550, 300 },
+	{ "1671", 480, 315 },
+	{ "1672", 540, 330 },
+	{ "1673", 470, 345 },
+	{ "1674", 530, 360 },
+	{ "1675", 460, 375 },
+	{ "1678", 510, 390 },
+	{ "1680", 430, 405 },
+	{ "1681", 490, 420 },
+	{ "1682", 400, 435 },
+	{ "1683", 450, 450 },
+	{ "1684", 156, 444 },
+	{ "1685",  81, 439 },
+	{ "1686", 140, 422 },
+	{ "1687",  73, 413 },
+	{ "1689", 128, 401 },
+	{ "1697",  62, 389 },
+	{ "1700", 121, 378 },
+	{ "1701",  62, 366 },
+	{ "1702", 121, 355 },
+	{ "1709",  62, 344 },
+	{ "1710", 121, 333 },
+	{ "1712",  67, 322 },
+	{ "1715", 128, 311 },
+};
+
+void Versailles_Documentation::init(const Sprites *sprites, FontManager *fontManager,
+                                    const Common::StringArray *messages, CryOmni3DEngine *engine) {
+	_sprites = sprites;
+	_fontManager = fontManager;
+	_messages = messages;
+	_engine = engine;
+
+	// Build list of records
+	Common::File allDocsFile;
+
+	if (!allDocsFile.open(kAllDocsFile)) {
+		error("Can't open %s", kAllDocsFile);
+	}
+
+	unsigned int allDocsSize = allDocsFile.size();
+	char *allDocs = new char[allDocsSize + 1];
+	char *end = allDocs + allDocsSize;
+	allDocsFile.read(allDocs, allDocsSize);
+	allDocs[allDocsSize] = '\0';
+	allDocsFile.close();
+
+	const char *patterns[] = { "FICH=", nullptr };
+	RecordInfo record;
+
+	char *currentPos = allDocs;
+	char *lastRecordName;
+	bool first = true;
+
+	while (true) {
+		currentPos = getDocPartAddress(currentPos, end, patterns);
+		if (!currentPos) {
+			break;
+		}
+		currentPos -= 5;
+		if (first) {
+			record.position = currentPos - allDocs;
+			record.id = 0;
+
+			lastRecordName = currentPos + 5;
+
+			first = false;
+		} else {
+			record.size = (currentPos - allDocs) - record.position;
+			//debug("Found record %s", lastRecordName);
+			_records[lastRecordName] = record;
+			_recordsOrdered.push_back(lastRecordName);
+
+			record.id++;
+			record.position = currentPos - allDocs;
+
+			lastRecordName = currentPos + 5;
+		}
+		// Next line
+		currentPos += strlen(currentPos) + 1;
+	}
+	record.size = allDocsSize - record.position;
+	_records[lastRecordName] = record;
+	_recordsOrdered.push_back(lastRecordName);
+
+	delete[] allDocs;
+}
+
+void Versailles_Documentation::handleDocArea() {
+	g_system->showMouse(false);
+
+	// Load all links lazily and free them at the end to not waste memory
+	// Maybe it's not really useful
+	getLinks("ALL00", _allLinks);
+
+	bool end = false;
+	while (!end) {
+		Common::String selectedRecord = docAreaHandleSummary();
+		if (selectedRecord == "") {
+			end = true;
+		} else if (selectedRecord == "VT00") {
+			selectedRecord = docAreaHandleTimeline();
+			if (selectedRecord != "") {
+				if (docAreaHandleRecords(selectedRecord) == 2) {
+					end = true;
+				}
+			}
+		} else {
+			if (docAreaHandleRecords(selectedRecord) == 2) {
+				end = true;
+			}
+		}
+	}
+
+	_allLinks.clear();
+
+	g_system->showMouse(true);
+}
+
+void Versailles_Documentation::handleDocInGame(const Common::String &record) {
+	_visitTrace.clear();
+	_currentRecord = record;
+
+	Graphics::ManagedSurface docSurface;
+	Common::String nextRecord;
+	MouseBoxes boxes(3);
+
+	g_system->showMouse(false);
+	bool end = false;
+	while (!end) {
+		inGamePrepareRecord(docSurface, boxes);
+		unsigned int action = inGameHandleRecord(docSurface, boxes, nextRecord);
+		switch (action) {
+		case 0:
+			// Back
+			if (!_visitTrace.empty()) {
+				_currentRecord = _visitTrace.back();
+				_visitTrace.pop_back();
+				break;
+			}
+		// No previous record, like a quit
+		// fall through
+		case 1:
+			// Quit
+			end = true;
+			break;
+		case 2:
+			// Follow hyperlink keeping trace
+			_visitTrace.push_back(_currentRecord);
+			_currentRecord = nextRecord;
+			break;
+		default:
+			error("Invalid case %d when displaying doc record", action);
+		}
+	}
+	g_system->showMouse(true);
+}
+
+Common::String Versailles_Documentation::docAreaHandleSummary() {
+	struct Category {
+		const char *record;
+		const char *bmp;
+		Common::Point imgPos;
+		Common::Rect linesPos;
+		const Common::String *title;
+		Graphics::Surface highlightedImg;
+
+		Category(const char *record_, const char *bmp_, const Common::Point &imgPos_,
+		         const Common::Rect &linesPos_, const Common::String *title_) :
+			record(record_), bmp(bmp_), imgPos(imgPos_), linesPos(linesPos_), title(title_) { }
+	} categories[8] = {
+		Category(
+		    "VA00",
+		    "VA.bmp",
+		    Common::Point(142, 402),
+		    Common::Rect(174, 372, 284, 372),
+		    &(*_messages)[68]),
+		Category(
+		    "VR00",
+		    "VR.bmp",
+		    Common::Point(82, 187),
+		    Common::Rect(89, 187, 217, 212),
+		    &(*_messages)[69]),
+		Category(
+		    "VC00",
+		    "VC.bmp",
+		    Common::Point(176, 105),
+		    Common::Rect(177, 107, 292, 130),
+		    &(*_messages)[70]),
+		Category(
+		    "VT00",
+		    "VH.bmp", //sic
+		    Common::Point(283, 467),
+		    Common::Rect(311, 451, 466, 451),
+		    &(*_messages)[73]),
+		Category(
+		    "VV00",
+		    "VV.bmp",
+		    Common::Point(68, 305),
+		    Common::Rect(94, 292, 300, 292),
+		    &(*_messages)[71]),
+		Category(
+		    "VS00",
+		    "VS.bmp",
+		    Common::Point(321, 70),
+		    Common::Rect(322, 71, 540, 94),
+		    &(*_messages)[72]),
+		Category(
+		    nullptr,
+		    nullptr,
+		    Common::Point(256, 212),
+		    Common::Rect(),
+		    nullptr),
+		Category(
+		    nullptr,
+		    nullptr,
+		    Common::Point(600, 450),
+		    Common::Rect(),
+		    nullptr)
+	};
+	Image::BitmapDecoder bmpDecoder;
+	Common::File file;
+
+	for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
+		if (!categories[i].bmp) {
+			// No BMP to load
+			continue;
+		}
+		if (!file.open(categories[i].bmp)) {
+			error("Failed to open BMP file: %s", categories[i].bmp);
+		}
+		if (!bmpDecoder.loadStream(file)) {
+			error("Failed to load BMP file: %s", categories[i].bmp);
+		}
+		categories[i].highlightedImg.copyFrom(*bmpDecoder.getSurface());
+		bmpDecoder.destroy();
+		file.close();
+	}
+
+	Image::ImageDecoder *imageDecoder = _engine->loadHLZ("SOM1.HLZ");
+	if (!imageDecoder) {
+		return "";
+	}
+	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
+
+	Graphics::ManagedSurface docSurface;
+	docSurface.create(bgFrame->w, bgFrame->h, bgFrame->format);
+	docSurface.blitFrom(*bgFrame);
+
+	_fontManager->setCurrentFont(0);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setLineHeight(14);
+	_fontManager->setSpaceWidth(0);
+	_fontManager->setCharSpacing(1);
+	_fontManager->setSurface(&docSurface);
+
+	MouseBoxes boxes(8);
+	boxes.setupBox(0, 104, 335, 177, 408);
+	boxes.setupBox(1, 46, 122, 119, 195);
+	boxes.setupBox(2, 140, 40, 213, 113);
+	boxes.setupBox(3, 247, 402, 320, 475);
+	boxes.setupBox(4, 32, 240, 105, 313);
+	boxes.setupBox(5, 285, 5, 358, 78);
+	// No box for 6
+	boxes.setupBox(7, 0, 480 - _sprites->getCursor(225).getHeight(), 640, 480);
+
+	_engine->setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+	                      imageDecoder->getPaletteColorCount());
+
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int selectedBox = -1;
+
+	while (selectedBox == -1u) {
+		if (redraw) {
+			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
+			for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
+				unsigned int foreColor = 243;
+				if (i == hoveredBox) {
+					foreColor = 241;
+					if (categories[hoveredBox].highlightedImg.getPixels() != nullptr) {
+						docSurface.transBlitFrom(categories[i].highlightedImg, categories[i].imgPos - Common::Point(36,
+						                         65));
+					}
+				}
+				_fontManager->setForeColor(foreColor);
+				if (categories[i].title) {
+					unsigned int x = categories[i].linesPos.right - _fontManager->getStrWidth(*categories[i].title);
+					unsigned int y = categories[i].linesPos.bottom - _fontManager->getFontMaxHeight() - 5;
+					_fontManager->displayStr(x, y, *categories[i].title);
+
+					// Draw line to text
+					docSurface.vLine(categories[i].linesPos.left, categories[i].linesPos.top,
+					                 categories[i].linesPos.bottom, foreColor);
+					docSurface.hLine(categories[i].linesPos.left, categories[i].linesPos.bottom,
+					                 categories[i].linesPos.right - 1, foreColor); // minus 1 because hLine draws inclusive
+				}
+			}
+			docSurface.transBlitFrom(_sprites->getSurface(225), boxes.getBoxOrigin(7),
+			                         _sprites->getKeyColor(225));
+
+			g_system->copyRectToScreen(docSurface.getPixels(), docSurface.pitch, 0, 0, docSurface.w,
+			                           docSurface.h);
+
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			if (!_engine->getCurrentMouseButton()) {
+				// Don't change highlighted icon when clicking
+				Common::Point mouse = _engine->getMousePos();
+				bool foundBox = false;
+				for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
+					if (boxes.hitTest(i, mouse)) {
+						foundBox = true;
+						if (i != hoveredBox) {
+							hoveredBox = i;
+							redraw = true;
+						}
+					}
+				}
+				if (!foundBox && hoveredBox != -1u) {
+					if (categories[hoveredBox].highlightedImg.getPixels() != nullptr) {
+						// Restore original icon
+						const Common::Point &imgPos = categories[hoveredBox].imgPos;
+						docSurface.blitFrom(*bgFrame, Common::Rect(
+						                        imgPos.x - 36, imgPos.y - 65, imgPos.x + 37, imgPos.y + 8),
+						                    Common::Point(imgPos.x - 36, imgPos.y - 65));
+					}
+					hoveredBox = -1;
+					redraw = true;
+				}
+			}
+			if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (hoveredBox != -1u) {
+					selectedBox = hoveredBox;
+				}
+			}
+			if (_engine->checkKeysPressed(1, Common::KEYCODE_ESCAPE)) {
+				selectedBox = 7;
+			}
+		}
+		if (g_engine->shouldQuit()) {
+			selectedBox = 7;
+		}
+	}
+
+	g_system->showMouse(false);
+
+	delete imageDecoder;
+
+	if (selectedBox == 7) {
+		return "";
+	} else {
+		return categories[selectedBox].record;
+	}
+}
+
+Common::String Versailles_Documentation::docAreaHandleTimeline() {
+	Image::ImageDecoder *imageDecoder = _engine->loadHLZ("chrono1.HLZ");
+	if (!imageDecoder) {
+		return "";
+	}
+	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
+
+	Graphics::ManagedSurface docSurface;
+	docSurface.create(bgFrame->w, bgFrame->h, bgFrame->format);
+	docSurface.blitFrom(*bgFrame);
+
+	_fontManager->setCurrentFont(1);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setLineHeight(14);
+	_fontManager->setSpaceWidth(0);
+	_fontManager->setCharSpacing(1);
+	_fontManager->setSurface(&docSurface);
+
+	_engine->setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+	                      imageDecoder->getPaletteColorCount());
+
+	_fontManager->displayStr(78, 10, (*_messages)[73]);
+	docSurface.hLine(0, 39, 171, 241); // minus 1 because hLine draws inclusive
+
+	_fontManager->setCurrentFont(0);
+
+	MouseBoxes boxes(ARRAYSIZE(kTimelineEntries) + 1);
+	for (unsigned int box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
+		boxes.setupBox(box_id, kTimelineEntries[box_id].x, kTimelineEntries[box_id].y,
+		               kTimelineEntries[box_id].x + 30, kTimelineEntries[box_id].y + 20);
+	}
+	const unsigned int leaveBoxId = ARRAYSIZE(kTimelineEntries);
+	boxes.setupBox(leaveBoxId, 639 - _sprites->getCursor(105).getWidth(),
+	               479 - _sprites->getCursor(105).getHeight(), 640, 480);
+
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int selectedBox = -1;
+
+	while (selectedBox == -1u) {
+		if (redraw) {
+			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
+			for (unsigned int i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
+				_fontManager->setForeColor(i == hoveredBox ? 241 : 243);
+				_fontManager->displayStr(kTimelineEntries[i].x, kTimelineEntries[i].y, kTimelineEntries[i].year);
+			}
+			docSurface.transBlitFrom(_sprites->getSurface(105), boxes.getBoxOrigin(leaveBoxId),
+			                         _sprites->getKeyColor(105));
+
+			g_system->copyRectToScreen(docSurface.getPixels(), docSurface.pitch, 0, 0,
+			                           docSurface.w, docSurface.h);
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			Common::Point mouse = _engine->getMousePos();
+			if (!_engine->getCurrentMouseButton()) {
+				// Don't change highlighted date when clicking
+				bool foundBox = false;
+				for (unsigned int i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
+					if (boxes.hitTest(i, mouse)) {
+						foundBox = true;
+						if (i != hoveredBox) {
+							hoveredBox = i;
+							redraw = true;
+						}
+					}
+				}
+				if (!foundBox && hoveredBox != -1u) {
+					hoveredBox = -1;
+					redraw = true;
+				}
+			}
+			if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (hoveredBox != -1u) {
+					selectedBox = hoveredBox;
+				}
+				if (boxes.hitTest(leaveBoxId, mouse)) {
+					selectedBox = leaveBoxId;
+				}
+			}
+			if (_engine->checkKeysPressed(1, Common::KEYCODE_ESCAPE)) {
+				selectedBox = leaveBoxId;
+			}
+		}
+		if (g_engine->shouldQuit()) {
+			selectedBox = leaveBoxId;
+		}
+	}
+
+	g_system->showMouse(false);
+
+	delete imageDecoder;
+
+	if (selectedBox == leaveBoxId) {
+		return "";
+	} else {
+		Common::String ret = "VT";
+		ret += kTimelineEntries[selectedBox].year;
+		return ret;
+	}
+}
+
+unsigned int Versailles_Documentation::docAreaHandleRecords(const Common::String &record) {
+	unsigned int action = -1;
+
+	_currentRecord = record;
+	_visitTrace.clear();
+
+	Graphics::ManagedSurface docSurface;
+	Common::String nextRecord;
+	MouseBoxes boxes(10 + ARRAYSIZE(kTimelineEntries));
+
+	while (true) {
+		if (action == -1u) {
+			_currentRecord.toUppercase();
+
+			//debug("Displaying %s", _currentRecord.c_str());
+			docAreaPrepareNavigation();
+			docAreaPrepareRecord(docSurface, boxes);
+			action = docAreaHandleRecord(docSurface, boxes, nextRecord);
+		}
+
+		switch (action) {
+		case 0:
+			action = -1;
+			// Back
+			if (!_visitTrace.empty()) {
+				_currentRecord = _visitTrace.back();
+				_visitTrace.pop_back();
+				break;
+			}
+		// No previous record, like a back to root
+		// fall through
+		case 1:
+			// Back to root
+			return 1;
+		case 2:
+			action = -1;
+			// Follow hyperlink keeping trace
+			_visitTrace.push_back(_currentRecord);
+			_currentRecord = nextRecord;
+			break;
+		case 3:
+			action = -1;
+			// Follow hyperlink losing trace
+			_visitTrace.clear();
+			_currentRecord = nextRecord;
+			break;
+		case 6:
+			// Quit
+			return 2;
+		case 7:
+			action = -1;
+			// General map
+			_visitTrace.clear();
+			nextRecord = docAreaHandleGeneralMap();
+			if (nextRecord == "") {
+				// Go back to current record
+				break;
+			} else if (nextRecord != "VS00") {
+				_currentRecord = nextRecord;
+				break;
+			}
+		// castle has been selected, display its map
+		// fall through
+		case 8:
+			action = -1;
+			// Castle map
+			_visitTrace.clear();
+			nextRecord = docAreaHandleCastleMap();
+			if (nextRecord == "") {
+				// Go back to current record
+				break;
+			} else if (nextRecord != "planG") {
+				_currentRecord = nextRecord;
+				break;
+			} else {
+				// We can't go up to previous case, so let's do a round
+				action = 7;
+				break;
+			}
+		case 9:
+			action = -1;
+			// Start of category
+			_currentRecord = _categoryStartRecord;
+			break;
+		default:
+			error("Invalid case %d when displaying doc record", action);
+		}
+	}
+	error("shouldn't be there");
+}
+
+void Versailles_Documentation::docAreaPrepareNavigation() {
+	_currentInTimeline = false;
+	_currentMapLayout = false;
+	_currentHasMap = false;
+	_currentLinks.clear();
+
+	if (_currentRecord.hasPrefix("VA")) {
+		_categoryStartRecord = "VA00";
+		_categoryEndRecord = "VA15";
+		_categoryTitle = (*_messages)[68];
+	} else if (_currentRecord.hasPrefix("VC")) {
+		_categoryStartRecord = "VC00";
+		_categoryEndRecord = "VC26";
+		_categoryTitle = (*_messages)[70];
+	} else if (_currentRecord.hasPrefix("VR")) {
+		_categoryStartRecord = "VR00";
+		_categoryEndRecord = "VR14";
+		_categoryTitle = (*_messages)[69];
+	} else if (_currentRecord.hasPrefix("VS")) {
+		_categoryStartRecord = "VS00";
+		_categoryEndRecord = "VS37";
+		_categoryTitle = (*_messages)[72];
+		unsigned int id = atoi(_currentRecord.c_str() + 2);
+		if (id >= 16 && id <= 40) {
+			_currentMapLayout = true;
+		}
+		if ((id >= 16 && id <= 31) ||
+		        (id >= 35 && id <= 39)) {
+			_currentHasMap = true;
+		}
+	} else if (_currentRecord.hasPrefix("VT")) {
+		_categoryStartRecord = "VT00";
+		_categoryEndRecord = "VT1715";
+		_categoryTitle = (*_messages)[73];
+		_currentInTimeline = true;
+	} else if (_currentRecord.hasPrefix("VV")) {
+		_categoryStartRecord = "VV00";
+		_categoryEndRecord = "VV15";
+		_categoryTitle = (*_messages)[71];
+	}
+	getLinks(_currentRecord, _currentLinks);
+}
+
+void Versailles_Documentation::docAreaPrepareRecord(Graphics::ManagedSurface &surface,
+        MouseBoxes &boxes) {
+	boxes.reset();
+
+	setupRecordBoxes(true, boxes);
+
+	Common::String title, subtitle, caption;
+	Common::StringArray hyperlinks;
+	Common::String text = getRecordData(_currentRecord, title, subtitle, caption, hyperlinks);
+
+	drawRecordData(surface, text, title, subtitle, caption);
+
+	if (_currentInTimeline) {
+		surface.hLine(0, 39, 171, 241); // minus 1 because hLine draws inclusive
+		_fontManager->setCurrentFont(0);
+		_fontManager->setTransparentBackground(true);
+		_fontManager->setLineHeight(14);
+		_fontManager->setSpaceWidth(0);
+		_fontManager->setCharSpacing(1);
+		_fontManager->setSurface(&surface);
+		_fontManager->setForeColor(243);
+		for (unsigned int box_id = 10; box_id < ARRAYSIZE(kTimelineEntries) + 10; box_id++) {
+			boxes.display(box_id, *_fontManager);
+		}
+	}
+
+	drawRecordBoxes(surface, true, boxes);
+}
+
+unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurface &surface,
+        MouseBoxes &boxes, Common::String &nextRecord) {
+	// Hovering is only handled for timeline entries
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	bool first = true;
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int action = -1;
+
+	while (action == -1u) {
+		if (redraw) {
+			g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.w, surface.h);
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents() || first) {
+			first = false;
+			if (g_engine->shouldQuit()) {
+				// Fake the quit
+				action = 6;
+			}
+			Common::Point mouse = _engine->getMousePos();
+			if (_currentInTimeline) {
+				bool foundBox = false;
+				for (unsigned int i = 10; i < 10 + ARRAYSIZE(kTimelineEntries); i++) {
+					if (boxes.hitTest(i, mouse)) {
+						foundBox = true;
+						if (i != hoveredBox) {
+							_fontManager->setCurrentFont(0);
+							_fontManager->setTransparentBackground(true);
+							_fontManager->setSurface(&surface);
+							if (hoveredBox != -1u) {
+								// Restore the previous entry hovered
+								_fontManager->setForeColor(243);
+								boxes.display(hoveredBox, *_fontManager);
+							}
+							hoveredBox = i;
+							_fontManager->setForeColor(241);
+							boxes.display(hoveredBox, *_fontManager);
+							redraw = true;
+						}
+					}
+				}
+				if (!foundBox && hoveredBox != -1u) {
+					// Restore the previous entry hovered
+					_fontManager->setForeColor(243);
+					boxes.display(hoveredBox, *_fontManager);
+					hoveredBox = -1;
+					redraw = true;
+				}
+			} else if (_currentHasMap) { // Mutually exclusive with timeline
+				// No clash is possible for hoveredBox between timeline and map
+				if (boxes.hitTest(8, mouse)) {
+					if (hoveredBox != 8) {
+						_engine->setCursor(145);
+						hoveredBox = 8;
+					}
+				} else {
+					if (hoveredBox == 8) {
+						_engine->setCursor(181);
+						hoveredBox = -1;
+					}
+				}
+			}
+			if (_engine->getDragStatus() == kDragStatus_Pressed) {
+				if (boxes.hitTest(2, mouse) && _currentLinks.size()) {
+					Common::StringArray items;
+					for (Common::Array<LinkInfo>::const_iterator it = _currentLinks.begin(); it != _currentLinks.end();
+					        it++) {
+						items.push_back(it->title);
+					}
+					Common::Rect iconRect = boxes.getBoxRect(2);
+					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                            true, 20, items);
+					if (selectedItem != -1u) {
+						nextRecord = _currentLinks[selectedItem].record;
+						action = 2;
+					}
+				} else if (boxes.hitTest(3, mouse)) {
+					Common::StringArray items;
+					for (Common::Array<LinkInfo>::const_iterator it = _allLinks.begin(); it != _allLinks.end(); it++) {
+						items.push_back(it->title);
+					}
+					Common::Rect iconRect = boxes.getBoxRect(3);
+					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                            true, 20, items);
+					if (selectedItem != -1u) {
+						nextRecord = _allLinks[selectedItem].record;
+						action = 3;
+					}
+				}
+			} else if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (boxes.hitTest(0, mouse)) {
+					// Back in history
+					action = 0;
+				} else if (boxes.hitTest(1, mouse)) {
+					// Handle summary menu
+					Common::StringArray items;
+					items.push_back((*_messages)[61]);
+					items.push_back((*_messages)[62]);
+					unsigned int selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(1), false, 20, items);
+					if (selectedItem == 0) {
+						action = 1;
+					} else if (selectedItem == 1) {
+						action = 7;
+					}
+				} else if (boxes.hitTest(4, mouse)) {
+					// Next
+					action = 4;
+				} else if (boxes.hitTest(5, mouse)) {
+					// Previous
+					action = 5;
+				} else if (boxes.hitTest(6, mouse)) {
+					// Handle quit menu
+					Common::StringArray items;
+					items.push_back((*_messages)[60]);
+					unsigned int selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(6), false, 20, items);
+					if (selectedItem == 0) {
+						action = 6;
+					}
+				} else if (_currentHasMap && boxes.hitTest(8, mouse)) {
+					// Map
+					action = 8;
+				} else if (boxes.hitTest(9, mouse)) {
+					// Category name
+					action = 9;
+				} else if (_currentInTimeline && hoveredBox != -1u) {
+					// Clicked on a timeline entry
+					nextRecord = "VT";
+					nextRecord += kTimelineEntries[hoveredBox - 10].year;
+					// Fake a global jump
+					action = 3;
+				}
+			}
+			if (action == 4 || action == 5) {
+				if (action == 4 && _currentRecord == _categoryEndRecord) {
+					action = -1;
+					continue;
+				}
+				if (action == 5 && _currentRecord == _categoryStartRecord) {
+					action = -1;
+					continue;
+				}
+				Common::HashMap<Common::String, RecordInfo>::iterator hmIt = _records.find(_currentRecord);
+				if (hmIt == _records.end()) {
+					// Shouldn't happen
+					action = -1;
+					continue;
+				}
+				unsigned int recordId = hmIt->_value.id;
+				if (action == 4) {
+					recordId++;
+				} else if (action == 5) {
+					recordId--;
+				}
+				assert(recordId < _recordsOrdered.size());
+				nextRecord = _recordsOrdered[recordId];
+				// Fake a global jump
+				action = 3;
+			}
+		}
+	}
+
+	g_system->showMouse(false);
+	_engine->setCursor(181);
+	return action;
+}
+
+Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
+	struct Area {
+		Common::Rect areaPos;
+		const char *record;
+		const char *bmp;
+		unsigned int messageId;
+		const Common::String *message;
+		Common::Point messagePos;
+		Graphics::Surface highlightedImg;
+
+		Area(const Common::Point &areaPos_, const char *bmp_, unsigned int messageId_,
+		     const char *record_ = nullptr) :
+			areaPos(areaPos_.x, areaPos_.y, areaPos_.x, areaPos_.y), record(record_), bmp(bmp_),
+			messageId(messageId_), message(nullptr) { }
+		Area(const Common::Rect &areaPos_, unsigned int messageId_, const char *record_ = nullptr) :
+			areaPos(areaPos_), record(record_), bmp(nullptr), messageId(messageId_), message(nullptr) { }
+	} areas[] = {
+		Area(Common::Point(174, 181), "APL.bmp", 74),
+		Area(Common::Point(422, 129), "CHAT.bmp", 75, "VS00"),
+		Area(Common::Point(193, 204), "COLN.bmp", 76, "VS02"),
+		Area(Common::Point(327, 269), "LABY.bmp", 77, "VS33"),
+		Area(Common::Point(327, 170), "LATN.bmp", 78),
+		Area(Common::Point(396, 271), "ORG.bmp", 79, "VS32"),
+		Area(Common::Point(385, 203), "PART.bmp", 80, "VS06"),
+		Area(Common::Point(212, 193), "TAP.bmp", 81),
+		Area(Common::Rect(0, 194, 154, 211), 86, "VS09"),
+		Area(Common::Rect(396, 229, 450, 268), 87),
+		Area(Common::Rect(394, 133, 450, 177), 88),
+		Area(Common::Rect(489, 376, 592, 479), 89, "VS07"),
+		Area(Common::Rect(327, 233, 386, 266), 90),
+		Area(Common::Rect(395, 18, 451, 60), 91),
+		Area(Common::Rect(383, 381, 477, 479), 92)
+	};
+
+	_fontManager->setCurrentFont(0);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setLineHeight(14);
+	_fontManager->setSpaceWidth(0);
+	_fontManager->setCharSpacing(1);
+
+	MouseBoxes boxes(ARRAYSIZE(areas) + 1);
+
+	Image::BitmapDecoder bmpDecoder;
+	Common::File file;
+
+	for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+		if (areas[i].bmp) {
+			if (!file.open(areas[i].bmp)) {
+				error("Failed to open BMP file: %s", areas[i].bmp);
+			}
+			if (!bmpDecoder.loadStream(file)) {
+				error("Failed to load BMP file: %s", areas[i].bmp);
+			}
+			areas[i].highlightedImg.copyFrom(*bmpDecoder.getSurface());
+			bmpDecoder.destroy();
+			file.close();
+			areas[i].areaPos.setWidth(areas[i].highlightedImg.w);
+			areas[i].areaPos.setHeight(areas[i].highlightedImg.h);
+		}
+		areas[i].message = &(*_messages)[areas[i].messageId];
+		unsigned int lineWidth = _fontManager->getStrWidth(*areas[i].message);
+		areas[i].messagePos.x = (areas[i].areaPos.left + areas[i].areaPos.right) / 2 - lineWidth / 2;
+		areas[i].messagePos.y = areas[i].areaPos.top - 40;
+		if (areas[i].messagePos.x < 8) {
+			areas[i].messagePos.x = 8;
+		} else if (areas[i].messagePos.x + lineWidth > 627) {
+			areas[i].messagePos.x = 627 - lineWidth;
+		}
+		if (areas[i].messagePos.y < 5) {
+			areas[i].messagePos.y = 5;
+		}
+		const Common::Rect &areaPos = areas[i].areaPos;
+		boxes.setupBox(i, areaPos.left, areaPos.top, areaPos.right, areaPos.bottom);
+	}
+	boxes.setupBox(ARRAYSIZE(areas), 639 - _sprites->getCursor(105).getWidth(),
+	               479 - _sprites->getCursor(105).getHeight(), 640, 480);
+
+	Image::ImageDecoder *imageDecoder = _engine->loadHLZ("PLANGR.HLZ");
+	if (!imageDecoder) {
+		return "";
+	}
+	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
+
+	Graphics::ManagedSurface mapSurface;
+	mapSurface.create(bgFrame->w, bgFrame->h, bgFrame->format);
+	mapSurface.blitFrom(*bgFrame);
+
+	_fontManager->setSurface(&mapSurface);
+
+	_engine->setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+	                      imageDecoder->getPaletteColorCount());
+
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int selectedBox = -1;
+
+	while (selectedBox == -1u) {
+		if (redraw) {
+			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
+			if (hoveredBox != -1u) {
+				if (areas[hoveredBox].highlightedImg.getPixels() != nullptr) {
+					mapSurface.transBlitFrom(areas[hoveredBox].highlightedImg,
+					                         Common::Point(areas[hoveredBox].areaPos.left, areas[hoveredBox].areaPos.top));
+				} else {
+					unsigned int middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
+					unsigned int middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
+					unsigned int spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
+					unsigned int spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
+					mapSurface.transBlitFrom(_sprites->getSurface(163), Common::Point(spriteX, spriteY),
+					                         _sprites->getKeyColor(163));
+				}
+				_fontManager->setForeColor(areas[hoveredBox].record == nullptr ? 243 : 240);
+				Graphics::Surface subSurface = mapSurface.getSubArea(Common::Rect(areas[hoveredBox].messagePos.x -
+				                               3,
+				                               areas[hoveredBox].messagePos.y - 3,
+				                               areas[hoveredBox].messagePos.x + _fontManager->getStrWidth(*areas[hoveredBox].message) + 3,
+				                               areas[hoveredBox].messagePos.y + _fontManager->getFontMaxHeight() + 8));
+				_engine->makeTranslucent(subSurface, subSurface);
+				_fontManager->displayStr(areas[hoveredBox].messagePos.x, areas[hoveredBox].messagePos.y,
+				                         *areas[hoveredBox].message);
+			}
+			mapSurface.transBlitFrom(_sprites->getSurface(105), boxes.getBoxOrigin(ARRAYSIZE(areas)),
+			                         _sprites->getKeyColor(105));
+			/*
+			// For debugging only
+			for(unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+			    mapSurface.frameRect(areas[i].areaPos, 0);
+			}
+			*/
+
+			g_system->copyRectToScreen(mapSurface.getPixels(), mapSurface.pitch, 0, 0, mapSurface.w,
+			                           mapSurface.h);
+
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			Common::Point mouse = _engine->getMousePos();
+			if (!_engine->getCurrentMouseButton()) {
+				// Don't change highlighted icon when clicking
+				bool foundBox = false;
+				unsigned int oldHoveredBox = hoveredBox;
+				for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+					if (boxes.hitTest(i, mouse)) {
+						if (i != hoveredBox) {
+							hoveredBox = i;
+							redraw = true;
+						}
+						foundBox = true;
+						break;
+					}
+				}
+				if (!foundBox && hoveredBox != -1u) {
+					hoveredBox = -1;
+					redraw = true;
+				}
+				if (hoveredBox != oldHoveredBox && oldHoveredBox != -1u) {
+					// Restore original area
+					mapSurface.blitFrom(*bgFrame, areas[oldHoveredBox].areaPos,
+					                    Common::Point(areas[oldHoveredBox].areaPos.left, areas[oldHoveredBox].areaPos.top));
+					Common::Rect textRect(areas[oldHoveredBox].messagePos.x - 3,
+					                      areas[oldHoveredBox].messagePos.y - 3,
+					                      areas[oldHoveredBox].messagePos.x + _fontManager->getStrWidth(*areas[oldHoveredBox].message) + 3,
+					                      areas[oldHoveredBox].messagePos.y + _fontManager->getFontMaxHeight() + 8);
+					mapSurface.blitFrom(*bgFrame, textRect,
+					                    Common::Point(textRect.left, textRect.top));
+				}
+			}
+			if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (hoveredBox != -1u && areas[hoveredBox].record) {
+					selectedBox = hoveredBox;
+				} else if (boxes.hitTest(ARRAYSIZE(areas), mouse)) {
+					selectedBox = ARRAYSIZE(areas);
+				}
+			}
+			if (_engine->checkKeysPressed(1, Common::KEYCODE_ESCAPE)) {
+				selectedBox = ARRAYSIZE(areas);
+			}
+			if (g_engine->shouldQuit()) {
+				selectedBox = ARRAYSIZE(areas);
+			}
+		}
+	}
+
+	g_system->showMouse(false);
+
+	delete imageDecoder;
+
+	if (selectedBox == ARRAYSIZE(areas)) {
+		return "";
+	} else {
+		return areas[selectedBox].record;
+	}
+}
+
+Common::String Versailles_Documentation::docAreaHandleCastleMap() {
+	struct Area {
+		Common::Rect areaPos;
+		bool fillArea;
+		const char *record;
+		unsigned int messageId;
+		Common::String message;
+		Common::Point messagePos;
+		Common::Rect areaPos1;
+		Common::Rect areaPos2;
+
+		Area(const Common::Rect &areaPos_, const char *record_, bool fillArea_ = true,
+		     unsigned int messageId_ = -1) :
+			areaPos(areaPos_), record(record_), fillArea(fillArea_), messageId(messageId_) { }
+		Area(const Common::Rect &areaPos_, const Common::Rect &areaPos1_,
+		     const Common::Rect &areaPos2_, const char *record_, bool fillArea_ = true,
+		     unsigned int messageId_ = -1) :
+			areaPos(areaPos_), areaPos1(areaPos1_), areaPos2(areaPos2_),
+			record(record_), fillArea(fillArea_), messageId(messageId_) { }
+	} areas[] = {
+		/* 0 */
+		Area(Common::Rect(212, 134, 239, 164), "VS16"),
+		Area(Common::Rect(74, 160, 89, 173), "VS24"),
+		Area(Common::Rect(93, 160, 109, 173), "VS25"),
+		Area(Common::Rect(130, 160, 154, 173), "VS26"),
+		Area(Common::Rect(158, 160, 171, 173), "VS27"),
+		Area(Common::Rect(199, 160, 209, 171), "VS28"),
+		Area(Common::Rect(74, 177, 89, 291), "VS31"),
+		Area(Common::Rect(158, 178, 195, 193), "VS30"),
+		Area(Common::Rect(199, 175, 209, 188), "VS29"),
+		Area(Common::Rect(112, 220, 160, 249), "VS35"),
+		/* 10 */
+		Area(Common::Rect(93, 227, 106, 240), "VS23"),
+		Area(Common::Rect(93, 244, 106, 257), "VS22"),
+		Area(Common::Rect(93, 261, 106, 274), "VS20"),
+		Area(Common::Rect(110, 255, 126, 269), "VS19"),
+		Area(Common::Rect(133, 255, 155, 271), "VS18"),
+		Area(Common::Rect(93, 285, 99, 295), "VS21"),
+		Area(Common::Rect(152, 279, 173, 288), "VS17"),
+		Area(Common::Rect(336, 113, 359, 136), Common::Rect(359, 116, 448, 134), Common::Rect(449, 113, 473, 136), "VS36"),
+		Area(Common::Rect(336, 328, 359, 351), Common::Rect(359, 331, 448, 348), Common::Rect(449, 328, 473, 351), "VS36"),
+		Area(Common::Rect(563, 0, 624, 139), "planG", false, 82),
+		/* 20 */
+		Area(Common::Rect(563, 300, 624, 462), "planG", false, 83),
+		Area(Common::Rect(0, 0, 205, 152), "planG", false, 84),
+		Area(Common::Rect(0, 318, 205, 465), "planG", false, 84),
+		Area(Common::Rect(160, 210, 329, 267), "VS40", false),
+		Area(Common::Rect(330, 158, 561, 315), "planG", false, 85),
+	};
+
+	_fontManager->setCurrentFont(0);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setLineHeight(14);
+	_fontManager->setSpaceWidth(0);
+	_fontManager->setCharSpacing(1);
+
+	MouseBoxes boxes(ARRAYSIZE(areas) + 1);
+
+	for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+		if (areas[i].messageId != -1u) {
+			areas[i].message = (*_messages)[areas[i].messageId];
+		} else {
+			areas[i].message = getRecordTitle(areas[i].record);
+		}
+		unsigned int lineWidth = _fontManager->getStrWidth(areas[i].message);
+		unsigned int right;
+		if (areas[i].areaPos2.right) {
+			right = areas[i].areaPos2.right;
+		} else {
+			right = areas[i].areaPos.right;
+		}
+		areas[i].messagePos.x = (areas[i].areaPos.left + right) / 2 - lineWidth / 2;
+		if (areas[i].fillArea) {
+			areas[i].messagePos.y = areas[i].areaPos.top - 30;
+		} else {
+			areas[i].messagePos.y = (areas[i].areaPos.top + areas[i].areaPos.bottom) / 2 - 50;
+		}
+		if (areas[i].messagePos.x < 5) {
+			areas[i].messagePos.x = 5;
+		} else if (areas[i].messagePos.x + lineWidth > 630) {
+			areas[i].messagePos.x = 630 - lineWidth;
+		}
+		if (areas[i].messagePos.y < 2) {
+			areas[i].messagePos.y = 2;
+		}
+		Common::Rect areaPos = areas[i].areaPos;
+		if (areas[i].areaPos2.right) {
+			areaPos.right = areas[i].areaPos2.right;
+			areaPos.bottom = areas[i].areaPos2.bottom;
+		}
+		boxes.setupBox(i, areaPos.left, areaPos.top, areaPos.right, areaPos.bottom);
+	}
+	boxes.setupBox(ARRAYSIZE(areas), 639 - _sprites->getCursor(105).getWidth(),
+	               479 - _sprites->getCursor(105).getHeight(), 640, 480);
+
+	Image::ImageDecoder *imageDecoder = _engine->loadHLZ("PLAN.HLZ");
+	if (!imageDecoder) {
+		return "";
+	}
+	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
+
+	Graphics::ManagedSurface mapSurface;
+	mapSurface.create(bgFrame->w, bgFrame->h, bgFrame->format);
+	mapSurface.blitFrom(*bgFrame);
+
+	_fontManager->setSurface(&mapSurface);
+
+	_engine->setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+	                      imageDecoder->getPaletteColorCount());
+
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int selectedBox = -1;
+
+	while (selectedBox == -1u) {
+		if (redraw) {
+			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
+			if (hoveredBox != -1u) {
+				if (areas[hoveredBox].fillArea) {
+					Common::Rect rect(areas[hoveredBox].areaPos);
+					rect.bottom += 1; // fillRect needs to fill including the limit
+					rect.right += 1;
+					mapSurface.fillRect(rect, 243);
+					if (areas[hoveredBox].areaPos1.right) {
+						rect = Common::Rect(areas[hoveredBox].areaPos1);
+						rect.bottom += 1; // fillRect needs to fill including the limit
+						rect.right += 1;
+						mapSurface.fillRect(rect, 243);
+					}
+					if (areas[hoveredBox].areaPos2.right) {
+						rect = Common::Rect(areas[hoveredBox].areaPos2);
+						rect.bottom += 1; // fillRect needs to fill including the limit
+						rect.right += 1;
+						mapSurface.fillRect(rect, 243);
+					}
+				} else {
+					unsigned int middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
+					unsigned int middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
+					unsigned int spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
+					unsigned int spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
+					mapSurface.transBlitFrom(_sprites->getSurface(163), Common::Point(spriteX, spriteY),
+					                         _sprites->getKeyColor(163));
+				}
+				Common::Rect textRect(areas[hoveredBox].messagePos.x - 4,
+				                      areas[hoveredBox].messagePos.y,
+				                      areas[hoveredBox].messagePos.x + _fontManager->getStrWidth(areas[hoveredBox].message) + 5,
+				                      areas[hoveredBox].messagePos.y + _fontManager->getFontMaxHeight() + 5);
+				mapSurface.fillRect(textRect, 247);
+				_fontManager->setForeColor(strcmp(areas[hoveredBox].record, "planG") == 0 ? 243 : 241);
+				_fontManager->displayStr(areas[hoveredBox].messagePos.x, areas[hoveredBox].messagePos.y,
+				                         areas[hoveredBox].message);
+			}
+			mapSurface.transBlitFrom(_sprites->getSurface(105), boxes.getBoxOrigin(ARRAYSIZE(areas)),
+			                         _sprites->getKeyColor(105));
+			/*
+			// For debugging only
+			for(unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+			    mapSurface.frameRect(areas[i].areaPos, 0);
+			    if (areas[i].areaPos1.right) {
+			        mapSurface.frameRect(areas[i].areaPos1, 0);
+			    }
+			    if (areas[i].areaPos2.right) {
+			        mapSurface.frameRect(areas[i].areaPos2, 0);
+			    }
+			}
+			*/
+
+			g_system->copyRectToScreen(mapSurface.getPixels(), mapSurface.pitch, 0, 0,
+			                           mapSurface.w, mapSurface.h);
+
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			Common::Point mouse = _engine->getMousePos();
+			if (!_engine->getCurrentMouseButton()) {
+				// Don't change highlighted icon when clicking
+				bool foundBox = false;
+				unsigned int oldHoveredBox = hoveredBox;
+				for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+					if (boxes.hitTest(i, mouse)) {
+						if (i != hoveredBox) {
+							hoveredBox = i;
+							redraw = true;
+						}
+						foundBox = true;
+						break;
+					}
+				}
+				if (!foundBox && hoveredBox != -1u) {
+					hoveredBox = -1;
+					redraw = true;
+				}
+				if (hoveredBox != oldHoveredBox && oldHoveredBox != -1u) {
+					// Restore original area
+					Common::Rect areaPos = areas[oldHoveredBox].areaPos;
+					if (areas[oldHoveredBox].areaPos2.right) {
+						areaPos.right = areas[oldHoveredBox].areaPos2.right;
+						areaPos.bottom = areas[oldHoveredBox].areaPos2.bottom;
+					}
+					areaPos.right += 1;
+					areaPos.bottom += 1;
+					mapSurface.blitFrom(*bgFrame, areaPos,
+					                    Common::Point(areaPos.left, areaPos.top));
+					Common::Rect textRect(areas[oldHoveredBox].messagePos.x - 4,
+					                      areas[oldHoveredBox].messagePos.y,
+					                      areas[oldHoveredBox].messagePos.x + _fontManager->getStrWidth(areas[oldHoveredBox].message) + 5,
+					                      areas[oldHoveredBox].messagePos.y + _fontManager->getFontMaxHeight() + 5);
+					mapSurface.blitFrom(*bgFrame, textRect,
+					                    Common::Point(textRect.left, textRect.top));
+				}
+			}
+			if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (hoveredBox != -1u && areas[hoveredBox].record) {
+					selectedBox = hoveredBox;
+				} else if (boxes.hitTest(ARRAYSIZE(areas), mouse)) {
+					selectedBox = ARRAYSIZE(areas);
+				}
+			}
+			if (_engine->checkKeysPressed(1, Common::KEYCODE_ESCAPE)) {
+				selectedBox = ARRAYSIZE(areas);
+			}
+			if (g_engine->shouldQuit()) {
+				selectedBox = ARRAYSIZE(areas);
+			}
+		}
+	}
+
+	g_system->showMouse(false);
+
+	delete imageDecoder;
+
+	if (selectedBox == ARRAYSIZE(areas)) {
+		return "";
+	} else {
+		return areas[selectedBox].record;
+	}
+}
+
+void Versailles_Documentation::inGamePrepareRecord(Graphics::ManagedSurface &surface,
+        MouseBoxes &boxes) {
+	_categoryStartRecord = "";
+	_categoryEndRecord = "";
+	_categoryTitle = "";
+	_currentLinks.clear();
+	_currentInTimeline = false;
+	_currentMapLayout = false;
+	_currentHasMap = false;
+
+	if (_currentRecord.hasPrefix("VS")) {
+		unsigned int id = atoi(_currentRecord.c_str() + 2);
+		if (id >= 16 && id <= 40) {
+			_currentMapLayout = true;
+		}
+	} else if (_currentRecord.hasPrefix("VT")) {
+		error("There shouldn't be the timeline in game");
+	}
+
+	boxes.reset();
+
+	setupRecordBoxes(false, boxes);
+
+	Common::String title, subtitle, caption;
+	Common::StringArray hyperlinks;
+	Common::String text = getRecordData(_currentRecord, title, subtitle, caption, hyperlinks);
+	convertHyperlinks(hyperlinks, _currentLinks);
+
+	drawRecordData(surface, text, title, subtitle, caption);
+	drawRecordBoxes(surface, false, boxes);
+}
+
+unsigned int Versailles_Documentation::inGameHandleRecord(Graphics::ManagedSurface &surface,
+        MouseBoxes &boxes, Common::String &nextRecord) {
+	_engine->setCursor(181);
+	g_system->showMouse(true);
+
+	unsigned int action = -1;
+
+	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.w, surface.h);
+
+	while (action == -1u) {
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			if (g_engine->shouldQuit()) {
+				// Fake the quit
+				action = 6;
+			}
+			Common::Point mouse = _engine->getMousePos();
+			if (_engine->getDragStatus() == kDragStatus_Pressed) {
+				if (boxes.hitTest(2, mouse) && _currentLinks.size()) {
+					Common::StringArray items;
+					for (Common::Array<LinkInfo>::const_iterator it = _currentLinks.begin(); it != _currentLinks.end();
+					        it++) {
+						items.push_back(it->title);
+					}
+					Common::Rect iconRect = boxes.getBoxRect(2);
+					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                            true, 20, items);
+					if (selectedItem != -1u) {
+						nextRecord = _currentLinks[selectedItem].record;
+						action = 2;
+					}
+				}
+			} else if (_engine->getDragStatus() == kDragStatus_Finished) {
+				if (boxes.hitTest(0, mouse)) {
+					// Back in history
+					action = 0;
+				} else if (boxes.hitTest(1, mouse)) {
+					// Quit
+					action = 1;
+				}
+			}
+		}
+	}
+
+	g_system->showMouse(false);
+	_engine->setCursor(181);
+	return action;
+}
+
+void Versailles_Documentation::drawRecordData(Graphics::ManagedSurface &surface,
+        const Common::String &text, const Common::String &title,
+        const Common::String &subtitle, const Common::String &caption) {
+	bool displayMap = false;
+	unsigned char foreColor = 247;
+	Common::String background;
+	Common::Rect blockTitle;
+	Common::Rect blockHLine;
+	Common::Rect blockSubTitle;
+	Common::Rect blockCaption;
+	Common::Rect blockContent1;
+	Common::Rect blockContent2;
+
+	if (_currentMapLayout) {
+		blockTitle = Common::Rect(30, 8, 361, 38);
+		blockHLine = Common::Rect(60, 35, 286, 35);
+		blockSubTitle = Common::Rect(60, 40, 361, 70);
+		blockCaption = Common::Rect(378, 293, 630, 344);
+		blockContent1 = Common::Rect(60, 60, 272, 295);
+		blockContent2 = Common::Rect(60, 295, 383, 437);
+	} else if (_currentInTimeline) {
+		blockTitle = Common::Rect(78, 10, 170, 33);
+		//blockHLine = Common::Rect();
+		blockSubTitle = Common::Rect(60, 40, 361, 70);
+		blockCaption = Common::Rect(378, 293, 630, 344);
+		blockContent1 = Common::Rect(47, 70, 420, 306);
+		blockContent2 = Common::Rect(174, 306, 414, 411);
+	} else if (_currentRecord == "VC02" ||
+	           _currentRecord == "VC03" ||
+	           _currentRecord == "VV01") {
+		blockTitle = Common::Rect(30, 8, 361, 38);
+		blockHLine = Common::Rect(60, 35, 378, 35);
+		blockSubTitle = Common::Rect(60, 40, 361, 70);
+		blockCaption = Common::Rect(378, 293, 630, 360);
+		blockContent1 = Common::Rect(60, 80, 351, 355);
+		blockContent2 = Common::Rect(60, 355, 605, 437);
+	} else if (_currentRecord == "VV13" ||
+	           _currentRecord == "VV08") {
+		blockTitle = Common::Rect(30, 8, 361, 38);
+		blockHLine = Common::Rect(60, 35, 286, 35);
+		blockSubTitle = Common::Rect(60, 40, 361, 70);
+		blockCaption = Common::Rect(378, 422, 630, 480);
+		blockContent1 = Common::Rect(60, 60, 378, 285);
+		blockContent2 = Common::Rect(60, 285, 378, 437);
+	} else {
+		blockTitle = Common::Rect(30, 8, 361, 38);
+		blockHLine = Common::Rect(60, 35, 378, 35);
+		blockSubTitle = Common::Rect(60, 40, 361, 70);
+		blockCaption = Common::Rect(378, 293, 630, 360);
+		blockContent1 = Common::Rect(60, 80, 351, 345);
+		blockContent2 = Common::Rect(60, 345, 605, 437);
+	}
+	if (_currentInTimeline) {
+		background = "CHRONO1";
+		foreColor = 241;
+	} else {
+		background = _currentRecord;
+	}
+	background += ".HLZ";
+	Common::File backgroundFl;
+	if (!backgroundFl.open(background)) {
+		background = displayMap ? "pas_fonP.hlz" : "pas_fond.hlz";
+	} else {
+		backgroundFl.close();
+	}
+
+	Image::ImageDecoder *imageDecoder = _engine->loadHLZ(background);
+	const Graphics::Surface *bgFrame = imageDecoder->getSurface();
+
+	_engine->setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+	                      imageDecoder->getPaletteColorCount());
+
+	surface.create(bgFrame->w, bgFrame->h, bgFrame->format);
+	surface.blitFrom(*bgFrame);
+
+	/*Common::String title, subtitle, caption;
+	Common::StringArray hyperlinks;
+
+	Common::String text = getRecordData(_currentRecord, title, subtitle, caption, hyperlinks);*/
+
+	unsigned int lineHeight = 21;
+	_fontManager->setCurrentFont(4);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setSpaceWidth(1);
+	_fontManager->setCharSpacing(1);
+	_fontManager->setForeColor(foreColor);
+	_fontManager->setSurface(&surface);
+
+	/*
+	surface.frameRect(blockContent1, foreColor);
+	surface.frameRect(blockContent2, foreColor);
+	surface.frameRect(blockTitle, foreColor);
+	surface.frameRect(blockSubTitle, foreColor);
+	surface.frameRect(blockCaption, foreColor);
+	*/
+
+	Graphics::ManagedSurface backupSurface;
+	backupSurface.copyFrom(surface);
+
+	// This loop tries to adapt the interline space to make all the text fit in the blocks
+	while (true) {
+		_fontManager->setLineHeight(lineHeight);
+		_fontManager->setupBlock(blockContent1);
+		if (!_fontManager->displayBlockText(text)) {
+			// All text was drawn
+			break;
+		}
+
+		// Setup second zone
+		blockContent2.top = _fontManager->blockTextLastPos().y + lineHeight;
+		_fontManager->setupBlock(blockContent2);
+
+		if (!_fontManager->displayBlockText(text, _fontManager->blockTextRemaining())) {
+			// All text was drawn
+			break;
+		}
+
+		// Not all text could be drawn: shrink everything, restore image and do it again
+		lineHeight--;
+		surface.copyFrom(backupSurface);
+	}
+
+	_fontManager->setForeColor(foreColor);
+	_fontManager->setCurrentFont(0);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setLineHeight(20);
+	_fontManager->setCharSpacing(0);
+	_fontManager->setSpaceWidth(2);
+
+	//debug("Title: %s", title.c_str());
+	_fontManager->setupBlock(blockTitle);
+	_fontManager->displayBlockText(title);
+
+	_fontManager->setCurrentFont(6);
+	_fontManager->setLineHeight(14);
+	_fontManager->setSpaceWidth(1);
+
+	//debug("Subtitle: %s", subtitle.c_str());
+	_fontManager->setupBlock(blockSubTitle);
+	_fontManager->displayBlockText(subtitle);
+
+	if (!_currentInTimeline) {
+		surface.hLine(blockHLine.left, blockHLine.top, blockHLine.right - 1,
+		              foreColor); // minus 1 because hLine draws inclusive
+	}
+
+	_fontManager->setSpaceWidth(0);
+
+	_fontManager->setupBlock(blockCaption);
+	_fontManager->displayBlockText(caption);
+}
+
+void Versailles_Documentation::setupRecordBoxes(bool inDocArea, MouseBoxes &boxes) {
+	// Layout of bar in doc area is Quit | Back |   | Previous | Category | Next |   | Trace | Hyperlinks | All records
+	// Layout of bar in game is ==> Trace | Hyperlinks | Quit
+	unsigned int allRecordsX = 640 - _sprites->getCursor(19).getWidth();
+	unsigned int hyperlinksX = allRecordsX - _sprites->getCursor(242).getWidth() - 10;
+	unsigned int traceX = hyperlinksX - _sprites->getCursor(105).getWidth() - 10;
+
+	if (_visitTrace.size()) {
+		boxes.setupBox(0, traceX, 480 - _sprites->getCursor(105).getHeight() - 3,
+		               traceX + _sprites->getCursor(105).getWidth(), 480);
+	}
+	if (inDocArea) {
+		unsigned int backX = _sprites->getCursor(225).getWidth() + 10; //Right to quit button
+
+		_fontManager->setCurrentFont(0);
+		_fontManager->setTransparentBackground(true);
+		_fontManager->setSpaceWidth(0);
+		_fontManager->setCharSpacing(1);
+		unsigned int categoryHalfWidth = _fontManager->getStrWidth(_categoryTitle) / 2;
+		unsigned nextX = 320 + categoryHalfWidth + 20;
+		unsigned prevX = 320 - categoryHalfWidth - 20 - _sprites->getCursor(76).getWidth();
+
+		boxes.setupBox(3, allRecordsX, 480 - _sprites->getCursor(19).getHeight(),
+		               allRecordsX + _sprites->getCursor(19).getWidth(), 480);
+		boxes.setupBox(1, backX, 480 - _sprites->getCursor(227).getHeight(),
+		               backX + _sprites->getCursor(227).getWidth(), 480);
+		boxes.setupBox(9, 320 - categoryHalfWidth - 5, 480 - _sprites->getCursor(227).getHeight(),
+		               320 + categoryHalfWidth + 5, 480);
+		boxes.setupBox(4, nextX, 476 - _sprites->getCursor(72).getHeight(),
+		               nextX + _sprites->getCursor(72).getWidth(), 476);
+		boxes.setupBox(5, prevX, 476 - _sprites->getCursor(76).getHeight(),
+		               prevX + _sprites->getCursor(76).getWidth(), 476);
+		// Quit button
+		boxes.setupBox(6, 0, 480 - _sprites->getCursor(225).getHeight(),
+		               _sprites->getCursor(225).getWidth(), 480);
+		// Map
+		boxes.setupBox(8, 403, 305, 622, 428);
+		if (_currentInTimeline) {
+			for (unsigned int box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
+				boxes.setupBox(10 + box_id, kTimelineEntries[box_id].x, kTimelineEntries[box_id].y,
+				               kTimelineEntries[box_id].x + 30, kTimelineEntries[box_id].y + 15, kTimelineEntries[box_id].year);
+			}
+		}
+	} else {
+		unsigned int quitInGameX = 640 - _sprites->getCursor(105).getWidth();
+		boxes.setupBox(1, quitInGameX, 480 - _sprites->getCursor(105).getHeight(),
+		               quitInGameX + _sprites->getCursor(105).getWidth(), 480);
+	}
+	boxes.setupBox(2, hyperlinksX, 480 - _sprites->getCursor(242).getHeight(),
+	               hyperlinksX + _sprites->getCursor(242).getWidth(), 480);
+}
+
+void Versailles_Documentation::drawRecordBoxes(Graphics::ManagedSurface &surface, bool inDocArea,
+        MouseBoxes &boxes) {
+	if (_visitTrace.size()) {
+		surface.transBlitFrom(_sprites->getSurface(105), boxes.getBoxOrigin(0), _sprites->getKeyColor(105));
+	}
+	if (inDocArea) {
+		surface.transBlitFrom(_sprites->getSurface(19), boxes.getBoxOrigin(3), _sprites->getKeyColor(19));
+		surface.transBlitFrom(_sprites->getSurface(227), boxes.getBoxOrigin(1), _sprites->getKeyColor(227));
+
+		surface.fillRect(boxes.getBoxRect(9), 243);
+
+		_fontManager->setCurrentFont(0);
+		_fontManager->setTransparentBackground(true);
+		_fontManager->setSpaceWidth(0);
+		_fontManager->setCharSpacing(1);
+		_fontManager->setForeColor(240);
+		Common::Point catPos = boxes.getBoxOrigin(9);
+		catPos += Common::Point(5, 3);
+		_fontManager->displayStr(catPos.x, catPos.y, _categoryTitle);
+
+		if (_currentRecord == _categoryEndRecord) {
+			surface.transBlitFrom(_sprites->getSurface(75), boxes.getBoxOrigin(4), _sprites->getKeyColor(75));
+		} else {
+			surface.transBlitFrom(_sprites->getSurface(72), boxes.getBoxOrigin(4), _sprites->getKeyColor(72));
+		}
+		if (_currentRecord == _categoryStartRecord) {
+			surface.transBlitFrom(_sprites->getSurface(77), boxes.getBoxOrigin(5), _sprites->getKeyColor(77));
+		} else {
+			surface.transBlitFrom(_sprites->getSurface(76), boxes.getBoxOrigin(5), _sprites->getKeyColor(76));
+		}
+		surface.transBlitFrom(_sprites->getSurface(225), boxes.getBoxOrigin(6), _sprites->getKeyColor(225));
+	} else {
+		surface.transBlitFrom(_sprites->getSurface(105), boxes.getBoxOrigin(1), _sprites->getKeyColor(105));
+	}
+	if (_currentLinks.size()) {
+		surface.transBlitFrom(_sprites->getSurface(242), boxes.getBoxOrigin(2), _sprites->getKeyColor(242));
+	} else {
+		surface.transBlitFrom(_sprites->getSurface(244), boxes.getBoxOrigin(2), _sprites->getKeyColor(244));
+	}
+}
+
+unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSurface
+        &originalSurface,
+        const Common::Point &anchor, bool rightAligned, unsigned int itemHeight,
+        const Common::StringArray &items) {
+
+	unsigned int maxTextWidth = 0;
+
+	_fontManager->setCurrentFont(4);
+	_fontManager->setTransparentBackground(true);
+	_fontManager->setCharSpacing(1);
+
+	for (Common::StringArray::const_iterator it = items.begin(); it != items.end(); it++) {
+		unsigned int width = _fontManager->getStrWidth(*it);
+		if (width > maxTextWidth) {
+			maxTextWidth = width;
+		}
+	}
+
+	unsigned int width = maxTextWidth + 2 * kPopupMenuMargin;
+	unsigned int height = itemHeight * items.size() + 2 * kPopupMenuMargin;
+
+	unsigned int hiddenItems = 0;
+	int top = anchor.y - height;
+	while (top < 0) {
+		hiddenItems++;
+		top += itemHeight;
+	}
+	unsigned shownItems = items.size() - hiddenItems;
+
+	Common::Rect popupRect;
+	if (rightAligned) {
+		popupRect = Common::Rect(anchor.x - width, top, anchor.x, anchor.y);
+	} else {
+		popupRect = Common::Rect(anchor.x, top, anchor.x + width, anchor.y);
+	}
+
+	Graphics::ManagedSurface surface;
+	surface.copyFrom(originalSurface);
+
+	MouseBoxes boxes(shownItems);
+	for (unsigned int i = 0; i < shownItems; i++) {
+		boxes.setupBox(i, popupRect.left + kPopupMenuMargin,
+		               popupRect.top + kPopupMenuMargin + i * itemHeight,
+		               popupRect.right - kPopupMenuMargin,
+		               popupRect.top + kPopupMenuMargin + (i + 1) * itemHeight);
+	}
+
+	_fontManager->setSurface(&surface);
+
+	bool fullRedraw = true;
+	bool redraw = true;
+	unsigned int hoveredBox = -1;
+	unsigned int action = -1;
+	unsigned int lastShownItem = items.size() - 1;
+	unsigned int firstShownItem = lastShownItem - shownItems + 1;
+
+	unsigned int slowScrollNextEvent = g_system->getMillis() + 250;
+
+	Common::Point mouse;
+
+	while (action == -1u) {
+		if (redraw) {
+			if (fullRedraw) {
+				surface.fillRect(popupRect, 247);
+				fullRedraw = false;
+			}
+			for (unsigned int i = 0; i < shownItems; i++) {
+				if (i == 0 && firstShownItem != 0) {
+					// There are items before the first one: display an arrow
+					surface.transBlitFrom(_sprites->getSurface(162),
+					                      Common::Point(popupRect.left + kPopupMenuMargin,
+					                                    popupRect.top + kPopupMenuMargin + i * itemHeight + 3),
+					                      _sprites->getKeyColor(162));
+				} else if (i == shownItems - 1 && lastShownItem != items.size() - 1) {
+					// There are items after the last one: display an arrow
+					surface.transBlitFrom(_sprites->getSurface(185),
+					                      Common::Point(popupRect.left + kPopupMenuMargin,
+					                                    popupRect.top + kPopupMenuMargin + i * itemHeight + 3),
+					                      _sprites->getKeyColor(185));
+				} else {
+					// Display the item text
+					_fontManager->setForeColor(i == hoveredBox ? 241 : 243);
+					_fontManager->displayStr(popupRect.left + kPopupMenuMargin,
+					                         popupRect.top + kPopupMenuMargin + i * itemHeight + 3, items[firstShownItem + i]);
+				}
+			}
+			g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.w, surface.h);
+			redraw = false;
+		}
+		g_system->updateScreen();
+
+		if (_engine->pollEvents()) {
+			if (g_engine->shouldQuit()) {
+				// Fake the quit
+				break;
+			}
+			mouse = _engine->getMousePos();
+
+			unsigned int newHovered = -1;
+			for (unsigned int i = 0; i < shownItems; i++) {
+				if (boxes.hitTest(i, mouse)) {
+					newHovered = i;
+					break;
+				}
+			}
+
+			if (newHovered != hoveredBox) {
+				hoveredBox = newHovered;
+				redraw = true;
+			}
+		}
+
+		DragStatus dragStatus = _engine->getDragStatus();
+
+		if (hoveredBox == -1u) {
+			if (dragStatus == kDragStatus_Pressed) {
+				break;
+			} else {
+				continue;
+			}
+		}
+
+		// From there we only act if there is something hovered
+		if (hoveredBox == 0 && firstShownItem > 0) {
+			// Scroll up fast
+			firstShownItem--;
+			lastShownItem--;
+			slowScrollNextEvent = g_system->getMillis() + 250;
+			fullRedraw = true;
+			redraw = true;
+		} else if (hoveredBox == 1 && firstShownItem > 0) {
+			// Scroll up slow
+			if (g_system->getMillis() > slowScrollNextEvent) {
+				firstShownItem--;
+				lastShownItem--;
+				slowScrollNextEvent = g_system->getMillis() + 250;
+				fullRedraw = true;
+				redraw = true;
+			}
+		} else if (hoveredBox == shownItems - 2 && lastShownItem < items.size() - 1) {
+			// Scroll down slow
+			if (g_system->getMillis() > slowScrollNextEvent) {
+				firstShownItem++;
+				lastShownItem++;
+				slowScrollNextEvent = g_system->getMillis() + 250;
+				fullRedraw = true;
+				redraw = true;
+			}
+		} else if (hoveredBox == shownItems - 1 && lastShownItem < items.size() - 1) {
+			// Scroll down fast
+			firstShownItem++;
+			lastShownItem++;
+			slowScrollNextEvent = g_system->getMillis() + 250;
+			fullRedraw = true;
+			redraw = true;
+		} else if (dragStatus == kDragStatus_Finished) {
+			action = hoveredBox + firstShownItem;
+			continue;
+		}
+	}
+
+	// Restore original surface
+	g_system->copyRectToScreen(originalSurface.getPixels(), originalSurface.pitch, 0, 0,
+	                           originalSurface.w, originalSurface.h);
+	g_system->updateScreen();
+
+	_engine->waitMouseRelease();
+
+	return action;
+}
+
+/* Below is documentation files parsing */
+
+char *Versailles_Documentation::getDocPartAddress(char *start, char *end, const char *patterns[]) {
+	if (!start) {
+		return nullptr;
+	}
+	char *foundPos = nullptr;
+	const char *pattern;
+	unsigned int patternLen;
+	for (const char **patternP = patterns; *patternP && !foundPos; patternP++) {
+		pattern = *patternP;
+		patternLen = strlen(pattern);
+		/*debug("Matching %.10s", pattern);*/
+		for (char *p = start; p < end - patternLen - 1; p++) {
+			/*if (p == start || *p == '\r' || *p == '\0') {
+			    debug("Line %.10s", p == start ? start : p+1);
+			}*/
+			if (p == start && !strncmp(p, pattern, patternLen)) {
+				foundPos = p;
+				break;
+			} else if ((*p == '\r' || *p == '\0') && !strncmp(p + 1, pattern, patternLen)) {
+				foundPos = p + 1;
+				break;
+			}
+		}
+	}
+	if (!foundPos) {
+		return nullptr;
+	}
+	/*debug("Matched %.10s", foundPos);*/
+	foundPos += patternLen;
+	char *eol = foundPos;
+	for (; *eol != '\r' && *eol != '\0'; eol++) {}
+	*eol = '\0';
+	return foundPos;
+}
+
+static bool hasEqualInLine(const char *text, const char *end) {
+	for (; text < end && *text && *text != '\r' && *text != '='; text++) { }
+	return text < end && *text == '=';
+}
+
+static const char *nextLine(const char *text, const char *end) {
+	for (; text < end && *text && *text != '\r'; text++) { }
+	return text < end ? text + 1 : end;
+}
+
+const char *Versailles_Documentation::getDocTextAddress(char *start, char *end) {
+	if (!start) {
+		return nullptr;
+	}
+	const char *foundPos = nullptr;
+	const char *p = start;
+	while (p < end) {
+		if (hasEqualInLine(p, end)) {
+			p = nextLine(p, end);
+			if (p < end && !hasEqualInLine(p, end)) {
+				// Only return the text that is after the last =
+				foundPos = p;
+			}
+		} else {
+			p = nextLine(p, end);
+		}
+	}
+	return foundPos;
+}
+
+const char *Versailles_Documentation::getRecordCaption(char *start, char *end) {
+	const char *patterns[] = { "LEGENDE=", "LEGENDE =", nullptr };
+	const char *ret = getDocPartAddress(start, end, patterns);
+	return ret;
+}
+
+const char *Versailles_Documentation::getRecordTitle(char *start, char *end) {
+	const char *patterns[] = { "TITRE=", "TITRE =", nullptr };
+	const char *ret = getDocPartAddress(start, end, patterns);
+	return ret;
+}
+
+const char *Versailles_Documentation::getRecordSubtitle(char *start, char *end) {
+	const char *patterns[] = { "SOUS-TITRE=", "SOUS_TITRE=", "SOUS-TITRE =", "SOUS_TITRE =", "SOUS TITRE=", nullptr };
+	char *ret = getDocPartAddress(start, end, patterns);
+	if (!ret) {
+		return nullptr;
+	}
+
+	unsigned int ln = strlen(ret);
+	char *p = ret + ln + 1; // Got to end of line and check next line
+	for (; p < end && *p && *p != '\r' && *p != '=' ; p++) { }
+	if (*p == '=') {
+		// Next line has a =, so it's not multiline
+		return ret;
+	}
+
+	if (*p == '\r') {
+		*p = '\0';
+	}
+	ret[ln] = '\r';
+
+	return ret;
+}
+
+void Versailles_Documentation::getRecordHyperlinks(char *start, char *end,
+        Common::StringArray &hyperlinks) {
+	const char *const hyperlinksPatterns[] = { "SAVOIR-PLUS 1=", "SAVOIR-PLUS 2=", "SAVOIR-PLUS 3=" };
+
+	hyperlinks.clear();
+	for (unsigned int hyperlinkId = 0; hyperlinkId < ARRAYSIZE(hyperlinksPatterns); hyperlinkId++) {
+		const char *patterns[] = { hyperlinksPatterns[hyperlinkId], nullptr };
+		const char *ret = getDocPartAddress(start, end, patterns);
+		if (ret) {
+			hyperlinks.push_back(ret);
+		}
+	}
+}
+
+Common::String Versailles_Documentation::getRecordTitle(const Common::String &record) {
+	Common::HashMap<Common::String, RecordInfo>::iterator it = _records.find(record);
+	if (it == _records.end()) {
+		return "";
+	}
+
+	const RecordInfo &recordInfo = it->_value;
+	Common::File allDocsFile;
+
+	if (!allDocsFile.open(kAllDocsFile)) {
+		error("Can't open %s", kAllDocsFile);
+	}
+	allDocsFile.seek(recordInfo.position);
+
+	char *recordData = new char[recordInfo.size + 1];
+	allDocsFile.read(recordData, recordInfo.size);
+	recordData[recordInfo.size] = '\0';
+	char *recordDataEnd = recordData + recordInfo.size + 1;
+
+	Common::String title = getRecordTitle(recordData, recordDataEnd);
+
+	delete[] recordData;
+
+	return title;
+}
+
+Common::String Versailles_Documentation::getRecordData(const Common::String &record,
+        Common::String &title, Common::String &subtitle, Common::String &caption,
+        Common::StringArray &hyperlinks) {
+	Common::HashMap<Common::String, RecordInfo>::iterator it = _records.find(record);
+	if (it == _records.end()) {
+		warning("Can't find %s record data", record.c_str());
+		return "";
+	}
+
+	const RecordInfo &recordInfo = it->_value;
+	Common::File allDocsFile;
+
+	if (!allDocsFile.open(kAllDocsFile)) {
+		error("Can't open %s", kAllDocsFile);
+	}
+	allDocsFile.seek(recordInfo.position);
+
+	char *recordData = new char[recordInfo.size + 1];
+	allDocsFile.read(recordData, recordInfo.size);
+	recordData[recordInfo.size] = '\0';
+	char *recordDataEnd = recordData + recordInfo.size + 1;
+
+	const char *titleP = getRecordTitle(recordData, recordDataEnd);
+	/*debug("Title: %s", titleP);*/
+	title = titleP ? titleP : "";
+	const char *subtitleP = getRecordSubtitle(recordData, recordDataEnd);
+	/*debug("SubTitle: %s", subtitleP);*/
+	subtitle = subtitleP ? subtitleP : "";
+	const char *captionP = getRecordCaption(recordData, recordDataEnd);
+	/*debug("Caption: %s", captionP);*/
+	caption = captionP ? captionP : "";
+	getRecordHyperlinks(recordData, recordDataEnd, hyperlinks);
+
+	Common::String text(getDocTextAddress(recordData, recordDataEnd));
+
+	delete[] recordData;
+
+	return text;
+}
+
+void Versailles_Documentation::convertHyperlinks(const Common::StringArray &hyperlinks,
+        Common::Array<LinkInfo> &links) {
+	for (Common::StringArray::const_iterator it = hyperlinks.begin(); it != hyperlinks.end(); it++) {
+		LinkInfo link;
+		link.record = *it;
+		link.record.toUppercase();
+		link.title = getRecordTitle(link.record);
+		links.push_back(link);
+	}
+}
+
+void Versailles_Documentation::loadLinksFile() {
+	if (_linksData) {
+		return;
+	}
+
+	Common::File linksFile;
+	if (!linksFile.open(kLinksDocsFile)) {
+		error("Can't open links file: %s", kLinksDocsFile);
+	}
+
+	_linksSize = linksFile.size();
+	_linksData = new char[_linksSize + 1];
+
+	linksFile.read(_linksData, _linksSize);
+	_linksData[_linksSize] = '\0';
+}
+
+void Versailles_Documentation::getLinks(const Common::String &record,
+                                        Common::Array<LinkInfo> &links) {
+	loadLinksFile();
+
+	links.clear();
+
+	Common::String pattern = "\r";
+	pattern += record;
+
+	const char *recordStart = strstr(_linksData, pattern.c_str());
+	if (!recordStart) {
+		return;
+	}
+
+	const char *p = recordStart + pattern.size(); // Go beyond the record name
+	for (; *p != '\r' && *p != '\0'; p++) { } // Goto next line
+	if (!*p) {
+		return;
+	}
+	p++;
+
+	bool finished = false;
+	while (!finished) {
+		if (!scumm_strnicmp(p, "REM=", 4)) {
+			// Comment: goto next line
+			for (; *p != '\r' && *p != '\0'; p++) { }
+		} else if (!scumm_strnicmp(p, "LIEN=", 5)) {
+			// Link: read it
+			const char *linkStart = p + 5;
+			const char *linkEnd = linkStart;
+			for (; *linkEnd != '\r' && *linkEnd != ' ' && *linkEnd != '\0'; linkEnd++) { }
+			LinkInfo link;
+			link.record = Common::String(linkStart, linkEnd);
+			link.record.toUppercase();
+			link.title = getRecordTitle(link.record);
+			links.push_back(link);
+			// Advance to end of link and finish the line
+			p = linkEnd;
+			for (; *p != '\r' && *p != '\0'; p++) { }
+			//debug("Link %s/%s", link.record.c_str(), link.title.c_str());
+		} else {
+			// Something else: we expect a blank line to continue, else we are on a new record
+			for (; *p != '\r' && *p != '\0'; p++) {
+				if (*p != ' ' && *p != '\t' && *p != '\n') {
+					finished = true;
+					break;
+				}
+			}
+		}
+		if (*p == '\0') {
+			break;
+		}
+		p++;
+	}
+}
+
+} // End of namespace Versailles
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/documentation.h b/engines/cryomni3d/versailles/documentation.h
new file mode 100644
index 0000000..0a581d9
--- /dev/null
+++ b/engines/cryomni3d/versailles/documentation.h
@@ -0,0 +1,143 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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;
+
+class CryOmni3DEngine;
+
+namespace Versailles {
+class Versailles_Documentation {
+public:
+	Versailles_Documentation() : _engine(nullptr), _fontManager(nullptr), _messages(nullptr),
+		_linksData(nullptr), _linksSize(0) { }
+	~Versailles_Documentation() { delete _linksData; }
+
+	void init(const Sprites *sprites, FontManager *fontManager, const Common::StringArray *messages,
+	          CryOmni3DEngine *engine);
+	void handleDocArea();
+	void handleDocInGame(const Common::String &record);
+
+private:
+	Common::String docAreaHandleSummary();
+	Common::String docAreaHandleTimeline();
+	Common::String docAreaHandleGeneralMap();
+	Common::String docAreaHandleCastleMap();
+	unsigned int docAreaHandleRecords(const Common::String &record);
+
+	void docAreaPrepareNavigation();
+	void docAreaPrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
+	unsigned int docAreaHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
+	                                 Common::String &nextRecord);
+
+	void inGamePrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
+	unsigned int 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);
+
+	unsigned int handlePopupMenu(const Graphics::ManagedSurface &surface,
+	                             const Common::Point &anchor, bool rightAligned, unsigned int itemHeight,
+	                             const Common::StringArray &items);
+
+	struct RecordInfo {
+		unsigned int id;
+		unsigned int position;
+		unsigned int size;
+	};
+
+	struct LinkInfo {
+		Common::String record;
+		Common::String title;
+	};
+
+	struct TimelineEntry {
+		char year[8];
+		unsigned int x;
+		unsigned int y;
+	};
+	static const TimelineEntry kTimelineEntries[];
+
+	static char *getDocPartAddress(char *start, char *end, const char *patterns[]);
+	static const char *getDocTextAddress(char *start, char *end);
+	static const char *getRecordTitle(char *start, char *end);
+	static const char *getRecordSubtitle(char *start, char *end);
+	static const char *getRecordCaption(char *start, char *end);
+	static 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);
+
+	static const char *kAllDocsFile;
+	static const char *kLinksDocsFile;
+
+	static const unsigned int kPopupMenuMargin = 5;
+
+	CryOmni3DEngine *_engine;
+	FontManager *_fontManager;
+	const Sprites *_sprites;
+	const Common::StringArray *_messages;
+
+	Common::StringArray _recordsOrdered;
+	Common::HashMap<Common::String, RecordInfo> _records;
+	char *_linksData;
+	unsigned int _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
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
new file mode 100644
index 0000000..b25efc7
--- /dev/null
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -0,0 +1,1443 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "engines/util.h"
+#include "image/bmp.h"
+
+#include "cryomni3d/font_manager.h"
+#include "cryomni3d/dialogs_manager.h"
+#include "cryomni3d/fixed_image.h"
+#include "cryomni3d/omni3d.h"
+
+#include "cryomni3d/versailles/engine.h"
+
+#define DEBUG_FAST_START 1
+
+namespace CryOmni3D {
+namespace Versailles {
+
+const FixedImageConfiguration CryOmni3DEngine_Versailles::kFixedImageConfiguration = {
+	45, 223, 243, 238, 226, 198, 136, 145, 99, 113,
+	470
+};
+
+CryOmni3DEngine_Versailles::CryOmni3DEngine_Versailles(OSystem *syst,
+        const CryOmni3DGameDescription *gamedesc) : CryOmni3DEngine(syst, gamedesc),
+	_mainPalette(nullptr), _cursorPalette(nullptr), _transparentPaletteMap(nullptr),
+	_currentPlace(nullptr), _currentWarpImage(nullptr), _fixedImage(nullptr),
+	_transitionAnimateWarp(true), _forceRedrawWarp(false), _forcePaletteUpdate(false),
+	_fadedPalette(false), _loadedSave(-1), _dialogsMan(this),
+	_musicVolumeFactor(1.), _musicCurrentFile(nullptr) {
+}
+
+CryOmni3DEngine_Versailles::~CryOmni3DEngine_Versailles() {
+	delete _currentWarpImage;
+	delete[] _mainPalette;
+	delete[] _cursorPalette;
+	delete[] _transparentPaletteMap;
+
+	delete _fixedImage;
+}
+
+Common::Error CryOmni3DEngine_Versailles::run() {
+	CryOmni3DEngine::run();
+
+	const Common::FSNode gameDataDir(ConfMan.get("path"));
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/sc_trans", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/menu", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/basedoc/fonds", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/fonts", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/spr8col", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/spr8col/bmpok", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/wam", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/objets", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/gto", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/dial/flc_dial", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/dial/voix", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/textes", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/music", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/sound", 1);
+
+	setupMessages();
+
+	_dialogsMan.init(138, _messages[22]);
+	_gameVariables.resize(GameVariables::kMax);
+	_omni3dMan.init(75. / 180. * M_PI);
+
+	_dialogsMan.loadGTO("DIALOG1.GTO");
+	setupDialogVariables();
+	setupDialogShows();
+
+	setupPaintingsTitles();
+	setupImgScripts();
+
+	_mainPalette = new byte[3 * 256];
+	setupFonts();
+	setupSprites();
+	loadCursorsPalette();
+
+	// Objects need messages and sprites
+	setupObjects();
+
+	_transparentPaletteMap = new byte[256];
+	_transparentSrcStart = 0;
+	_transparentSrcStop = 240;
+	_transparentDstStart = 0;
+	_transparentDstStop = 248;
+	_transparentNewStart = 248;
+	_transparentNewStop = 254;
+
+	// Inventory has a size of 50
+	_inventory.init(50, new Common::Functor1Mem<unsigned int, void, Toolbar>(&_toolbar,
+	                &Toolbar::inventoryChanged));
+
+	// Init toolbar after we have setup sprites and fonts
+	_toolbar.init(&_sprites, &_fontManager, &_messages, &_inventory, this);
+
+	_fixedImage = new ZonFixedImage(*this, _inventory, _sprites, &kFixedImageConfiguration);
+
+	// Documentation is needed by noone at init time, let's do it last
+	initDocPeopleRecord();
+	_docManager.init(&_sprites, &_fontManager, &_messages, this);
+
+	initGraphics(640, 480);
+	setMousePos(Common::Point(320, 200));
+
+	_isPlaying = false;
+	_isVisiting = false;
+
+#if !defined(DEBUG_FAST_START) || DEBUG_FAST_START<1
+	playTransitionEndLevel(-2);
+	if (g_engine->shouldQuit()) {
+		return Common::kNoError;
+	}
+	playTransitionEndLevel(-1);
+	if (g_engine->shouldQuit()) {
+		return Common::kNoError;
+	}
+#endif
+
+	bool stopGame = false;
+	while (!stopGame) {
+		bool exitLoop = false;
+		unsigned int nextStep = 0;
+#if defined(DEBUG_FAST_START) && DEBUG_FAST_START>=2
+		nextStep = 27;
+		// Called in options
+		syncOmni3DSettings();
+#endif
+		setCursor(181);
+		while (!exitLoop) {
+			_isPlaying = false;
+			if (!nextStep) {
+				nextStep = displayOptions();
+			}
+			if (nextStep == 40) {
+				// Quit action
+				exitLoop = true;
+				stopGame = true;
+			} else if (nextStep == 27 || nextStep == 28 || nextStep == 65) {
+				// New game, Load game, Next level
+				if (nextStep == 27) {
+					// New game
+#if !defined(DEBUG_FAST_START) || DEBUG_FAST_START<1
+					playTransitionEndLevel(0);
+					if (g_engine->shouldQuit()) {
+						stopGame = true;
+						exitLoop = true;
+						break;
+					}
+#endif
+					changeLevel(1);
+				} else if (nextStep == 28) {
+					// Load game
+					loadGame(_isVisiting, _loadedSave);
+				} else if (nextStep == 65) {
+					changeLevel(_currentLevel + 1);
+				}
+
+				_isPlaying = true;
+				_toolbar.setInventoryEnabled(!_isVisiting);
+				nextStep = 0;
+				_abortCommand = AbortNoAbort;
+
+				gameStep();
+
+				// We shouldn't return from gameStep without an abort command
+				assert(_abortCommand != AbortNoAbort);
+				switch (_abortCommand) {
+				default:
+					error("Invalid abortCommand: %d", _abortCommand);
+					// Shouldn't return
+					return Common::kUnknownError;
+				case AbortFinished:
+				case AbortGameOver:
+					// Go back to menu
+					exitLoop = true;
+					break;
+				case AbortQuit:
+					exitLoop = true;
+					stopGame = true;
+					break;
+				case AbortNewGame:
+					nextStep = 27;
+					break;
+				case AbortLoadGame:
+					nextStep = 28;
+					break;
+				case AbortNextLevel:
+					nextStep = 65;
+					break;
+				}
+			}
+		}
+	}
+	return Common::kNoError;
+}
+
+void CryOmni3DEngine_Versailles::setupFonts() {
+	Common::Array<Common::String> fonts;
+	fonts.push_back("font01.CRF");
+	fonts.push_back("font02.CRF");
+	fonts.push_back("font03.CRF");
+	fonts.push_back("font04.CRF");
+	fonts.push_back("font05.CRF");
+	fonts.push_back("font06.CRF");
+	fonts.push_back("font07.CRF");
+	fonts.push_back("font08.CRF");
+	fonts.push_back("font09.CRF");
+	fonts.push_back("font10.CRF");
+	fonts.push_back("font11.CRF");
+
+	_fontManager.loadFonts(fonts);
+}
+
+void CryOmni3DEngine_Versailles::setupSprites() {
+	Common::File file;
+
+	if (!file.open("all_spr.bin")) {
+		error("Failed to open all_spr.bin file");
+	}
+	_sprites.loadSprites(file);
+
+	for (unsigned int i = 0; i < _sprites.getSpritesCount(); i++) {
+		const Graphics::Cursor &cursor = _sprites.getCursor(i);
+		if (cursor.getWidth() != 32 || cursor.getHeight() != 32) {
+			_sprites.setSpriteHotspot(i, 8, 8);
+		} else {
+			_sprites.setSpriteHotspot(i, 16, 16);
+		}
+	}
+	_sprites.setupMapTable(kSpritesMapTable, kSpritesMapTableSize);
+
+
+	_sprites.setSpriteHotspot(181, 4, 0);
+	// Replace 2-keys, 3-keys and 4-keys icons with 1-key ones
+	_sprites.replaceSprite(80, 64);
+	_sprites.replaceSprite(84, 66);
+	_sprites.replaceSprite(93, 78);
+	_sprites.replaceSprite(97, 82);
+	_sprites.replaceSprite(92, 64);
+	_sprites.replaceSprite(96, 66);
+	_sprites.replaceSprite(116, 78);
+	_sprites.replaceSprite(121, 82);
+	_sprites.replaceSprite(115, 64);
+	_sprites.replaceSprite(120, 66);
+	_sprites.replaceSprite(135, 78);
+	_sprites.replaceSprite(140, 82);
+}
+
+void CryOmni3DEngine_Versailles::loadCursorsPalette() {
+	Image::BitmapDecoder bmpDecoder;
+
+	Common::File file;
+
+	if (!file.open("bou1_cA.bmp")) {
+		error("Failed to open BMP file");
+	}
+
+	if (!bmpDecoder.loadStream(file)) {
+		error("Failed to load BMP file");
+	}
+
+	_cursorPalette = new byte[3 * (bmpDecoder.getPaletteColorCount() +
+	                               bmpDecoder.getPaletteStartIndex())];
+	memset(_cursorPalette, 0, 3 * (bmpDecoder.getPaletteColorCount() +
+	                               bmpDecoder.getPaletteStartIndex()));
+	memcpy(_cursorPalette + 3 * bmpDecoder.getPaletteStartIndex(), bmpDecoder.getPalette(),
+	       3 * bmpDecoder.getPaletteColorCount());
+}
+
+void CryOmni3DEngine_Versailles::setupPalette(const byte *palette, uint start, uint num,
+        bool commit) {
+	memcpy(_mainPalette + 3 * start, palette, 3 * num);
+	copySubPalette(_mainPalette, _cursorPalette, 240, 8);
+
+	calculateTransparentMapping();
+	if (commit) {
+		setPalette(_mainPalette, 0, 256);
+	}
+}
+
+struct transparentScore {
+	unsigned int score;
+	byte redScaled;
+	byte greenScaled;
+
+	int dScore(transparentScore &other) { return abs((int)score - (int)other.score); }
+	int dRed(transparentScore &other) { return abs((int)redScaled - (int)other.redScaled); }
+	int dGreen(transparentScore &other) { return abs((int)greenScaled - (int)other.greenScaled); }
+};
+
+static transparentScore transparentCalculateScore(byte red, byte green, byte blue) {
+	transparentScore ret;
+	ret.score = 10 * (blue + 3 * (red + 2 * green)) / 30;
+	if (ret.score) {
+		ret.redScaled = ((unsigned int)red) * 256 / ret.score;
+		ret.greenScaled = ((unsigned int)green) * 256 / ret.score;
+	} else {
+		ret.redScaled = 0;
+		ret.greenScaled = 0;
+	}
+	return ret;
+}
+
+void CryOmni3DEngine_Versailles::calculateTransparentMapping() {
+	// Calculate colors proximity array
+	transparentScore *proximities = new transparentScore[256];
+
+	for (unsigned int i = _transparentSrcStart; i < _transparentSrcStop; i++) {
+		proximities[i] = transparentCalculateScore(_mainPalette[3 * i + 0], _mainPalette[3 * i + 1],
+		                 _mainPalette[3 * i + 2]);
+	}
+
+	unsigned int newColorsNextId = _transparentNewStart;
+	unsigned int newColorsCount = 0;
+	for (unsigned int i = _transparentDstStart; i < _transparentDstStop; i++) {
+		byte transparentRed = ((unsigned int)_mainPalette[3 * i + 0]) * 60 / 128;
+		byte transparentGreen = ((unsigned int)_mainPalette[3 * i + 1]) * 50 / 128;
+		byte transparentBlue = ((unsigned int)_mainPalette[3 * i + 2]) * 35 / 128;
+
+		// Find nearest color
+		transparentScore newColorScore = transparentCalculateScore(transparentRed, transparentGreen,
+		                                 transparentBlue);
+		unsigned int distanceMin = -1u;
+		unsigned int nearestId = -1u;
+		for (unsigned int j = _transparentSrcStart; j < _transparentSrcStop; j++) {
+			if (j != i && newColorScore.dScore(proximities[j]) < 15) {
+				unsigned int distance = newColorScore.dRed(proximities[j]) + newColorScore.dGreen(proximities[j]);
+				if (distance < distanceMin) {
+					distanceMin = distance;
+					nearestId = j;
+				}
+			}
+		}
+
+		if (nearestId == -1u) {
+			// Couldn't find a good enough color, try to create one
+			if (_transparentNewStart != -1u && newColorsNextId <= _transparentNewStop) {
+				_mainPalette[3 * newColorsNextId + 0] = transparentRed;
+				_mainPalette[3 * newColorsNextId + 1] = transparentGreen;
+				_mainPalette[3 * newColorsNextId + 2] = transparentBlue;
+				nearestId = newColorsNextId;
+
+				newColorsCount++;
+				newColorsNextId++;
+			}
+		}
+
+		if (nearestId == -1u) {
+			// Couldn't allocate a new color, return the original one
+			nearestId = i;
+		}
+
+		_transparentPaletteMap[i] = nearestId;
+	}
+
+	delete[] proximities;
+}
+
+void CryOmni3DEngine_Versailles::makeTranslucent(Graphics::Surface &dst,
+        const Graphics::Surface &src) const {
+	assert(dst.w == src.w && dst.h == src.h);
+
+	const byte *srcP = (const byte *) src.getPixels();
+	byte *dstP = (byte *) dst.getPixels();
+	for (unsigned int y = 0; y < dst.h; y++) {
+		for (unsigned int x = 0; x < dst.w; x++) {
+			dstP[x] = _transparentPaletteMap[srcP[x]];
+		}
+		dstP += dst.pitch;
+		srcP += src.pitch;
+	}
+}
+
+bool CryOmni3DEngine_Versailles::hasPlaceDocumentation() {
+	return _placeStates[_currentPlaceId].docImage != nullptr;
+}
+
+bool CryOmni3DEngine_Versailles::displayPlaceDocumentation() {
+	if (!_placeStates[_currentPlaceId].docImage) {
+		return false;
+	}
+
+	_docManager.handleDocInGame(_placeStates[_currentPlaceId].docImage);
+	return true;
+}
+
+void CryOmni3DEngine_Versailles::syncOmni3DSettings() {
+	ConfMan.registerDefault("omni3d_speed", 0);
+	int confOmni3DSpeed = ConfMan.getInt("omni3d_speed");
+	if (confOmni3DSpeed == 0) {
+		_omni3dSpeed = 0;
+	} else if (confOmni3DSpeed == 1) {
+		_omni3dSpeed = 2;
+	} else if (confOmni3DSpeed == 2) {
+		_omni3dSpeed = 4;
+	} else if (confOmni3DSpeed == 3) {
+		_omni3dSpeed = -1;
+	} else if (confOmni3DSpeed == 4) {
+		_omni3dSpeed = -2;
+	} else {
+		// Invalid value
+		_omni3dSpeed = 0;
+	}
+}
+
+void CryOmni3DEngine_Versailles::syncSoundSettings() {
+	CryOmni3DEngine::syncSoundSettings();
+
+	int soundVolumeMusic = ConfMan.getInt("music_volume") / _musicVolumeFactor;
+
+	bool mute = false;
+	if (ConfMan.hasKey("mute")) {
+		mute = ConfMan.getBool("mute");
+	}
+
+	bool musicMute = mute  || ConfMan.getBool("music_mute");
+
+	_mixer->muteSoundType(Audio::Mixer::kMusicSoundType, musicMute);
+	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
+}
+
+void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
+	musicStop();
+	_gameVariables[GameVariables::kWarnedIncomplete] = 0;
+
+	Common::String video;
+
+	unlockPalette();
+	switch (level) {
+	case -2:
+		video = "logo.hnm";
+		break;
+	case -1:
+		video = "a0_vf.hns";
+		break;
+	case 0:
+		video = "a1_vf.hns";
+		break;
+	case 1:
+		video = "a2_vf.hns";
+		break;
+	case 2:
+		video = "a3_vf.hns";
+		_inventory.removeByNameId(96);
+		_inventory.removeByNameId(104);
+		break;
+	case 3:
+		video = "a4_vf.hns";
+		break;
+	case 4:
+		video = "a5_vf.hns";
+		_inventory.removeByNameId(101);
+		_inventory.removeByNameId(127);
+		_inventory.removeByNameId(129);
+		_inventory.removeByNameId(130);
+		_inventory.removeByNameId(131);
+		_inventory.removeByNameId(132);
+		_inventory.removeByNameId(126);
+		break;
+	case 5:
+		video = "a6_vf.hns";
+		_inventory.removeByNameId(115);
+		break;
+	case 6:
+		video = "a7_vf.hns";
+		break;
+	case 7:
+		video = "a9_vf.hns";
+		break;
+	case 8:
+		video = "a8_vf.hns";
+		break;
+	default:
+		error("Invalid level : %d", level);
+	}
+
+	fadeOutPalette();
+	if (g_engine->shouldQuit()) {
+		_abortCommand = AbortQuit;
+		return;
+	}
+
+	fillSurface(0);
+
+	// Videos are like music because if you mute music in game it will mute videos soundtracks
+	playHNM(video, Audio::Mixer::kMusicSoundType);
+	clearKeys();
+	if (g_engine->shouldQuit()) {
+		_abortCommand = AbortQuit;
+		return;
+	}
+
+	fadeOutPalette();
+	if (g_engine->shouldQuit()) {
+		_abortCommand = AbortQuit;
+		return;
+	}
+
+	fillSurface(0);
+
+	if (level == 7 || level == 8) {
+		_abortCommand = AbortFinished;
+	} else {
+		_abortCommand = AbortNextLevel;
+	}
+}
+
+void CryOmni3DEngine_Versailles::changeLevel(int level) {
+	_currentLevel = level;
+
+	musicStop();
+	_mixer->stopAll();
+
+	if (_currentLevel == 1) {
+		_dialogsMan.reinitVariables();
+		for (Common::Array<unsigned int>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
+		        it++) {
+			*it = 0;
+		}
+		// TODO: countdown
+		_inventory.clear();
+	} else {
+		// TODO: to implement
+		error("New level %d is not implemented (yet)", level);
+	}
+
+	_gameVariables[GameVariables::kCurrentTime] = 1;
+
+	// keep back place state for level 2
+	int place8_state_backup;
+	if (level == 2) {
+		place8_state_backup = _placeStates[8].state;
+	}
+	_nextPlaceId = -1;
+	initNewLevel(_currentLevel);
+	// restore place state for level 2
+	if (level == 2) {
+		_placeStates[8].state = place8_state_backup;
+	}
+}
+
+void CryOmni3DEngine_Versailles::initNewLevel(int level) {
+	// SearchMan can't add several times the same basename
+	// We create several SearchSet with different names that we add to SearchMan instead
+
+	// Visiting uses all levels
+	SearchMan.remove("__visitFiles");
+
+	SearchMan.remove("__levelFiles_animacti");
+	SearchMan.remove("__levelFiles_warp");
+	SearchMan.remove("__levelFiles_img_fix");
+
+	const Common::FSNode gameDataDir(ConfMan.get("path"));
+	if (level >= 1 && level <= 7) {
+		Common::SearchSet *levelFilesAnimacti = new Common::SearchSet();
+		Common::SearchSet *levelFilesWarp = new Common::SearchSet();
+		Common::SearchSet *levelFilesImgFix = new Common::SearchSet();
+
+		levelFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "datas_v/animacti/level%d", level), 1);
+		levelFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		        "datas_v/warp/level%d/cyclo", level), 1);
+		levelFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		        "datas_v/warp/level%d/hnm", level), 1);
+		levelFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "datas_v/img_fix/level%d", level), 1);
+
+		SearchMan.add("__levelFiles_animacti", levelFilesAnimacti);
+		SearchMan.add("__levelFiles_warp", levelFilesWarp);
+		SearchMan.add("__levelFiles_img_fix", levelFilesImgFix);
+	} else if (level == 8 && _isVisiting) {
+		// In visit mode, we take files from all levels, happily they have unique names
+		// Create a first SearchSet in which we will add all others to easily cleanup the mess
+		Common::SearchSet *visitFiles = new Common::SearchSet();
+
+		for (unsigned int lvl = 1; lvl <= 7; lvl++) {
+			Common::SearchSet *visitFilesAnimacti = new Common::SearchSet();
+			Common::SearchSet *visitFilesWarp = new Common::SearchSet();
+			Common::SearchSet *visitFilesImgFix = new Common::SearchSet();
+
+			visitFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
+			            "datas_v/animacti/level%d", lvl), 1);
+			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+			        "datas_v/warp/level%d/cyclo", lvl), 1);
+			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+			        "datas_v/warp/level%d/hnm", lvl), 1);
+			visitFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
+			            "datas_v/img_fix/level%d", lvl), 1);
+
+			visitFiles->add(Common::String::format("__visitFiles_animacti_%d", lvl), visitFilesAnimacti);
+			visitFiles->add(Common::String::format("__visitFiles_warp_%d", lvl), visitFilesWarp);
+			visitFiles->add(Common::String::format("__visitFiles_img_fix_%d", lvl), visitFilesImgFix);
+		}
+
+		SearchMan.add("__visitFiles", visitFiles);
+	} else {
+		error("Invalid level %d", level);
+	}
+
+	// TODO: countdown
+	initPlacesStates();
+	initWhoSpeaksWhere();
+	setupLevelWarps(level);
+	updateGameTimeDialVariables();
+	_dialogsMan["{JOUEUR-ESSAYE-OUVRIR-PORTE-SALON}"] = 'Y';
+	_dialogsMan["{JOUEUR-ESSAYE-OUVRIR-PORTE-CHAMBRE}"] = 'Y';
+	setupLevelActionsMask();
+}
+
+void CryOmni3DEngine_Versailles::setupLevelWarps(int level) {
+	Common::File wamFile;
+	Common::String wamFName = Common::String::format("level%d.wam", level);
+	if (!wamFile.open(wamFName)) {
+		error("Can't open WAM file '%s'", wamFName.c_str());
+	}
+	_wam.loadStream(wamFile);
+
+	const LevelInitialState &initialState = kLevelInitialStates[level - 1];
+
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = initialState.placeId;
+	}
+	_omni3dMan.setAlpha(initialState.alpha);
+	_omni3dMan.setBeta(initialState.beta);
+}
+
+void CryOmni3DEngine_Versailles::setGameTime(unsigned int newTime, unsigned int level) {
+	if (_currentLevel != level) {
+		error("Level %u != current level %u", level, _currentLevel);
+	}
+
+	_gameVariables[GameVariables::kCurrentTime] = newTime;
+	updateGameTimeDialVariables();
+
+	if (_currentLevel == 1) {
+		if (newTime == 2) {
+			setPlaceState(1, 1);
+			setPlaceState(2, 1);
+			_whoSpeaksWhere[PlaceActionKey(2, 11201)] = "12E_HUI";
+			setPlaceState(3, 1);
+		} else if (newTime == 3) {
+			setPlaceState(2, 2);
+		}
+	} else if (_currentLevel == 2) {
+		if (newTime == 2) {
+			setPlaceState(9, 1);
+			_whoSpeaksWhere[PlaceActionKey(9, 52902)] = "22G_DAU";
+		} else if (newTime == 4) {
+			setPlaceState(10, 1);
+			setPlaceState(11, 1);
+			setPlaceState(12, 1);
+			setPlaceState(13, 1);
+		}
+	} else if (_currentLevel == 3) {
+		if (newTime == 2) {
+			if (_placeStates[13].state) {
+				setPlaceState(13, 3);
+			} else {
+				setPlaceState(13, 2);
+			}
+			setPlaceState(15, 1);
+			setPlaceState(17, 1);
+		} else if (newTime == 3) {
+			setPlaceState(10, 1);
+			setPlaceState(14, 1);
+		}
+	} else if (_currentLevel == 4) {
+		if (newTime == 2) {
+			setPlaceState(7, 1);
+			setPlaceState(8, 1);
+			setPlaceState(10, 1);
+			setPlaceState(16, 1);
+		} else if (newTime == 3) {
+			setPlaceState(10, 2);
+			setPlaceState(9, 1);
+		} else if (newTime == 4) {
+			setPlaceState(9, 2);
+			_whoSpeaksWhere[PlaceActionKey(9, 54091)] = "4_MAI";
+			_whoSpeaksWhere[PlaceActionKey(9, 14091)] = "4_MAI";
+		}
+	} else if (_currentLevel == 5) {
+		if (newTime == 2) {
+			setPlaceState(9, 1);
+			setPlaceState(13, 1);
+		} else if (newTime == 3) {
+			if (!_placeStates[16].state) {
+				setPlaceState(16, 2);
+			}
+		} else if (newTime == 4) {
+			_whoSpeaksWhere[PlaceActionKey(9, 15090)] = "54I_BON";
+		}
+	} else if (_currentLevel == 6) {
+		if (newTime == 2) {
+			setPlaceState(14, 1);
+			setPlaceState(19, 2);
+		}
+	}
+}
+
+void CryOmni3DEngine_Versailles::gameStep() {
+	while (!_abortCommand) {
+		if (_nextPlaceId != -1u) {
+			// TODO: check selected object == -2 if needed
+			if (_placeStates[_nextPlaceId].initPlace) {
+				(this->*_placeStates[_nextPlaceId].initPlace)();
+				// TODO: check selected object == -2 if needed
+			}
+			doPlaceChange();
+			musicUpdate();
+		}
+		if (_forcePaletteUpdate) {
+			redrawWarp();
+		}
+		unsigned int actionId = handleWarp();
+		debug("handleWarp returned %u", actionId);
+		// TODO: handle keyboard levels 4 and 5
+
+		// Get selected object there to detect when it has just been deselected
+		Object *selectedObject = _inventory.selectedObject();
+
+		_nextPlaceId = -1;
+		bool doEvent;
+		if (_placeStates[_currentPlaceId].filterEvent && !_isVisiting) {
+			doEvent = (this->*_placeStates[_currentPlaceId].filterEvent)(&actionId);
+		} else {
+			doEvent = true;
+		}
+
+		if (_abortCommand) {
+			break;
+		}
+
+		if (!selectedObject) {
+			// Execute only when no object was used before filtering event
+			if (actionId >= 1 && actionId < 10000) {
+				// Move to another place
+				if (doEvent) {
+					executeTransition(actionId);
+				}
+			} else if (actionId >= 10000 && actionId < 20000) {
+				// Speak
+				if (doEvent) {
+					executeSpeakAction(actionId);
+					// Force refresh of place
+					if (_nextPlaceId == -1u) {
+						_nextPlaceId = _currentPlaceId;
+					}
+				}
+			} else if (actionId >= 20000 && actionId < 30000) {
+				// Documentation
+				executeDocAction(actionId);
+			} else if (actionId >= 30000 && actionId < 40000) {
+				// Use
+				// In original game there is a handler for use actions but it's
+				// only for some events, we will implement them in the filterEvent handler
+				if (doEvent) {
+					error("Not implemented yet");
+				}
+			} else if (actionId >= 40000 && actionId < 50000) {
+				// See
+				executeSeeAction(actionId);
+			} else if (actionId >= 50000 && actionId < 60000) {
+				// Listening
+				// never filtered
+				executeSpeakAction(actionId);
+				// Force refresh of place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+			} else if (actionId == 66666) {
+				// Abort
+				assert(_abortCommand != AbortNoAbort);
+				return;
+			}
+		} else if (!actionId) {
+			// Click on nothing with an object: deselect it
+			_inventory.setSelectedObject(nullptr);
+		}
+		// TODO: selected_object == -2 if needed
+	}
+}
+
+void CryOmni3DEngine_Versailles::doGameOver() {
+	musicStop();
+	fadeOutPalette();
+	fillSurface(0);
+	// This test is not really relevant because it's for 2CDs edition but let's follow the code
+	if (_currentLevel < 4) {
+		playInGameVideo("1gameove");
+	} else {
+		playInGameVideo("4gameove");
+	}
+	fillSurface(0);
+	_abortCommand = AbortGameOver;
+}
+
+void CryOmni3DEngine_Versailles::doPlaceChange() {
+	const Place *nextPlace = _wam.findPlaceById(_nextPlaceId);
+	unsigned int state = _placeStates[_nextPlaceId].state;
+	if (state == -1u) {
+		state = 0;
+	}
+
+	if (state >= nextPlace->warps.size()) {
+		error("invalid warp %d/%d/%d", _currentLevel, _nextPlaceId, state);
+	}
+
+	Common::String warpFile = nextPlace->warps[state];
+	warpFile.toUppercase();
+	if (warpFile.size() > 0) {
+		if (warpFile.hasPrefix("NOT_MOVE")) {
+			// Don't move so do nothing but cancel place change
+			_nextPlaceId = -1;
+		} else {
+			_currentPlace = nextPlace;
+			if (!warpFile.hasPrefix("NOT_STOP")) {
+				if (_currentWarpImage) {
+					delete _currentWarpImage;
+				}
+				debug("Loading warp %s", warpFile.c_str());
+				_currentWarpImage = loadHLZ(warpFile);
+				if (!_currentWarpImage) {
+					error("Can't load warp %s", warpFile.c_str());
+				}
+#if 0
+				// This is not correct but to debug zones I think it's OK
+				Graphics::Surface *tmpSurf = (Graphics::Surface *) _currentWarpImage->getSurface();
+				for (Common::Array<Zone>::const_iterator it = _currentPlace->zones.begin();
+				        it != _currentPlace->zones.end(); it++) {
+					Common::Rect tmp = it->rct;
+					tmp.bottom = tmpSurf->h - it->rct.top;
+					tmp.top = tmpSurf->h - it->rct.bottom;
+					tmpSurf->frameRect(tmp, 244);
+				}
+#endif
+				_currentPlace->setupWarpConstraints(_omni3dMan);
+				_omni3dMan.setSourceSurface(_currentWarpImage->getSurface());
+
+				setupPalette(_currentWarpImage->getPalette(), _currentWarpImage->getPaletteStartIndex(),
+				             _currentWarpImage->getPaletteColorCount(), !_fadedPalette);
+
+				setMousePos(Common::Point(320, 240)); // Center of screen
+
+				_currentPlaceId = _nextPlaceId;
+				_nextPlaceId = -1;
+			}
+		}
+	} else {
+		error("invalid warp %d/%d/%d", _currentLevel, _nextPlaceId, state);
+	}
+}
+
+void CryOmni3DEngine_Versailles::setPlaceState(unsigned int placeId, unsigned int newState) {
+	unsigned int numStates = _wam.findPlaceById(placeId)->getNumStates();
+	unsigned int oldState = _placeStates[placeId].state;
+
+	if (newState > numStates) {
+		warning("CryOmni3DEngine_Versailles::setPlaceState: newState '%d' > numStates '%d'",
+		        newState, numStates);
+		return;
+	}
+	_placeStates[placeId].state = newState;
+
+	if (_currentPlaceId == placeId && oldState != newState) {
+		// force reload of the place
+		_nextPlaceId = _currentPlaceId;
+	}
+}
+
+void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
+	const Transition *transition;
+	unsigned int animationId = determineTransitionAnimation(_currentPlaceId, nextPlaceId, &transition);
+
+	_nextPlaceId = nextPlaceId;
+
+	Common::String animation = transition->animations[animationId];
+	animation.toUppercase();
+	debug("Transition animation: %s", animation.c_str());
+	if (animation.hasPrefix("NOT_FLI")) {
+		return;
+	}
+
+	if (_transitionAnimateWarp) {
+		animateWarpTransition(transition);
+	} else {
+		_transitionAnimateWarp = true;
+	}
+	if (musicWouldChange(_currentLevel, _nextPlaceId)) {
+		musicStop();
+	}
+	if (animation.hasPrefix("FADE_PAL")) {
+		_fadedPalette = true;
+		fadeOutPalette();
+	} else if (animation != "") {
+		_fadedPalette = false;
+		// Normally transitions don't overwrite the cursors colors and game doesn't restore palette
+		playInGameVideo(animation, false);
+	}
+
+	_omni3dMan.setAlpha(transition->dstAlpha);
+	_omni3dMan.setBeta(-transition->dstBeta);
+
+	unsigned int nextState = _placeStates[nextPlaceId].state;
+	if (nextState == -1u) {
+		nextState = 0;
+	}
+	const Place *nextPlace = _wam.findPlaceById(nextPlaceId);
+	Common::String warpFile = nextPlace->warps[nextState];
+	warpFile.toUppercase();
+	if (warpFile.hasPrefix("NOT_STOP")) {
+		unsigned int transitionNum;
+		// Determine transition to take
+		if (nextPlace->getNumTransitions() == 1) {
+			// Only one
+			transitionNum = 0;
+		} else if (nextPlace->findTransition(_currentPlaceId) == &nextPlace->transitions[0]) {
+			// Don't take the transition returning to where we come from
+			transitionNum = 1;
+		} else {
+			transitionNum = 0;
+		}
+		unsigned int nextNextPlaceId = nextPlace->transitions[transitionNum].dstId;
+
+		animationId = determineTransitionAnimation(nextPlaceId, nextNextPlaceId, &transition);
+		animation = transition->animations[animationId];
+
+		animation.toUppercase();
+		if (animation.hasPrefix("NOT_FLI")) {
+			return;
+		}
+		if (animation.hasPrefix("FADE_PAL")) {
+			_fadedPalette = true;
+			fadeOutPalette();
+		} else if (animation != "") {
+			_fadedPalette = false;
+			// Normally transitions don't overwrite the cursors colors and game doesn't restore palette
+			playInGameVideo(animation, false);
+		}
+
+		_nextPlaceId = nextNextPlaceId;
+
+		_omni3dMan.setAlpha(transition->dstAlpha);
+		_omni3dMan.setBeta(-transition->dstBeta);
+	}
+}
+
+void CryOmni3DEngine_Versailles::fakeTransition(unsigned int dstPlaceId) {
+	// No need of animation, caller will take care
+	// We just setup the camera in good place for the caller
+	const Place *srcPlace = _wam.findPlaceById(_currentPlaceId);
+	const Transition *transition = srcPlace->findTransition(dstPlaceId);
+
+	animateWarpTransition(transition);
+
+	_omni3dMan.setAlpha(transition->dstAlpha);
+	_omni3dMan.setBeta(-transition->dstBeta);
+}
+
+unsigned int CryOmni3DEngine_Versailles::determineTransitionAnimation(unsigned int srcPlaceId,
+        unsigned int dstPlaceId, const Transition **transition_) {
+	const Place *srcPlace = _wam.findPlaceById(srcPlaceId);
+	const Place *dstPlace = _wam.findPlaceById(dstPlaceId);
+	const Transition *transition = srcPlace->findTransition(dstPlaceId);
+
+	if (transition_) {
+		*transition_ = transition;
+	}
+
+	unsigned int srcNumStates = srcPlace->getNumStates();
+	unsigned int dstNumStates = dstPlace->getNumStates();
+	unsigned int animsNum = transition->getNumAnimations();
+
+	unsigned int srcState = _placeStates[srcPlaceId].state;
+	unsigned int dstState = _placeStates[dstPlaceId].state;
+
+	if (srcState >= srcNumStates) {
+		error("Invalid src state");
+	}
+
+	if (dstState >= dstNumStates) {
+		error("Invalid dst state");
+	}
+
+	if (animsNum <= 1) {
+		return 0;
+	}
+
+	if (srcNumStates == 2 && dstNumStates == 2) {
+		if (animsNum == 2) {
+			return dstState;
+		} else if (animsNum == 4) {
+			return srcState * 2 + dstState;
+		}
+	}
+
+	if (animsNum == dstNumStates) {
+		return dstState;
+	}
+
+	if (animsNum == srcNumStates) {
+		return srcState;
+	}
+
+	// Other case
+	return 0;
+}
+
+int CryOmni3DEngine_Versailles::handleWarp() {
+	bool exit = false;
+	bool leftButtonPressed = false;
+	bool firstDraw = true;
+	bool moving = true;
+	unsigned int actionId;
+	g_system->showMouse(true);
+	while (!leftButtonPressed && !exit) {
+		int xDelta = 0, yDelta = 0;
+		unsigned int movingCursor = -1;
+
+		pollEvents();
+		Common::Point mouse = getMousePos();
+
+		if (mouse.y < 100) {
+			movingCursor = 245;
+			yDelta = 100 - mouse.y;
+		} else if (mouse.y > 380) {
+			movingCursor = 224;
+			yDelta = 380 - mouse.y;
+		}
+		if (mouse.x < 100) {
+			movingCursor = 241;
+			xDelta = 100 - mouse.x;
+		} else if (mouse.x > 540) {
+			movingCursor = 228;
+			xDelta = 540 - mouse.x;
+		}
+		if (_omni3dSpeed > 0) {
+			xDelta <<= _omni3dSpeed;
+			yDelta <<= _omni3dSpeed;
+		} else if (_omni3dSpeed < 0) {
+			xDelta >>= -_omni3dSpeed;
+			yDelta >>= -_omni3dSpeed;
+		}
+		leftButtonPressed = (getCurrentMouseButton() == 1);
+
+		Common::Point mouseRev = _omni3dMan.mapMouseCoords(mouse);
+		mouseRev.y = 768 - mouseRev.y;
+
+		actionId = _currentPlace->hitTest(mouseRev);
+
+		exit = handleWarpMouse(&actionId, movingCursor);
+		if (g_engine->shouldQuit()) {
+			_abortCommand = AbortQuit;
+			exit = true;
+		}
+		if (exit) {
+			actionId = 66666;
+		}
+
+		if (firstDraw || xDelta || yDelta || _omni3dMan.hasSpeed()) {
+			bool useOldSpeed = false;
+			if (_omni3dSpeed <= 2) {
+				useOldSpeed = true;
+			}
+			_omni3dMan.updateCoords(xDelta, -yDelta, useOldSpeed);
+
+			const Graphics::Surface *result = _omni3dMan.getSurface();
+			g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
+			if (!exit) {
+				// TODO: countdown
+				g_system->updateScreen();
+				if (firstDraw && _fadedPalette) {
+					fadeInPalette(_mainPalette);
+					_fadedPalette = false;
+				}
+			}
+			moving = true;
+			firstDraw = false;
+		} else if (moving) {
+			const Graphics::Surface *result = _omni3dMan.getSurface();
+			g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
+			if (!exit) {
+				// TODO: countdown
+				g_system->updateScreen();
+			}
+			// TODO: cursorUseZones
+			moving = false;
+		} else {
+			if (!exit) {
+				// TODO: countdown
+				g_system->updateScreen();
+			}
+		}
+		if (!exit && !leftButtonPressed) {
+			g_system->delayMillis(50);
+		}
+	}
+	g_system->showMouse(false);
+	return actionId;
+}
+
+bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
+        unsigned int movingCursor) {
+	PlaceStateActionKey mask = PlaceStateActionKey(_currentPlaceId, _placeStates[_currentPlaceId].state,
+	                           *actionId);
+	*actionId = _actionMasks.getVal(mask, *actionId);
+
+	if (getCurrentMouseButton() == 2 ||
+	        getNextKey().keycode == Common::KEYCODE_SPACE) {
+		// Prepare background using alpha
+		const Graphics::Surface *original = _omni3dMan.getSurface();
+		bool mustRedraw = displayToolbar(original);
+		// Don't redraw if we abort game
+		if (_abortCommand != AbortNoAbort) {
+			return true;
+		}
+		if (mustRedraw) {
+			_forceRedrawWarp = true;
+			redrawWarp();
+		}
+		// Force a cycle to recalculate the correct mouse cursor
+		return false;
+	}
+
+	// TODO: countdown
+
+	const Object *selectedObj = _inventory.selectedObject();
+	if (selectedObj) {
+		if (*actionId != 0) {
+			setCursor(selectedObj->idSA());
+		} else {
+			setCursor(selectedObj->idSl());
+		}
+	} else if (*actionId >= 1 && *actionId < 10000) {
+		setCursor(243);
+	} else if (*actionId >= 10000 && *actionId < 20000) {
+		setCursor(113);
+	} else if (*actionId >= 20000 && *actionId < 30000) {
+		setCursor(198);
+	} else if (*actionId >= 30000 && *actionId < 40000) {
+		setCursor(99);
+	} else if (*actionId >= 40000 && *actionId < 50000) {
+		setCursor(145);
+	} else if (*actionId >= 50000 && *actionId < 60000) {
+		setCursor(136);
+	} else if (movingCursor != -1u) {
+		setCursor(movingCursor);
+	} else {
+		setCursor(45);
+	}
+	return false;
+}
+
+void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transition) {
+	double srcAlpha = transition->srcAlpha;
+	double srcBeta = transition->srcBeta;
+
+	double oldDeltaAlpha = 1000., oldDeltaBeta = 1000.;
+
+	clearKeys();
+
+	bool exit = false;
+	while (!exit) {
+		double deltaAlpha = 2.*M_PI - srcAlpha + _omni3dMan.getAlpha();
+		if (deltaAlpha >= 2.*M_PI) {
+			deltaAlpha -= 2.*M_PI;
+		} else if (deltaAlpha < 0) {
+			deltaAlpha += 2.*M_PI;
+		}
+		int deltaAlphaI;
+		if (deltaAlpha < M_PI) {
+			deltaAlphaI = -(deltaAlpha * 512.);
+		} else {
+			deltaAlphaI = (2.*M_PI - deltaAlpha) * 512.;
+		}
+
+		double deltaBeta = -srcBeta - _omni3dMan.getBeta();
+		int deltaBetaI = -(deltaBeta * 512.);
+
+		if (_omni3dSpeed > 0) {
+			deltaAlphaI <<= 2;
+			deltaBetaI <<= 2;
+		} else if (_omni3dSpeed < 0) {
+			deltaAlphaI >>= 2;
+			deltaBetaI >>= 2;
+		}
+
+		_omni3dMan.updateCoords(deltaAlphaI, -deltaBetaI, false);
+
+		const Graphics::Surface *result = _omni3dMan.getSurface();
+		g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
+		// TODO: countdown
+		g_system->updateScreen();
+
+		if (abs(oldDeltaAlpha - deltaAlpha) < 0.001 && abs(oldDeltaBeta - deltaBeta) < 0.001) {
+			exit = true;
+		}
+		oldDeltaAlpha = deltaAlpha;
+		oldDeltaBeta = deltaBeta;
+
+		if (pollEvents() && checkKeysPressed(2, Common::KEYCODE_ESCAPE, Common::KEYCODE_SPACE)) {
+			exit = true;
+		}
+
+		if (!exit) {
+			g_system->delayMillis(50);
+		}
+	}
+}
+
+void CryOmni3DEngine_Versailles::redrawWarp() {
+	setupPalette(_currentWarpImage->getPalette(), _currentWarpImage->getPaletteStartIndex(),
+	             _currentWarpImage->getPaletteColorCount(), true);
+	if (_forceRedrawWarp) {
+		const Graphics::Surface *result = _omni3dMan.getSurface();
+		g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
+		// TODO: countdown
+		g_system->updateScreen();
+		_forceRedrawWarp = false;
+	}
+	_forcePaletteUpdate = false;
+}
+
+void CryOmni3DEngine_Versailles::warpMsgBoxCB() {
+	pollEvents();
+}
+
+void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
+	if (obj == nullptr) {
+		return;
+	}
+
+	g_system->showMouse(true);
+
+	for (unsigned int i = 4; i > 0; i--) {
+		// Wait 100ms
+		for (unsigned int j = 10; j > 0; j--) {
+			// pollEvents sleeps 10ms
+			pollEvents();
+			g_system->updateScreen();
+		}
+		setCursor(obj->idSA());
+		g_system->updateScreen();
+		// Wait 100ms
+		for (unsigned int j = 10; j > 0; j--) {
+			// pollEvents sleeps 10ms
+			pollEvents();
+			g_system->updateScreen();
+		}
+		setCursor(obj->idSl());
+		g_system->updateScreen();
+	}
+
+	g_system->showMouse(false);
+}
+
+void CryOmni3DEngine_Versailles::collectObject(unsigned int nameID, const ZonFixedImage *fimg,
+        bool showObject) {
+	Object *obj = _objects.findObjectByNameID(nameID);
+	_inventory.add(obj);
+	Object::ViewCallback cb = obj->viewCallback();
+	if (showObject && cb) {
+		(*cb)();
+		if (fimg) {
+			fimg->display();
+		} else {
+			_forceRedrawWarp = true;
+			redrawWarp();
+		}
+	}
+	animateCursor(obj);
+}
+
+void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
+        DisplayObjectHook hook) {
+	Image::ImageDecoder *imageDecoder = loadHLZ(imgName);
+	if (!imageDecoder) {
+		error("Can't display object");
+	}
+
+	if (imageDecoder->hasPalette()) {
+		// We don't need to calculate transparency but it's simpler to call this function
+		setupPalette(imageDecoder->getPalette(), imageDecoder->getPaletteStartIndex(),
+		             imageDecoder->getPaletteColorCount());
+	}
+
+	const Graphics::Surface *image = imageDecoder->getSurface();
+
+	// Duplicate image to let hook modify it
+	Graphics::ManagedSurface dstSurface(image->w, image->h, image->format);
+	dstSurface.blitFrom(*image);
+
+	delete imageDecoder;
+	imageDecoder = nullptr;
+
+	if (hook) {
+		(this->*hook)(dstSurface);
+	}
+
+	g_system->copyRectToScreen(dstSurface.getPixels(), dstSurface.pitch, 0, 0,
+	                           dstSurface.w, dstSurface.h);
+	g_system->updateScreen();
+
+	setMousePos(Common::Point(320, 240)); // Center of screen
+	setCursor(181);
+
+	g_system->showMouse(true);
+
+	bool exitImg = false;
+	while (!g_engine->shouldQuit() && !exitImg) {
+		if (pollEvents()) {
+			if (getCurrentMouseButton() == 1) {
+				exitImg = true;
+			}
+		}
+		g_system->updateScreen();
+	}
+	waitMouseRelease();
+	clearKeys();
+
+	g_system->showMouse(false);
+	setMousePos(Common::Point(320, 240)); // Center of screen
+}
+
+void CryOmni3DEngine_Versailles::executeSeeAction(unsigned int actionId) {
+	if (_currentLevel == 7 && _currentPlaceId != 20) {
+		// Not enough time for paintings
+		displayMessageBoxWarp(14);
+		return;
+	}
+
+	const FixedImgCallback &cb = _imgScripts.getVal(actionId, nullptr);
+	if (cb != nullptr) {
+		handleFixedImg(cb);
+	} else {
+		warning("Image script %u not found", actionId);
+	}
+}
+
+void CryOmni3DEngine_Versailles::executeSpeakAction(unsigned int actionId) {
+	PlaceActionKey key(_currentPlaceId, actionId);
+	Common::HashMap<PlaceActionKey, Common::String>::iterator it = _whoSpeaksWhere.find(key);
+	g_system->showMouse(true);
+	bool doneSth = false;
+	if (it != _whoSpeaksWhere.end()) {
+		doneSth = _dialogsMan.play(it->_value);
+	}
+	g_system->showMouse(false);
+	_forcePaletteUpdate = true;
+	if (doneSth) {
+		setMousePos(Common::Point(320, 240)); // Center of screen
+	}
+}
+
+void CryOmni3DEngine_Versailles::executeDocAction(unsigned int actionId) {
+	if (_currentLevel == 7) {
+		// Not enough time for doc
+		displayMessageBoxWarp(13);
+		return;
+	}
+
+	Common::HashMap<unsigned int, const char *>::iterator it = _docPeopleRecord.find(actionId);
+	if (it == _docPeopleRecord.end() || !it->_value) {
+		warning("Missing documentation record for action %u", actionId);
+		return;
+	}
+
+	_docManager.handleDocInGame(it->_value);
+
+	_forcePaletteUpdate = true;
+	setMousePos(Common::Point(320, 240)); // Center of screen
+}
+
+void CryOmni3DEngine_Versailles::handleFixedImg(const FixedImgCallback &callback) {
+	if (!callback) {
+		return;
+	}
+
+	ZonFixedImage::CallbackFunctor *functor =
+	    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, callback);
+	_fixedImage->run(functor);
+	// functor is deleted in ZoneFixedImage
+	functor = nullptr;
+
+	if (_nextPlaceId == -1u) {
+		_forcePaletteUpdate = true;
+	}
+}
+
+unsigned int CryOmni3DEngine_Versailles::getFakeTransition(unsigned int actionId) const {
+	for (const FakeTransitionActionPlace *ft = kFakeTransitions; ft->actionId != nullptr; ft++) {
+		if (ft->actionId == actionId) {
+			return ft->placeId;
+		}
+	}
+	return 0;
+}
+
+void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
+        bool restoreCursorPalette) {
+	if (!_isPlaying) {
+		return;
+	}
+
+	g_system->showMouse(false);
+	lockPalette(0, 241);
+	// Videos are like music because if you mute music in game it will mute videos soundtracks
+	playHNM(filename, Audio::Mixer::kMusicSoundType);
+	clearKeys();
+	unlockPalette();
+	if (restoreCursorPalette) {
+		// Restore cursors colors as 2 first ones may have been erased by the video
+		setPalette(&_cursorPalette[3 * 240], 240, 248);
+	}
+	g_system->showMouse(true);
+}
+
+} // End of namespace Versailles
+} // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
new file mode 100644
index 0000000..4f56fd3
--- /dev/null
+++ b/engines/cryomni3d/versailles/engine.h
@@ -0,0 +1,453 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef 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/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;
+class Surface;
+}
+
+namespace CryOmni3D {
+struct FixedImageConfiguration;
+class ZonFixedImage;
+}
+
+namespace CryOmni3D {
+namespace Versailles {
+struct PlaceStateActionKey {
+	unsigned int placeId;
+	unsigned int placeState;
+	unsigned int actionId;
+	PlaceStateActionKey(unsigned int placeId_, unsigned int placeState_, unsigned int 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 {
+	unsigned int placeId;
+	unsigned int actionId;
+	PlaceActionKey(unsigned int placeId_, unsigned int 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 {
+	AbortNoAbort = 0,
+	AbortQuit = 1,
+	AbortLoadGame = 2,
+	AbortNewGame = 3,
+	AbortNextLevel = 5,
+	AbortFinished = 6,
+	AbortGameOver = 7
+};
+
+struct GameVariables {
+	enum Var {
+		// TODO: make these enum members more correct
+		kCollectPartition = 0,         // 0
+		kUnlockPetitePorte,
+		kAlreadyCame31,
+		kDrawerStatus,
+		kCurrentTime,
+		kGotMedaillesSolution,
+		kDrawerFurnitureStatus,
+		kCollectePartition,
+		kCollectPamphletArchi,
+		kGotRevealedPaper, // OK
+		kCollectCle,                   // 10
+		kCollectCartonDessin,
+		kEsquissePainted,
+		kStateFauxCroquis,
+		kCollectNourriture,
+		kCollectPlume,
+		kStatePamphletReligion,
+		kCollectPetiteCle3,
+		kCollectGravure,
+		kCollectCordon,
+		kCollectPlanVauban,            // 20
+		kCollectPlanVauban2,
+		kCollectEchelle,
+		kLostCordon,
+		kDescendreLustre,
+		kOrangerRatisse,
+		kDiscussedLabyrOrder,
+		kUsedBougieAllumee,
+		kStateBombe,
+		kInkSpilled, // OK
+		kCollectedPaperOnTable, // OK  // 30
+		kCoffreUnlocked,
+		//kUselessVar,
+		kCollectedPaperInTrunk = 33, // OK
+		kUsingPinceauColor,
+		kUsedScissors, // OK
+		kUsedClefsCombles,
+		kHasPlayedLebrun, // OK
+		kWarnedIncomplete,
+		kUsedPlanVauban1,
+		kUsedPlanVauban2,              // 40
+		kSeenMemorandum,
+		kCollectScissors, // OK
+		kSavedCountdown, // TODO: calculate it in real time
+		kMax
+	};
+};
+
+// For random sounds we set a constant ID and avoid to use it elsewhere
+struct SoundIds {
+	enum {
+		kOrgue = 0,
+		kLeb001,
+		kMax
+	};
+};
+
+struct PlaceState {
+	typedef void (CryOmni3DEngine_Versailles::*InitFunc)();
+	typedef bool (CryOmni3DEngine_Versailles::*FilterEventFunc)(unsigned int *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;
+	unsigned int state;
+};
+
+struct LevelInitialState {
+	unsigned int placeId;
+	double alpha;
+	double beta;
+};
+
+struct FakeTransitionActionPlace {
+	unsigned int actionId;
+	unsigned int placeId;
+};
+
+typedef void (CryOmni3DEngine_Versailles::*FixedImgCallback)(ZonFixedImage *);
+
+struct MsgBoxParameters {
+	int font;
+	byte foreColor;
+	unsigned int lineHeight;
+	unsigned int spaceWidth;
+	unsigned int charSpacing;
+	unsigned int initialWidth;
+	unsigned int incrementWidth;
+	unsigned int initialHeight;
+	unsigned int incrementHeight;
+	unsigned int timeoutChar;
+};
+
+class CryOmni3DEngine_Versailles : public CryOmni3DEngine {
+	friend class Versailles_DialogsManager;
+protected:
+	Common::Error run() override;
+
+public:
+	CryOmni3DEngine_Versailles(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
+	virtual ~CryOmni3DEngine_Versailles();
+
+	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;
+
+	virtual bool displayToolbar(const Graphics::Surface *original) override { return _toolbar.displayToolbar(original); };
+	virtual bool hasPlaceDocumentation() override;
+	virtual bool displayPlaceDocumentation() override;
+	virtual unsigned int displayOptions() override;
+	virtual bool shouldAbort() override { return g_engine->shouldQuit() || _abortCommand != AbortNoAbort; }
+
+
+private:
+	void setupFonts();
+	void setupSprites();
+	void loadCursorsPalette();
+	void calculateTransparentMapping();
+	void setupMessages();
+	void setupObjects();
+	void setupDialogVariables();
+	void setupImgScripts();
+	void setupPaintingsTitles();
+
+	void syncOmni3DSettings();
+	void syncSoundSettings();
+
+	void playTransitionEndLevel(int level);
+	void changeLevel(int level);
+	void initNewLevel(int level);
+	void setupLevelWarps(int level);
+	void initPlacesStates();
+	void initWhoSpeaksWhere();
+	void initDocPeopleRecord();
+	void setupLevelActionsMask();
+
+	unsigned int currentGameTime() const { return _gameVariables[GameVariables::kCurrentTime]; }
+	void setGameTime(unsigned int newTime, unsigned int level);
+	void updateGameTimeDialVariables();
+
+	void gameStep();
+	void doGameOver();
+
+	void setPlaceState(unsigned int placeId, unsigned int newState);
+	void doPlaceChange();
+	void executeTransition(unsigned int nextPlaceId);
+	void fakeTransition(unsigned int dstPlaceId);
+	unsigned int determineTransitionAnimation(unsigned int srcId, unsigned int dstId,
+	        const Transition **transition);
+
+	unsigned int getFakeTransition(unsigned int actionId) const;
+
+	int handleWarp();
+	bool handleWarpMouse(unsigned int *actionId, unsigned int movingCuror);
+	void animateWarpTransition(const Transition *transition);
+	void redrawWarp();
+
+	void handleFixedImg(const FixedImgCallback &callback);
+	void executeSeeAction(unsigned int actionId);
+
+	void executeSpeakAction(unsigned int actionId);
+	void setupDialogShows();
+	bool preprocessDialog(const Common::String &sequence);
+	void postprocessDialog(const Common::String &sequence);
+
+	void executeDocAction(unsigned int actionId);
+
+	void drawMenuTitle(Graphics::ManagedSurface *surface, byte color);
+	unsigned int displayFilePicker(const Graphics::Surface *bgFrame, bool saveMode,
+	                               Common::String &saveName);
+	unsigned int displayYesNoBox(Graphics::ManagedSurface &surface, const Common::Rect &position,
+	                             unsigned int msg_id);
+	void displayMessageBox(const MsgBoxParameters &params, const Graphics::Surface *surface,
+	                       unsigned int msg_id, const Common::Point &position,
+	                       const Common::Functor0<void> &callback) { displayMessageBox(params, surface, _messages[msg_id], position, callback); }
+	void displayMessageBox(const MsgBoxParameters &params, 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(unsigned int msg_id) { displayMessageBoxWarp(_messages[msg_id]); }
+	void displayCredits();
+
+	void warpMsgBoxCB();
+
+	bool canVisit() const;
+	Common::String getSaveFileName(bool visit, unsigned int saveNum) const;
+	void getSavesList(bool visit, Common::Array<Common::String> &saveNames);
+	void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName) const;
+	bool loadGame(bool visit, unsigned int saveNum);
+
+	void animateCursor(const Object *object);
+	void collectObject(unsigned int nameID, const ZonFixedImage *fimg = nullptr,
+	                   bool showObject = true);
+	typedef void (CryOmni3DEngine_Versailles::*DisplayObjectHook)(Graphics::ManagedSurface &surface);
+	void displayObject(const Common::String &imgName, DisplayObjectHook hook = nullptr);
+
+	void setupPalette(const byte *colors, uint start, uint num, bool commit);
+
+	bool showSubtitles() const;
+
+	void playInGameVideo(const Common::String &filename, bool restoreCursorPalette = true);
+
+	unsigned int getMusicId(unsigned int level, unsigned int placeId) const;
+	bool musicWouldChange(unsigned int level, unsigned int placeId) const;
+	void musicUpdate();
+	void musicPause();
+	void musicResume();
+	void musicStop();
+	void musicSetQuiet(bool quiet);
+
+	Common::StringArray _messages;
+	static const unsigned int kSpritesMapTable[];
+	static const unsigned int kSpritesMapTableSize;
+	static const LevelInitialState kLevelInitialStates[];
+	static const FakeTransitionActionPlace kFakeTransitions[];
+	Common::HashMap<unsigned int, FixedImgCallback> _imgScripts;
+	Common::Array<Common::String> _paintingsTitles;
+
+	Toolbar _toolbar;
+
+	byte *_mainPalette;
+	byte *_cursorPalette;
+	bool _fadedPalette;
+	bool _forcePaletteUpdate;
+	bool _forceRedrawWarp;
+
+	byte *_transparentPaletteMap;
+	unsigned int _transparentSrcStart;
+	unsigned int _transparentSrcStop;
+	unsigned int _transparentDstStart;
+	unsigned int _transparentDstStop;
+	unsigned int _transparentNewStart;
+	unsigned int _transparentNewStop;
+
+	bool _isPlaying;
+	bool _isVisiting;
+	AbortCommand _abortCommand;
+	unsigned int _loadedSave;
+
+	int _omni3dSpeed;
+
+	unsigned int _currentLevel;
+	Versailles_DialogsManager _dialogsMan;
+
+	Omni3DManager _omni3dMan;
+	ZonFixedImage *_fixedImage;
+
+	Common::Array<unsigned int> _gameVariables;
+	Common::Array<PlaceState> _placeStates;
+	Common::HashMap<PlaceStateActionKey, unsigned int> _actionMasks;
+	Common::HashMap<PlaceActionKey, Common::String> _whoSpeaksWhere;
+	Common::HashMap<unsigned int, const char *> _docPeopleRecord;
+	bool _transitionAnimateWarp;
+	unsigned int _nextPlaceId;
+	WAMParser _wam;
+	unsigned int _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;
+
+	//Objects
+	template<unsigned int ID>
+	void genericDisplayObject();
+
+	// Fixed image
+	template<unsigned int ID>
+	void genericDumbImage(ZonFixedImage *fimg);
+	template<unsigned int ID>
+	void genericPainting(ZonFixedImage *fimg);
+#define IMG_CB(name) void img_ ## name(ZonFixedImage *fimg)
+	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(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);
+#undef IMG_CB
+


Commit: 8d770af865c3ee01a230f68f3d5bf3f67c8da277
    https://github.com/scummvm/scummvm/commit/8d770af865c3ee01a230f68f3d5bf3f67c8da277
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix compilation error with -std=c++11

Comparison of non-pointer with nullptr was from a bad copy-paste

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index b25efc7..4425a03 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1412,7 +1412,7 @@ void CryOmni3DEngine_Versailles::handleFixedImg(const FixedImgCallback &callback
 }
 
 unsigned int CryOmni3DEngine_Versailles::getFakeTransition(unsigned int actionId) const {
-	for (const FakeTransitionActionPlace *ft = kFakeTransitions; ft->actionId != nullptr; ft++) {
+	for (const FakeTransitionActionPlace *ft = kFakeTransitions; ft->actionId != 0; ft++) {
 		if (ft->actionId == actionId) {
 			return ft->placeId;
 		}


Commit: c7205da58b7d7a82d86e0877f4933b0b5bfa74ca
    https://github.com/scummvm/scummvm/commit/c7205da58b7d7a82d86e0877f4933b0b5bfa74ca
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix use after free when playing dialog

Changed paths:
    engines/cryomni3d/dialogs_manager.cpp


diff --git a/engines/cryomni3d/dialogs_manager.cpp b/engines/cryomni3d/dialogs_manager.cpp
index 6c1c2ac..badd742 100644
--- a/engines/cryomni3d/dialogs_manager.cpp
+++ b/engines/cryomni3d/dialogs_manager.cpp
@@ -257,6 +257,9 @@ bool DialogsManager::play(const Common::String &sequence, bool &slowStop) {
 	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) {
@@ -284,7 +287,7 @@ bool DialogsManager::play(const Common::String &sequence, bool &slowStop) {
 			didSomething = true;
 			actions = nextLine(text);
 		}
-		Common::Array<DialogsManager::Goto> gotoList = executeAfterPlayAndBuildGotoList(actions);
+		gotoList = executeAfterPlayAndBuildGotoList(actions);
 		Common::StringArray questions;
 		bool endOfConversationFound = false;;
 		if (_ignoreNoEndOfConversation) {


Commit: a055268a08d1e277a9335d92aab62e76c3e1e4c8
    https://github.com/scummvm/scummvm/commit/a055268a08d1e277a9335d92aab62e76c3e1e4c8
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: remove debug define which skipped videos

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 4425a03..8d7d7fa 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -35,7 +35,7 @@
 
 #include "cryomni3d/versailles/engine.h"
 
-#define DEBUG_FAST_START 1
+//#define DEBUG_FAST_START 1
 
 namespace CryOmni3D {
 namespace Versailles {


Commit: ba6506d8d3b9a171bcf314e8042db89bbda4565e
    https://github.com/scummvm/scummvm/commit/ba6506d8d3b9a171bcf314e8042db89bbda4565e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix struct declarations

Changed paths:
    engines/cryomni3d/cryomni3d.h
    engines/cryomni3d/fixed_image.h
    engines/cryomni3d/mouse_boxes.h
    engines/cryomni3d/sprites.h
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index 0220001..9d2c4e9 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -40,7 +40,7 @@
 class OSystem;
 
 namespace Common {
-class Point;
+struct Point;
 class SeekableReadStream;
 }
 
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 5690788..7e3d266 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -29,7 +29,7 @@
 #include "engines/cryomni3d/objects.h"
 
 namespace Graphics {
-class Surface;
+struct Surface;
 }
 
 namespace CryOmni3D {
diff --git a/engines/cryomni3d/mouse_boxes.h b/engines/cryomni3d/mouse_boxes.h
index 5e4d496..66ddc4a 100644
--- a/engines/cryomni3d/mouse_boxes.h
+++ b/engines/cryomni3d/mouse_boxes.h
@@ -27,8 +27,8 @@
 #include "common/str.h"
 
 namespace Common {
-class Point;
-class Rect;
+struct Point;
+struct Rect;
 }
 
 namespace CryOmni3D {
diff --git a/engines/cryomni3d/sprites.h b/engines/cryomni3d/sprites.h
index eac4be3..5721ea8 100644
--- a/engines/cryomni3d/sprites.h
+++ b/engines/cryomni3d/sprites.h
@@ -33,7 +33,7 @@ class ReadStream;
 }
 
 namespace Graphics {
-class Surface;
+struct Surface;
 }
 
 namespace CryOmni3D {
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 4f56fd3..34f2c6c 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -40,7 +40,7 @@
 
 namespace Graphics {
 class ManagedSurface;
-class Surface;
+struct Surface;
 }
 
 namespace CryOmni3D {


Commit: 6ef4fba3d1bc8df40eb7bcddbefab0531d7a55d5
    https://github.com/scummvm/scummvm/commit/6ef4fba3d1bc8df40eb7bcddbefab0531d7a55d5
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix type of return to match prototype

Changed paths:
    engines/cryomni3d/dialogs_manager.cpp


diff --git a/engines/cryomni3d/dialogs_manager.cpp b/engines/cryomni3d/dialogs_manager.cpp
index badd742..ef68495 100644
--- a/engines/cryomni3d/dialogs_manager.cpp
+++ b/engines/cryomni3d/dialogs_manager.cpp
@@ -139,7 +139,7 @@ const char *DialogsManager::findSequence(const char *sequence) const {
 Common::String DialogsManager::findVideo(const char *data) const {
 	data = previousMatch(data, ".FLC");
 	if (data == nullptr) {
-		return nullptr;
+		return Common::String();
 	}
 
 	// Video name is without the extension


Commit: db85320bcc2deaa1753be24462d768a535b84b1c
    https://github.com/scummvm/scummvm/commit/db85320bcc2deaa1753be24462d768a535b84b1c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove DATAS_V folder level for searching files

It's useless and Macintosh has a DATAV_HD folder which PC hasn't.
So let's put all folders directly at root with the Versailles program

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/saveload.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 8d7d7fa..48c63d3 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -67,20 +67,20 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	CryOmni3DEngine::run();
 
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/sc_trans", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/menu", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/basedoc/fonds", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/fonts", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/spr8col", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/spr8col/bmpok", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/wam", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/objets", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/gto", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/dial/flc_dial", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/dial/voix", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/textes", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/music", 1);
-	SearchMan.addSubDirectoryMatching(gameDataDir, "datas_v/sound", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "sc_trans", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "menu", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "basedoc/fonds", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "fonts", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "spr8col", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "spr8col/bmpok", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "wam", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "objets", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "gto", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "dial/flc_dial", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "dial/voix", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "textes", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "music", 1);
+	SearchMan.addSubDirectoryMatching(gameDataDir, "sound", 1);
 
 	setupMessages();
 
@@ -582,13 +582,13 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 		Common::SearchSet *levelFilesImgFix = new Common::SearchSet();
 
 		levelFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
-		            "datas_v/animacti/level%d", level), 1);
+		            "animacti/level%d", level), 1);
 		levelFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-		        "datas_v/warp/level%d/cyclo", level), 1);
+		        "warp/level%d/cyclo", level), 1);
 		levelFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-		        "datas_v/warp/level%d/hnm", level), 1);
+		        "warp/level%d/hnm", level), 1);
 		levelFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
-		            "datas_v/img_fix/level%d", level), 1);
+		            "img_fix/level%d", level), 1);
 
 		SearchMan.add("__levelFiles_animacti", levelFilesAnimacti);
 		SearchMan.add("__levelFiles_warp", levelFilesWarp);
@@ -604,13 +604,13 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 			Common::SearchSet *visitFilesImgFix = new Common::SearchSet();
 
 			visitFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			            "datas_v/animacti/level%d", lvl), 1);
+			            "animacti/level%d", lvl), 1);
 			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			        "datas_v/warp/level%d/cyclo", lvl), 1);
+			        "warp/level%d/cyclo", lvl), 1);
 			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			        "datas_v/warp/level%d/hnm", lvl), 1);
+			        "warp/level%d/hnm", lvl), 1);
 			visitFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			            "datas_v/img_fix/level%d", lvl), 1);
+			            "img_fix/level%d", lvl), 1);
 
 			visitFiles->add(Common::String::format("__visitFiles_animacti_%d", lvl), visitFilesAnimacti);
 			visitFiles->add(Common::String::format("__visitFiles_warp_%d", lvl), visitFilesWarp);
diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index 8afefa3..d4985dc 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -42,7 +42,7 @@ bool CryOmni3DEngine_Versailles::canVisit() const {
 	// Build a custom SearchSet
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
 	Common::SearchSet visitsSearchSet;
-	visitsSearchSet.addSubDirectoryMatching(gameDataDir, "datas_v/savegame/visite", 1);
+	visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
 	return visitsSearchSet.hasFile("game0001.sav");
 }
 
@@ -66,7 +66,7 @@ void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &s
 		// Add bootstrap visit
 		const Common::FSNode gameDataDir(ConfMan.get("path"));
 		Common::SearchSet visitsSearchSet;
-		visitsSearchSet.addSubDirectoryMatching(gameDataDir, "datas_v/savegame/visite", 1);
+		visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
 		if (visitsSearchSet.hasFile("game0001.sav")) {
 			Common::File visitFile;
 			if (!visitFile.open("game0001.sav", visitsSearchSet)) {
@@ -203,7 +203,7 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 		// Load bootstrap visit
 		const Common::FSNode gameDataDir(ConfMan.get("path"));
 		Common::SearchSet visitsSearchSet;
-		visitsSearchSet.addSubDirectoryMatching(gameDataDir, "datas_v/savegame/visite", 1);
+		visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
 		Common::File *visitFile = new Common::File();
 		if (!visitFile->open("game0001.sav", visitsSearchSet)) {
 			delete visitFile;


Commit: acb8349a91ae0262e6fee7b9457eeb76e4eacdac
    https://github.com/scummvm/scummvm/commit/acb8349a91ae0262e6fee7b9457eeb76e4eacdac
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add Macintosh support to Versailles

There is still some work to do on fonts to make them match what it's
used by the original executable

Changed paths:
    engines/cryomni3d/detection_tables.h
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/detection_tables.h b/engines/cryomni3d/detection_tables.h
index 49a7cb0..d791a34a 100644
--- a/engines/cryomni3d/detection_tables.h
+++ b/engines/cryomni3d/detection_tables.h
@@ -81,6 +81,24 @@ static const CryOmni3DGameDescription gameDescriptions[] = {
 		0,
 	},
 
+	// Versailles 1685
+	// French Macintosh
+	// From criezy
+	{
+		{
+			"versailles",
+			"",
+			AD_ENTRY1s("Versailles", "f81935517b1bbb58acf70f25efa5c7f3", 375868),
+			Common::FR_FRA,
+			Common::kPlatformMacintosh,
+			ADGF_UNSTABLE,
+			GUIO1(GUIO_NOASPECT)
+		},
+		GType_VERSAILLES,
+		0,
+		0,
+	},
+
 	{ AD_TABLE_END_MARKER, 0, 0, 0 }
 };
 
@@ -108,6 +126,7 @@ static const CryOmni3DGameDescription fallbackDescs[] = {
 static const ADFileBasedFallback fileBased[] = {
 	{ &fallbackDescs[0].desc,  { "VERSAILL.EXE", 0 } },
 	{ &fallbackDescs[0].desc,  { "VERSAILL.PGM", 0 } },
+	{ &fallbackDescs[0].desc,  { "Versailles", 0 } },
 	{ 0, { 0 } }
 };
 
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 48c63d3..c3b0482 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -221,17 +221,49 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 
 void CryOmni3DEngine_Versailles::setupFonts() {
 	Common::Array<Common::String> fonts;
-	fonts.push_back("font01.CRF");
-	fonts.push_back("font02.CRF");
-	fonts.push_back("font03.CRF");
-	fonts.push_back("font04.CRF");
-	fonts.push_back("font05.CRF");
-	fonts.push_back("font06.CRF");
-	fonts.push_back("font07.CRF");
-	fonts.push_back("font08.CRF");
-	fonts.push_back("font09.CRF");
-	fonts.push_back("font10.CRF");
-	fonts.push_back("font11.CRF");
+
+	if (getPlatform() == Common::kPlatformMacintosh) {
+		// TODO: Disassemble MacOS executable to find which 11 fonts are used
+		fonts.push_back("MPW12.CRF");
+		fonts.push_back("MPW9.CRF");
+		fonts.push_back("arial11.CRF");
+		fonts.push_back("fruitL10.CRF");
+		fonts.push_back("fruitL11.CRF");
+		fonts.push_back("fruitL12.CRF");
+		fonts.push_back("fruitL13.CRF");
+		fonts.push_back("fruitL14.CRF");
+		fonts.push_back("fruitL16.CRF");
+		fonts.push_back("fruitL18.CRF");
+		fonts.push_back("fruitL9.CRF");
+		fonts.push_back("garamB18.CRF");
+		fonts.push_back("garamB20.CRF");
+		fonts.push_back("garamB22.CRF");
+		fonts.push_back("geneva10.CRF");
+		fonts.push_back("geneva12.CRF");
+		fonts.push_back("geneva13.CRF");
+		fonts.push_back("geneva14.CRF");
+		fonts.push_back("geneva15.CRF");
+		fonts.push_back("geneva9.CRF");
+		fonts.push_back("helvet11.CRF");
+		fonts.push_back("helvet12.CRF");
+		fonts.push_back("helvet13.CRF");
+		fonts.push_back("helvet14.CRF");
+		fonts.push_back("helvet16.CRF");
+		fonts.push_back("helvet24.CRF");
+		fonts.push_back("helvet9.CRF");
+	} else {
+		fonts.push_back("font01.CRF");
+		fonts.push_back("font02.CRF");
+		fonts.push_back("font03.CRF");
+		fonts.push_back("font04.CRF");
+		fonts.push_back("font05.CRF");
+		fonts.push_back("font06.CRF");
+		fonts.push_back("font07.CRF");
+		fonts.push_back("font08.CRF");
+		fonts.push_back("font09.CRF");
+		fonts.push_back("font10.CRF");
+		fonts.push_back("font11.CRF");
+	}
 
 	_fontManager.loadFonts(fonts);
 }


Commit: f50d89841d324c66a0ba01d41564b54921ea1840
    https://github.com/scummvm/scummvm/commit/f50d89841d324c66a0ba01d41564b54921ea1840
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix fonts for MacOS version

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index c3b0482..912425a 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -222,47 +222,49 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 void CryOmni3DEngine_Versailles::setupFonts() {
 	Common::Array<Common::String> fonts;
 
+	// Explainations below are based on original binaries, debug is not used in this engine
 	if (getPlatform() == Common::kPlatformMacintosh) {
-		// TODO: Disassemble MacOS executable to find which 11 fonts are used
-		fonts.push_back("MPW12.CRF");
-		fonts.push_back("MPW9.CRF");
-		fonts.push_back("arial11.CRF");
-		fonts.push_back("fruitL10.CRF");
-		fonts.push_back("fruitL11.CRF");
-		fonts.push_back("fruitL12.CRF");
-		fonts.push_back("fruitL13.CRF");
-		fonts.push_back("fruitL14.CRF");
-		fonts.push_back("fruitL16.CRF");
-		fonts.push_back("fruitL18.CRF");
-		fonts.push_back("fruitL9.CRF");
-		fonts.push_back("garamB18.CRF");
-		fonts.push_back("garamB20.CRF");
-		fonts.push_back("garamB22.CRF");
-		fonts.push_back("geneva10.CRF");
-		fonts.push_back("geneva12.CRF");
-		fonts.push_back("geneva13.CRF");
-		fonts.push_back("geneva14.CRF");
-		fonts.push_back("geneva15.CRF");
-		fonts.push_back("geneva9.CRF");
-		fonts.push_back("helvet11.CRF");
-		fonts.push_back("helvet12.CRF");
-		fonts.push_back("helvet13.CRF");
-		fonts.push_back("helvet14.CRF");
-		fonts.push_back("helvet16.CRF");
-		fonts.push_back("helvet24.CRF");
-		fonts.push_back("helvet9.CRF");
+		fonts.push_back("garamB18.CRF"); // 0: Doc titles
+		fonts.push_back("garamB22.CRF"); // 1: Menu and T0 in credits
+		//fonts.push_back("geneva15.CRF");
+		fonts.push_back("geneva14.CRF"); // 3: T1 and T3 in credits
+		fonts.push_back("geneva13.CRF"); // 4: Menu title, options messages boxes buttons
+		fonts.push_back("geneva12.CRF"); // 5: T2 in credits, text in docs
+		fonts.push_back("geneva10.CRF"); // 6: objects description in toolbar, options messages boxes text, T4 in credits
+		fonts.push_back("geneva9.CRF");  // 7: T5 in credits, doc subtitle
+		//fonts.push_back("helvet24.CRF");
+		fonts.push_back("helvet16.CRF"); // 9: dialogs texts
+		//fonts.push_back("helvet14.CRF");
+		//fonts.push_back("helvet13.CRF");
+		//fonts.push_back("helvet12.CRF");
+		//fonts.push_back("helvet11.CRF");
+		//fonts.push_back("helvet9.CRF");
+		//fonts.push_back("fruitL9.CRF");
+		fonts.push_back("fruitL10.CRF"); // 16: debug doc
+		//fonts.push_back("fruitL11.CRF");
+		//fonts.push_back("fruitL12.CRF");
+		//fonts.push_back("fruitL13.CRF");
+		//fonts.push_back("fruitL14.CRF");
+		//fonts.push_back("fruitL16.CRF");
+		fonts.push_back("fruitL18.CRF"); // 22: Warp messages texts
+		//fonts.push_back("arial11.CRF");
+		fonts.push_back("MPW12.CRF");    // 24: debug
+		//fonts.push_back("MPW9.CRF");
+
+		// This file isn't even loaded by MacOS executable
+		//fonts.push_back("garamB20.CRF");
 	} else {
-		fonts.push_back("font01.CRF");
-		fonts.push_back("font02.CRF");
-		fonts.push_back("font03.CRF");
-		fonts.push_back("font04.CRF");
-		fonts.push_back("font05.CRF");
-		fonts.push_back("font06.CRF");
-		fonts.push_back("font07.CRF");
-		fonts.push_back("font08.CRF");
-		fonts.push_back("font09.CRF");
-		fonts.push_back("font10.CRF");
-		fonts.push_back("font11.CRF");
+		fonts.push_back("font01.CRF"); // 0: Doc titles
+		fonts.push_back("font02.CRF"); // 1: Menu and T0 in credits
+		fonts.push_back("font03.CRF"); // 2: T1 and T3 in credits
+		fonts.push_back("font04.CRF"); // 3: Menu title, options messages boxes buttons
+		fonts.push_back("font05.CRF"); // 4: T2 in credits, text in docs
+		fonts.push_back("font06.CRF"); // 5: objects description in toolbar, options messages boxes text, T4 in credits
+		fonts.push_back("font07.CRF"); // 6: T5 in credits, doc subtitle
+		fonts.push_back("font08.CRF"); // 7: dialogs texts
+		fonts.push_back("font09.CRF"); // 8: unused
+		fonts.push_back("font10.CRF"); // 9: Warp messages texts
+		fonts.push_back("font11.CRF"); // 10: debug
 	}
 
 	_fontManager.loadFonts(fonts);


Commit: 92a306e56ea52e8601f71ce966e7851ae80f5157
    https://github.com/scummvm/scummvm/commit/92a306e56ea52e8601f71ce966e7851ae80f5157
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove long delayMillis as they lower the framerate

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 49347a2..e663e5d 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -366,8 +366,11 @@ void CryOmni3DEngine::fadeOutPalette() {
 			palOut[i] = palWork[i] >> 8;
 		}
 		setPalette(palOut, 0, 256);
-		g_system->updateScreen();
-		g_system->delayMillis(50);
+		// Wait 50ms between each steps but refresh screen every 10ms
+		for(unsigned int i = 0; i < 5; i++) {
+			g_system->updateScreen();
+			g_system->delayMillis(10);
+		}
 	}
 	setBlackPalette();
 }
@@ -390,8 +393,11 @@ void CryOmni3DEngine::fadeInPalette(const byte *palette) {
 			palOut[i] = palWork[i] >> 8;
 		}
 		setPalette(palOut, 0, 256);
-		g_system->updateScreen();
-		g_system->delayMillis(50);
+		// Wait 50ms between each steps but refresh screen every 10ms
+		for(unsigned int i = 0; i < 5; i++) {
+			g_system->updateScreen();
+			g_system->delayMillis(10);
+		}
 	}
 	setPalette(palette, 0, 256);
 	g_system->updateScreen();
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 912425a..3192aa6 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1099,6 +1099,9 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 			xDelta >>= -_omni3dSpeed;
 			yDelta >>= -_omni3dSpeed;
 		}
+		// This correction factor is to slow down movements for modern CPUs
+		xDelta /= 5;
+		yDelta /= 5;
 		leftButtonPressed = (getCurrentMouseButton() == 1);
 
 		Common::Point mouseRev = _omni3dMan.mapMouseCoords(mouse);
@@ -1149,9 +1152,6 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 				g_system->updateScreen();
 			}
 		}
-		if (!exit && !leftButtonPressed) {
-			g_system->delayMillis(50);
-		}
 	}
 	g_system->showMouse(false);
 	return actionId;
@@ -1225,15 +1225,17 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 		} else if (deltaAlpha < 0) {
 			deltaAlpha += 2.*M_PI;
 		}
+
+		// We devide by 5 to slow down movement for modern CPUs
 		int deltaAlphaI;
 		if (deltaAlpha < M_PI) {
-			deltaAlphaI = -(deltaAlpha * 512.);
+			deltaAlphaI = -(deltaAlpha * 512. / 5.);
 		} else {
-			deltaAlphaI = (2.*M_PI - deltaAlpha) * 512.;
+			deltaAlphaI = (2.*M_PI - deltaAlpha) * 512. / 5.;
 		}
 
 		double deltaBeta = -srcBeta - _omni3dMan.getBeta();
-		int deltaBetaI = -(deltaBeta * 512.);
+		int deltaBetaI = -(deltaBeta * 512. / 5.);
 
 		if (_omni3dSpeed > 0) {
 			deltaAlphaI <<= 2;
@@ -1259,10 +1261,6 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 		if (pollEvents() && checkKeysPressed(2, Common::KEYCODE_ESCAPE, Common::KEYCODE_SPACE)) {
 			exit = true;
 		}
-
-		if (!exit) {
-			g_system->delayMillis(50);
-		}
 	}
 }
 


Commit: 769f8d46ef3c58847969cf772e38c98a062b7267
    https://github.com/scummvm/scummvm/commit/769f8d46ef3c58847969cf772e38c98a062b7267
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix cursor not shown in some events

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 3192aa6..235a923 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1286,7 +1286,7 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 		return;
 	}
 
-	g_system->showMouse(true);
+	bool cursorWasVisible = g_system->showMouse(true);
 
 	for (unsigned int i = 4; i > 0; i--) {
 		// Wait 100ms
@@ -1307,7 +1307,7 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 		g_system->updateScreen();
 	}
 
-	g_system->showMouse(false);
+	g_system->showMouse(cursorWasVisible);
 }
 
 void CryOmni3DEngine_Versailles::collectObject(unsigned int nameID, const ZonFixedImage *fimg,
@@ -1360,7 +1360,7 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 	setMousePos(Common::Point(320, 240)); // Center of screen
 	setCursor(181);
 
-	g_system->showMouse(true);
+	bool cursorWasVisible = g_system->showMouse(true);
 
 	bool exitImg = false;
 	while (!g_engine->shouldQuit() && !exitImg) {
@@ -1374,7 +1374,7 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 	waitMouseRelease();
 	clearKeys();
 
-	g_system->showMouse(false);
+	g_system->showMouse(cursorWasVisible);
 	setMousePos(Common::Point(320, 240)); // Center of screen
 }
 


Commit: 01234cd773832548113e4607eaacb6022bfd829b
    https://github.com/scummvm/scummvm/commit/01234cd773832548113e4607eaacb6022bfd829b
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix cursor shown in transitions

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 235a923..d4ddea6 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -541,8 +541,12 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 
 	fillSurface(0);
 
+	// In original game the HNM player just doesn't render the cursor
+	bool cursorWasVisible = g_system->showMouse(false);
+
 	// Videos are like music because if you mute music in game it will mute videos soundtracks
 	playHNM(video, Audio::Mixer::kMusicSoundType);
+
 	clearKeys();
 	if (g_engine->shouldQuit()) {
 		_abortCommand = AbortQuit;
@@ -555,6 +559,9 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 		return;
 	}
 
+	// Display back cursor there once the palette has been zeroed
+	g_system->showMouse(cursorWasVisible);
+
 	fillSurface(0);
 
 	if (level == 7 || level == 8) {


Commit: 84b60b92bdd68077394e35c7b189b4f827b1c607
    https://github.com/scummvm/scummvm/commit/84b60b92bdd68077394e35c7b189b4f827b1c607
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix appending of files extensions

We clear the previous extension and even if there is none, we must
append the new one

Changed paths:
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/versailles/dialogs_manager.cpp


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index fa2b4a2..4522f2a 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -119,8 +119,8 @@ void ZonFixedImage::loadZones(const Common::String &image) {
 	}
 	if (lastDotPos > -1) {
 		fname.erase(lastDotPos);
-		fname += ".zon";
 	}
+	fname += ".zon";
 
 	Common::File zonFile;
 	if (!zonFile.open(fname)) {
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index 4180a65..59bcedd 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -353,8 +353,8 @@ void Versailles_DialogsManager::loadFrame(const Common::String &video) {
 	}
 	if (lastDotPos > -1) {
 		videoFName.erase(lastDotPos);
-		videoFName += ".hnm";
 	}
+	videoFName += ".hnm";
 
 	Video::HNMDecoder *videoDecoder = new Video::HNMDecoder();
 


Commit: 2860d5caacf76897e6ef1c857270e48f0fdc7a4a
    https://github.com/scummvm/scummvm/commit/2860d5caacf76897e6ef1c857270e48f0fdc7a4a
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Apply sound settings at startup

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index d4ddea6..5ea89f4 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -127,6 +127,8 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	initGraphics(640, 480);
 	setMousePos(Common::Point(320, 200));
 
+	syncSoundSettings();
+
 	_isPlaying = false;
 	_isVisiting = false;
 


Commit: 4ceb3e4b079cd9df9fc28267c900e51fdcef5ff0
    https://github.com/scummvm/scummvm/commit/4ceb3e4b079cd9df9fc28267c900e51fdcef5ff0
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Let user type spaces in save names

Changed paths:
    engines/cryomni3d/versailles/menus.cpp


diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index a60726f..da212ea 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -724,7 +724,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 					selectedSaveName.deleteLastChar();
 					textCursorNextState = 0;
 					redraw = true;
-				} else if (key.ascii > 32 && key.ascii < 256 && selectedSaveName.size() < 20) {
+				} else if (key.ascii >= 32 && key.ascii < 256 && selectedSaveName.size() < 20) {
 					selectedSaveName += key.ascii;
 					textCursorNextState = 0;
 					redraw = true;


Commit: 49c90c74a607e755342e4b41729381cd2ea17cc2
    https://github.com/scummvm/scummvm/commit/49c90c74a607e755342e4b41729381cd2ea17cc2
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a function to deselect object

In original Versailles game, there is such a function used to determine if an
object has just been deselected. We don't need it in this engine for now
but who knows that will may come handy.

Changed paths:
    engines/cryomni3d/objects.h
    engines/cryomni3d/versailles/dialogs.cpp


diff --git a/engines/cryomni3d/objects.h b/engines/cryomni3d/objects.h
index 917233c..03e6a5d 100644
--- a/engines/cryomni3d/objects.h
+++ b/engines/cryomni3d/objects.h
@@ -90,6 +90,7 @@ public:
 
 	Object *selectedObject() const { return _selectedObject; }
 	void setSelectedObject(Object *obj) { _selectedObject = obj; }
+	void deselectObject() { _selectedObject = nullptr; }
 
 private:
 	Object *_selectedObject;
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index ff5a9ff..f2d4253 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -153,7 +153,7 @@ void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequenc
 			_inventory.removeByNameId(125);
 			_gameVariables[GameVariables::kStatePamphletReligion] = 3;
 			collectObject(125);
-			_inventory.setSelectedObject(nullptr);
+			_inventory.deselectObject();
 		}
 	}
 }
@@ -231,14 +231,14 @@ void CryOmni3DEngine_Versailles::dialogShowBontempsShowThird() {
 
 void CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet() {
 	collectObject(101);
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 }
 
 void CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts() {
 	_inventory.removeByNameId(105);
 	collectObject(106);
 	_gameVariables[GameVariables::kEsquissePainted] = 2;
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 	setGameTime(3, 2);
 	_dialogsMan["MONSEIGNEUR-ATTEND-ESQUISSES"] = 'N';
 }
@@ -270,7 +270,7 @@ void CryOmni3DEngine_Versailles::dialogShowCroissyLeave() {
 
 void CryOmni3DEngine_Versailles::dialogShowMaintenonGives() {
 	collectObject(125);
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 }
 
 void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesBack() {
@@ -287,13 +287,13 @@ void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesPamphlet() {
 
 void CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey() {
 	collectObject(140);
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 }
 
 void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
 	playInGameVideo("62S_DUC1");
 	_inventory.removeByNameId(144);
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 	setPlaceState(19, 1);
 }
 
@@ -306,7 +306,7 @@ void CryOmni3DEngine_Versailles::dialogShowEndOfGame() {
 
 void CryOmni3DEngine_Versailles::dialogShowLeBrunGives() {
 	collectObject(107);
-	_inventory.setSelectedObject(nullptr);
+	_inventory.deselectObject();
 }
 
 void CryOmni3DEngine_Versailles::dialogShowLeBrunLeave() {


Commit: cd9aefc425d723803135abe2dd41b542033f6e0e
    https://github.com/scummvm/scummvm/commit/cd9aefc425d723803135abe2dd41b542033f6e0e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a function to disable a zone in fixed images

Changed paths:
    engines/cryomni3d/fixed_image.h


diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 7e3d266..b462315 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -74,6 +74,7 @@ public:
 	const Graphics::Surface *surface() const { return _imageSurface; }
 	void changeCallback(CallbackFunctor *callback) { delete _callback; _callback = callback; }
 	Common::Point getZoneCenter(unsigned int zoneId) const;
+	void disableZone(unsigned int zoneId) { _zones[zoneId].valid = false; }
 
 	ZonesMode _zonesMode;
 


Commit: f4d274c41e560a85152e98f74400892a017b71fc
    https://github.com/scummvm/scummvm/commit/f4d274c41e560a85152e98f74400892a017b71fc
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add missing actions masks

Changed paths:
    engines/cryomni3d/versailles/data.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 7439f4d..be1a20c 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -803,7 +803,7 @@ void CryOmni3DEngine_Versailles::setupLevelActionsMask() {
 		SET_MASK(9, 2, 52903, 0);
 		SET_MASK(9, 2, 22903, 0);
 		SET_MASK(9, 2, 52902, 0);
-		SET_MASK(9, 2, 22902, 1);
+		SET_MASK(9, 2, 22902, 0);
 	} else if (_currentLevel == 3) {
 		SET_MASK(13, 0, 13131, 0);
 		SET_MASK(13, 0, 23131, 0);
@@ -831,12 +831,95 @@ void CryOmni3DEngine_Versailles::setupLevelActionsMask() {
 		SET_MASK(22, 2, 23220, 0);
 		SET_MASK(22, 2, 33220, 0);
 	} else if (_currentLevel == 4) {
-		// TODO: finish the boring job
-		error("TODO:");
+		// 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) {
-		error("TODO:");
+		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) {
-		error("TODO:");
+		//  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);


Commit: 9e31e4dfb910c2ef8c73d6b3b040118b53ed88fb
    https://github.com/scummvm/scummvm/commit/9e31e4dfb910c2ef8c73d6b3b040118b53ed88fb
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Mark clearly missing parts for next levels

Changed paths:
    engines/cryomni3d/versailles/data.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index be1a20c..688a22b 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -536,6 +536,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(1, 14), nullptr);
 	} else if (_currentLevel == 2) {
 		_placeStates.resize(15);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS22");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS20");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS19");
@@ -552,6 +553,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(14, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 3) {
 		_placeStates.resize(25);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
@@ -578,6 +580,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
 	} else if (_currentLevel == 4) {
 		_placeStates.resize(18);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
@@ -597,6 +600,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 5) {
 		_placeStates.resize(35);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS36");
@@ -633,6 +637,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(34, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 6) {
 		_placeStates.resize(45);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS34");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS32");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS32");
@@ -679,6 +684,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(44, nullptr, nullptr, "VS33");
 	} else if (_currentLevel == 7) {
 		_placeStates.resize(30);
+		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(2, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(3, nullptr, nullptr, nullptr);


Commit: 28702028a23f5d8063dee788931f6e696b0528eb
    https://github.com/scummvm/scummvm/commit/28702028a23f5d8063dee788931f6e696b0528eb
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a function to not look for end of conversations

Changed paths:
    engines/cryomni3d/dialogs_manager.h


diff --git a/engines/cryomni3d/dialogs_manager.h b/engines/cryomni3d/dialogs_manager.h
index ce84dcd..da1ccdb 100644
--- a/engines/cryomni3d/dialogs_manager.h
+++ b/engines/cryomni3d/dialogs_manager.h
@@ -61,6 +61,7 @@ public:
 
 	void registerSubtitlesSettings(const Common::String &videoName, const SubtitlesSettings &settings);
 
+	void setIgnoreNoEndOfConversation(bool ignore) { _ignoreNoEndOfConversation = ignore; }
 	bool play(const Common::String &sequence, bool &slowStop);
 
 protected:


Commit: d655fb5530e2a6ffc23d3a8c3d6009e02eec8fcc
    https://github.com/scummvm/scummvm/commit/d655fb5530e2a6ffc23d3a8c3d6009e02eec8fcc
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add function to change sprite color

Changed paths:
    engines/cryomni3d/sprites.cpp
    engines/cryomni3d/sprites.h


diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
index b1c5f95..df09afb 100644
--- a/engines/cryomni3d/sprites.cpp
+++ b/engines/cryomni3d/sprites.cpp
@@ -146,6 +146,18 @@ void Sprites::replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId)
 	_cursors[oldSpriteId]->refCnt++;
 }
 
+void Sprites::replaceSpriteColor(unsigned int spriteId, byte currentColor, byte newColor) {
+	MAP_ID(spriteId);
+
+	byte *data = _cursors[spriteId]->_data;
+	unsigned int size = _cursors[spriteId]->_width * _cursors[spriteId]->_height;
+	for (; size > 0; size--, data++) {
+		if (*data == currentColor) {
+			*data = newColor;
+		}
+	}
+}
+
 unsigned int Sprites::getSpritesCount() const {
 	if (_map) {
 		return _map->size();
diff --git a/engines/cryomni3d/sprites.h b/engines/cryomni3d/sprites.h
index 5721ea8..bd4a867 100644
--- a/engines/cryomni3d/sprites.h
+++ b/engines/cryomni3d/sprites.h
@@ -52,6 +52,8 @@ public:
 
 	unsigned int getSpritesCount() const;
 
+	void replaceSpriteColor(unsigned int spriteId, byte currentColor, byte newColor);
+
 	const Graphics::Surface &getSurface(unsigned int spriteId) const;
 	const Graphics::Cursor &getCursor(unsigned int spriteId) const;
 


Commit: 812d75e4e46b497f9a8b5a4b201a3325e4f3fabf
    https://github.com/scummvm/scummvm/commit/812d75e4e46b497f9a8b5a4b201a3325e4f3fabf
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Make objects functions names more consistent

Changed paths:
    engines/cryomni3d/objects.cpp
    engines/cryomni3d/objects.h
    engines/cryomni3d/versailles/dialogs.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
index 5963a1d..1c06eb1 100644
--- a/engines/cryomni3d/objects.cpp
+++ b/engines/cryomni3d/objects.cpp
@@ -66,9 +66,9 @@ void Inventory::remove(unsigned int position) {
 	(*_changeCallback)(-1u);
 }
 
-void Inventory::removeByCursorId(unsigned int cursorId) {
+void Inventory::removeByIconID(unsigned int iconID) {
 	for (iterator it = begin(); it != end(); it++) {
-		if ((*it) && (*it)->idCA() == cursorId) {
+		if ((*it) && (*it)->idCA() == iconID) {
 			remove(it - begin());
 			return;
 		}
@@ -76,9 +76,9 @@ void Inventory::removeByCursorId(unsigned int cursorId) {
 	// Don't bail out
 }
 
-void Inventory::removeByNameId(unsigned int nameId) {
+void Inventory::removeByNameID(unsigned int nameID) {
 	for (iterator it = begin(); it != end(); it++) {
-		if ((*it) && (*it)->idOBJ() == nameId) {
+		if ((*it) && (*it)->idOBJ() == nameID) {
 			remove(it - begin());
 			return;
 		}
@@ -86,18 +86,18 @@ void Inventory::removeByNameId(unsigned int nameId) {
 	// Don't bail out
 }
 
-bool Inventory::inInventoryByCursorId(unsigned int cursorId) const {
+bool Inventory::inInventoryByIconID(unsigned int iconID) const {
 	for (const_iterator it = begin(); it != end(); it++) {
-		if ((*it) && (*it)->idCA() == cursorId) {
+		if ((*it) && (*it)->idCA() == iconID) {
 			return true;
 		}
 	}
 	return false;
 }
 
-bool Inventory::inInventoryByNameId(unsigned int nameId) const {
+bool Inventory::inInventoryByNameID(unsigned int nameID) const {
 	for (const_iterator it = begin(); it != end(); it++) {
-		if ((*it) && (*it)->idOBJ() == nameId) {
+		if ((*it) && (*it)->idOBJ() == nameID) {
 			return true;
 		}
 	}
diff --git a/engines/cryomni3d/objects.h b/engines/cryomni3d/objects.h
index 03e6a5d..c34f30d 100644
--- a/engines/cryomni3d/objects.h
+++ b/engines/cryomni3d/objects.h
@@ -83,10 +83,10 @@ public:
 	void clear();
 	void add(Object *);
 	void remove(unsigned int position);
-	void removeByCursorId(unsigned int cursorId);
-	void removeByNameId(unsigned int nameId);
-	bool inInventoryByCursorId(unsigned int cursorId) const;
-	bool inInventoryByNameId(unsigned int nameId) const;
+	void removeByNameID(unsigned int nameID);
+	void removeByIconID(unsigned int iconID);
+	bool inInventoryByNameID(unsigned int nameID) const;
+	bool inInventoryByIconID(unsigned int iconID) const;
 
 	Object *selectedObject() const { return _selectedObject; }
 	void setSelectedObject(Object *obj) { _selectedObject = obj; }
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index f2d4253..a415101 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -26,10 +26,10 @@ namespace CryOmni3D {
 namespace Versailles {
 
 bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence) {
-	if (_inventory.inInventoryByNameId(96) && _inventory.inInventoryByNameId(98)) {
+	if (_inventory.inInventoryByNameID(96) && _inventory.inInventoryByNameID(98)) {
 		_dialogsMan["{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}"] = 'Y';
 	}
-	if (_inventory.inInventoryByNameId(126)) {
+	if (_inventory.inInventoryByNameID(126)) {
 		_dialogsMan["{JOUEUR_POSSEDE_EPIGRAPHE}"] = 'Y';
 	}
 
@@ -39,14 +39,14 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 
 	_dialogsMan["{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}"] = 'N';
 	if (_currentLevel == 5 && _gameVariables[GameVariables::kSeenMemorandum] &&
-	        !_inventory.inInventoryByNameId(140)) {
+	        !_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))) {
+	        (!_inventory.inInventoryByNameID(96) || !_inventory.inInventoryByNameID(98))) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -54,7 +54,7 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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))) {
+	        (!_inventory.inInventoryByNameID(101) || !_inventory.inInventoryByNameID(103))) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -62,8 +62,8 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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::kGotMedaillesSolution] == 0)) {
+	        (!_inventory.inInventoryByNameID(121) || !_inventory.inInventoryByNameID(119) ||
+	         !_inventory.inInventoryByNameID(115) || _gameVariables[GameVariables::kGotMedaillesSolution] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -71,7 +71,7 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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::kUsedPlanVauban1] == 0 ||
+	        (!_inventory.inInventoryByNameID(127) || _gameVariables[GameVariables::kUsedPlanVauban1] == 0 ||
 	         _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
@@ -80,7 +80,7 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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::kUsedPlanVauban1] == 0 ||
+	        (!_inventory.inInventoryByNameID(127) || _gameVariables[GameVariables::kUsedPlanVauban1] == 0 ||
 	         _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
@@ -150,7 +150,7 @@ void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequenc
 		if (sequence == "52A4_LAC" && _gameVariables[GameVariables::kStatePamphletReligion] != 3 &&
 		        _dialogsMan["LACHAIZE-DIT-REFORME"] == 'Y' && _dialogsMan["LACHAIZE-DIT-DRAGONNADES"] == 'Y' &&
 		        _dialogsMan["LACHAIZE-TROUVE-ECROUELLES"] == 'Y') {
-			_inventory.removeByNameId(125);
+			_inventory.removeByNameID(125);
 			_gameVariables[GameVariables::kStatePamphletReligion] = 3;
 			collectObject(125);
 			_inventory.deselectObject();
@@ -235,9 +235,9 @@ void CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet() {
 }
 
 void CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts() {
-	_inventory.removeByNameId(105);
+	_inventory.removeByNameID(105);
 	collectObject(106);
-	_gameVariables[GameVariables::kEsquissePainted] = 2;
+	_gameVariables[GameVariables::kSketchState] = 2; // Sketches sorted
 	_inventory.deselectObject();
 	setGameTime(3, 2);
 	_dialogsMan["MONSEIGNEUR-ATTEND-ESQUISSES"] = 'N';
@@ -292,7 +292,7 @@ void CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey() {
 
 void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
 	playInGameVideo("62S_DUC1");
-	_inventory.removeByNameId(144);
+	_inventory.removeByNameID(144);
 	_inventory.deselectObject();
 	setPlaceState(19, 1);
 }
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 5ea89f4..bb01825 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -502,25 +502,25 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 		break;
 	case 2:
 		video = "a3_vf.hns";
-		_inventory.removeByNameId(96);
-		_inventory.removeByNameId(104);
+		_inventory.removeByNameID(96);
+		_inventory.removeByNameID(104);
 		break;
 	case 3:
 		video = "a4_vf.hns";
 		break;
 	case 4:
 		video = "a5_vf.hns";
-		_inventory.removeByNameId(101);
-		_inventory.removeByNameId(127);
-		_inventory.removeByNameId(129);
-		_inventory.removeByNameId(130);
-		_inventory.removeByNameId(131);
-		_inventory.removeByNameId(132);
-		_inventory.removeByNameId(126);
+		_inventory.removeByNameID(101);
+		_inventory.removeByNameID(127);
+		_inventory.removeByNameID(129);
+		_inventory.removeByNameID(130);
+		_inventory.removeByNameID(131);
+		_inventory.removeByNameID(132);
+		_inventory.removeByNameID(126);
 		break;
 	case 5:
 		video = "a6_vf.hns";
-		_inventory.removeByNameId(115);
+		_inventory.removeByNameID(115);
 		break;
 	case 6:
 		video = "a7_vf.hns";
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 1144318..5ebb514 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -360,7 +360,7 @@ IMG_CB(31142b) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (_gameVariables[GameVariables::kCollectScissors] || _inventory.inInventoryByNameId(94)) {
+			if (_gameVariables[GameVariables::kCollectScissors] || _inventory.inInventoryByNameID(94)) {
 				// Empty drawer
 				ZonFixedImage::CallbackFunctor *functor =
 				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
@@ -388,7 +388,7 @@ IMG_CB(31142c) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (!_inventory.inInventoryByNameId(94) && !_gameVariables[GameVariables::kCollectScissors]) {
+			if (!_inventory.inInventoryByNameID(94) && !_gameVariables[GameVariables::kCollectScissors]) {
 				collectObject(94, fimg);
 			}
 			_gameVariables[GameVariables::kCollectScissors] = 1;
@@ -446,7 +446,7 @@ IMG_CB(31143b) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (_inventory.inInventoryByNameId(96)) {
+			if (_inventory.inInventoryByNameID(96)) {
 				// Empty drawer
 				ZonFixedImage::CallbackFunctor *functor =
 				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
@@ -474,7 +474,7 @@ IMG_CB(31143c) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (!_inventory.inInventoryByNameId(96)) {
+			if (!_inventory.inInventoryByNameID(96)) {
 				collectObject(96, fimg);
 			}
 			// Display empty drawer
@@ -516,7 +516,7 @@ IMG_CB(41202) {
 		}
 		HANDLE_QUESTION(1);
 		if (fimg->_zoneUse) {
-			if (fimg->_currentZone == 2 && !_inventory.inInventoryByNameId(97)) {
+			if (fimg->_currentZone == 2 && !_inventory.inInventoryByNameID(97)) {
 				// Open the jar
 				ZonFixedImage::CallbackFunctor *functor =
 				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
@@ -549,7 +549,7 @@ IMG_CB(41202b) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (!_inventory.inInventoryByNameId(97)) {
+			if (!_inventory.inInventoryByNameID(97)) {
 				collectObject(97, fimg);
 			}
 			// Go back to jars closed
@@ -584,7 +584,7 @@ IMG_CB(41801) {
 				}
 			} else if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 94) {
 				_gameVariables[GameVariables::kUsedScissors] = 1;
-				_inventory.removeByNameId(94);
+				_inventory.removeByNameID(94);
 				open = true;
 			}
 			if (open) {
@@ -633,7 +633,7 @@ IMG_CB(41801b) {
 			break;
 		}
 		if (fimg->_zoneUse) {
-			if (!_inventory.inInventoryByNameId(100)) {
+			if (!_inventory.inInventoryByNameID(100)) {
 				collectObject(100, fimg);
 			}
 			_gameVariables[GameVariables::kCollectedPaperInTrunk] = 1;
@@ -736,7 +736,7 @@ IMG_CB(41802) {
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
 				}
-				_inventory.removeByNameId(100);
+				_inventory.removeByNameID(100);
 				// Revealed paper
 				collectObject(98, fimg);
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
@@ -783,7 +783,7 @@ IMG_CB(41802b) {
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
 				}
-				_inventory.removeByNameId(100);
+				_inventory.removeByNameID(100);
 				// Revealed paper
 				collectObject(98, fimg);
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
@@ -828,7 +828,7 @@ IMG_CB(41802c) {
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
 				}
-				_inventory.removeByNameId(100);
+				_inventory.removeByNameID(100);
 				// Revealed paper
 				collectObject(98, fimg);
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
@@ -863,7 +863,7 @@ IMG_CB(41802d) {
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
 				}
-				_inventory.removeByNameId(100);
+				_inventory.removeByNameID(100);
 				// Revealed paper
 				collectObject(98, fimg);
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;


Commit: 6e692195c8b305fac026c139e8b0d199755a0656
    https://github.com/scummvm/scummvm/commit/6e692195c8b305fac026c139e8b0d199755a0656
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Let change individual color in main palette

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index bb01825..b9795c2 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -339,6 +339,13 @@ void CryOmni3DEngine_Versailles::setupPalette(const byte *palette, uint start, u
 	}
 }
 
+void CryOmni3DEngine_Versailles::setMainPaletteColor(byte color, byte red, byte green, byte blue) {
+	_mainPalette[3 * color + 0] = red;
+	_mainPalette[3 * color + 1] = green;
+	_mainPalette[3 * color + 2] = blue;
+	setPalette(_mainPalette, 0, 256);
+}
+
 struct transparentScore {
 	unsigned int score;
 	byte redScaled;
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 34f2c6c..e38e57c 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -311,6 +311,7 @@ private:
 	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;


Commit: 0619120f3a71a9db513b3bc277b1ca291b0de764
    https://github.com/scummvm/scummvm/commit/0619120f3a71a9db513b3bc277b1ca291b0de764
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a function to collect an Object *

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index b9795c2..cdb3f63 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1326,9 +1326,8 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 	g_system->showMouse(cursorWasVisible);
 }
 
-void CryOmni3DEngine_Versailles::collectObject(unsigned int nameID, const ZonFixedImage *fimg,
+void CryOmni3DEngine_Versailles::collectObject(Object *obj, const ZonFixedImage *fimg,
         bool showObject) {
-	Object *obj = _objects.findObjectByNameID(nameID);
 	_inventory.add(obj);
 	Object::ViewCallback cb = obj->viewCallback();
 	if (showObject && cb) {
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index e38e57c..efc9941 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -306,8 +306,10 @@ private:
 	bool loadGame(bool visit, unsigned int saveNum);
 
 	void animateCursor(const Object *object);
-	void collectObject(unsigned int nameID, const ZonFixedImage *fimg = nullptr,
+	void collectObject(Object *object, const ZonFixedImage *fimg = nullptr,
 	                   bool showObject = true);
+	void collectObject(unsigned int 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);
 


Commit: 3a12d53ffc72fd99cdfbb9627bb699236d32f235
    https://github.com/scummvm/scummvm/commit/3a12d53ffc72fd99cdfbb9627bb699236d32f235
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement level 2

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 688a22b..56c7fda 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -537,20 +537,20 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 	} else if (_currentLevel == 2) {
 		_placeStates.resize(15);
 		// TODO: implement functions
-		SET_PLACE_STATE(1, nullptr, nullptr, "VS22");
-		SET_PLACE_STATE(2, nullptr, nullptr, "VS20");
+		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, nullptr, nullptr);
+		SET_PLACE_STATE(5, nullptr, FILTER_EVENT(2, 5), nullptr);
 		SET_PLACE_STATE(6, nullptr, nullptr, "VS19");
 		SET_PLACE_STATE(7, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(9, nullptr, nullptr, "VS23");
+		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, nullptr, "VS31");
-		SET_PLACE_STATE(12, nullptr, nullptr, "VS24");
+		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, nullptr, nullptr);
+		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(2, 14), nullptr);
 	} else if (_currentLevel == 3) {
 		_placeStates.resize(25);
 		// TODO: implement functions
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index cdb3f63..398bf3c 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -594,8 +594,9 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		// TODO: countdown
 		_inventory.clear();
+	} else if (_currentLevel <= 2) {
+		// TODO: remove this when we implemented all levels
 	} else {
-		// TODO: to implement
 		error("New level %d is not implemented (yet)", level);
 	}
 
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index efc9941..74d8c96 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -122,10 +122,10 @@ struct GameVariables {
 		kCollectePartition,
 		kCollectPamphletArchi,
 		kGotRevealedPaper, // OK
-		kCollectCle,                   // 10
-		kCollectCartonDessin,
-		kEsquissePainted,
-		kStateFauxCroquis,
+		kCollectKey, // OK             // 10
+		kCollectPortfolio, // OK
+		kSketchState, // OK
+		kFakeSketchChatState, // OK
 		kCollectNourriture,
 		kCollectPlume,
 		kStatePamphletReligion,
@@ -146,7 +146,7 @@ struct GameVariables {
 		kCoffreUnlocked,
 		//kUselessVar,
 		kCollectedPaperInTrunk = 33, // OK
-		kUsingPinceauColor,
+		kBrushColor, // OK
 		kUsedScissors, // OK
 		kUsedClefsCombles,
 		kHasPlayedLebrun, // OK
@@ -398,6 +398,8 @@ private:
 	template<unsigned int 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);
@@ -406,6 +408,14 @@ private:
 	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(41202);
 	IMG_CB(41202b);
 	IMG_CB(41801);
@@ -425,6 +435,15 @@ private:
 	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);
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 5ebb514..e87bc60 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -335,6 +335,50 @@ void CryOmni3DEngine_Versailles::genericPainting(ZonFixedImage *fimg) {
 // Specific fixed images callbacks
 #define IMG_CB(name) void CryOmni3DEngine_Versailles::img_ ## name(ZonFixedImage *fimg)
 
+IMG_CB(31101) {
+	fimg->load("21F_11.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				// Collect key and change image
+				collectObject(104, fimg);
+				_gameVariables[GameVariables::kCollectKey] = 1;
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_31101b);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1 && !_inventory.inInventoryByNameID(103)) {
+				collectObject(103, fimg);
+			}
+		}
+	}
+}
+
+IMG_CB(31101b) {
+	fimg->load("21F_10.GIF");
+	if (_inventory.inInventoryByNameID(103)) {
+		fimg->disableZone(1);
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse && !_inventory.inInventoryByNameID(103)) {
+			collectObject(103, fimg);
+			// Original game resets callback with this one, this is useless
+			break;
+		}
+	}
+}
+
 IMG_CB(31142) {
 	fimg->load("10D2_4.GIF");
 	while (1) {
@@ -506,6 +550,140 @@ IMG_CB(31143d) {
 	}
 }
 
+IMG_CB(32120) {
+	if (currentGameTime() != 3) {
+		fimg->_exit = true;
+		return;
+	}
+
+	// Already painted
+	if (_gameVariables[GameVariables::kSketchState] == 3 ||
+	        _gameVariables[GameVariables::kSketchState] == 4) {
+		fimg->_exit = true;
+		return;
+	}
+
+	fimg->load("23I_10.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			_sprites.replaceSpriteColor(59, 254, 244);
+			_sprites.replaceSpriteColor(63, 254, 247);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0 && !_inventory.inInventoryByIconID(38)) {
+				// Pick the brush
+				Object *obj = _objects.findObjectByIconID(38);
+				collectObject(obj, fimg);
+				// collectObject animates the cursor
+				// Make it selected
+				_inventory.setSelectedObject(obj);
+				setCursor(obj->idSA()); // 59 in original game
+				fimg->_zonesMode = ZonFixedImage::kZonesMode_Object;
+			}
+		} else if (fimg->_usedObject && fimg->_usedObject->idCA() == 38) {
+			// Brush used
+			if (fimg->_currentZone == 1) { // on gold paint
+				_inventory.removeByIconID(38);
+				Object *obj = _objects.findObjectByIconID(38);
+				obj->rename(111); // Brush has gold on it
+				setMainPaletteColor(254, 128, 128, 0);
+				_sprites.replaceSpriteColor(59, 244, 254);
+				_sprites.replaceSpriteColor(63, 247, 254);
+				// Collect only there once we set the color on the cursors
+				collectObject(obj, fimg);
+				_inventory.setSelectedObject(obj);
+				setCursor(obj->idSA()); // 59 in original game
+				fimg->_zonesMode = ZonFixedImage::kZonesMode_Object;
+				_gameVariables[GameVariables::kBrushColor] = 1;
+			} else if (fimg->_currentZone == 2) { // on red paint
+				_inventory.removeByIconID(38);
+				Object *obj = _objects.findObjectByIconID(38);
+				obj->rename(112); // Brush has red on it
+				setMainPaletteColor(254, 128, 0, 0);
+				_sprites.replaceSpriteColor(59, 244, 254);
+				_sprites.replaceSpriteColor(63, 247, 254);
+				// Collect only there once we set the color on the cursors
+				collectObject(obj, fimg);
+				_inventory.setSelectedObject(obj);
+				setCursor(obj->idSA()); // 59 in original game
+				fimg->_zonesMode = ZonFixedImage::kZonesMode_Object;
+				_gameVariables[GameVariables::kBrushColor] = 2;
+			} else if (fimg->_currentZone == 3) { // on sketch
+				if (fimg->_usedObject->idOBJ() == 111 &&
+				        _gameVariables[GameVariables::kBrushColor] == 1) {
+					// Gold brush used on sketch
+					_gameVariables[GameVariables::kSketchState] = 3;
+					playInGameVideo("23I_11");
+					// Force reload of the place
+					if (_nextPlaceId == -1u) {
+						_nextPlaceId = _currentPlaceId;
+					}
+					_inventory.removeByIconID(38);
+					ZonFixedImage::CallbackFunctor *functor =
+					    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+					            &CryOmni3DEngine_Versailles::img_32120b);
+					fimg->changeCallback(functor);
+					break;
+				} else if (fimg->_usedObject->idOBJ() == 112 &&
+				           _gameVariables[GameVariables::kBrushColor] == 2) {
+					// Red brush used on sketch
+					_gameVariables[GameVariables::kSketchState] = 4;
+					playInGameVideo("23I_12");
+					// Force reload of the place
+					if (_nextPlaceId == -1u) {
+						_nextPlaceId = _currentPlaceId;
+					}
+					_inventory.removeByIconID(38);
+					ZonFixedImage::CallbackFunctor *functor =
+					    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+					            &CryOmni3DEngine_Versailles::img_32120c);
+					fimg->changeCallback(functor);
+					break;
+				}
+			}
+		}
+	}
+}
+
+IMG_CB(32120b) {
+	fimg->load("23I_11.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneUse) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+	_inventory.removeByNameID(107);
+	collectObject(107, fimg);
+
+	_sprites.replaceSpriteColor(59, 254, 244);
+	_sprites.replaceSpriteColor(63, 254, 247);
+
+	setGameTime(4, 2);
+}
+
+IMG_CB(32120c) {
+	fimg->load("23I_12.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneUse) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+	_inventory.removeByNameID(107);
+	collectObject(109, fimg);
+
+	_sprites.replaceSpriteColor(59, 254, 244);
+	_sprites.replaceSpriteColor(63, 254, 247);
+
+	setGameTime(4, 2);
+}
+
 IMG_CB(41202) {
 	fimg->load("10E_20.GIF");
 	while (1) {
@@ -562,6 +740,85 @@ IMG_CB(41202b) {
 	}
 }
 
+IMG_CB(32201) {
+	fimg->load("21E_41.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		// There is a check of use but only to change sound path
+		// That must be a leftover
+		/*
+		if (fimg->_zoneUse) {
+		}
+		*/
+	}
+}
+
+IMG_CB(32202) {
+	fimg->load("21E_42.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(32203) {
+	fimg->load("21E_43.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		// There is a check of use but only to change sound path
+		// That must be a leftover
+		/*
+		if (fimg->_zoneUse) {
+		}
+		*/
+	}
+}
+
+IMG_CB(32204) {
+	fimg->load("21E_44.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse && !_inventory.inInventoryByNameID(105)) {
+			// Collect portfolio
+			collectObject(105, fimg);
+			_gameVariables[GameVariables::kSketchState] = 1;
+			_gameVariables[GameVariables::kCollectPortfolio] = 1;
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_32204b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(32204b) {
+	fimg->load("21E_45.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
 IMG_CB(41801) {
 	fimg->load("12E2_10.GIF");
 	while (1) {
@@ -1029,6 +1286,320 @@ FILTER_EVENT(1, 14) {
 	return false;
 }
 
+FILTER_EVENT(2, 1) {
+	if (*event == 22101 && _inventory.selectedObject()) {
+		_dialogsMan["{JOUEUR-MONTRE-UN-PAMPHLET}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}"] = 'N';
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 96  || idOBJ == 101 || idOBJ == 115 ||
+		        idOBJ == 125 || idOBJ == 127) {
+			_dialogsMan["{JOUEUR-MONTRE-UN-PAMPHLET}"] = 'Y';
+		} else if (idOBJ == 98) {
+			_dialogsMan["{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+		_dialogsMan.play("21F_BON");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-UN-PAMPHLET}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}"] = 'N';
+
+		if (idOBJ == 98 && _dialogsMan["JOUEUR-CONFIE-MESSAGE-HUISSIER"] == 'Y') {
+			_inventory.removeByNameID(98);
+			_inventory.deselectObject();
+			setGameTime(2, 2);
+		}
+	} else if (*event == 31101) {
+		if (!_inventory.selectedObject() && currentGameTime() > 1) {
+			const char *video;
+			FixedImgCallback callback;
+
+			if (!_gameVariables[GameVariables::kCollectKey]) {
+				video = "21F_11";
+				callback = &CryOmni3DEngine_Versailles::img_31101;
+			} else {
+				video = "21F_10";
+				callback = &CryOmni3DEngine_Versailles::img_31101b;
+			}
+
+			playInGameVideo(video);
+
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			handleFixedImg(callback);
+		}
+		// Don't pass the event as we try to avoid implementing use
+		return false;
+	} else if (*event >= 1 && *event <= 9999 && currentGameTime() == 2) {
+		setPlaceState(1, 1);
+	}
+	return true;
+}
+
+FILTER_EVENT(2, 2) {
+	if (*event < 32201 || *event > 32204) {
+		// Not handled here
+		return true;
+	}
+
+	const char *video = nullptr;
+	FixedImgCallback callback;
+
+	const Object *obj = _inventory.selectedObject();
+	bool deselectObj = false;
+
+	if (*event == 32201) {
+		if (!obj) {
+			// Opening left drawer
+			video = "21E_41";
+			callback = &CryOmni3DEngine_Versailles::img_32201;
+		} else {
+			return false;
+		}
+	} else if (*event == 32202) {
+		if (obj && obj->idOBJ() == 104) {
+			// Using key on left door
+			video = "21E_42";
+			callback = &CryOmni3DEngine_Versailles::img_32202;
+		} else {
+			// This door is locked
+			displayMessageBoxWarp(1);
+			return false;
+		}
+	} else if (*event == 32203) {
+		if (!obj) {
+			// Opening right drawer
+			video = "21E_43";
+			callback = &CryOmni3DEngine_Versailles::img_32203;
+		} else {
+			return false;
+		}
+	} else if (*event == 32204) {
+		if (obj && obj->idOBJ() == 104) {
+			// Using key on right door
+			if (_gameVariables[GameVariables::kCollectPortfolio]) {
+				video = "21E_45";
+				callback = &CryOmni3DEngine_Versailles::img_32204b;
+			} else {
+				video = "21E_44";
+				callback = &CryOmni3DEngine_Versailles::img_32204;
+			}
+			deselectObj = true;
+		} else {
+			// This door is locked
+			displayMessageBoxWarp(1);
+			return false;
+		}
+	}
+
+	assert(video != nullptr);
+	assert(callback != nullptr);
+
+	// Adjust viewpoint for video
+	unsigned int fakePlaceId = getFakeTransition(*event);
+	fakeTransition(fakePlaceId);
+
+	playInGameVideo(video);
+
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+
+	handleFixedImg(callback);
+
+	if (deselectObj) {
+		_inventory.deselectObject();
+	}
+
+	// Don't pass the event: it has been handled
+	return false;
+}
+
+FILTER_EVENT(2, 5) {
+	if (*event == 22501 && _inventory.selectedObject()) {
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 96) {
+			if (!_inventory.inInventoryByNameID(101)) {
+				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARTS}"] = 'Y';
+			}
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'Y';
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+
+		_dialogsMan.play("21B1_HUI");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARTS}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+
+		_inventory.deselectObject();
+	} else if (*event >= 1 && *event <= 9999 &&
+	           _inventory.inInventoryByNameID(96) && !_inventory.inInventoryByNameID(101)) {
+		// Give your clues at the bailiff
+		displayMessageBoxWarp(15);
+		return false;
+	}
+	return true;
+}
+
+INIT_PLACE(2, 9) {
+	// BUG: This dialog gets played twice when Monseigneur is waiting for the sketches and we speak to him
+	// The bug is in original version too
+	if (_gameVariables[GameVariables::kSketchState] == 1 && currentGameTime() == 2) {
+		// Sketches are not yet sorted
+		_dialogsMan["{JOUEUR-SE-DIRIGE-VERS-MONSEIGNEUR-AVEC-ESQUISSES}"] = 'Y';
+
+		_dialogsMan.play("22G_DAU");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		// Change warp viewpoint
+		_omni3dMan.setAlpha(4.17);
+		_omni3dMan.setBeta(0.097);
+
+		_inventory.deselectObject();
+
+		_dialogsMan["{JOUEUR-SE-DIRIGE-VERS-MONSEIGNEUR-AVEC-ESQUISSES}"] = 'N';
+	}
+}
+
+FILTER_EVENT(2, 9) {
+	if (*event == 22902 && _inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 105) {
+		_dialogsMan["{JOUEUR-DONNE-ESQUISSES}"] = 'Y';
+
+		_dialogsMan.setIgnoreNoEndOfConversation(true);
+		_dialogsMan.play("22G_DAU");
+		_dialogsMan.setIgnoreNoEndOfConversation(false);
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-DONNE-ESQUISSES}"] = 'N';
+
+		_inventory.deselectObject();
+	} else if (*event >= 1 && *event <= 9999 && currentGameTime() == 3 &&
+	           _placeStates[9].state != 2) {
+		setPlaceState(9, 2);
+	}
+	return true;
+}
+
+FILTER_EVENT(2, 11) {
+	if (*event == 22111 && _inventory.selectedObject()) {
+		bool gameOver = false;
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 107) {
+			_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] = 'Y';
+		} else if (idOBJ == 109) {
+			_dialogsMan["{JOUEUR-MONTRE-ESQUISSE-DETRUITE}"] = 'Y';
+			gameOver = true;
+		}
+
+		_dialogsMan.play("24Z_BON");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-ESQUISSE-DETRUITE}"] = 'N';
+
+		_inventory.deselectObject();
+
+		if (gameOver) {
+			doGameOver();
+		}
+	}
+	return true;
+}
+
+FILTER_EVENT(2, 12) {
+	if (*event == 22121 && _inventory.selectedObject()) {
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 105) {
+			_dialogsMan["{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}"] = 'Y';
+			_dialogsMan["{JOUEUR-A-MONTRE-ESQUISSES-NON-TRIEES-LEBRUN}"] = 'Y';
+		} else if (idOBJ == 106) {
+			_dialogsMan["{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}"] = 'Y';
+			_inventory.removeByNameID(106);
+		} else if (idOBJ == 107 && _gameVariables[GameVariables::kSketchState] == 2) {
+			if (_gameVariables[GameVariables::kFakeSketchChatState] == 0) {
+				_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS}"] = 'Y';
+				_gameVariables[GameVariables::kFakeSketchChatState] = 1;
+			} else if (_gameVariables[GameVariables::kFakeSketchChatState] == 1) {
+				_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS2}"] = 'Y';
+				_gameVariables[GameVariables::kFakeSketchChatState] = 2;
+			} else if (_gameVariables[GameVariables::kFakeSketchChatState] == 2) {
+				_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS3}"] = 'Y';
+			}
+		} else if (idOBJ == 96) {
+			_dialogsMan["{JOUEUR-PRESENTE-PAMPHLET-SUR-LEBRUN}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-PRESENTE-TOUT-AUTRE-PAMPHLET-OU-LETTRE}"] = 'Y';
+		}
+
+		_dialogsMan.play("23I_LEB");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-PRESENTE-PAMPHLET-SUR-LEBRUN}"] = 'N';
+		_dialogsMan["{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}"] = 'N';
+		_dialogsMan["{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}"] = 'N';
+		_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS}"] = 'N';
+		_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS2}"] = 'N';
+		_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS3}"] = 'N';
+		_dialogsMan["{JOUEUR-PRESENTE-TOUT-AUTRE-PAMPHLET-OU-LETTRE}"] = 'N';
+
+		_inventory.deselectObject();
+	} else if (*event == 32120) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 107 &&
+		        _gameVariables[GameVariables::kSketchState] == 2) {
+			handleFixedImg(&CryOmni3DEngine_Versailles::img_32120);
+		}
+		// We handle use here
+		return false;
+	}
+	return true;
+}
+
+FILTER_EVENT(2, 14) {
+	return filterEventLevel1Place14(event);
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: c83f86a245dae1ae13c2cc170aa4374cae01230b
    https://github.com/scummvm/scummvm/commit/c83f86a245dae1ae13c2cc170aa4374cae01230b
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix file names for Macintosh version

Add a function to unify extensions handling.
That lets us substitute dashes by underscore on PC versions of
Versailles and fix dashes for Macintosh.

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/cryomni3d.h
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/versailles/dialogs_manager.cpp
    engines/cryomni3d/versailles/documentation.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp
    engines/cryomni3d/versailles/music.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index e663e5d..d1968d0 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -80,11 +80,9 @@ void CryOmni3DEngine::pauseEngineIntern(bool pause) {
 	*/
 }
 
-void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::SoundType soundType) {
-	Common::String fname(filename);
-
-	Video::VideoDecoder *videoDecoder = new Video::HNMDecoder();
-	videoDecoder->setSoundType(soundType);
+Common::String CryOmni3DEngine::prepareFileName(const Common::String &baseName,
+        const char *const *extensions) const {
+	Common::String fname(baseName);
 
 	int lastDotPos = fname.size() - 1;
 	for (; lastDotPos >= 0; --lastDotPos) {
@@ -92,17 +90,36 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 			break;
 		}
 	}
+
+	int extBegin;
 	if (lastDotPos > -1) {
-		fname.erase(lastDotPos);
+		extBegin = lastDotPos + 1;
+		fname.erase(extBegin);
 	} else {
-		lastDotPos = fname.size();
+		fname += ".";
+		extBegin = fname.size();
 	}
-	fname += ".hnm";
 
-	if (!Common::File::exists(fname)) {
-		fname.erase(lastDotPos);
-		fname += ".hns";
+	while (*extensions != nullptr) {
+		fname += *extensions;
+		debug("Trying file %s", fname.c_str());
+		if (Common::File::exists(fname)) {
+			return fname;
+		}
+		fname.erase(extBegin);
+		extensions++;
 	}
+	fname.deleteLastChar();
+	warning("Failed to find file %s/%s", baseName.c_str(), fname.c_str());
+	return baseName;
+}
+
+void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::SoundType soundType) {
+	const char *const extensions[] = { "hns", "hnm", nullptr };
+	Common::String fname(prepareFileName(filename, extensions));
+
+	Video::VideoDecoder *videoDecoder = new Video::HNMDecoder();
+	videoDecoder->setSoundType(soundType);
 
 	if (!videoDecoder->loadFile(fname)) {
 		warning("Failed to open movie file %s/%s", filename.c_str(), fname.c_str());
@@ -143,23 +160,12 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 }
 
 Image::ImageDecoder *CryOmni3DEngine::loadHLZ(const Common::String &filename) {
-	Common::String fname(filename);
+	Common::String fname(prepareFileName(filename, "hlz"));
 
 	Image::ImageDecoder *imageDecoder = new Image::HLZFileDecoder();
 
 	Common::File file;
 
-	int lastDotPos = fname.size() - 1;
-	for (; lastDotPos >= 0; --lastDotPos) {
-		if (fname[lastDotPos] == '.') {
-			break;
-		}
-	}
-	if (lastDotPos > -1) {
-		fname.erase(lastDotPos);
-	}
-	fname += ".hlz";
-
 	if (!file.open(fname)) {
 		warning("Failed to open hlz file %s/%s", filename.c_str(), fname.c_str());
 		return nullptr;
diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index 9d2c4e9..c06df5b 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -124,6 +124,13 @@ public:
 	void setAutoRepeatClick(unsigned int millis);
 	DragStatus getDragStatus() { return _dragStatus; }
 
+	Common::String prepareFileName(const Common::String &baseName, const char *extension) const {
+		const char *const extensions[] = { extension, nullptr };
+		return prepareFileName(baseName, extensions);
+	}
+	virtual Common::String prepareFileName(const Common::String &baseName,
+	                                       const char *const *extensions) const;
+
 	virtual bool displayToolbar(const Graphics::Surface *original) = 0;
 	virtual bool hasPlaceDocumentation() = 0;
 	virtual bool displayPlaceDocumentation() = 0;
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index 4522f2a..0fb9513 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -109,18 +109,7 @@ void ZonFixedImage::display() const {
 void ZonFixedImage::loadZones(const Common::String &image) {
 	_zones.clear();
 
-	Common::String fname(image);
-
-	int lastDotPos = fname.size() - 1;
-	for (; lastDotPos >= 0; --lastDotPos) {
-		if (fname[lastDotPos] == '.') {
-			break;
-		}
-	}
-	if (lastDotPos > -1) {
-		fname.erase(lastDotPos);
-	}
-	fname += ".zon";
+	Common::String fname(_engine.prepareFileName(image, "zon"));
 
 	Common::File zonFile;
 	if (!zonFile.open(fname)) {
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index 59bcedd..3ebc4cf 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -88,16 +88,14 @@ void Versailles_DialogsManager::executeShow(const Common::String &show) {
 
 void Versailles_DialogsManager::playDialog(const Common::String &video, const Common::String &sound,
         const Common::String &text, const SubtitlesSettings &settings) {
-	Common::String videoFName(video);
-	Common::String soundFName(sound);
-
-	videoFName += ".hnm";
 	// Don't look for HNS file here
+	Common::String videoFName(_engine->prepareFileName(video, "hnm"));
+	Common::String soundFName(sound);
 
 	while (soundFName.size() < 8) {
 		soundFName += '_';
 	}
-	soundFName += ".wav";
+	soundFName = _engine->prepareFileName(soundFName, "wav");
 
 	Video::HNMDecoder *videoDecoder = new Video::HNMDecoder(true);
 
@@ -344,17 +342,7 @@ unsigned int Versailles_DialogsManager::askPlayerQuestions(const Common::String
 }
 
 void Versailles_DialogsManager::loadFrame(const Common::String &video) {
-	Common::String videoFName(video);
-	int lastDotPos = videoFName.size() - 1;
-	for (; lastDotPos >= 0; --lastDotPos) {
-		if (videoFName[lastDotPos] == '.') {
-			break;
-		}
-	}
-	if (lastDotPos > -1) {
-		videoFName.erase(lastDotPos);
-	}
-	videoFName += ".hnm";
+	Common::String videoFName(_engine->prepareFileName(video, "hnm"));
 
 	Video::HNMDecoder *videoDecoder = new Video::HNMDecoder();
 
diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
index bbc9242..79c6001 100644
--- a/engines/cryomni3d/versailles/documentation.cpp
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -1442,7 +1442,7 @@ void Versailles_Documentation::drawRecordData(Graphics::ManagedSurface &surface,
 	} else {
 		background = _currentRecord;
 	}
-	background += ".HLZ";
+	background = _engine->prepareFileName(background, "hlz");
 	Common::File backgroundFl;
 	if (!backgroundFl.open(background)) {
 		background = displayMap ? "pas_fonP.hlz" : "pas_fond.hlz";
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 398bf3c..3baaf81 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -221,6 +221,20 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	return Common::kNoError;
 }
 
+Common::String CryOmni3DEngine_Versailles::prepareFileName(const Common::String &baseName,
+        const char *const *extensions) const {
+	Common::String baseName_(baseName);
+	if (getPlatform() != Common::kPlatformMacintosh) {
+		// Replace dashes by underscores for PC versions
+		char *p = baseName_.begin();
+		while ((p = strchr(p, '-')) != nullptr) {
+			*p = '_';
+			p++;
+		}
+	}
+	return CryOmni3DEngine::prepareFileName(baseName_, extensions);
+}
+
 void CryOmni3DEngine_Versailles::setupFonts() {
 	Common::Array<Common::String> fonts;
 
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 74d8c96..cb677cd 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -218,6 +218,13 @@ public:
 	CryOmni3DEngine_Versailles(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
 	virtual ~CryOmni3DEngine_Versailles();
 
+	Common::String prepareFileName(const Common::String &baseName, const char *extension) const {
+		const char *const extensions[] = { extension, nullptr };
+		return prepareFileName(baseName, extensions);
+	}
+	virtual Common::String prepareFileName(const Common::String &baseName,
+	                                       const char *const *extensions) const override;
+
 	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;
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index e87bc60..e824031 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -1000,7 +1000,7 @@ IMG_CB(41802) {
 				setGameTime(3, 1);
 			} else if (objID == 96) {
 				// Pamphlet about arts
-				playInGameVideo("PAP_BRUL");
+				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
@@ -1047,7 +1047,7 @@ IMG_CB(41802b) {
 				setGameTime(3, 1);
 			} else if (objID == 96) {
 				// Pamphlet about arts
-				playInGameVideo("PAP_BRUL");
+				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
@@ -1092,7 +1092,7 @@ IMG_CB(41802c) {
 				setGameTime(3, 1);
 			} else if (objID == 96) {
 				// Pamphlet about arts
-				playInGameVideo("PAP_BRUL");
+				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
@@ -1127,7 +1127,7 @@ IMG_CB(41802d) {
 				setGameTime(3, 1);
 			} else if (objID == 96) {
 				// Pamphlet about arts
-				playInGameVideo("PAP_BRUL");
+				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
 					_nextPlaceId = _currentPlaceId;
diff --git a/engines/cryomni3d/versailles/music.cpp b/engines/cryomni3d/versailles/music.cpp
index 524c524..a19e82a 100644
--- a/engines/cryomni3d/versailles/music.cpp
+++ b/engines/cryomni3d/versailles/music.cpp
@@ -67,8 +67,7 @@ void CryOmni3DEngine_Versailles::musicUpdate() {
 	// New file, stop the old one first
 	musicStop();
 
-	Common::String musicFName = musicBName;
-	musicFName += ".wav";
+	Common::String musicFName(prepareFileName(musicBName, "wav"));
 
 	Common::File *musicFile = new Common::File();
 	if (!musicFile->open(musicFName)) {


Commit: 6d36bc3ccad575d35286eae1cbda985947ba5242
    https://github.com/scummvm/scummvm/commit/6d36bc3ccad575d35286eae1cbda985947ba5242
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix style

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/versailles/dialogs.cpp
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index d1968d0..ae05778 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -373,7 +373,7 @@ void CryOmni3DEngine::fadeOutPalette() {
 		}
 		setPalette(palOut, 0, 256);
 		// Wait 50ms between each steps but refresh screen every 10ms
-		for(unsigned int i = 0; i < 5; i++) {
+		for (unsigned int i = 0; i < 5; i++) {
 			g_system->updateScreen();
 			g_system->delayMillis(10);
 		}
@@ -400,7 +400,7 @@ void CryOmni3DEngine::fadeInPalette(const byte *palette) {
 		}
 		setPalette(palOut, 0, 256);
 		// Wait 50ms between each steps but refresh screen every 10ms
-		for(unsigned int i = 0; i < 5; i++) {
+		for (unsigned int i = 0; i < 5; i++) {
 			g_system->updateScreen();
 			g_system->delayMillis(10);
 		}
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index a415101..b74e2f0 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -63,7 +63,8 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	        sequence.hasPrefix("31O_SUIA") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
 	        _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y' &&
 	        (!_inventory.inInventoryByNameID(121) || !_inventory.inInventoryByNameID(119) ||
-	         !_inventory.inInventoryByNameID(115) || _gameVariables[GameVariables::kGotMedaillesSolution] == 0)) {
+	         !_inventory.inInventoryByNameID(115) ||
+	         _gameVariables[GameVariables::kGotMedaillesSolution] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index cb677cd..189fe9b 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -234,7 +234,6 @@ public:
 	virtual unsigned int displayOptions() override;
 	virtual bool shouldAbort() override { return g_engine->shouldQuit() || _abortCommand != AbortNoAbort; }
 
-
 private:
 	void setupFonts();
 	void setupSprites();


Commit: 9bfc24eee3f724fab4aadad17d6c4664682f7aa3
    https://github.com/scummvm/scummvm/commit/9bfc24eee3f724fab4aadad17d6c4664682f7aa3
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Deselect object when removing from inventory

Changed paths:
    engines/cryomni3d/objects.cpp
    engines/cryomni3d/versailles/dialogs.cpp
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
index 1c06eb1..5d79c5f 100644
--- a/engines/cryomni3d/objects.cpp
+++ b/engines/cryomni3d/objects.cpp
@@ -69,6 +69,7 @@ void Inventory::remove(unsigned int position) {
 void Inventory::removeByIconID(unsigned int iconID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idCA() == iconID) {
+			deselectObject();
 			remove(it - begin());
 			return;
 		}
@@ -79,6 +80,7 @@ void Inventory::removeByIconID(unsigned int iconID) {
 void Inventory::removeByNameID(unsigned int nameID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idOBJ() == nameID) {
+			deselectObject();
 			remove(it - begin());
 			return;
 		}
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index b74e2f0..ed59213 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -294,7 +294,6 @@ void CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey() {
 void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
 	playInGameVideo("62S_DUC1");
 	_inventory.removeByNameID(144);
-	_inventory.deselectObject();
 	setPlaceState(19, 1);
 }
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index e824031..f898778 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -1314,7 +1314,6 @@ FILTER_EVENT(2, 1) {
 
 		if (idOBJ == 98 && _dialogsMan["JOUEUR-CONFIE-MESSAGE-HUISSIER"] == 'Y') {
 			_inventory.removeByNameID(98);
-			_inventory.deselectObject();
 			setGameTime(2, 2);
 		}
 	} else if (*event == 31101) {


Commit: 7d6c3ee12bbef5a7b02f1782ba18840f381e2307
    https://github.com/scummvm/scummvm/commit/7d6c3ee12bbef5a7b02f1782ba18840f381e2307
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix some comments and order of callback

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 56c7fda..cd294d4 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -536,7 +536,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(1, 14), nullptr);
 	} else if (_currentLevel == 2) {
 		_placeStates.resize(15);
-		// TODO: implement functions
 		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");
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 189fe9b..2c1c6e4 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -116,7 +116,7 @@ struct GameVariables {
 		kUnlockPetitePorte,
 		kAlreadyCame31,
 		kDrawerStatus,
-		kCurrentTime,
+		kCurrentTime, // OK
 		kGotMedaillesSolution,
 		kDrawerFurnitureStatus,
 		kCollectePartition,
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index f898778..8552c50 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -684,62 +684,6 @@ IMG_CB(32120c) {
 	setGameTime(4, 2);
 }
 
-IMG_CB(41202) {
-	fimg->load("10E_20.GIF");
-	while (1) {
-		fimg->manage();
-		if (fimg->_exit || fimg->_zoneLow) {
-			fimg->_exit = true;
-			break;
-		}
-		HANDLE_QUESTION(1);
-		if (fimg->_zoneUse) {
-			if (fimg->_currentZone == 2 && !_inventory.inInventoryByNameID(97)) {
-				// Open the jar
-				ZonFixedImage::CallbackFunctor *functor =
-				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
-				            &CryOmni3DEngine_Versailles::img_41202b);
-				fimg->changeCallback(functor);
-				break;
-			} else {
-				displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 11,
-				                  fimg->getZoneCenter(fimg->_currentZone),
-				                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
-			}
-		}
-	}
-}
-
-IMG_CB(41202b) {
-	fimg->load("10E_21.GIF");
-	while (1) {
-		fimg->manage();
-		if (fimg->_exit) {
-			break;
-		}
-		HANDLE_QUESTION(1);
-		if (fimg->_zoneLow) {
-			// Go back to jars closed
-			ZonFixedImage::CallbackFunctor *functor =
-			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
-			            &CryOmni3DEngine_Versailles::img_41202);
-			fimg->changeCallback(functor);
-			break;
-		}
-		if (fimg->_zoneUse) {
-			if (!_inventory.inInventoryByNameID(97)) {
-				collectObject(97, fimg);
-			}
-			// Go back to jars closed
-			ZonFixedImage::CallbackFunctor *functor =
-			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
-			            &CryOmni3DEngine_Versailles::img_41202);
-			fimg->changeCallback(functor);
-			break;
-		}
-	}
-}
-
 IMG_CB(32201) {
 	fimg->load("21E_41.GIF");
 	while (1) {
@@ -819,6 +763,62 @@ IMG_CB(32204b) {
 	}
 }
 
+IMG_CB(41202) {
+	fimg->load("10E_20.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		HANDLE_QUESTION(1);
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 2 && !_inventory.inInventoryByNameID(97)) {
+				// Open the jar
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_41202b);
+				fimg->changeCallback(functor);
+				break;
+			} else {
+				displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 11,
+				                  fimg->getZoneCenter(fimg->_currentZone),
+				                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+			}
+		}
+	}
+}
+
+IMG_CB(41202b) {
+	fimg->load("10E_21.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		HANDLE_QUESTION(1);
+		if (fimg->_zoneLow) {
+			// Go back to jars closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_41202);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (!_inventory.inInventoryByNameID(97)) {
+				collectObject(97, fimg);
+			}
+			// Go back to jars closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_41202);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
 IMG_CB(41801) {
 	fimg->load("12E2_10.GIF");
 	while (1) {
@@ -999,7 +999,7 @@ IMG_CB(41802) {
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
 				setGameTime(3, 1);
 			} else if (objID == 96) {
-				// Pamphlet about arts
+				// Lampoon about arts
 				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
@@ -1046,7 +1046,7 @@ IMG_CB(41802b) {
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
 				setGameTime(3, 1);
 			} else if (objID == 96) {
-				// Pamphlet about arts
+				// Lampoon about arts
 				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
@@ -1091,7 +1091,7 @@ IMG_CB(41802c) {
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
 				setGameTime(3, 1);
 			} else if (objID == 96) {
-				// Pamphlet about arts
+				// Lampoon about arts
 				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {
@@ -1126,7 +1126,7 @@ IMG_CB(41802d) {
 				_gameVariables[GameVariables::kGotRevealedPaper] = 1;
 				setGameTime(3, 1);
 			} else if (objID == 96) {
-				// Pamphlet about arts
+				// Lampoon about arts
 				playInGameVideo("PAP-BRUL");
 				// Force reload of the place
 				if (_nextPlaceId == -1u) {


Commit: 47908def70d1cae1d04155e436dae7dc05226948
    https://github.com/scummvm/scummvm/commit/47908def70d1cae1d04155e436dae7dc05226948
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix palette not applied when loading frame

Changed paths:
    engines/cryomni3d/versailles/dialogs_manager.cpp


diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index 3ebc4cf..f7a2146 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -352,15 +352,15 @@ void Versailles_DialogsManager::loadFrame(const Common::String &video) {
 		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);
 	}
-
-	// Preload first frame to draw subtitles from it
-	const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
-	_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
-	_lastImage.blitFrom(*firstFrame);
 }
 
 } // End of namespace Versailles


Commit: 7cbf7095fc4599c88755a3d600a822478ecfdf07
    https://github.com/scummvm/scummvm/commit/7cbf7095fc4599c88755a3d600a822478ecfdf07
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix messages

Changed paths:
    engines/cryomni3d/versailles/data.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index cd294d4..ed29e6c 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -85,7 +85,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	SET_MESSAGE(10, "Il faudrait quelque chose pour atteindre la bombe.");
 	SET_MESSAGE(11, "Ce vase est vide.");
 	SET_MESSAGE(12, "Maintenant, vous pouvez y aller.");
-	SET_MESSAGE(13, "Vous niavez plus le temps de vous renseigner sur la Cour!");
+	SET_MESSAGE(13, "Vous n" "\xd5" "avez plus le temps de vous renseigner sur la Cour!");
 	SET_MESSAGE(14, "Il est trop tard pour regarder les tableaux!");
 	SET_MESSAGE(16, "Vous ne pouvez pas atteindre le papier.");
 	SET_MESSAGE(15, "Attendez ! Transmettez donc vos indices " "\x88" " l'huissier.");
@@ -191,7 +191,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	SET_MESSAGE(112, "pinceau Rouge");
 	SET_MESSAGE(113, "Fusain");
 	SET_MESSAGE(114, "Papier");
-	SET_MESSAGE(115, "Pamphlet sur liarchitecture");
+	SET_MESSAGE(115, "Pamphlet sur l" "\xd5" "architecture");
 	SET_MESSAGE(116, "Petite clef 2");
 	SET_MESSAGE(117, "Archer(inutile!)");
 	SET_MESSAGE(118, "Partition");
@@ -199,7 +199,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	SET_MESSAGE(120, "Autorisation");
 	SET_MESSAGE(121, "Reproduction des m" "\x8e" "dailles");
 	SET_MESSAGE(122, "Tiroir " "\x88" " m" "\x8e" "dailles");
-	SET_MESSAGE(123, "Clef de la petite porte diApollon");
+	SET_MESSAGE(123, "Clef de la petite porte d" "\xd5" "Apollon");
 	SET_MESSAGE(124, "Nourriture");
 	SET_MESSAGE(125, "Pamphlet sur la religion");
 	SET_MESSAGE(126, "Epigraphe");


Commit: 9496c796bccc0c71b08b5d48c38a5ac9090c6977
    https://github.com/scummvm/scummvm/commit/9496c796bccc0c71b08b5d48c38a5ac9090c6977
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement missing objects callbacks

Two callbacks quite special are still to be implemented

Changed paths:
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 2c1c6e4..c19976b 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -397,6 +397,12 @@ private:
 	//Objects
 	template<unsigned int ID>
 	void genericDisplayObject();
+	void obj_105();
+	void obj_106();
+	void obj_107();
+	void obj_118();
+	void obj_121();
+	void obj_125();
 
 	// Fixed image
 	template<unsigned int ID>
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 8552c50..7baba9f 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -66,11 +66,12 @@ static const char *imagesObjects[] = {
 void CryOmni3DEngine_Versailles::setupObjects() {
 	_objects.reserve(51);
 #define SET_OBJECT(cursorId, nameId) _objects.push_back(Object(_sprites, cursorId, nameId))
-#define SET_OBJECT_CB(cursorId, nameId, cb) do { \
+#define SET_OBJECT_AND_CB(cursorId, nameId, cb) do { \
         _objects.push_back(Object(_sprites, cursorId, nameId)); \
         _objects.back().setViewCallback(new Common::Functor0Mem<void, CryOmni3DEngine_Versailles>(this, &CryOmni3DEngine_Versailles::cb)); \
     } while (false)
-#define SET_OBJECT_GENERIC_CB(cursorId, nameId, imageId) SET_OBJECT_CB(cursorId, nameId, genericDisplayObject<imageId>)
+#define SET_OBJECT_GENERIC_CB(cursorId, nameId, imageId) SET_OBJECT_AND_CB(cursorId, nameId, genericDisplayObject<imageId>)
+#define SET_OBJECT_CB(cursorId, nameId) SET_OBJECT_AND_CB(cursorId, nameId, obj_ ## nameId)
 	SET_OBJECT(161, 93);
 	SET_OBJECT(107, 94);
 	SET_OBJECT(69, 95);
@@ -83,9 +84,9 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT(191, 102);
 	SET_OBJECT(171, 103);
 	SET_OBJECT(47, 104);
-	SET_OBJECT(205, 105);
-	SET_OBJECT(214, 106);
-	SET_OBJECT(6, 107);
+	SET_OBJECT_CB(205, 105);
+	SET_OBJECT_CB(214, 106);
+	SET_OBJECT_CB(6, 107);
 	SET_OBJECT(58, 108);
 	SET_OBJECT_GENERIC_CB(5, 109, 8);
 	SET_OBJECT(38, 110);
@@ -94,14 +95,14 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT_GENERIC_CB(246, 115, 9);
 	SET_OBJECT(80, 116);
 	SET_OBJECT(180, 117);
-	SET_OBJECT(34, 118);
+	SET_OBJECT_CB(34, 118);
 	SET_OBJECT(173, 119);
 	SET_OBJECT(81, 120);
-	SET_OBJECT(156, 121);
+	SET_OBJECT_CB(156, 121);
 	SET_OBJECT(143, 122);
 	SET_OBJECT(101, 123);
 	SET_OBJECT(204, 124);
-	SET_OBJECT(10, 125);
+	SET_OBJECT(10, 125); // TODO:
 	SET_OBJECT(112, 126); // TODO: EPIL.gif
 	SET_OBJECT_GENERIC_CB(90, 127, 17);
 	SET_OBJECT(216, 128);
@@ -122,6 +123,9 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT(157, 143);
 	SET_OBJECT(168, 144);
 	SET_OBJECT(65, 145);
+#undef SET_OBJECT_CB
+#undef SET_OBJECT_GENERIC_CB
+#undef SET_OBJECT_AND_CB
 #undef SET_OBJECT
 }
 
@@ -130,6 +134,51 @@ void CryOmni3DEngine_Versailles::genericDisplayObject() {
 	displayObject(imagesObjects[ID]);
 }
 
+void CryOmni3DEngine_Versailles::obj_105() {
+	displayObject(imagesObjects[3]);
+	displayObject(imagesObjects[4]);
+	displayObject(imagesObjects[5]);
+	displayObject(imagesObjects[6]);
+}
+
+void CryOmni3DEngine_Versailles::obj_106() {
+	displayObject(imagesObjects[6]);
+	displayObject(imagesObjects[3]);
+	displayObject(imagesObjects[4]);
+}
+
+void CryOmni3DEngine_Versailles::obj_107() {
+	if (_gameVariables[GameVariables::kSketchState] == 3) {
+		displayObject(imagesObjects[7]);
+	} else {
+		displayObject(imagesObjects[6]);
+	}
+}
+
+void CryOmni3DEngine_Versailles::obj_118() {
+	if (_gameVariables[GameVariables::kDecipherScore]) {
+		displayObject(imagesObjects[11]);
+	} else {
+		displayObject(imagesObjects[10]);
+	}
+}
+
+void CryOmni3DEngine_Versailles::obj_121() {
+	if (_gameVariables[GameVariables::kGotMedalsSolution]) {
+		displayObject(imagesObjects[13]);
+	} else {
+		displayObject(imagesObjects[12]);
+	}
+}
+
+void CryOmni3DEngine_Versailles::obj_125() {
+	if (_gameVariables[GameVariables::kStatePamphletReligion]) {
+		displayObject(imagesObjects[15]);
+	} else {
+		displayObject(imagesObjects[14]);
+	}
+}
+
 // This array contains images for all paintings it must be kept in sync with _paintingsTitles
 static const char *imagesPaintings[] = {
 	"10E_1.GIF",      //  0: 41201


Commit: c427cd9dcab111dd7f11a5ae96d0e20fd94ddb13
    https://github.com/scummvm/scummvm/commit/c427cd9dcab111dd7f11a5ae96d0e20fd94ddb13
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement level 3

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/dialogs.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index ed29e6c..3b7c577 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -552,30 +552,29 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(2, 14), nullptr);
 	} else if (_currentLevel == 3) {
 		_placeStates.resize(25);
-		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
-		SET_PLACE_STATE(3, 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, nullptr, "VS28");
+		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, nullptr, "VS27");
+		SET_PLACE_STATE(13, nullptr, FILTER_EVENT(3, 13), "VS27");
 		SET_PLACE_STATE(14, nullptr, nullptr, "VS26");
-		SET_PLACE_STATE(15, nullptr, nullptr, "VS25");
+		SET_PLACE_STATE(15, nullptr, FILTER_EVENT(3, 15), "VS25");
 		SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
-		SET_PLACE_STATE(17, nullptr, nullptr, "VS25");
-		SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(19, nullptr, nullptr, "VS26");
-		SET_PLACE_STATE(20, nullptr, nullptr, nullptr);
+		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, nullptr, "VS26");
-		SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
+		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) {
 		_placeStates.resize(18);
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index ed59213..580b56e 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -64,7 +64,7 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	        _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y' &&
 	        (!_inventory.inInventoryByNameID(121) || !_inventory.inInventoryByNameID(119) ||
 	         !_inventory.inInventoryByNameID(115) ||
-	         _gameVariables[GameVariables::kGotMedaillesSolution] == 0)) {
+	         _gameVariables[GameVariables::kGotMedalsSolution] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -116,18 +116,18 @@ void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequenc
 		if (currentGameTime() == 1 && _dialogsMan["LULLY-DONNE-MISSION1-JOUEUR"] == 'Y') {
 			setGameTime(2, 3);
 		}
-		if (!_gameVariables[GameVariables::kGotMedaillesSolution] &&
+		if (!_gameVariables[GameVariables::kGotMedalsSolution] &&
 		        _dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
 			playInGameVideo("32M_MR2");
-			_gameVariables[GameVariables::kGotMedaillesSolution] = 1;
+			_gameVariables[GameVariables::kGotMedalsSolution] = 1;
 		}
-		if (!_gameVariables[GameVariables::kCollectePartition] &&
+		if (!_gameVariables[GameVariables::kDecipherScore] &&
 		        _dialogsMan["LULLY-DIT-CHAT-PENDU-JOUEUR"] == 'Y') {
-			_gameVariables[GameVariables::kCollectePartition] = 1;
+			_gameVariables[GameVariables::kDecipherScore] = 1;
 			collectObject(118);
 			setGameTime(3, 3);
 		}
-		if (currentGameTime() == 1 && _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y') {
+		if (currentGameTime() == 3 && _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y') {
 			setGameTime(4, 3);
 		}
 		if (_dialogsMan["{LEVEL3_FINI}"] == 'Y') {
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 3baaf81..a227a26 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -608,7 +608,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		// TODO: countdown
 		_inventory.clear();
-	} else if (_currentLevel <= 2) {
+	} else if (_currentLevel <= 3) {
 		// TODO: remove this when we implemented all levels
 	} else {
 		error("New level %d is not implemented (yet)", level);
@@ -1190,9 +1190,7 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 
 bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
         unsigned int movingCursor) {
-	PlaceStateActionKey mask = PlaceStateActionKey(_currentPlaceId, _placeStates[_currentPlaceId].state,
-	                           *actionId);
-	*actionId = _actionMasks.getVal(mask, *actionId);
+	fixActionId(actionId);
 
 	if (getCurrentMouseButton() == 2 ||
 	        getNextKey().keycode == Common::KEYCODE_SPACE) {
@@ -1240,6 +1238,44 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
 	return false;
 }
 
+void CryOmni3DEngine_Versailles::fixActionId(unsigned int *actionId) const {
+	PlaceStateActionKey mask = PlaceStateActionKey(_currentPlaceId, _placeStates[_currentPlaceId].state,
+	                           *actionId);
+	Common::HashMap<PlaceStateActionKey, unsigned int>::const_iterator it = _actionMasks.find(mask);
+	if (it != _actionMasks.end()) {
+		*actionId = it->_value;
+		return;
+	}
+
+	// Special case for level 3 taking dialogs variables into account
+	if (_currentLevel == 3) {
+		if (_dialogsMan["{LE JOUEUR-A-TENTE-OUVRIR-PETITE-PORTE}"] == 'N') {
+			if (*actionId == 13060) {
+				*actionId = 23060;
+			} else if (*actionId == 13100) {
+				if (currentGameTime() != 4) {
+					*actionId = 23100;
+				}
+			} else if (*actionId == 13130) {
+				*actionId = 23130;
+			} else if (*actionId == 13150) {
+				*actionId = 23150;
+			}
+		} else if (_dialogsMan["{JOUEUR-POSSEDE-CLE}"] == 'Y') {
+			if (*actionId == 13100) {
+				if (currentGameTime() != 4) {
+					*actionId = 23100;
+				}
+			} else if (*actionId == 13130) {
+				*actionId = 23130;
+			} else if (*actionId == 13150) {
+				*actionId = 23150;
+			}
+
+		}
+	}
+}
+
 void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transition) {
 	double srcAlpha = transition->srcAlpha;
 	double srcBeta = transition->srcBeta;
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index c19976b..9d0b7ac 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -112,15 +112,15 @@ enum AbortCommand {
 struct GameVariables {
 	enum Var {
 		// TODO: make these enum members more correct
-		kCollectPartition = 0,         // 0
-		kUnlockPetitePorte,
-		kAlreadyCame31,
-		kDrawerStatus,
+		kCollectScore = 0, // OK       // 0
+		kUnlockHiddenDoor, // OK
+		kAlreadyWent3_19, // OK
+		kMedalsDrawerStatus, // OK
 		kCurrentTime, // OK
-		kGotMedaillesSolution,
-		kDrawerFurnitureStatus,
-		kCollectePartition,
-		kCollectPamphletArchi,
+		kGotMedalsSolution, // OK
+		kCabinetDrawerStatus, // OK
+		kDecipherScore, // OK
+		kCollectLampoonArchitecture, // OK
 		kGotRevealedPaper, // OK
 		kCollectKey, // OK             // 10
 		kCollectPortfolio, // OK
@@ -148,7 +148,7 @@ struct GameVariables {
 		kCollectedPaperInTrunk = 33, // OK
 		kBrushColor, // OK
 		kUsedScissors, // OK
-		kUsedClefsCombles,
+		kUnlockedAttic, // OK
 		kHasPlayedLebrun, // OK
 		kWarnedIncomplete,
 		kUsedPlanVauban1,
@@ -272,6 +272,7 @@ private:
 	        const Transition **transition);
 
 	unsigned int getFakeTransition(unsigned int actionId) const;
+	void fixActionId(unsigned int *actionId) const;
 
 	int handleWarp();
 	bool handleWarpMouse(unsigned int *actionId, unsigned int movingCuror);
@@ -437,6 +438,30 @@ private:
 	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(88001);
+	IMG_CB(88001b);
+	IMG_CB(88001c);
+	IMG_CB(88004);
+	IMG_CB(88004b);
 #undef IMG_CB
 
 #define FILTER_EVENT(level, place) bool filterEventLevel ## level ## Place ## place(unsigned int *event)
@@ -456,6 +481,20 @@ private:
 	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);
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 7baba9f..2f4555b 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -293,7 +293,7 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	SET_SCRIPT_BY_PAINTING(43140, 34);
 	SET_SCRIPT_BY_PAINTING(43141, 35);
 	SET_SCRIPT_BY_PAINTING(43142, 36);
-	//SET_SCRIPT_BY_ID(43143); // TODO: implement it
+	SET_SCRIPT_BY_ID(43143);
 	SET_SCRIPT_BY_PAINTING(43144, 38);
 	SET_SCRIPT_BY_PAINTING(43150, 39);
 	SET_SCRIPT_BY_PAINTING(43151, 40);
@@ -329,19 +329,19 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	// From now specific handlers for anything that is not a painting
 	SET_SCRIPT_BY_ID(41801);
 	SET_SCRIPT_BY_ID(41802);
-	//SET_SCRIPT_BY_ID(43145); // TODO: implement it
-	//SET_SCRIPT_BY_ID(43146); // TODO: implement it
-	//SET_SCRIPT_BY_ID(43160); // TODO: implement it
-	//SET_SCRIPT_BY_ID(43190); // TODO: implement it
+	SET_SCRIPT_BY_ID(43145);
+	SET_SCRIPT_BY_ID(43146);
+	SET_SCRIPT_BY_ID(43160);
+	SET_SCRIPT_BY_ID(43190);
 	//SET_SCRIPT_BY_ID(44071); // TODO: implement it
 	//SET_SCRIPT_BY_ID(44161); // TODO: implement it
 	//SET_SCRIPT_BY_ID(45130); // TODO: implement it // Almost dumb
 	//SET_SCRIPT_BY_ID(45270); // TODO: implement it
 	//SET_SCRIPT_BY_ID(45280); // TODO: implement it // Almost dumb
-	//SET_SCRIPT_BY_ID(88001); // TODO: implement it
+	SET_SCRIPT_BY_ID(88001);
 	//SET_SCRIPT_BY_ID(88002); // TODO: implement it
 	//SET_SCRIPT_BY_ID(88003); // TODO: implement it
-	//SET_SCRIPT_BY_ID(88004); // TODO: implement it
+	SET_SCRIPT_BY_ID(88004);
 #undef SET_SCRIPT_BY_ID
 }
 
@@ -1187,6 +1187,629 @@ IMG_CB(41802d) {
 	}
 }
 
+IMG_CB(43143) {
+	// Lampoon is there: display it
+	if (!_gameVariables[GameVariables::kCollectLampoonArchitecture] &&
+	        (_currentLevel == 5 || currentGameTime() >= 3)) {
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_43143b);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	fimg->load("30L_31.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		HANDLE_QUESTION(37);
+	}
+}
+
+IMG_CB(43143b) {
+	fimg->load("30L_3101.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		HANDLE_QUESTION(37);
+		if (fimg->_zoneUse) {
+			// Paper is out of reach
+			displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 16,
+			                  fimg->getZoneCenter(fimg->_currentZone),
+			                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+		} else if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 119 && fimg->_currentZone == 0) {
+			_inventory.removeByNameID(119);
+			collectLampoonArchitecture(fimg);
+			// Display without the lampoon
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43143);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43145) {
+	fimg->load("30L_50.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				playInGameVideo("30L_51");
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43145b);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1) {
+				playInGameVideo("30L_52");
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43145c);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(43145b) {
+	fimg->load("30L_51.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneLow) {
+			// Go back to drawer closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43145);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (_gameVariables[GameVariables::kCabinetDrawerStatus] == 1) {
+				// Small key 2 has been put in it and not yet picked by us
+				collectObject(116, fimg);
+				_gameVariables[GameVariables::kCabinetDrawerStatus] = 2;
+			} else {
+				// Drawer is empty
+				displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 3,
+				                  fimg->getZoneCenter(fimg->_currentZone),
+				                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+			}
+		}
+	}
+}
+
+IMG_CB(43145c) {
+	fimg->load("30L_52.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneLow) {
+			// Go back to drawer closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43145);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Drawer is empty
+			displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 3,
+			                  fimg->getZoneCenter(fimg->_currentZone),
+			                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+		}
+	}
+}
+
+IMG_CB(43146) {
+	fimg->load("30L_40.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				playInGameVideo("30L_41");
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43146b);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1) {
+				playInGameVideo("30L_42");
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43146c);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(43146b) {
+	fimg->load("30L_41.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneLow) {
+			// Go back to drawer closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43146);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Drawer is empty
+			displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 3,
+			                  fimg->getZoneCenter(fimg->_currentZone),
+			                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+		}
+	}
+}
+
+IMG_CB(43146c) {
+	fimg->load("30L_42.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneLow) {
+			// Go back to drawer closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43146);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Drawer is empty
+			displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 3,
+			                  fimg->getZoneCenter(fimg->_currentZone),
+			                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+		}
+	}
+}
+
+IMG_CB(43160) {
+	// Dispatch to the correct state
+	bool inInvCharcoal = _inventory.inInventoryByNameID(113);
+	bool inInvPaper = _inventory.inInventoryByNameID(114);
+	if (inInvCharcoal && inInvPaper) {
+		// When everything is collected, state of place change and we shouldn't be able to look at the table
+		error("BUG: Shouldn't be here");
+	} else if (inInvCharcoal && !inInvPaper) {
+		// Draw table with paper but without charcoal
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_43160b);
+		fimg->changeCallback(functor);
+		return;
+	} else if (!inInvCharcoal && inInvPaper) {
+		// Draw table with charcoal but without paper
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_43160c);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	// There we have charcoal and paper on table
+	fimg->load("31I01.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				// Collected charcoal
+				collectObject(113, fimg);
+				// Draw table with paper but without charcoal
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43160b);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1) {
+				// Collected paper
+				collectObject(114, fimg);
+				// Draw table with charcoal but without paper
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_43160c);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(43160b) {
+	// There we have paper on table but without charcoal
+	fimg->load("31I02.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Collected paper
+			collectObject(114, fimg);
+			// Draw table empty
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43160d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43160c) {
+	// There we have charcoal on table but without paper
+	fimg->load("31I03.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Collected charcoal
+			collectObject(113, fimg);
+			// Draw table empty
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43160d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43160d) {
+	// There we have neither charcoal nor paper on table
+	fimg->load("31I04.GIF");
+	setPlaceState(16, 1);
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(43190) {
+	fimg->load("31L1_20.GIF");
+	if (_gameVariables[GameVariables::kCollectScore]) {
+		fimg->disableZone(0);
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			playInGameVideo("31L1_2A");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43190b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43190b) {
+	fimg->load("31L1_20B.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			playInGameVideo("31L1_2B");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43190c);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43190c) {
+	fimg->load("31L1_20C.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			playInGameVideo("31L1_2C");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43190d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43190d) {
+	fimg->load("31L1_20D.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			playInGameVideo("31L1_2D");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43190e);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43190e) {
+	fimg->load("31L1_20E.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_43190f);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(43190f) {
+	fimg->load("31L1_22.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			_gameVariables[GameVariables::kCollectScore] = 1;
+			collectObject(118, fimg);
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(88001) {
+	if (!_inventory.inInventoryByNameID(121) &&
+	        _gameVariables[GameVariables::kMedalsDrawerStatus] == 3) {
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_88001c);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	fimg->load("33P_10.GIF");
+	if (_inventory.inInventoryByNameID(121)) {
+		fimg->disableZone(0);
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse &&
+		        !_inventory.inInventoryByNameID(121)) {
+			// Open the drawer
+
+			playInGameVideo("33P_10");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88001b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(88001b) {
+	_gameVariables[GameVariables::kMedalsDrawerStatus] = 2;
+
+	fimg->load("33P_12.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit) {
+			break;
+		}
+		if (fimg->_zoneLow) {
+			_gameVariables[GameVariables::kMedalsDrawerStatus] = 0;
+			// Go back to drawer closed
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88001);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 114 &&
+		        fimg->_currentZone == 0) {
+			// Lay the paper on the medals
+			_inventory.removeByNameID(114);
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88001c);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(88001c) {
+	// Paper is laid on the medals
+	_gameVariables[GameVariables::kMedalsDrawerStatus] = 3;
+
+	fimg->load("33P_13.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 113 &&
+		        fimg->_currentZone == 0) {
+			// Use charcoal on paper and medals
+			_inventory.removeByNameID(113);
+
+			playInGameVideo("33P_14");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			collectObject(121, fimg);
+			_dialogsMan["{JOUEUR-POSSEDE-FUSAIN-MEDAILLES}"] = 'Y';
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88001);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(88004) {
+	fimg->load("31j31.gif");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88004b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(88004b) {
+	// Open the toilets
+	playInGameVideo("31j32");
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+	fimg->load("31j32.gif");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88004);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+	if (!shouldQuit()) {
+		// Close the toilets
+		playInGameVideo("31j32b");
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+	}
+}
+
 #undef IMG_CB
 
 // Init place and filter event
@@ -1648,6 +2271,297 @@ FILTER_EVENT(2, 14) {
 	return filterEventLevel1Place14(event);
 }
 
+FILTER_EVENT(3, 3) {
+	if (*event == 23030 && _inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 118 &&
+	        _gameVariables[GameVariables::kDecipherScore]) {
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-DECHIFFRE-PAR-LULLY}"] = 'Y';
+		_dialogsMan.play("31X_BON");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-DECHIFFRE-PAR-LULLY}"] = 'N';
+		_inventory.deselectObject();
+	}
+	return true;
+}
+
+FILTER_EVENT(3, 10) {
+	if (*event == 23101 && _inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 120) {
+		_inventory.removeByNameID(120);
+
+		_dialogsMan["{JOUEUR-MONTRE-AUTORISATION-DE-BONTEMPS}"] = 'Y';
+		_dialogsMan.play("31O_SUIP");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-AUTORISATION-DE-BONTEMPS}"] = 'N';
+		_inventory.deselectObject();
+		return true;
+	} else if (*event == 21) {
+		if (_dialogsMan["SUISSE-VU-AUTORISATION"] == 'Y') {
+			fakeTransition(*event);
+			playInGameVideo("33O_SUIP");
+			playInGameVideo("33O_P");
+			executeSeeAction(88001);
+			if (!shouldAbort()) {
+				playInGameVideo("33P_O");
+			}
+			_forcePaletteUpdate = true;
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+		}
+		// This place is a fake one: so never go in there
+		return false;
+	}
+	return true;
+}
+
+FILTER_EVENT(3, 13) {
+	_dialogsMan["{JOUEUR-MONTRE-FUSAIN-MEDAILLES}"] = 'N';
+	_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+	if (*event == 33130 && !_inventory.inInventoryByNameID(119)) {
+		collectObject(119);
+		if (_placeStates[13].state) {
+			setPlaceState(13, 3);
+		} else {
+			setPlaceState(13, 1);
+		}
+		// We handle use here
+		return false;
+	} else if (*event == 23131 && _inventory.selectedObject()) {
+		if (_inventory.selectedObject()->idOBJ() == 121) {
+			_dialogsMan["{JOUEUR-MONTRE-FUSAIN-MEDAILLES}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+		_dialogsMan.play("32M_MR");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-FUSAIN-MEDAILLES}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+		_inventory.deselectObject();
+		return true;
+	} else {
+		return true;
+	}
+}
+
+FILTER_EVENT(3, 15) {
+	if (*event == 23151 && _inventory.selectedObject()) {
+		return filterEventLevel3Obj23151();
+	}
+	return true;
+}
+
+FILTER_EVENT(3, 17) {
+	if (*event == 18) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 123) {
+			_gameVariables[GameVariables::kUnlockHiddenDoor] = 1;
+			_inventory.removeByNameID(123);
+			return true;
+		} else if (_gameVariables[GameVariables::kUnlockHiddenDoor] != 1) {
+			// Locked
+			displayMessageBoxWarp(1);
+			_dialogsMan["{LE JOUEUR-A-TENTE-OUVRIR-PETITE-PORTE}"] = 'Y';
+			return false;
+		} else {
+			return true;
+		}
+	} else if (*event == 23151) {
+		return filterEventLevel3Obj23151();
+	} else {
+		return true;
+	}
+}
+
+FILTER_EVENT(3, 18) {
+	if (*event != 19) {
+		return true;
+	}
+
+	// Only take care of event 19
+
+	// Adjust camera
+	fakeTransition(*event);
+	// As we have just adjusted camera, don't do it later
+	_transitionAnimateWarp = false;
+
+	if (_placeStates[22].state) {
+		playInGameVideo("31J1_L2");
+	} else if (_gameVariables[GameVariables::kAlreadyWent3_19]) {
+		playInGameVideo("31J1_L1");
+	} else {
+		playInGameVideo("31J1_L0");
+		playInGameVideo("31L1_AL2");
+		playInGameVideo("31L1_AL3");
+		_gameVariables[GameVariables::kAlreadyWent3_19] = 1;
+		_gameVariables[GameVariables::kCabinetDrawerStatus] = 1;
+	}
+
+	_forcePaletteUpdate = true;
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+	return true;
+}
+
+FILTER_EVENT(3, 19) {
+	if (*event != 18) {
+		return true;
+	}
+	if (currentGameTime() != 3 || _placeStates[22].state) {
+		return true;
+	}
+
+	if (_gameVariables[GameVariables::kCollectLampoonArchitecture]) {
+		setPlaceState(22, 2);
+	} else {
+		setPlaceState(22, 1);
+	}
+	setPlaceState(19, 1);
+
+	return true;
+}
+
+FILTER_EVENT(3_5, 20) {
+	if (*event != 25) {
+		return true;
+	}
+
+	fakeTransition(*event);
+	playInGameVideo("31j31");
+
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+
+	// Toilets
+	executeSeeAction(88004);
+
+	_forcePaletteUpdate = true;
+
+	return false;
+}
+
+FILTER_EVENT(3, 22) {
+	if (*event == 33220) {
+		if (!_gameVariables[GameVariables::kCollectLampoonArchitecture]) {
+			if (_inventory.selectedObject() &&
+			        _inventory.selectedObject()->idOBJ() == 119) {
+				// Using pool cue
+				_inventory.removeByNameID(119);
+				collectLampoonArchitecture();
+				_forcePaletteUpdate = true;
+			} else {
+				// Paper is out of reach
+				displayMessageBoxWarp(16);
+			}
+		}
+		// We handle use here
+		return false;
+	}
+
+	if (*event >= 20000 && *event < 30000 &&
+	        _inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 118) {
+		_dialogsMan["{JOUEUR-PRESENTE-PAMPHLET-PARTITION}"] = 'Y';
+		_dialogsMan.play("31L1_LUL");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-PRESENTE-PAMPHLET-PARTITION}"] = 'N';
+		if (_dialogsMan["LULLY-DONNE-MISSION1-JOUEUR"] != 'Y' ||
+		        _gameVariables[GameVariables::kDecipherScore]) {
+			_inventory.deselectObject();
+		} else {
+			_inventory.removeByNameID(118);
+		}
+	}
+	return true;
+}
+
+FILTER_EVENT(3, 23) {
+	if (*event != 32) {
+		return true;
+	}
+
+	if (_inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 140) {
+		_gameVariables[GameVariables::kUnlockedAttic] = 1;
+		_inventory.removeByNameID(140);
+		return true;
+	} else if (_gameVariables[GameVariables::kUnlockedAttic] != 1) {
+		// Locked
+		displayMessageBoxWarp(1);
+		return false;
+	} else {
+		return true;
+	}
+}
+
+bool CryOmni3DEngine_Versailles::filterEventLevel3Obj23151() {
+	if (_inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 115) {
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'Y';
+	} else if (_inventory.selectedObject() &&
+	           _inventory.selectedObject()->idOBJ() == 121 &&
+	           _gameVariables[GameVariables::kGotMedalsSolution]) {
+		_inventory.removeByNameID(121);
+		_dialogsMan["{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}"] = 'Y';
+	} else {
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'Y';
+	}
+
+	_dialogsMan.play("32J_CRO");
+
+	_forcePaletteUpdate = true;
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+
+	_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'N';
+	_dialogsMan["{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}"] = 'N';
+	_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'N';
+
+	_inventory.deselectObject();
+
+	return true;
+}
+
+void CryOmni3DEngine_Versailles::collectLampoonArchitecture(const ZonFixedImage *fimg) {
+	_gameVariables[GameVariables::kCollectLampoonArchitecture] = 1;
+	collectObject(115, fimg);
+	if (_currentLevel == 3) {
+		setPlaceState(22, 2);
+	}
+	_dialogsMan["{JOUEUR_POSSEDE_PAMPHLET_ARCHI}"] = 'Y';
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: 5a0d511ebd249d21b5390d26add991e2c2d1bda2
    https://github.com/scummvm/scummvm/commit/5a0d511ebd249d21b5390d26add991e2c2d1bda2
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Use typedef instead of repeating

Changed paths:
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/fixed_image.h


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index 0fb9513..660190a 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -42,7 +42,7 @@ ZonFixedImage::~ZonFixedImage() {
 	delete _imageDecoder;
 }
 
-void ZonFixedImage::run(const Common::Functor1<ZonFixedImage *, void> *callback) {
+void ZonFixedImage::run(const CallbackFunctor *callback) {
 	_exit = false;
 	_zonesMode = kZonesMode_None;
 
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index b462315..7f2b1e0 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -65,7 +65,7 @@ public:
 
 	void run(const CallbackFunctor *callback);
 
-	/* THis function is used to refresh image after various events */
+	/* This function is used to refresh image after various events */
 	void display() const;
 
 	/* These functions and attributes are used in image handler */
@@ -96,7 +96,7 @@ public:
 	Common::KeyState _key;
 
 protected:
-	const Common::Functor1<ZonFixedImage *, void> *_callback;
+	const CallbackFunctor *_callback;
 	CryOmni3DEngine &_engine;
 	Inventory &_inventory;
 	const Sprites &_sprites;


Commit: 349201ba153bd80597a0c4154afea4d9499166c6
    https://github.com/scummvm/scummvm/commit/349201ba153bd80597a0c4154afea4d9499166c6
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Let callback modify displayed fixed image

Changed paths:
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/fixed_image.h


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index 660190a..08bc78e 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -60,6 +60,9 @@ void ZonFixedImage::run(const CallbackFunctor *callback) {
 
 	delete _callback;
 	_callback = nullptr;
+
+	// Don't use the current _imageSurface, we may not own it anymore
+	_imageSurface = nullptr;
 }
 
 void ZonFixedImage::load(const Common::String &image) {
@@ -294,4 +297,17 @@ void ZonFixedImage::handleMouseZones(const Common::Array<Zone>::const_iterator &
 	}
 }
 
+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
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 7f2b1e0..3cabfa3 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -71,6 +71,7 @@ public:
 	/* These functions and attributes are used in image handler */
 	void load(const Common::String &image);
 	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(unsigned int zoneId) const;


Commit: ac5d392a76eeb3e1d09bc4c585d6e29f5c9f47d8
    https://github.com/scummvm/scummvm/commit/ac5d392a76eeb3e1d09bc4c585d6e29f5c9f47d8
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a function to load a set of BMP files

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index a227a26..608da9c 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1537,5 +1537,25 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
 	g_system->showMouse(true);
 }
 
+void CryOmni3DEngine_Versailles::loadBMPs(const char *pattern, Graphics::Surface *bmps,
+        unsigned int count) {
+	Image::BitmapDecoder bmpDecoder;
+	Common::File file;
+
+	for (unsigned int i = 0; i < count; i++) {
+		Common::String bmp = Common::String::format(pattern, i);
+
+		if (!file.open(bmp)) {
+			error("Failed to open BMP file: %s", bmp.c_str());
+		}
+		if (!bmpDecoder.loadStream(file)) {
+			error("Failed to load BMP file: %s", bmp.c_str());
+		}
+		bmps[i].copyFrom(*bmpDecoder.getSurface());
+		bmpDecoder.destroy();
+		file.close();
+	}
+}
+
 } // End of namespace Versailles
 } // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 9d0b7ac..438ae16 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -327,6 +327,8 @@ private:
 
 	void playInGameVideo(const Common::String &filename, bool restoreCursorPalette = true);
 
+	void loadBMPs(const char *pattern, Graphics::Surface *bmps, unsigned int count);
+
 	unsigned int getMusicId(unsigned int level, unsigned int placeId) const;
 	bool musicWouldChange(unsigned int level, unsigned int placeId) const;
 	void musicUpdate();


Commit: 5eb8b19a9c8921ddd4d6964bcd5aaa2c38663ae4
    https://github.com/scummvm/scummvm/commit/5eb8b19a9c8921ddd4d6964bcd5aaa2c38663ae4
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: If save name can't be read don't add it

Changed paths:
    engines/cryomni3d/versailles/saveload.cpp


diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index d4985dc..4ffdaf5 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -100,8 +100,9 @@ void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &s
 			Common::InSaveFile *in = _saveFileMan->openForLoading(*file);
 #endif
 			if (in) {
-				in->read(saveName, SAVE_DESCRIPTION_LEN);
-				saveNames.push_back(saveName);
+				if (in->read(saveName, SAVE_DESCRIPTION_LEN) == SAVE_DESCRIPTION_LEN) {
+					saveNames.push_back(saveName);
+				}
 				delete in;
 			}
 		}


Commit: 75e5339246e85fd025fa972b6a4334b53866801b
    https://github.com/scummvm/scummvm/commit/75e5339246e85fd025fa972b6a4334b53866801b
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix comments

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 608da9c..b021a63 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -35,7 +35,10 @@
 
 #include "cryomni3d/versailles/engine.h"
 
-//#define DEBUG_FAST_START 1
+// 0 or commented: All videos and options screen
+// 1: Skip videos at startup and at game start
+// 2: Directly start a new game
+#define DEBUG_FAST_START 1
 
 namespace CryOmni3D {
 namespace Versailles {
@@ -803,7 +806,7 @@ void CryOmni3DEngine_Versailles::gameStep() {
 		}
 		unsigned int actionId = handleWarp();
 		debug("handleWarp returned %u", actionId);
-		// TODO: handle keyboard levels 4 and 5
+		// Don't handle keyboard for levels 4 and 5, it was a debug leftover
 
 		// Get selected object there to detect when it has just been deselected
 		Object *selectedObject = _inventory.selectedObject();


Commit: 36405f483f588b6153e617f122834818394329d2
    https://github.com/scummvm/scummvm/commit/36405f483f588b6153e617f122834818394329d2
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Make placeStates array always the same size

Else we have some places not defined and errors with transitions

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/saveload.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 3b7c577..ea44442 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -515,11 +515,18 @@ void CryOmni3DEngine_Versailles::setupDialogVariables() {
 }
 
 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) {
-		_placeStates.resize(15);
 		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");
@@ -535,7 +542,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
 		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(1, 14), nullptr);
 	} else if (_currentLevel == 2) {
-		_placeStates.resize(15);
 		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");
@@ -551,7 +557,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
 		SET_PLACE_STATE(14, nullptr, FILTER_EVENT(2, 14), nullptr);
 	} else if (_currentLevel == 3) {
-		_placeStates.resize(25);
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
 		SET_PLACE_STATE(3, nullptr, FILTER_EVENT(3, 3), "VS40");
@@ -577,7 +582,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(23, nullptr, FILTER_EVENT(3, 23), nullptr);
 		SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
 	} else if (_currentLevel == 4) {
-		_placeStates.resize(18);
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
@@ -597,7 +601,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(16, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 5) {
-		_placeStates.resize(35);
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS35");
@@ -634,7 +637,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(33, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(34, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 6) {
-		_placeStates.resize(45);
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS34");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS32");
@@ -681,7 +683,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(43, nullptr, nullptr, "VS33");
 		SET_PLACE_STATE(44, nullptr, nullptr, "VS33");
 	} else if (_currentLevel == 7) {
-		_placeStates.resize(30);
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(2, nullptr, nullptr, nullptr);
@@ -713,7 +714,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
 		SET_PLACE_STATE(29, nullptr, nullptr, nullptr);
 	} else if (_currentLevel == 8) {
-		_placeStates.resize(50);
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index 4ffdaf5..a5ea1a1 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -173,7 +173,7 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
 	out->writeDoubleBE(_omni3dMan.getBeta());
 
 	// Places states
-	assert(_placeStates.size() < 100);
+	assert(_placeStates.size() <= 100);
 	Common::Array<PlaceState>::const_iterator placeIt = _placeStates.begin();
 	for (unsigned int i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
 		out->writeUint32BE(placeIt->state);


Commit: 17887c713e89917db1daf07004079b9f33fb86a7
    https://github.com/scummvm/scummvm/commit/17887c713e89917db1daf07004079b9f33fb86a7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Reset key pressed

Without that we have spurious presses when there is no event

Changed paths:
    engines/cryomni3d/fixed_image.cpp


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index 08bc78e..d4b9f37 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -183,6 +183,7 @@ void ZonFixedImage::manage() {
 	_zoneUse = false;
 	_zoneSpeak = false;
 	_usedObject = nullptr;
+	_key.reset();
 
 	// Force poll events even when we must refresh the cursor
 	if (!_engine.pollEvents() && !_refreshCursor) {


Commit: 91d0f43cbffddf413d6f8abe9c8015ce37482133
    https://github.com/scummvm/scummvm/commit/91d0f43cbffddf413d6f8abe9c8015ce37482133
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add ability to choose ZON file

That's only used for workaround when an unused image file hasn't any ZON
file for it

Changed paths:
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/fixed_image.h


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index d4b9f37..f4e900f 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -65,7 +65,8 @@ void ZonFixedImage::run(const CallbackFunctor *callback) {
 	_imageSurface = nullptr;
 }
 
-void ZonFixedImage::load(const Common::String &image) {
+// 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::String &image, const char *zone) {
 	_imageSurface = nullptr;
 	delete _imageDecoder;
 	_imageDecoder = nullptr;
@@ -76,7 +77,9 @@ void ZonFixedImage::load(const Common::String &image) {
 	}
 	_imageSurface = _imageDecoder->getSurface();
 
-	loadZones(image);
+	const Common::String &zoneFName = zone == nullptr ? image : zone;
+	loadZones(zoneFName);
+
 #if 0
 	// This is not correct but to debug zones I think it's OK
 	Graphics::Surface *tmpSurf = (Graphics::Surface *) _imageSurface;
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 3cabfa3..7321a30 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -69,7 +69,7 @@ public:
 	void display() const;
 
 	/* These functions and attributes are used in image handler */
-	void load(const Common::String &image);
+	void load(const Common::String &image, const char *zone = nullptr);
 	void manage();
 	void updateSurface(const Graphics::Surface *newSurface);
 	const Graphics::Surface *surface() const { return _imageSurface; }


Commit: c18f209c900b8fb2190d799bf5dea50461e1ecc8
    https://github.com/scummvm/scummvm/commit/c18f209c900b8fb2190d799bf5dea50461e1ecc8
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement level 4

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/dialogs.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index ea44442..365afbb 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -582,7 +582,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(23, nullptr, FILTER_EVENT(3, 23), nullptr);
 		SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
 	} else if (_currentLevel == 4) {
-		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
 		SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
 		SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
@@ -591,15 +590,15 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		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, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(10, nullptr, nullptr, "VS18");
+		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, nullptr, "VS31");
-		SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
-		SET_PLACE_STATE(14, nullptr, nullptr, "VS31");
-		SET_PLACE_STATE(15, nullptr, nullptr, "VS36");
-		SET_PLACE_STATE(16, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
+		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) {
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index 580b56e..cd7de6c 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -72,8 +72,9 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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::kUsedPlanVauban1] == 0 ||
-	         _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) {
+	        (!_inventory.inInventoryByNameID(127) ||
+	         _gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
+	         _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -81,8 +82,9 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence
 	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::kUsedPlanVauban1] == 0 ||
-	         _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) {
+	        (!_inventory.inInventoryByNameID(127) ||
+	         _gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
+	         _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
 		displayMessageBoxWarp(18);
 		_gameVariables[GameVariables::kWarnedIncomplete] = 1;
 		return 0;
@@ -148,11 +150,11 @@ void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequenc
 			collectObject(141);
 			playTransitionEndLevel(5);
 		}
-		if (sequence == "52A4_LAC" && _gameVariables[GameVariables::kStatePamphletReligion] != 3 &&
+		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::kStatePamphletReligion] = 3;
+			_gameVariables[GameVariables::kStateLampoonReligion] = 3;
 			collectObject(125);
 			_inventory.deselectObject();
 		}
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index b021a63..d68cfaa 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -611,7 +611,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		// TODO: countdown
 		_inventory.clear();
-	} else if (_currentLevel <= 3) {
+	} else if (_currentLevel <= 4) {
 		// TODO: remove this when we implemented all levels
 	} else {
 		error("New level %d is not implemented (yet)", level);
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 438ae16..44ef651 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -126,14 +126,14 @@ struct GameVariables {
 		kCollectPortfolio, // OK
 		kSketchState, // OK
 		kFakeSketchChatState, // OK
-		kCollectNourriture,
-		kCollectPlume,
-		kStatePamphletReligion,
+		kCollectFood, // OK
+		kCollectQuill, // OK
+		kStateLampoonReligion, // OK
 		kCollectPetiteCle3,
 		kCollectGravure,
 		kCollectCordon,
-		kCollectPlanVauban,            // 20
-		kCollectPlanVauban2,
+		kCollectVaubanBlueprint1, // OK// 20
+		kCollectVaubanBlueprint2, // OK
 		kCollectEchelle,
 		kLostCordon,
 		kDescendreLustre,
@@ -143,7 +143,7 @@ struct GameVariables {
 		kStateBombe,
 		kInkSpilled, // OK
 		kCollectedPaperOnTable, // OK  // 30
-		kCoffreUnlocked,
+		kSafeUnlocked, // OK
 		//kUselessVar,
 		kCollectedPaperInTrunk = 33, // OK
 		kBrushColor, // OK
@@ -151,8 +151,8 @@ struct GameVariables {
 		kUnlockedAttic, // OK
 		kHasPlayedLebrun, // OK
 		kWarnedIncomplete,
-		kUsedPlanVauban1,
-		kUsedPlanVauban2,              // 40
+		kUsedVaubanBlueprint1, // OK
+		kUsedVaubanBlueprint2, // OK   // 40
 		kSeenMemorandum,
 		kCollectScissors, // OK
 		kSavedCountdown, // TODO: calculate it in real time
@@ -397,7 +397,7 @@ private:
 	static const MsgBoxParameters kFixedimageMsgBoxParameters;
 	static const FixedImageConfiguration kFixedImageConfiguration;
 
-	//Objects
+	// Objects
 	template<unsigned int ID>
 	void genericDisplayObject();
 	void obj_105();
@@ -406,6 +406,8 @@ private:
 	void obj_118();
 	void obj_121();
 	void obj_125();
+	void obj_126();
+	void obj_126hk(Graphics::ManagedSurface &surface);
 
 	// Fixed image
 	template<unsigned int ID>
@@ -431,6 +433,27 @@ private:
 	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 unsigned int kSafeDigitsCount = 12;
+	static const unsigned int kSafeDigitsX[];
+	static const unsigned int 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);
@@ -458,6 +481,20 @@ private:
 	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 unsigned int kEpigraphMaxLetters = 32;
+	static const char *kEpigraphContent;
+	static const char *kEpigraphPassword;
+	bool handleEpigraph(ZonFixedImage *fimg);
+	void drawEpigraphLetters(Graphics::ManagedSurface &surface,
+	                         const Graphics::Surface(&bmpLetters)[26], const Common::String &letters);
 
 	IMG_CB(88001);
 	IMG_CB(88001b);
@@ -497,6 +534,13 @@ private:
 	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);
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 2f4555b..e45c574 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -102,8 +102,8 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT(143, 122);
 	SET_OBJECT(101, 123);
 	SET_OBJECT(204, 124);
-	SET_OBJECT(10, 125); // TODO:
-	SET_OBJECT(112, 126); // TODO: EPIL.gif
+	SET_OBJECT_CB(10, 125);
+	SET_OBJECT_CB(112, 126);
 	SET_OBJECT_GENERIC_CB(90, 127, 17);
 	SET_OBJECT(216, 128);
 	SET_OBJECT_GENERIC_CB(32, 129, 18);
@@ -172,13 +172,28 @@ void CryOmni3DEngine_Versailles::obj_121() {
 }
 
 void CryOmni3DEngine_Versailles::obj_125() {
-	if (_gameVariables[GameVariables::kStatePamphletReligion]) {
+	if (_gameVariables[GameVariables::kStateLampoonReligion]) {
 		displayObject(imagesObjects[15]);
 	} else {
 		displayObject(imagesObjects[14]);
 	}
 }
 
+void CryOmni3DEngine_Versailles::obj_126() {
+	displayObject(imagesObjects[16], &CryOmni3DEngine_Versailles::obj_126hk);
+}
+
+void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) {
+	Graphics::Surface bmpLetters[26];
+	loadBMPs("bomb_%02d.bmp", bmpLetters, 26);
+
+	drawEpigraphLetters(surface, bmpLetters, kEpigraphPassword);
+
+	for (unsigned int i = 0; i < 26; i++) {
+		bmpLetters[i].free();
+	}
+}
+
 // This array contains images for all paintings it must be kept in sync with _paintingsTitles
 static const char *imagesPaintings[] = {
 	"10E_1.GIF",      //  0: 41201
@@ -333,8 +348,8 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	SET_SCRIPT_BY_ID(43146);
 	SET_SCRIPT_BY_ID(43160);
 	SET_SCRIPT_BY_ID(43190);
-	//SET_SCRIPT_BY_ID(44071); // TODO: implement it
-	//SET_SCRIPT_BY_ID(44161); // TODO: implement it
+	SET_SCRIPT_BY_ID(44071);
+	SET_SCRIPT_BY_ID(44161);
 	//SET_SCRIPT_BY_ID(45130); // TODO: implement it // Almost dumb
 	//SET_SCRIPT_BY_ID(45270); // TODO: implement it
 	//SET_SCRIPT_BY_ID(45280); // TODO: implement it // Almost dumb
@@ -812,6 +827,397 @@ IMG_CB(32204b) {
 	}
 }
 
+IMG_CB(34131) {
+	fimg->load("43ZA_1.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(34132) {
+	fimg->load("43ZB_2.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(34172) {
+	playInGameVideo("43X3_10");
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+	fimg->_exit = true;
+}
+
+IMG_CB(34173) {
+	fimg->load("43X3_2.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// WORKAROUND: The video doesn't exist there is only a fixed image unused in original game. We will use it.
+			/*
+			playInGameVideo("43X3_21");
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+			    _nextPlaceId = _currentPlaceId;
+			}
+			*/
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34173b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+// WORKAROUND: In original game an empty clickable drawer is displayed
+// Happily for them, when you click on an area and change zones, the next zone
+// under the cursor get activated too (fixed in fixed_image.cpp). So you don't
+// see what happens. You just get the reminder and see the empty drawer.
+IMG_CB(34173b) {
+	// 43X3_21 doesn't have a ZON file, use the one of 43X3_22
+	fimg->load("43X3_21.GIF", "43X3_22.ZON");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse && !_inventory.inInventoryByNameID(129)) {
+			// Collect reminder
+			collectObject(129, fimg);
+			setGameTime(3, 4);
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34173c);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(34173c) {
+	fimg->load("43X3_22.GIF");
+	// WORKAROUND: Drawer is empty, just disable the use zone
+	fimg->disableZone(0);
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(34174) {
+	fimg->load("43X3_42.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Open the door
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34174b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(34174b) {
+	// Door is open but safe is closed
+	fimg->load("43X3_40.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (_gameVariables[GameVariables::kSafeUnlocked]) {
+				// Open the safe
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_34174c);
+				fimg->changeCallback(functor);
+				break;
+			}
+			_dialogsMan["{JOUEUR-ALLER-BUREAU-LOUVOIS}"] = 'Y';
+			if (handleSafe(fimg)) {
+				// Unlocked the safe
+				_gameVariables[GameVariables::kSafeUnlocked] = 1;
+				_dialogsMan["{JOUEUR-ALLER-BUREAU-LOUVOIS}"] = 'N';
+				// Open it
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_34174c);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(34174c) {
+	// Dispatch to the correct state
+	if (_gameVariables[GameVariables::kCollectVaubanBlueprint1] &&
+	        _gameVariables[GameVariables::kCollectVaubanBlueprint2]) {
+		// Safe is empty
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_34174f);
+		fimg->changeCallback(functor);
+		return;
+	}
+	if (!_gameVariables[GameVariables::kCollectVaubanBlueprint1] &&
+	        _gameVariables[GameVariables::kCollectVaubanBlueprint2] == 1) {
+		// Blueprint 1 is there not the 2nd one
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_34174e);
+		fimg->changeCallback(functor);
+		return;
+	}
+	if (_gameVariables[GameVariables::kCollectVaubanBlueprint1] &&
+	        !_gameVariables[GameVariables::kCollectVaubanBlueprint2]) {
+		// Blueprint 2 is there not the 1st one
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_34174d);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	playInGameVideo("cofouv");
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+
+	// Safe has both blueprints
+	fimg->load("43X3_30.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				// Collect 1st blueprint
+				collectObject(131, fimg);
+				_dialogsMan["{JOUEUR-TROUVE-PLANS-VAUBAN}"] = 'Y';
+				_gameVariables[GameVariables::kCollectVaubanBlueprint1] = 1;
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_34174d);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1) {
+				// Collect 2nd blueprint
+				collectObject(132, fimg);
+				_gameVariables[GameVariables::kCollectVaubanBlueprint2] = 1;
+
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_34174e);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(34174d) {
+	// Safe has only blueprint 2
+	fimg->load("43X3_43.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Collect 2nd blueprint
+			collectObject(132, fimg);
+			_gameVariables[GameVariables::kCollectVaubanBlueprint2] = 1;
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34174f);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(34174e) {
+	// Safe has only blueprint 1
+	fimg->load("43X3_41.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Collect 1st blueprint
+			collectObject(131, fimg);
+			_dialogsMan["{JOUEUR-TROUVE-PLANS-VAUBAN}"] = 'Y';
+			_gameVariables[GameVariables::kCollectVaubanBlueprint1] = 1;
+
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34174f);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(34174f) {
+	// Safe is empty
+	fimg->load("43X3_45.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Close safe
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_34174b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) {
+	bool success = false;
+	Common::RandomSource rnd("VersaillesSafe");
+	Graphics::Surface bmpDigits[10];
+	unsigned char safeDigits[kSafeDigitsCount];
+	Graphics::ManagedSurface tempSurf;
+
+	loadBMPs("coff_%02d.bmp", bmpDigits, 10);
+	for (unsigned int i = 0; i < kSafeDigitsCount; i++) {
+		safeDigits[i] = rnd.getRandomNumber(9);
+	}
+
+	fimg->load("43x3_cof.GIF");
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawSafeDigits(tempSurf, bmpDigits, safeDigits);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 15) {
+				// Safe handle
+
+				// Animate handle
+				playInGameVideo("43x3_poi");
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+
+				// Redraw our safe image
+				fimg->display();
+
+				if (checkSafeDigits(safeDigits)) {
+					success = true;
+					break;
+				}
+			} else if (fimg->_currentZone < kSafeDigitsCount) {
+				// Safe digit
+				safeDigits[fimg->_currentZone] = (safeDigits[fimg->_currentZone] + 1) % 10;
+				// Reset the surface and redraw digits on it
+				tempSurf.blitFrom(*fimgSurface);
+				drawSafeDigits(tempSurf, bmpDigits, safeDigits);
+				fimg->updateSurface(&tempSurf.rawSurface());
+
+				waitMouseRelease();
+			}
+		}
+	}
+
+	for (unsigned int i = 0; i < 10; i++) {
+		bmpDigits[i].free();
+	}
+	return success;
+}
+
+const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 };
+const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 };
+
+void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surface,
+        const Graphics::Surface(&bmpDigits)[10], const unsigned char (&safeDigits)[kSafeDigitsCount]) {
+	for (unsigned int i = 0; i < ARRAYSIZE(safeDigits); i++) {
+		const Graphics::Surface &digit = bmpDigits[safeDigits[i]];
+		Common::Point dst(kSafeDigitsX[i % 4], kSafeDigitsY[i / 4]);
+		surface.transBlitFrom(digit, dst);
+	}
+}
+
+const char *CryOmni3DEngine_Versailles::kSafeDates[] = { "1643", "1668", "1674" };
+bool CryOmni3DEngine_Versailles::checkSafeDigits(unsigned char (&safeDigits)[kSafeDigitsCount]) {
+	unsigned int dateChecked;
+	for (dateChecked = 0; dateChecked < ARRAYSIZE(kSafeDates); dateChecked++) {
+		const char *checkDate = kSafeDates[dateChecked];
+		// Find the date in one of safe digits lines
+		unsigned int line;
+		for (line = 0; line < kSafeDigitsCount; line += 4) {
+			unsigned int digit;
+			for (digit = 0; digit < 4; digit++) {
+				if (safeDigits[line + digit] != checkDate[digit] - '0') {
+					break;
+				}
+			}
+			if (digit == 4) {
+				// Check was a success: go to next date
+				break;
+			}
+			// Failure: try next line
+		}
+		if (line >= kSafeDigitsCount) {
+			// All lines were tested and none had the date: failure
+			return false;
+		}
+	}
+	// All dates were found
+	return true;
+}
+
 IMG_CB(41202) {
 	fimg->load("10E_20.GIF");
 	while (1) {
@@ -1653,28 +2059,323 @@ IMG_CB(43190f) {
 	}
 }
 
-IMG_CB(88001) {
-	if (!_inventory.inInventoryByNameID(121) &&
-	        _gameVariables[GameVariables::kMedalsDrawerStatus] == 3) {
+IMG_CB(44071) {
+	// Dispatch to the correct state
+	if (_gameVariables[GameVariables::kCollectFood]) {
+		// Draw plate with less food
 		ZonFixedImage::CallbackFunctor *functor =
 		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
-		            &CryOmni3DEngine_Versailles::img_88001c);
+		            &CryOmni3DEngine_Versailles::img_44071b);
 		fimg->changeCallback(functor);
 		return;
 	}
 
-	fimg->load("33P_10.GIF");
-	if (_inventory.inInventoryByNameID(121)) {
-		fimg->disableZone(0);
-	}
+	// There we have a full plate
+	fimg->load("41B_bboy.GIF");
 	while (1) {
 		fimg->manage();
 		if (fimg->_exit || fimg->_zoneLow) {
 			fimg->_exit = true;
 			break;
 		}
-		if (fimg->_zoneUse &&
-		        !_inventory.inInventoryByNameID(121)) {
+		if (fimg->_zoneUse) {
+			// Collected food
+			collectObject(124, fimg);
+			_gameVariables[GameVariables::kCollectFood] = 1;
+			// Draw plate with less food
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44071b);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44071b) {
+	// There we have less food on plate
+	fimg->load("41B_bbo2.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(44161) {
+	// Dispatch to the correct state
+	if (_gameVariables[GameVariables::kCollectQuill] == 1 && !_inventory.inInventoryByNameID(126)) {
+		// We have collected quill but not solved epigraph yet
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_44161b);
+		fimg->changeCallback(functor);
+		return;
+	} else if (_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 1 &&
+	           _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 1) {
+		// We have used vauban blueprints: display the solution
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_44161f);
+		fimg->changeCallback(functor);
+		return;
+	} else if (_gameVariables[GameVariables::kCollectQuill] == 1 &&
+	           _inventory.inInventoryByNameID(126)) {
+		// We have collected quill and epigraph
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_44161c);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	// There we have blueprints, quill and epigraph on desk
+	fimg->load("42X2_20.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse && fimg->_currentZone == 0 && currentGameTime() >= 2) {
+			// Collected quill
+			collectObject(128, fimg);
+			_gameVariables[GameVariables::kCollectQuill] = 1;
+			// Try to solve epigraph
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161b);
+			fimg->changeCallback(functor);
+			break;
+		} else if (fimg->_zoneSee) {
+			// Look at blueprints
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44161b) {
+	// There we have blueprints and epigraph on desk.
+	fimg->load("42X2_10.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 128 && fimg->_currentZone == 1) {
+			if (handleEpigraph(fimg)) {
+				// Epigraph is solved
+				_inventory.removeByNameID(128);
+				collectObject(126, fimg, false);
+				_dialogsMan["{JOUEUR_POSSEDE_EPIGRAPHE}"] = 'Y';
+				setPlaceState(16, 2);
+				// No more epigraphe nor quill
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_44161c);
+				fimg->changeCallback(functor);
+			}
+			// If failed to solve: just display this image again
+			break;
+		} else if (fimg->_zoneSee) {
+			// Look at blueprints
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44161c) {
+	// There we have no quill nor epigraph anymore
+	fimg->load("42X2_11.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneSee) {
+			// Look at blueprints
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161d);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44161d) {
+	// Look at blueprints
+	fimg->load("VAU1.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 131) {
+			// Overlay blueprints
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161e);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44161e) {
+	// Look at blueprints
+	fimg->load("VAUB22.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 132) {
+			// Overlay blueprints
+			_gameVariables[GameVariables::kUsedVaubanBlueprint1] = 1;
+			_gameVariables[GameVariables::kUsedVaubanBlueprint2] = 1;
+			_inventory.removeByNameID(131);
+			_inventory.removeByNameID(132);
+			setGameTime(4, 4);
+			// Look at the final result
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_44161f);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(44161f) {
+	// Look at blueprints result
+	fimg->load("VAU.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+bool CryOmni3DEngine_Versailles::handleEpigraph(ZonFixedImage *fimg) {
+	bool success = false;
+	Graphics::Surface bmpLetters[26];
+	Common::String password;
+	Graphics::ManagedSurface tempSurf;
+
+	loadBMPs("bomb_%02d.bmp", bmpLetters, 26);
+
+	fimg->load("EPIL.GIF");
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	// No need to customize image yet
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (password.size() >= kEpigraphMaxLetters) {
+				continue;
+			}
+			// Find which letter got clicked
+			char letter = kEpigraphContent[fimg->_currentZone];
+			password += letter;
+			// Reset the surface and redraw digits on it
+			tempSurf.blitFrom(*fimgSurface);
+			drawEpigraphLetters(tempSurf, bmpLetters, password);
+			fimg->updateSurface(&tempSurf.rawSurface());
+
+			waitMouseRelease();
+		} else if (fimg->_key.keycode) {
+			Common::KeyCode keyCode = fimg->_key.keycode;
+			if (keyCode == Common::KEYCODE_BACKSPACE) {
+				password.deleteLastChar();
+			} else {
+				if (password.size() >= kEpigraphMaxLetters) {
+					continue;
+				}
+				if (keyCode >= Common::KEYCODE_a &&
+				        keyCode <= Common::KEYCODE_z &&
+				        strchr(kEpigraphContent, keyCode - Common::KEYCODE_a + 'A')) {
+					password += keyCode - Common::KEYCODE_a + 'A';
+				} else {
+					continue;
+				}
+			}
+			// Reset the surface and redraw digits on it
+			tempSurf.blitFrom(*fimgSurface);
+			drawEpigraphLetters(tempSurf, bmpLetters, password);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+
+		if (password == kEpigraphPassword) {
+			success = true;
+			break;
+		}
+	}
+
+	for (unsigned int i = 0; i < 26; i++) {
+		bmpLetters[i].free();
+	}
+	return success;
+}
+
+const char *CryOmni3DEngine_Versailles::kEpigraphContent = "FELIXFORTUNADIVINUMEXPLORATUMACTUIIT";
+const char *CryOmni3DEngine_Versailles::kEpigraphPassword = "LELOUPETLATETE";
+
+void CryOmni3DEngine_Versailles::drawEpigraphLetters(Graphics::ManagedSurface &surface,
+        const Graphics::Surface(&bmpLetters)[26], const Common::String &letters) {
+	for (unsigned int i = 0; i < letters.size() && i < kEpigraphMaxLetters; i++) {
+		unsigned int letterId = 0;
+		if (letters[i] >= 'A' && letters[i] <= 'Z') {
+			letterId = letters[i] - 'A';
+		}
+		const Graphics::Surface &letter = bmpLetters[letterId];
+		Common::Point dst(34 * i + 4, 380);
+		surface.transBlitFrom(letter, dst);
+	}
+}
+
+IMG_CB(88001) {
+	if (!_inventory.inInventoryByNameID(121) &&
+	        _gameVariables[GameVariables::kMedalsDrawerStatus] == 3) {
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+		            &CryOmni3DEngine_Versailles::img_88001c);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	fimg->load("33P_10.GIF");
+	if (_inventory.inInventoryByNameID(121)) {
+		fimg->disableZone(0);
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse &&
+		        !_inventory.inInventoryByNameID(121)) {
 			// Open the drawer
 
 			playInGameVideo("33P_10");
@@ -2562,6 +3263,174 @@ void CryOmni3DEngine_Versailles::collectLampoonArchitecture(const ZonFixedImage
 	_dialogsMan["{JOUEUR_POSSEDE_PAMPHLET_ARCHI}"] = 'Y';
 }
 
+INIT_PLACE(4, 9) {
+	if (currentGameTime() == 4 && !_inventory.inInventoryByNameID(125)) {
+		_dialogsMan.play("4_MAI");
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+	}
+}
+
+FILTER_EVENT(4, 10) {
+	if (*event == 24104 && _inventory.selectedObject()) {
+		_dialogsMan["{JOUEUR-PRESENTE-OBJET-HUISSIER}"] = 'Y';
+		_dialogsMan.play("41C_HUI");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-PRESENTE-OBJET-HUISSIER}"] = 'N';
+		_inventory.deselectObject();
+		return true;
+	} else if (*event == 24105 && _inventory.selectedObject()) {
+		if (_inventory.selectedObject()->idOBJ() == 127) {
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}"] = 'Y';
+		} else if (_inventory.selectedObject()->idOBJ() == 125) {
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
+		} else if (_inventory.selectedObject()->idOBJ() == 126) {
+			_dialogsMan["{JOUEUR-MONTRE-PAPIER-CROISSY}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+		_dialogsMan.play("42C_BON");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-PAPIER-CROISSY}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+		_inventory.deselectObject();
+		return true;
+	} else if (*event == 11 && currentGameTime() < 3) {
+		// Closed
+		displayMessageBoxWarp(2);
+		return false;
+	} else {
+		return true;
+	}
+}
+
+FILTER_EVENT(4, 12_13_14) {
+	if (*event != 34131 && *event != 34132) {
+		// Not for us
+		return true;
+	}
+
+	if (!_inventory.selectedObject() ||
+	        _inventory.selectedObject()->idOBJ() != 130) {
+		// Not using scope: do nothing
+		return false;
+	}
+
+	// Using scope
+	const char *video;
+	FixedImgCallback callback;
+
+	if (*event == 34131) {
+		video = "43ZA_1";
+		callback = &CryOmni3DEngine_Versailles::img_34131;
+	} else if (*event == 34132) {
+		video = "43ZB_2";
+		callback = &CryOmni3DEngine_Versailles::img_34132;
+	}
+
+	playInGameVideo(video);
+
+	// Force reload of the place
+	if (_nextPlaceId == -1u) {
+		_nextPlaceId = _currentPlaceId;
+	}
+
+	handleFixedImg(callback);
+
+	// Don't pass the event: it has been handled
+	return false;
+}
+
+FILTER_EVENT(4, 15) {
+	if (*event == 17 && (_dialogsMan["BONTEMPS-VU-PAPIER-CROISSY"] == 'N' ||
+	                     _dialogsMan["BONTEMPS-VU-PAMPHLET-GOUVERNEMENT"] == 'N')) {
+		// Closed
+		displayMessageBoxWarp(2);
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(4, 16) {
+	if (*event == 24161 && _inventory.selectedObject()) {
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 124) {
+			_dialogsMan["{JOUEUR-DONNE-REPAS}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+		_dialogsMan.play("41X2_CRO");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-DONNE-REPAS}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+
+		if (idOBJ == 124) {
+			_inventory.removeByNameID(124);
+			playInGameVideo("41X2_CR1");
+			setGameTime(2, 4);
+		}
+		_inventory.deselectObject();
+		return true;
+	} else if (*event == 34162) {
+		if (!_inventory.inInventoryByNameID(127)) {
+			collectObject(127);
+			_forcePaletteUpdate = true;
+		} else {
+			// Nothing there anymore
+			displayMessageBoxWarp(21);
+		}
+
+		// Don't pass the event: it has been handled
+		return false;
+	}
+	return true;
+}
+
+FILTER_EVENT(4, 17) {
+	if (*event == 34171) {
+		collectObject(130);
+		setPlaceState(17, 1);
+		return false;
+	} else if (*event == 34172) {
+		unsigned int fakePlaceId = getFakeTransition(*event);
+		fakeTransition(fakePlaceId);
+		handleFixedImg(&CryOmni3DEngine_Versailles::img_34172);
+		return false;
+	} else if (*event == 34173) {
+		handleFixedImg(&CryOmni3DEngine_Versailles::img_34173);
+		return false;
+	} else if (*event == 34174) {
+		handleFixedImg(&CryOmni3DEngine_Versailles::img_34174);
+		return false;
+	}
+
+	return true;
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: adf6ab006cc7b2031f428cf166d0aeaebd3342b7
    https://github.com/scummvm/scummvm/commit/adf6ab006cc7b2031f428cf166d0aeaebd3342b7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Use fabs instead of abs

This should correct LLVM warning

Changed paths:
    engines/cryomni3d/omni3d.cpp
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/omni3d.cpp b/engines/cryomni3d/omni3d.cpp
index 5c6d6db..d0169a4 100644
--- a/engines/cryomni3d/omni3d.cpp
+++ b/engines/cryomni3d/omni3d.cpp
@@ -90,10 +90,10 @@ void Omni3DManager::updateCoords(int xDelta, int yDelta, bool useOldSpeed) {
 	_ySpeed *= 0.6;
 
 	if (useOldSpeed) {
-		if (abs(_xSpeed) < 0.001) {
+		if (fabs(_xSpeed) < 0.001) {
 			_xSpeed = 0.;
 		}
-		if (abs(_ySpeed) < 0.001) {
+		if (fabs(_ySpeed) < 0.001) {
 			_ySpeed = 0.;
 		}
 	}
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index d68cfaa..87967cc 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1322,7 +1322,7 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 		// TODO: countdown
 		g_system->updateScreen();
 
-		if (abs(oldDeltaAlpha - deltaAlpha) < 0.001 && abs(oldDeltaBeta - deltaBeta) < 0.001) {
+		if (fabs(oldDeltaAlpha - deltaAlpha) < 0.001 && fabs(oldDeltaBeta - deltaBeta) < 0.001) {
 			exit = true;
 		}
 		oldDeltaAlpha = deltaAlpha;


Commit: bdc6969ea4982363f5d698f62ee6f0f72a9c6a82
    https://github.com/scummvm/scummvm/commit/bdc6969ea4982363f5d698f62ee6f0f72a9c6a82
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove unused private members

This should remove LLVM warnings

Changed paths:
    engines/cryomni3d/image/codecs/hlz.h
    engines/cryomni3d/video/hnm_decoder.cpp
    engines/cryomni3d/video/hnm_decoder.h


diff --git a/engines/cryomni3d/image/codecs/hlz.h b/engines/cryomni3d/image/codecs/hlz.h
index 4ec8d3e..d8edc63 100644
--- a/engines/cryomni3d/image/codecs/hlz.h
+++ b/engines/cryomni3d/image/codecs/hlz.h
@@ -45,7 +45,6 @@ public:
 private:
 	Graphics::Surface *_surface;
 	int _width, _height;
-	int _bitsPerPixel;
 };
 
 } // End of namespace Image
diff --git a/engines/cryomni3d/video/hnm_decoder.cpp b/engines/cryomni3d/video/hnm_decoder.cpp
index 1e52744..355345b 100644
--- a/engines/cryomni3d/video/hnm_decoder.cpp
+++ b/engines/cryomni3d/video/hnm_decoder.cpp
@@ -337,8 +337,8 @@ void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *st
 }
 
 HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, unsigned int sampleRate,
-        Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _channels(channels), _bits(bits),
-	_audioStream(nullptr), _gotLUT(false), _lastSample(0) {
+        Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _audioStream(nullptr),
+	_gotLUT(false), _lastSample(0) {
 	if (bits != 16) {
 		error("Unsupported audio bits");
 	}
diff --git a/engines/cryomni3d/video/hnm_decoder.h b/engines/cryomni3d/video/hnm_decoder.h
index 681dd87..b09026b 100644
--- a/engines/cryomni3d/video/hnm_decoder.h
+++ b/engines/cryomni3d/video/hnm_decoder.h
@@ -106,8 +106,6 @@ private:
 	protected:
 		Audio::AudioStream *getAudioStream() const { return _audioStream; }
 	private:
-		uint16 _channels;
-		uint16 _bits;
 		Audio::QueuingAudioStream *_audioStream;
 		bool _gotLUT;
 		uint16 _lut[256];


Commit: 96978b207948502fc2da763627cc1964460498f2
    https://github.com/scummvm/scummvm/commit/96978b207948502fc2da763627cc1964460498f2
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Avoid LLVM warnings on the logic

The ifs should always be taken but better be safe

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index e45c574..68f5bc4 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -2629,6 +2629,8 @@ FILTER_EVENT(1, 14) {
 		} else if (*event == 31143) {
 			video = "10D2_3";
 			callback = &CryOmni3DEngine_Versailles::img_31143;
+		} else {
+			error("BUG: Shouldn't be here");
 		}
 	} else if (_currentLevel == 2 || _placeStates[14].state == 1) {
 		if (*event == 31142) {
@@ -2637,6 +2639,8 @@ FILTER_EVENT(1, 14) {
 		} else if (*event == 31143) {
 			video = "11D2_1";
 			callback = &CryOmni3DEngine_Versailles::img_31143b;
+		} else {
+			error("BUG: Shouldn't be here");
 		}
 	} else {
 		error("Invalid state in filter event 1/14: level: %d/ placeState: %d", _currentLevel,
@@ -3343,6 +3347,8 @@ FILTER_EVENT(4, 12_13_14) {
 	} else if (*event == 34132) {
 		video = "43ZB_2";
 		callback = &CryOmni3DEngine_Versailles::img_34132;
+	} else {
+		error("BUG: Shouldn't be here");
 	}
 
 	playInGameVideo(video);


Commit: 807c4c52477ffb30860a8d7e5a7350a8fc8b5def
    https://github.com/scummvm/scummvm/commit/807c4c52477ffb30860a8d7e5a7350a8fc8b5def
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Save savegames list offset in settings

Changed paths:
    engines/cryomni3d/versailles/menus.cpp


diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index da212ea..f052cd7 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -593,7 +593,8 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 
 	setCursor(181);
 
-	unsigned int fileListOffset = 0; // TODO: store in config
+	unsigned int fileListOffset = CLIP(ConfMan.getInt(_isVisiting ? "visits_list_off" :
+	                                   "saves_list_off"), 0, 100 - 6);
 
 	unsigned int boxHovered = -1;
 	unsigned int boxSelected = -1;
@@ -796,7 +797,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 	}
 	if (boxSelected != -1u) {
 		saveName = savesList[boxSelected + fileListOffset];
-		// TODO: save list offset
+		ConfMan.setInt(_isVisiting ? "visits_list_off" : "saves_list_off", fileListOffset);
 		return boxSelected + fileListOffset + 1;
 	} else {
 		return -1;


Commit: 995b10e71ec9a69a30bab5bbe4da2cf44f3befa0
    https://github.com/scummvm/scummvm/commit/995b10e71ec9a69a30bab5bbe4da2cf44f3befa0
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix surface not reloaded after finished with safe

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 68f5bc4..5cf2354 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -974,6 +974,8 @@ IMG_CB(34174b) {
 				fimg->changeCallback(functor);
 				break;
 			}
+			// If failed to solve: just display this image again
+			break;
 		}
 	}
 }


Commit: 67e76c3b566f9ba8eb378644d935c6f06b32b675
    https://github.com/scummvm/scummvm/commit/67e76c3b566f9ba8eb378644d935c6f06b32b675
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Forgot to deselect object after talking to Bontemps

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 5cf2354..45a0d2e 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -2695,6 +2695,7 @@ FILTER_EVENT(2, 1) {
 			_inventory.removeByNameID(98);
 			setGameTime(2, 2);
 		}
+		_inventory.deselectObject();
 	} else if (*event == 31101) {
 		if (!_inventory.selectedObject() && currentGameTime() > 1) {
 			const char *video;


Commit: 07011e4fc7f617b70437625d1e5f610f6cad87a1
    https://github.com/scummvm/scummvm/commit/07011e4fc7f617b70437625d1e5f610f6cad87a1
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove almost dumb images

There is no such thing, an image is either handled by template or by its
specific handler and in this case we don't store its name in the array

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 45a0d2e..5c66720 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -247,23 +247,21 @@ static const char *imagesPaintings[] = {
 	// Now let's put dumb images, those without description and any special action, they are not synced with _paintingsTitles
 	"30Q_1.GIF",      // 48: 43060
 	"30Q_2.GIF",      // 49: 43061
-	"52M2.GIF",       // 50: 45130 // Almost dumb
-	"53I_LUST.GIF",   // 51: 45280 // Almost dumb
-	"DUC.GIF",        // 52: 46001
-	"COQ.GIF",        // 53: 46002
-	"CHAT.GIF",       // 54: 46003
-	"DRAGON.GIF",     // 55: 46004
-	"GRUE.GIF",       // 56: 46005
-	"RENARD.GIF",     // 57: 46006
-	"POULE.GIF",      // 58: 46007
-	"LOUP.GIF",       // 59: 46008
-	"MILAN.GIF",      // 60: 46009
-	"GRENOU.GIF",     // 61: 46010
-	"AIGLE.GIF",      // 62: 46011
-	"SOURIS.GIF",     // 63: 46012
-	"CYGNE.GIF",      // 64: 46013 and 46440
-	"LOUPTETE.GIF",   // 65: 46014
-	"CANNES.GIF",     // 66: 46015
+	"DUC.GIF",        // 50: 46001
+	"COQ.GIF",        // 51: 46002
+	"CHAT.GIF",       // 52: 46003
+	"DRAGON.GIF",     // 53: 46004
+	"GRUE.GIF",       // 54: 46005
+	"RENARD.GIF",     // 55: 46006
+	"POULE.GIF",      // 56: 46007
+	"LOUP.GIF",       // 57: 46008
+	"MILAN.GIF",      // 58: 46009
+	"GRENOU.GIF",     // 59: 46010
+	"AIGLE.GIF",      // 60: 46011
+	"SOURIS.GIF",     // 61: 46012
+	"CYGNE.GIF",      // 62: 46013 and 46440
+	"LOUPTETE.GIF",   // 63: 46014
+	"CANNES.GIF",     // 64: 46015
 };
 
 // Setup array for all see actions
@@ -324,22 +322,22 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 #define SET_SCRIPT_BY_DUMB(id, image) _imgScripts[id] = &CryOmni3DEngine_Versailles::genericDumbImage<image>
 	SET_SCRIPT_BY_DUMB(43060, 48);
 	SET_SCRIPT_BY_DUMB(43061, 49);
-	SET_SCRIPT_BY_DUMB(46001, 52);
-	SET_SCRIPT_BY_DUMB(46002, 53);
-	SET_SCRIPT_BY_DUMB(46003, 54);
-	SET_SCRIPT_BY_DUMB(46004, 55);
-	SET_SCRIPT_BY_DUMB(46005, 56);
-	SET_SCRIPT_BY_DUMB(46006, 57);
-	SET_SCRIPT_BY_DUMB(46007, 58);
-	SET_SCRIPT_BY_DUMB(46008, 59);
-	SET_SCRIPT_BY_DUMB(46009, 60);
-	SET_SCRIPT_BY_DUMB(46010, 61);
-	SET_SCRIPT_BY_DUMB(46011, 62);
-	SET_SCRIPT_BY_DUMB(46012, 63);
-	SET_SCRIPT_BY_DUMB(46013, 64);
-	SET_SCRIPT_BY_DUMB(46014, 65);
-	SET_SCRIPT_BY_DUMB(46015, 66);
-	SET_SCRIPT_BY_DUMB(46440, 64); // Same as 46013
+	SET_SCRIPT_BY_DUMB(46001, 50);
+	SET_SCRIPT_BY_DUMB(46002, 51);
+	SET_SCRIPT_BY_DUMB(46003, 52);
+	SET_SCRIPT_BY_DUMB(46004, 53);
+	SET_SCRIPT_BY_DUMB(46005, 54);
+	SET_SCRIPT_BY_DUMB(46006, 55);
+	SET_SCRIPT_BY_DUMB(46007, 56);
+	SET_SCRIPT_BY_DUMB(46008, 57);
+	SET_SCRIPT_BY_DUMB(46009, 58);
+	SET_SCRIPT_BY_DUMB(46010, 59);
+	SET_SCRIPT_BY_DUMB(46011, 60);
+	SET_SCRIPT_BY_DUMB(46012, 61);
+	SET_SCRIPT_BY_DUMB(46013, 62);
+	SET_SCRIPT_BY_DUMB(46014, 63);
+	SET_SCRIPT_BY_DUMB(46015, 64);
+	SET_SCRIPT_BY_DUMB(46440, 62); // Same as 46013
 #undef SET_SCRIPT_BY_DUMB
 	// From now specific handlers for anything that is not a painting
 	SET_SCRIPT_BY_ID(41801);
@@ -350,9 +348,9 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	SET_SCRIPT_BY_ID(43190);
 	SET_SCRIPT_BY_ID(44071);
 	SET_SCRIPT_BY_ID(44161);
-	//SET_SCRIPT_BY_ID(45130); // TODO: implement it // Almost dumb
+	//SET_SCRIPT_BY_ID(45130); // TODO: implement it
 	//SET_SCRIPT_BY_ID(45270); // TODO: implement it
-	//SET_SCRIPT_BY_ID(45280); // TODO: implement it // Almost dumb
+	//SET_SCRIPT_BY_ID(45280); // TODO: implement it
 	SET_SCRIPT_BY_ID(88001);
 	//SET_SCRIPT_BY_ID(88002); // TODO: implement it
 	//SET_SCRIPT_BY_ID(88003); // TODO: implement it


Commit: bf123ad630db8c9a673c5616d38768674b6844dc
    https://github.com/scummvm/scummvm/commit/bf123ad630db8c9a673c5616d38768674b6844dc
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement level 5

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 365afbb..7660f7e 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -600,41 +600,40 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(16, nullptr, FILTER_EVENT(4, 16), nullptr);
 		SET_PLACE_STATE(17, nullptr, FILTER_EVENT(4, 17), nullptr);
 	} else if (_currentLevel == 5) {
-		// TODO: implement functions
 		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, nullptr, nullptr, "VS30");
+		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, nullptr, "VS39");
+		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, nullptr, "VS26");
-		SET_PLACE_STATE(15, nullptr, nullptr, "VS25");
-		SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
+		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, 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, 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, nullptr, "VS16");
-		SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(29, nullptr, nullptr, "VS24");
+		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, nullptr, nullptr);
-		SET_PLACE_STATE(34, 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) {
 		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, "VS34");
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 87967cc..46d308f 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -611,7 +611,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		// TODO: countdown
 		_inventory.clear();
-	} else if (_currentLevel <= 4) {
+	} else if (_currentLevel <= 5) {
 		// TODO: remove this when we implemented all levels
 	} else {
 		error("New level %d is not implemented (yet)", level);
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 44ef651..8911151 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -129,14 +129,14 @@ struct GameVariables {
 		kCollectFood, // OK
 		kCollectQuill, // OK
 		kStateLampoonReligion, // OK
-		kCollectPetiteCle3,
-		kCollectGravure,
-		kCollectCordon,
+		kCollectSmallKey3, // OK
+		kCollectEngraving, // OK
+		kCollectCord, // OK
 		kCollectVaubanBlueprint1, // OK// 20
 		kCollectVaubanBlueprint2, // OK
-		kCollectEchelle,
-		kLostCordon,
-		kDescendreLustre,
+		kLadderState, // OK
+		kOpenedCurtain, // OK
+		kLoweredChandelier, // OK
 		kOrangerRatisse,
 		kDiscussedLabyrOrder,
 		kUsedBougieAllumee,
@@ -153,7 +153,7 @@ struct GameVariables {
 		kWarnedIncomplete,
 		kUsedVaubanBlueprint1, // OK
 		kUsedVaubanBlueprint2, // OK   // 40
-		kSeenMemorandum,
+		kSeenMemorandum, // OK
 		kCollectScissors, // OK
 		kSavedCountdown, // TODO: calculate it in real time
 		kMax
@@ -489,6 +489,12 @@ private:
 	IMG_CB(44161d);
 	IMG_CB(44161e);
 	IMG_CB(44161f);
+	IMG_CB(45130);
+	IMG_CB(45270);
+	IMG_CB(45270b);
+	IMG_CB(45270c);
+	IMG_CB(45270d);
+	IMG_CB(45280);
 	static const unsigned int kEpigraphMaxLetters = 32;
 	static const char *kEpigraphContent;
 	static const char *kEpigraphPassword;
@@ -499,6 +505,7 @@ private:
 	IMG_CB(88001);
 	IMG_CB(88001b);
 	IMG_CB(88001c);
+	IMG_CB(88002);
 	IMG_CB(88004);
 	IMG_CB(88004b);
 #undef IMG_CB
@@ -541,6 +548,20 @@ private:
 	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);
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 5c66720..2ffd925 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -348,11 +348,11 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	SET_SCRIPT_BY_ID(43190);
 	SET_SCRIPT_BY_ID(44071);
 	SET_SCRIPT_BY_ID(44161);
-	//SET_SCRIPT_BY_ID(45130); // TODO: implement it
-	//SET_SCRIPT_BY_ID(45270); // TODO: implement it
-	//SET_SCRIPT_BY_ID(45280); // TODO: implement it
+	SET_SCRIPT_BY_ID(45130);
+	SET_SCRIPT_BY_ID(45270);
+	SET_SCRIPT_BY_ID(45280);
 	SET_SCRIPT_BY_ID(88001);
-	//SET_SCRIPT_BY_ID(88002); // TODO: implement it
+	SET_SCRIPT_BY_ID(88002);
 	//SET_SCRIPT_BY_ID(88003); // TODO: implement it
 	SET_SCRIPT_BY_ID(88004);
 #undef SET_SCRIPT_BY_ID
@@ -2354,6 +2354,136 @@ void CryOmni3DEngine_Versailles::drawEpigraphLetters(Graphics::ManagedSurface &s
 	}
 }
 
+IMG_CB(45130) {
+	fimg->load("52M2.GIF");
+	_dialogsMan["{JOUEUR-VU-PLANS-SALON-DIANE}"] = 'Y';
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+	}
+}
+
+IMG_CB(45270) {
+	fimg->load("51A4_11.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone == 0) {
+				// Open left drawer
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_45270b);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 1) {
+				// Open middle drawer
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_45270c);
+				fimg->changeCallback(functor);
+				break;
+			} else if (fimg->_currentZone == 2) {
+				// Open right drawer
+				ZonFixedImage::CallbackFunctor *functor =
+				    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+				            &CryOmni3DEngine_Versailles::img_45270d);
+				fimg->changeCallback(functor);
+				break;
+			}
+		}
+	}
+}
+
+IMG_CB(45270b) {
+	fimg->load("51A4_22.GIF");
+	if (!_gameVariables[GameVariables::kCollectSmallKey3]) {
+		// Collected small key 3
+		collectObject(135, fimg);
+		_gameVariables[GameVariables::kCollectSmallKey3] = 1;
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Close drawer
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_45270);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(45270c) {
+	fimg->load("51A4_32.GIF");
+	if (!_gameVariables[GameVariables::kCollectEngraving]) {
+		// Collected engraving
+		collectObject(134, fimg);
+		_gameVariables[GameVariables::kCollectEngraving] = 1;
+	}
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Close drawer
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_45270);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(45270d) {
+	fimg->load("51A4_12.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			// Close drawer
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_45270);
+			fimg->changeCallback(functor);
+			break;
+		}
+	}
+}
+
+IMG_CB(45280) {
+	if (_gameVariables[GameVariables::kOpenedCurtain]) {
+		fimg->load("53I_LUST.GIF");
+		_gameVariables[GameVariables::kSeenMemorandum] = 1;
+		while (1) {
+			fimg->manage();
+			if (fimg->_exit || fimg->_zoneLow) {
+				fimg->_exit = true;
+				break;
+			}
+		}
+	} else {
+		fimg->_exit = true;
+	}
+}
+
 IMG_CB(88001) {
 	if (!_inventory.inInventoryByNameID(121) &&
 	        _gameVariables[GameVariables::kMedalsDrawerStatus] == 3) {
@@ -2461,6 +2591,25 @@ IMG_CB(88001c) {
 	}
 }
 
+IMG_CB(88002) {
+	fimg->load("53Z1c_10.GIF");
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (_currentLevel == 7) {
+				// You will need something to reach the bomb
+				displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 10,
+				                  fimg->getZoneCenter(fimg->_currentZone),
+				                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+			}
+		}
+	}
+}
+
 IMG_CB(88004) {
 	fimg->load("31j31.gif");
 	while (1) {
@@ -3438,6 +3587,345 @@ FILTER_EVENT(4, 17) {
 	return true;
 }
 
+INIT_PLACE(5, 6) {
+	if (currentGameTime() == 2) {
+		setPlaceState(27, 2);
+	}
+}
+
+FILTER_EVENT(5, 9) {
+	if (*event == 25090 && _inventory.selectedObject()) {
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (currentGameTime() < 4) {
+			if (idOBJ == 125 && _gameVariables[GameVariables::kStateLampoonReligion] == 3) {
+				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
+			} else if (idOBJ == 115) {
+				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'Y';
+			} else {
+				_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+			}
+
+			_dialogsMan.play("53N_BON");
+
+			_forcePaletteUpdate = true;
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			if (_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] == 'Y' && currentGameTime() != 3) {
+				setGameTime(3, 5);
+				_inventory.removeByNameID(125);
+			}
+
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'N';
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'N';
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+
+			_inventory.deselectObject();
+		} else {
+			if (_inventory.inInventoryByNameID(135) && _inventory.inInventoryByNameID(116)) {
+				_dialogsMan["{JOUEUR-POSSEDE-CLEF-3-ET-4}"] = 'Y';
+			}
+			// Useless?
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+
+			if (idOBJ == 137) {
+				_dialogsMan["{JOUEUR-MONTRE-MEMORANDUM}"] = 'Y';
+			} else {
+				_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+			}
+
+			_dialogsMan.play("54I_BON");
+
+			_forcePaletteUpdate = true;
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			_dialogsMan["{JOUEUR-MONTRE-MEMORANDUM}"] = 'N';
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+
+			_inventory.deselectObject();
+		}
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 14) {
+	if (*event == 25142 && _inventory.selectedObject()) {
+		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		if (idOBJ == 125) {
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
+		} else {
+			_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y';
+		}
+
+		_dialogsMan.play("52L_BOU");
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'N';
+		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
+		_inventory.deselectObject();
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 15) {
+	if (*event == 16 && _gameVariables[GameVariables::kLoweredChandelier]) {
+		*event = 29;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 16) {
+	if (*event == 35162) {
+		// Don't move the ladder when there is a guard
+		if (_placeStates[16].state != 0) {
+			// Take back the ladder from the scaffolding
+			if (_gameVariables[GameVariables::kLadderState] == 2) {
+				collectObject(108);
+				_gameVariables[GameVariables::kLadderState] = 1;
+				filterEventLevel5UpdatePlaceStates();
+			}
+		}
+		// Handled here
+		return false;
+	} else if (*event == 35160) {
+		// Don't move the ladder when there is a guard
+		if (_placeStates[16].state != 0) {
+			if (_gameVariables[GameVariables::kLadderState] == 0) {
+				// Take the ladder from the curtain
+				collectObject(108);
+				_gameVariables[GameVariables::kLadderState] = 1;
+				filterEventLevel5UpdatePlaceStates();
+			} else if (_gameVariables[GameVariables::kLadderState] == 1 &&
+			           _inventory.selectedObject() &&
+			           _inventory.selectedObject()->idOBJ() == 108) {
+				// Put back the ladder
+				_inventory.removeByNameID(108);
+				_gameVariables[GameVariables::kLadderState] = 0;
+				filterEventLevel5UpdatePlaceStates();
+			}
+		}
+		// Handled here
+		return false;
+	} else if (*event == 35161) {
+		// Don't move the ladder when there is a guard
+		if (_placeStates[16].state != 0) {
+			if (!_gameVariables[GameVariables::kOpenedCurtain] &&
+			        _inventory.selectedObject() &&
+			        _inventory.selectedObject()->idOBJ() == 133) {
+				// Try to open the curtain
+				if (_gameVariables[GameVariables::kLadderState]) {
+					// Ladder is not near the curtain
+					// Cannot reach the covering
+					displayMessageBoxWarp(4);
+				} else {
+					_inventory.removeByNameID(133);
+					_gameVariables[GameVariables::kOpenedCurtain] = 1;
+					filterEventLevel5UpdatePlaceStates();
+				}
+			}
+		}
+		// Handled here
+		return false;
+	} else if (*event == 28) {
+		// Try to go to scaffolding
+		if (_gameVariables[GameVariables::kLadderState] == 1 &&
+		        _inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 108) {
+			// Put the ladder on the scaffolding
+			_inventory.removeByNameID(108);
+			_gameVariables[GameVariables::kLadderState] = 2;
+			filterEventLevel5UpdatePlaceStates();
+		}
+		// Don't move if there is no ladder on the scaffolding
+		// Don't take selected object into account
+		return _gameVariables[GameVariables::kLadderState] == 2;
+	} else if (*event == 15 && _inventory.inInventoryByNameID(108)) {
+		// Cannot move carrying ladder
+		displayMessageBoxWarp(20);
+		return false;
+	} else {
+		return true;
+	}
+}
+
+void CryOmni3DEngine_Versailles::filterEventLevel5UpdatePlaceStates() {
+	// Place 28 (mirror of 16 with chandelier on the floor) only depends on curtain state
+	setPlaceState(28, _gameVariables[GameVariables::kOpenedCurtain]);
+	if (!_gameVariables[GameVariables::kOpenedCurtain]) {
+		// Curtain is closed
+		switch (_gameVariables[GameVariables::kLadderState]) {
+		case 0:
+			// Ladder is near the curtain
+			setPlaceState(16, 2);
+			break;
+		case 1:
+			// Ladder is with us
+			setPlaceState(16, 4);
+			break;
+		case 2:
+			// Ladder is on the scaffolding
+			setPlaceState(16, 5);
+			break;
+		}
+	} else {
+		// Curtain is opened
+		switch (_gameVariables[GameVariables::kLadderState]) {
+		case 0:
+			// Ladder is near the curtain
+			setPlaceState(16, 1);
+			break;
+		case 1:
+			// Ladder is with us
+			setPlaceState(16, 3);
+			break;
+		case 2:
+			// Ladder is on the scaffolding
+			setPlaceState(16, 6);
+			break;
+		}
+	}
+}
+
+FILTER_EVENT(5, 23) {
+	if (*event != 32) {
+		return true;
+	}
+
+	// Event 32 only
+	// Try to open attic door
+	if (_inventory.selectedObject() &&
+	        _inventory.selectedObject()->idOBJ() == 140) {
+		_gameVariables[GameVariables::kUnlockedAttic] = 1;
+		_inventory.removeByNameID(140);
+		return true;
+	} else if (_gameVariables[GameVariables::kUnlockedAttic] != 1) {
+		// Locked
+		displayMessageBoxWarp(1);
+		return false;
+	} else {
+		return true;
+	}
+}
+
+FILTER_EVENT(5, 27) {
+	if (*event == 25270) {
+		if (_inventory.selectedObject()) {
+			unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+			if (idOBJ == 115) {
+				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'Y';
+			} else if (idOBJ == 125) {
+				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
+			} else if (idOBJ == 134) {
+				_dialogsMan["{JOUEUR-MONTRE-ECROUELLES}"] = 'Y';
+			}
+
+			_dialogsMan.play("52A4_LAC");
+
+			_forcePaletteUpdate = true;
+			// Force reload of the place
+			if (_nextPlaceId == -1u) {
+				_nextPlaceId = _currentPlaceId;
+			}
+
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'N';
+			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'N';
+			_dialogsMan["{JOUEUR-MONTRE-ECROUELLES}"] = 'N';
+
+			if (_dialogsMan["LACHAIZE-TROUVE-ECROUELLES"] == 'Y') {
+				_inventory.removeByNameID(134);
+			}
+			_inventory.deselectObject();
+		}
+	} else if (*event == 35270) {
+		if (!_inventory.inInventoryByNameID(133)) {
+			collectObject(133);
+			_gameVariables[GameVariables::kCollectCord] = 1;
+			setPlaceState(27, 1);
+		}
+		// Handled here
+		return false;
+	} else if (*event > 0 && *event < 10000 && currentGameTime() == 1 &&
+	           _gameVariables[GameVariables::kCollectCord]) {
+		setGameTime(2, 5);
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 28) {
+	if (*event == 45280 && !_gameVariables[GameVariables::kOpenedCurtain]) {
+		// Too dark
+		displayMessageBoxWarp(7);
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 29) {
+	if (*event == 35290 && _placeStates[29].state == 0) {
+		// Collect memorandum
+		collectObject(137);
+		setPlaceState(29, 1);
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 33) {
+	if (*event == 35330 && !_gameVariables[GameVariables::kLoweredChandelier]) {
+		unsigned int fakePlaceId = getFakeTransition(*event);
+		fakeTransition(fakePlaceId);
+
+		playInGameVideo("LUSTRE");
+		// setPlaceState will force reload
+
+		setPlaceState(33, 1);
+		setGameTime(4, 5);
+
+		_gameVariables[GameVariables::kLoweredChandelier] = 1;
+
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(5, 34) {
+	if (*event == 35) {
+		fakeTransition(*event);
+
+		playInGameVideo("53z1c_10");
+
+		executeSeeAction(88002);
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: 8ad730260b92181da39938671a23f7e771b1dd8c
    https://github.com/scummvm/scummvm/commit/8ad730260b92181da39938671a23f7e771b1dd8c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove TODO as it's not needed anymore

Changed paths:
    engines/cryomni3d/objects.cpp


diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
index 5d79c5f..1559680 100644
--- a/engines/cryomni3d/objects.cpp
+++ b/engines/cryomni3d/objects.cpp
@@ -31,7 +31,6 @@ Object *Objects::findObjectByNameID(unsigned int nameID) {
 			return it;
 		}
 	}
-	// TODO: check if 111 and 112 are called and should be filtered out or not
 	error("nameID not found %u", nameID);
 }
 


Commit: 2ed2d617c09572a4bed3a9c9e2c808789024ebee
    https://github.com/scummvm/scummvm/commit/2ed2d617c09572a4bed3a9c9e2c808789024ebee
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix errors in strings

Changed paths:
    engines/cryomni3d/versailles/data.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 7660f7e..25b22f0 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -97,7 +97,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	    "Il est conseill" "\x8e" " de SAUVEGARDER votre partie maintenant.");
 	SET_MESSAGE(
 	    19,
-	    "Attention : Vous allez pouvoir terminer ce niveau, mais vous n'avez peut-" "\x89" "tre"
+	    "Attention : Vous allez pouvoir terminer ce niveau, mais vous n'avez peut-" "\x90" "tre"
 	    " pas effectu" "\x8e" " toutes les actions necessaires pour la suite. "
 	    "Il est conseill" "\x8e" " de SAUVEGARDER votre partie maintenant.");
 	SET_MESSAGE(20, "Vous ne pouvez pas vous d" "\x8e" "placer en portant une " "\x8e" "chelle!");
@@ -134,7 +134,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	SET_MESSAGE(54, "Annuler");
 	SET_MESSAGE(55, "libre");
 	SET_MESSAGE(56, "sans nom");
-	SET_MESSAGE(57, "Attention : la partie en cours va " "\x89" "tre abandonn" "\x8e" "e.");
+	SET_MESSAGE(57, "Attention : la partie en cours va " "\x90" "tre abandonn" "\x8e" "e.");
 	SET_MESSAGE(58, "Retour");
 	SET_MESSAGE(59, "Le chateau");
 	SET_MESSAGE(60, "Retour Menu Principal");
@@ -205,7 +205,7 @@ void CryOmni3DEngine_Versailles::setupMessages() {
 	SET_MESSAGE(126, "Epigraphe");
 	SET_MESSAGE(127, "Pamphlet sur le gouvernement");
 	SET_MESSAGE(128, "Plume");
-	SET_MESSAGE(129, "Pense-b" "\x89" "te");
+	SET_MESSAGE(129, "Pense-b" "\x90" "te");
 	SET_MESSAGE(130, "Lunette");
 	SET_MESSAGE(131, "Plan Vauban");
 	SET_MESSAGE(132, "Plan Vauban");
@@ -230,7 +230,7 @@ void CryOmni3DEngine_Versailles::setupPaintingsTitles() {
 #define SET_PAINTING_TITLE(str) _paintingsTitles.push_back(str)
 	SET_PAINTING_TITLE("\"Entr" "\x8e" "e des animaux dans l'arche\"\rGerolamo Bassano"); // 0: 41201
 	SET_PAINTING_TITLE("\"Le repas d'Emma" "\x9f" "s\"\rJacopo Bassano"); // 1: 41202
-	SET_PAINTING_TITLE("\"La Madeleine aux pieds de J\x8esus Christ\"\rSustris"); // 2: 41203
+	SET_PAINTING_TITLE("\"La Madeleine aux pieds de J" "\x8e" "sus Christ\"\rSustris"); // 2: 41203
 	SET_PAINTING_TITLE("\"La sortie de l'arche\"\rGerolamo Bassano"); // 3: 41204
 	SET_PAINTING_TITLE("\"Le frappement du rocher\"\rJacopo Bassano"); // 4: 41205
 	SET_PAINTING_TITLE("\"La Bataille d'Arbelles\"\rJoseph Parrocel"); // 5: 41301
@@ -277,7 +277,7 @@ void CryOmni3DEngine_Versailles::setupPaintingsTitles() {
 	SET_PAINTING_TITLE("\"Marie de m" "\x8e" "dicis\"\rVan Dyck"); // 39: 43150
 	SET_PAINTING_TITLE("\"Hercule luttant contre Achelous\"\rGuido R" "\x8e" "ni"); // 40: 43151
 	SET_PAINTING_TITLE("\"Le Centaure Nessus porte Dejanire\"\rGuido R" "\x8e" "ni"); // 41: 43152
-	SET_PAINTING_TITLE("\"Saint Franìois d'Assise r" "\x8e" "confort" "\x8e" " apr" "\x8f"
+	SET_PAINTING_TITLE("\"Saint Fran" "\x8d" "ois d'Assise r" "\x8e" "confort" "\x8e" " apr" "\x8f"
 	                   "s sa stigmatisation\"\rSeghers"); // 42: 43153
 	SET_PAINTING_TITLE("\"Thomiris faisant tremper la t" "\x90"
 	                   "te de Cyrus dans le sang\"\rRubens"); // 43: 43154


Commit: 6e0e3bb6b1cebfccb020fbe9696fb7d49f2e8fc4
    https://github.com/scummvm/scummvm/commit/6e0e3bb6b1cebfccb020fbe9696fb7d49f2e8fc4
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Don't abort when there is no transition defined

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 46d308f..eb3f030 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -966,7 +966,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 
 	_nextPlaceId = nextPlaceId;
 
-	Common::String animation = transition->animations[animationId];
+	Common::String animation = animationId == -1u ? "" : transition->animations[animationId];
 	animation.toUppercase();
 	debug("Transition animation: %s", animation.c_str());
 	if (animation.hasPrefix("NOT_FLI")) {
@@ -1015,7 +1015,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 		unsigned int nextNextPlaceId = nextPlace->transitions[transitionNum].dstId;
 
 		animationId = determineTransitionAnimation(nextPlaceId, nextNextPlaceId, &transition);
-		animation = transition->animations[animationId];
+		animation = animationId == -1u ? "" : transition->animations[animationId];
 
 		animation.toUppercase();
 		if (animation.hasPrefix("NOT_FLI")) {
@@ -1074,7 +1074,11 @@ unsigned int CryOmni3DEngine_Versailles::determineTransitionAnimation(unsigned i
 		error("Invalid dst state");
 	}
 
-	if (animsNum <= 1) {
+	if (animsNum == 0) {
+		return -1;
+	}
+
+	if (animsNum == 1) {
 		return 0;
 	}
 


Commit: c6999b091eb2aebf1fb1ea1a961e056bf0f5ae9a
    https://github.com/scummvm/scummvm/commit/c6999b091eb2aebf1fb1ea1a961e056bf0f5ae9a
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Number objects to help mangling of saves

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 2ffd925..f7e1708 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -72,57 +72,57 @@ void CryOmni3DEngine_Versailles::setupObjects() {
     } while (false)
 #define SET_OBJECT_GENERIC_CB(cursorId, nameId, imageId) SET_OBJECT_AND_CB(cursorId, nameId, genericDisplayObject<imageId>)
 #define SET_OBJECT_CB(cursorId, nameId) SET_OBJECT_AND_CB(cursorId, nameId, obj_ ## nameId)
-	SET_OBJECT(161, 93);
+	SET_OBJECT(161, 93); // 0
 	SET_OBJECT(107, 94);
 	SET_OBJECT(69, 95);
 	SET_OBJECT_GENERIC_CB(230, 96, 0);
 	SET_OBJECT(64, 97);
-	SET_OBJECT_GENERIC_CB(250, 98, 1);
+	SET_OBJECT_GENERIC_CB(250, 98, 1); // 5
 	SET_OBJECT(202, 99);
 	SET_OBJECT(235, 100);
 	SET_OBJECT_GENERIC_CB(167, 101, 2);
 	SET_OBJECT(191, 102);
-	SET_OBJECT(171, 103);
+	SET_OBJECT(171, 103); // 10
 	SET_OBJECT(47, 104);
 	SET_OBJECT_CB(205, 105);
 	SET_OBJECT_CB(214, 106);
 	SET_OBJECT_CB(6, 107);
-	SET_OBJECT(58, 108);
+	SET_OBJECT(58, 108); // 15
 	SET_OBJECT_GENERIC_CB(5, 109, 8);
 	SET_OBJECT(38, 110);
 	SET_OBJECT(119, 113);
 	SET_OBJECT(186, 114);
-	SET_OBJECT_GENERIC_CB(246, 115, 9);
+	SET_OBJECT_GENERIC_CB(246, 115, 9); // 20
 	SET_OBJECT(80, 116);
 	SET_OBJECT(180, 117);
 	SET_OBJECT_CB(34, 118);
 	SET_OBJECT(173, 119);
-	SET_OBJECT(81, 120);
+	SET_OBJECT(81, 120); // 25
 	SET_OBJECT_CB(156, 121);
 	SET_OBJECT(143, 122);
 	SET_OBJECT(101, 123);
 	SET_OBJECT(204, 124);
-	SET_OBJECT_CB(10, 125);
+	SET_OBJECT_CB(10, 125); // 30
 	SET_OBJECT_CB(112, 126);
 	SET_OBJECT_GENERIC_CB(90, 127, 17);
 	SET_OBJECT(216, 128);
 	SET_OBJECT_GENERIC_CB(32, 129, 18);
-	SET_OBJECT(37, 130);
+	SET_OBJECT(37, 130); // 35
 	SET_OBJECT_GENERIC_CB(134, 131, 19);
 	SET_OBJECT_GENERIC_CB(150, 132, 20);
 	SET_OBJECT(28, 133);
 	SET_OBJECT_GENERIC_CB(22, 134, 21);
-	SET_OBJECT(92, 135);
+	SET_OBJECT(92, 135); // 40
 	SET_OBJECT(115, 136); // Out of order in EXE
 	SET_OBJECT_GENERIC_CB(16, 137, 22);
 	SET_OBJECT_GENERIC_CB(237, 138, 23);
 	SET_OBJECT_GENERIC_CB(0, 139, 24);
-	SET_OBJECT(31, 140);
+	SET_OBJECT(31, 140); // 45
 	SET_OBJECT_GENERIC_CB(87, 141, 25);
 	SET_OBJECT(95, 142); // TODO: LABYR.gif
 	SET_OBJECT(157, 143);
 	SET_OBJECT(168, 144);
-	SET_OBJECT(65, 145);
+	SET_OBJECT(65, 145); // 50
 #undef SET_OBJECT_CB
 #undef SET_OBJECT_GENERIC_CB
 #undef SET_OBJECT_AND_CB


Commit: 3413768f8ed0a2b14dbeb5e657de782948df0518
    https://github.com/scummvm/scummvm/commit/3413768f8ed0a2b14dbeb5e657de782948df0518
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Don't skip videos (debug leftover)

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index eb3f030..81d7f53 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -38,7 +38,7 @@
 // 0 or commented: All videos and options screen
 // 1: Skip videos at startup and at game start
 // 2: Directly start a new game
-#define DEBUG_FAST_START 1
+//#define DEBUG_FAST_START 1
 
 namespace CryOmni3D {
 namespace Versailles {


Commit: 93bc6cf02be9b2260863d105e0c047cb472e9ab7
    https://github.com/scummvm/scummvm/commit/93bc6cf02be9b2260863d105e0c047cb472e9ab7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix incorrect dialog shows

Changed paths:
    engines/cryomni3d/versailles/dialogs.cpp


diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp
index cd7de6c..6289778 100644
--- a/engines/cryomni3d/versailles/dialogs.cpp
+++ b/engines/cryomni3d/versailles/dialogs.cpp
@@ -300,10 +300,11 @@ void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
 }
 
 void CryOmni3DEngine_Versailles::dialogShowTransitionScene() {
+	playTransitionEndLevel(6);
 }
 
 void CryOmni3DEngine_Versailles::dialogShowEndOfGame() {
-	playTransitionEndLevel(6);
+	doGameOver();
 }
 
 void CryOmni3DEngine_Versailles::dialogShowLeBrunGives() {


Commit: cba0ee7296aa3543e90329fd1928e5f9cea8a2dd
    https://github.com/scummvm/scummvm/commit/cba0ee7296aa3543e90329fd1928e5f9cea8a2dd
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement level 6

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 25b22f0..d2e733f 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -635,26 +635,25 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(33, nullptr, FILTER_EVENT(5, 33), nullptr);
 		SET_PLACE_STATE(34, nullptr, FILTER_EVENT(5, 34), nullptr);
 	} else if (_currentLevel == 6) {
-		// TODO: implement functions
-		SET_PLACE_STATE(1, nullptr, nullptr, "VS34");
-		SET_PLACE_STATE(2, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(3, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(4, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(5, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(6, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(7, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(8, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(9, nullptr, nullptr, "VS32");
-		SET_PLACE_STATE(10, nullptr, nullptr, "VS22");
-		SET_PLACE_STATE(11, nullptr, nullptr, "VS12");
-		SET_PLACE_STATE(12, nullptr, nullptr, "VS32");
+		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");
+		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, 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");
@@ -1016,7 +1015,7 @@ void CryOmni3DEngine_Versailles::initWhoSpeaksWhere() {
 		SET_WHO(9, 16090, "61_LEN");
 		SET_WHO(19, 16190, "61_DUC");
 		SET_WHO(14, 16140, "61_BON");
-		if (_gameVariables[GameVariables::kDiscussedLabyrOrder] == 1) {
+		if (_gameVariables[GameVariables::kMaineTalked] == 1) {
 			SET_WHO(19, 16190, "62_DUC");
 		}
 	}
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 81d7f53..124f638 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -611,7 +611,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		// TODO: countdown
 		_inventory.clear();
-	} else if (_currentLevel <= 5) {
+	} else if (_currentLevel <= 6) {
 		// TODO: remove this when we implemented all levels
 	} else {
 		error("New level %d is not implemented (yet)", level);
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 8911151..e958e3c 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -137,8 +137,8 @@ struct GameVariables {
 		kLadderState, // OK
 		kOpenedCurtain, // OK
 		kLoweredChandelier, // OK
-		kOrangerRatisse,
-		kDiscussedLabyrOrder,
+		kCombedOrangeTree, // OK
+		kMaineTalked, // OK
 		kUsedBougieAllumee,
 		kStateBombe,
 		kInkSpilled, // OK
@@ -408,6 +408,8 @@ private:
 	void obj_125();
 	void obj_126();
 	void obj_126hk(Graphics::ManagedSurface &surface);
+	void obj_142();
+	void obj_142hk(Graphics::ManagedSurface &surface);
 
 	// Fixed image
 	template<unsigned int ID>
@@ -562,6 +564,11 @@ private:
 	FILTER_EVENT(5, 33);
 	FILTER_EVENT(5, 34);
 
+	FILTER_EVENT(6, 1);
+	FILTER_EVENT(6, 3);
+	FILTER_EVENT(6, Orangery);
+	FILTER_EVENT(6, 19);
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index f7e1708..e65d5a6 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -119,7 +119,7 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT_GENERIC_CB(0, 139, 24);
 	SET_OBJECT(31, 140); // 45
 	SET_OBJECT_GENERIC_CB(87, 141, 25);
-	SET_OBJECT(95, 142); // TODO: LABYR.gif
+	SET_OBJECT_CB(95, 142);
 	SET_OBJECT(157, 143);
 	SET_OBJECT(168, 144);
 	SET_OBJECT(65, 145); // 50
@@ -194,6 +194,71 @@ void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) {
 	}
 }
 
+void CryOmni3DEngine_Versailles::obj_142() {
+	// Display a marker only when in maze
+	if (_currentLevel == 6 && _currentPlaceId >= 14 && _currentPlaceId <= 44) {
+		displayObject(imagesObjects[26], &CryOmni3DEngine_Versailles::obj_142hk);
+	} else {
+		displayObject(imagesObjects[26]);
+	}
+}
+
+void CryOmni3DEngine_Versailles::obj_142hk(Graphics::ManagedSurface &surface) {
+	const Common::Point markers[] = {
+		Common::Point(135, 403), // 14
+		Common::Point(136, 321), // 15
+		Common::Point(225, 109),
+		Common::Point(441,  88),
+		Common::Point(505,  78),
+		Common::Point(550,  82),
+		Common::Point(479, 242), // 20
+		Common::Point(529, 333),
+		Common::Point(466, 407),
+		Common::Point(359, 411),
+		Common::Point(305, 415),
+		Common::Point(217, 405), // 25
+		Common::Point(216, 325),
+		Common::Point(280, 378),
+		Common::Point(340, 313),
+		Common::Point(282, 313),
+		Common::Point(253, 285), // 30
+		Common::Point(225, 258),
+		Common::Point(154, 255),
+		Common::Point(219, 188),
+		Common::Point(294, 251),
+		Common::Point(341, 242), // 35
+		Common::Point(308, 206),
+		Common::Point(270, 172),
+		Common::Point(363, 161),
+		Common::Point(416, 201),
+		Common::Point(513, 195), // 40
+		Common::Point(412, 311),
+		Common::Point(446, 280),
+		Common::Point(377, 347),
+		Common::Point(448, 356),
+	};
+
+	unsigned int id = _currentPlaceId - 14;
+	assert(id < ARRAYSIZE(markers));
+
+	/*
+	_fontManager.setSurface(&surface);
+	_fontManager.setCurrentFont(4);
+	_fontManager.setTransparentBackground(true);
+	_fontManager.setForeColor(241);
+	for(id = 0; id < ARRAYSIZE(markers); id++) {
+	*/
+	// Why - 20? Ask to game creators, it's like that in the code
+	unsigned int spriteX = markers[id].x - _sprites.getCursor(4).getWidth() / 2 - 20;
+	unsigned int spriteY = markers[id].y - _sprites.getCursor(4).getHeight() / 2;
+	surface.transBlitFrom(_sprites.getSurface(4), Common::Point(spriteX, spriteY),
+	                      _sprites.getKeyColor(4));
+	/*
+	_fontManager.displayInt(markers[id].x - 10, markers[id].y, id + 14);
+	}
+	*/
+}
+
 // This array contains images for all paintings it must be kept in sync with _paintingsTitles
 static const char *imagesPaintings[] = {
 	"10E_1.GIF",      //  0: 41201
@@ -3926,6 +3991,97 @@ FILTER_EVENT(5, 34) {
 	return true;
 }
 
+FILTER_EVENT(6, 1) {
+	if (*event == 36010 && _placeStates[1].state == 0) {
+		collectObject(144);
+		setPlaceState(1, 1);
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(6, 3) {
+	if (!filterEventLevel6PlaceOrangery(event)) {
+		// Handled
+		return false;
+	} else if (*event == 36030 && _placeStates[3].state == 0) {
+		collectObject(143);
+		setPlaceState(3, 1);
+		// Handled here
+		return false;
+	} else if (*event == 1) {
+		// To apothecary
+		displayMessageBoxWarp(17);
+	}
+
+	return true;
+}
+
+FILTER_EVENT(6, Orangery) {
+	if (*event == 36000) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 143) {
+			_gameVariables[GameVariables::kCombedOrangeTree]++; // Not used afterwards
+			displayMessageBoxWarp(5);
+		}
+		// Handled here
+		return false;
+	} else if (*event == 36001) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 143) {
+			displayMessageBoxWarp(6);
+		}
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(6, 19) {
+	if (*event == 26190 && _inventory.selectedObject() &&
+	        _placeStates[19].state == 0) {
+		if (!_gameVariables[GameVariables::kMaineTalked]) {
+			if (_inventory.selectedObject()->idOBJ() == 144) {
+				_dialogsMan["{JOUEUR-DONNE-AUTRE-MEDICAMENT}"] = 'Y';
+			}
+
+			_dialogsMan.play("61_DUC");
+		} else {
+			if (_inventory.selectedObject()->idOBJ() == 144) {
+				_dialogsMan["{JOUEUR-DONNE-SIROP-DE-ROSE}"] = 'Y';
+				_dialogsMan.setIgnoreNoEndOfConversation(true);
+			}
+
+			_dialogsMan.play("62_DUC");
+			_dialogsMan.setIgnoreNoEndOfConversation(false);
+		}
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+
+		_dialogsMan["{JOUEUR-DONNE-AUTRE-MEDICAMENT}"] = 'N';
+		_dialogsMan["{JOUEUR-DONNE-SIROP-DE-ROSE}"] = 'N';
+
+		_inventory.deselectObject();
+	} else if (*event > 0 && *event < 10000 && _dialogsMan["{DUC_MAIN_A_PARLE}"] == 'Y') {
+		_gameVariables[GameVariables::kMaineTalked] = 1;
+		_whoSpeaksWhere[PlaceActionKey(19, 16190)] = "62_DUC";
+	} else if (*event == 36190 && _placeStates[19].state == 1) {
+		collectObject(142);
+		setGameTime(2, 6);
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: 1c4d0d87ecde1fdea1cf1473da3665605d956657
    https://github.com/scummvm/scummvm/commit/1c4d0d87ecde1fdea1cf1473da3665605d956657
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Use existing palette to init video one

This is useful when there will be hooks on video plays which use a
palette entry not defined in video

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/video/hnm_decoder.cpp
    engines/cryomni3d/video/hnm_decoder.h


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index ae05778..473fc7c 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -118,7 +118,11 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 	const char *const extensions[] = { "hns", "hnm", nullptr };
 	Common::String fname(prepareFileName(filename, extensions));
 
-	Video::VideoDecoder *videoDecoder = new Video::HNMDecoder();
+	byte *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(false, currentPalette);
 	videoDecoder->setSoundType(soundType);
 
 	if (!videoDecoder->loadFile(fname)) {
diff --git a/engines/cryomni3d/video/hnm_decoder.cpp b/engines/cryomni3d/video/hnm_decoder.cpp
index 355345b..0451828 100644
--- a/engines/cryomni3d/video/hnm_decoder.cpp
+++ b/engines/cryomni3d/video/hnm_decoder.cpp
@@ -35,13 +35,16 @@
 namespace Video {
 
 // When no sound display a frame every 80ms
-HNMDecoder::HNMDecoder(bool loop) : _regularFrameDelay(80), _videoTrack(nullptr),
-	_audioTrack(nullptr), _stream(nullptr), _loop(loop) {
+HNMDecoder::HNMDecoder(bool loop, byte *initialPalette) : _regularFrameDelay(80),
+	_videoTrack(nullptr), _audioTrack(nullptr), _stream(nullptr),
+	_loop(loop), _initialPalette(initialPalette) {
 }
 
 HNMDecoder::~HNMDecoder() {
 	close();
 
+	delete[] _initialPalette;
+
 	// We don't deallocate _videoTrack and _audioTrack as they are owned by base class
 }
 
@@ -79,7 +82,7 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
 		frameCount = 0;
 	}
 
-	_videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay);
+	_videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay, _initialPalette);
 	if (soundBits != 0 && soundChannels != 0) {
 		// HNM4 is 22050Hz
 		_audioTrack = new DPCMAudioTrack(soundChannels, soundBits, 22050, getSoundType());
@@ -149,13 +152,18 @@ void HNMDecoder::readNextPacket() {
 }
 
 HNMDecoder::HNM4VideoTrack::HNM4VideoTrack(uint32 width, uint32 height, uint32 frameSize,
-        uint32 frameCount, uint32 regularFrameDelay) :
+        uint32 frameCount, uint32 regularFrameDelay, const byte *initialPalette) :
 	_frameCount(frameCount), _regularFrameDelay(regularFrameDelay), _nextFrameStartTime(0) {
 
 	restart();
 
 	_curFrame = -1;
-	memset(_palette, 0, 256 * 3);
+	// Get the currently loaded palette for undefined colors
+	if (initialPalette) {
+		memcpy(_palette, initialPalette, 256 * 3);
+	} else {
+		memset(_palette, 0, 256 * 3);
+	}
 
 	if (width * height != frameSize) {
 		error("Invalid frameSize");
diff --git a/engines/cryomni3d/video/hnm_decoder.h b/engines/cryomni3d/video/hnm_decoder.h
index b09026b..c5d9307 100644
--- a/engines/cryomni3d/video/hnm_decoder.h
+++ b/engines/cryomni3d/video/hnm_decoder.h
@@ -43,7 +43,7 @@ namespace Video {
  */
 class HNMDecoder : public VideoDecoder {
 public:
-	HNMDecoder(bool loop = false);
+	HNMDecoder(bool loop = false, byte *initialPalette = nullptr);
 	virtual ~HNMDecoder();
 	bool loadStream(Common::SeekableReadStream *stream);
 	void readNextPacket();
@@ -55,7 +55,7 @@ private:
 	class HNM4VideoTrack : public VideoTrack {
 	public:
 		HNM4VideoTrack(uint32 width, uint32 height, uint32 frameSize, uint32 frameCount,
-		               uint32 regularFrameDelay);
+		               uint32 regularFrameDelay, const byte *initialPalette = nullptr);
 		~HNM4VideoTrack();
 
 		// When _frameCount is 0, it means we are looping
@@ -113,6 +113,7 @@ private:
 	};
 
 	bool _loop;
+	byte *_initialPalette;
 
 	uint32 _regularFrameDelay;
 	// These two pointer are owned by VideoDecoder


Commit: edf2fdb12880b2b96beb3a753da4c1ad44b0bbf4
    https://github.com/scummvm/scummvm/commit/edf2fdb12880b2b96beb3a753da4c1ad44b0bbf4
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add hook to video playing

That will be used for countdown

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/cryomni3d.h


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 473fc7c..bd27ea7 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -114,7 +114,8 @@ Common::String CryOmni3DEngine::prepareFileName(const Common::String &baseName,
 	return baseName;
 }
 
-void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::SoundType soundType) {
+void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::SoundType soundType,
+                              HNMCallback beforeDraw, HNMCallback afterDraw) {
 	const char *const extensions[] = { "hns", "hnm", nullptr };
 	Common::String fname(prepareFileName(filename, extensions));
 
@@ -137,6 +138,7 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 	uint16 height = videoDecoder->getHeight();
 
 	bool skipVideo = false;
+	unsigned int frameNum = 0;
 	while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
 		if (videoDecoder->needsUpdate()) {
 			const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
@@ -147,10 +149,15 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 					setPalette(palette, 0, 256);
 				}
 
-				// TODO: beforeDraw
+				if (beforeDraw) {
+					(this->*beforeDraw)(frameNum);
+				}
 				g_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, width, height);
-				// TODO: afterDraw
+				if (afterDraw) {
+					(this->*afterDraw)(frameNum);
+				}
 
+				frameNum++;
 			}
 		}
 		g_system->updateScreen();
diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index c06df5b..17e9cd3 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -108,8 +108,10 @@ public:
 	void fillSurface(byte color);
 	void setCursor(const Graphics::Cursor &cursor) const;
 	void setCursor(unsigned int cursorId) const;
+	typedef void (CryOmni3DEngine::*HNMCallback)(unsigned int frameNum);
 	void playHNM(const Common::String &filename,
-	             Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
+	             Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
+	             HNMCallback beforeDraw = nullptr, HNMCallback afterDraw = nullptr);
 	void displayHLZ(const Common::String &filename);
 
 	bool pollEvents();


Commit: 01f6e2db12aa980aa316b80bc0e4b29e58cf2b5e
    https://github.com/scummvm/scummvm/commit/01f6e2db12aa980aa316b80bc0e4b29e58cf2b5e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement countdown

Changed paths:
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp
    engines/cryomni3d/versailles/menus.cpp
    engines/cryomni3d/versailles/saveload.cpp
    engines/cryomni3d/versailles/toolbar.cpp


diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index f4e900f..f5f354a 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -191,7 +191,6 @@ void ZonFixedImage::manage() {
 	// Force poll events even when we must refresh the cursor
 	if (!_engine.pollEvents() && !_refreshCursor) {
 		g_system->updateScreen();
-		// TODO: countdown even when no events
 		return;
 	}
 	_refreshCursor = false;
@@ -266,7 +265,6 @@ void ZonFixedImage::manage() {
 
 	}
 
-	// TODO: handle countdown
 	g_system->updateScreen();
 }
 
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 124f638..fd88f8e 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -54,7 +54,8 @@ CryOmni3DEngine_Versailles::CryOmni3DEngine_Versailles(OSystem *syst,
 	_currentPlace(nullptr), _currentWarpImage(nullptr), _fixedImage(nullptr),
 	_transitionAnimateWarp(true), _forceRedrawWarp(false), _forcePaletteUpdate(false),
 	_fadedPalette(false), _loadedSave(-1), _dialogsMan(this),
-	_musicVolumeFactor(1.), _musicCurrentFile(nullptr) {
+	_musicVolumeFactor(1.), _musicCurrentFile(nullptr),
+	_countingDown(false), _countdownNextEvent(0) {
 }
 
 CryOmni3DEngine_Versailles::~CryOmni3DEngine_Versailles() {
@@ -127,6 +128,8 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	initDocPeopleRecord();
 	_docManager.init(&_sprites, &_fontManager, &_messages, this);
 
+	_countdownSurface.create(40, 15, Graphics::PixelFormat::createFormatCLUT8());
+
 	initGraphics(640, 480);
 	setMousePos(Common::Point(320, 200));
 
@@ -609,7 +612,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		        it++) {
 			*it = 0;
 		}
-		// TODO: countdown
+		initCountdown();
 		_inventory.clear();
 	} else if (_currentLevel <= 6) {
 		// TODO: remove this when we implemented all levels
@@ -1166,7 +1169,7 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 			const Graphics::Surface *result = _omni3dMan.getSurface();
 			g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
 			if (!exit) {
-				// TODO: countdown
+				drawCountdown();
 				g_system->updateScreen();
 				if (firstDraw && _fadedPalette) {
 					fadeInPalette(_mainPalette);
@@ -1179,14 +1182,13 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 			const Graphics::Surface *result = _omni3dMan.getSurface();
 			g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
 			if (!exit) {
-				// TODO: countdown
+				drawCountdown();
 				g_system->updateScreen();
 			}
-			// TODO: cursorUseZones
 			moving = false;
 		} else {
 			if (!exit) {
-				// TODO: countdown
+				// Countdown is updated as soon as it changes
 				g_system->updateScreen();
 			}
 		}
@@ -1203,6 +1205,11 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
 	        getNextKey().keycode == Common::KEYCODE_SPACE) {
 		// Prepare background using alpha
 		const Graphics::Surface *original = _omni3dMan.getSurface();
+
+		// Display surface with countdown before showing toolbar just to be sure
+		g_system->copyRectToScreen(original->getPixels(), original->pitch, 0, 0, original->w, original->h);
+		drawCountdown();
+
 		bool mustRedraw = displayToolbar(original);
 		// Don't redraw if we abort game
 		if (_abortCommand != AbortNoAbort) {
@@ -1216,7 +1223,16 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
 		return false;
 	}
 
-	// TODO: countdown
+	if (countDown()) {
+		// Time has changed: need redraw
+		// Don't redraw if we abort game
+		if (_abortCommand != AbortNoAbort) {
+			return true;
+		}
+
+		_forceRedrawWarp = true;
+		redrawWarp();
+	}
 
 	const Object *selectedObj = _inventory.selectedObject();
 	if (selectedObj) {
@@ -1323,7 +1339,7 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 
 		const Graphics::Surface *result = _omni3dMan.getSurface();
 		g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
-		// TODO: countdown
+		drawCountdown();
 		g_system->updateScreen();
 
 		if (fabs(oldDeltaAlpha - deltaAlpha) < 0.001 && fabs(oldDeltaBeta - deltaBeta) < 0.001) {
@@ -1344,7 +1360,7 @@ void CryOmni3DEngine_Versailles::redrawWarp() {
 	if (_forceRedrawWarp) {
 		const Graphics::Surface *result = _omni3dMan.getSurface();
 		g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h);
-		// TODO: countdown
+		drawCountdown();
 		g_system->updateScreen();
 		_forceRedrawWarp = false;
 	}
@@ -1534,7 +1550,8 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
 	g_system->showMouse(false);
 	lockPalette(0, 241);
 	// Videos are like music because if you mute music in game it will mute videos soundtracks
-	playHNM(filename, Audio::Mixer::kMusicSoundType);
+	playHNM(filename, Audio::Mixer::kMusicSoundType, nullptr,
+	        static_cast<HNMCallback>(&CryOmni3DEngine_Versailles::drawCountdownVideo));
 	clearKeys();
 	unlockPalette();
 	if (restoreCursorPalette) {
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index e958e3c..abfb1a4 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -155,7 +155,7 @@ struct GameVariables {
 		kUsedVaubanBlueprint2, // OK   // 40
 		kSeenMemorandum, // OK
 		kCollectScissors, // OK
-		kSavedCountdown, // TODO: calculate it in real time
+		kSavedCountdown, // OK
 		kMax
 	};
 };
@@ -309,7 +309,7 @@ private:
 	bool canVisit() const;
 	Common::String getSaveFileName(bool visit, unsigned int saveNum) const;
 	void getSavesList(bool visit, Common::Array<Common::String> &saveNames);
-	void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName) const;
+	void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName);
 	bool loadGame(bool visit, unsigned int saveNum);
 
 	void animateCursor(const Object *object);
@@ -397,6 +397,20 @@ private:
 	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(unsigned int frameNum) { drawCountdown(); }
+
+	bool _countingDown;
+	unsigned int _countdownNextEvent;
+	char _countdownValue[6];
+	Graphics::ManagedSurface _countdownSurface;
+	bool doCountDown();
+	void doDrawCountdown(Graphics::ManagedSurface *surface);
+
 	// Objects
 	template<unsigned int ID>
 	void genericDisplayObject();
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index e65d5a6..af20e9c 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -4085,5 +4085,85 @@ FILTER_EVENT(6, 19) {
 #undef FILTER_EVENT
 #undef INIT_PLACE
 
+// Countdown
+
+void CryOmni3DEngine_Versailles::initCountdown() {
+	strcpy(_countdownValue, "05:00");
+	if (_gameVariables[GameVariables::kSavedCountdown]) {
+		unsigned int counter = _gameVariables[GameVariables::kSavedCountdown];
+		_countdownValue[4] = counter;
+		counter >>= 8;
+		_countdownValue[3] = counter;
+		counter >>= 8;
+		_countdownValue[1] = counter;
+		counter >>= 8;
+		_countdownValue[0] = counter;
+	}
+}
+
+void CryOmni3DEngine_Versailles::syncCountdown() {
+	unsigned int counter = 0;
+	counter |= _countdownValue[0];
+	counter <<= 8;
+	counter |= _countdownValue[1];
+	counter <<= 8;
+	counter |= _countdownValue[3];
+	counter <<= 8;
+	counter |= _countdownValue[4];
+	_gameVariables[GameVariables::kSavedCountdown] = counter;
+}
+
+bool CryOmni3DEngine_Versailles::doCountDown() {
+	if (g_system->getMillis() > _countdownNextEvent) {
+		_countdownNextEvent = g_system->getMillis() + 1000;
+		// Decrement countdown
+		_countdownValue[4]--;
+		if (_countdownValue[4] < '0') {
+			_countdownValue[4] = '9';
+			_countdownValue[3]--;
+			if (_countdownValue[3] < '0') {
+				_countdownValue[3] = '5';
+				_countdownValue[1]--;
+				if (_countdownValue[1] < '0') {
+					_countdownValue[1] = '9';
+					_countdownValue[0]--;
+					if (_countdownValue[0] < '0') {
+						// Finished!
+						_countingDown = false;
+						playTransitionEndLevel(8);
+						_abortCommand = AbortGameOver;
+					}
+				}
+			}
+		}
+
+		// Redraw surface
+		_countdownSurface.clear(0);
+		_fontManager.setCurrentFont(3);
+		_fontManager.setTransparentBackground(true);
+		_fontManager.setForeColor(241);
+		_fontManager.setLineHeight(14);
+		_fontManager.setSpaceWidth(0);
+		_fontManager.setCharSpacing(1);
+		_fontManager.setSurface(&_countdownSurface);
+
+		_fontManager.displayStr(0, 2, _countdownValue);
+
+		// Surface changed: need redraw
+		return true;
+	} else {
+		return false;
+	}
+}
+
+void CryOmni3DEngine_Versailles::doDrawCountdown(Graphics::ManagedSurface *surface) {
+	if (surface) {
+		surface->blitFrom(_countdownSurface, Common::Point(600, 0));
+	} else {
+		g_system->copyRectToScreen(_countdownSurface.getPixels(), _countdownSurface.pitch, 600, 0,
+		                           _countdownSurface.w, _countdownSurface.h);
+	}
+}
+
 } // End of namespace Versailles
 } // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index f052cd7..9a44478 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -882,7 +882,8 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters &param
 	rct.grow(-6);
 	_fontManager.setupBlock(rct);
 	_fontManager.displayBlockText(msg);
-	// TODO: countdown
+
+	drawCountdown(&dstSurface);
 
 	g_system->copyRectToScreen(dstSurface.getPixels(), dstSurface.pitch, 0, 0,
 	                           dstSurface.w, dstSurface.h);
diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index a5ea1a1..752cb76 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -114,7 +114,7 @@ void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &s
 }
 
 void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
-        const Common::String &saveName) const {
+        const Common::String &saveName) {
 	if (visit && saveNum == 1) {
 		error("Can't erase bootstrap visit");
 	}
@@ -133,6 +133,9 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
 		return;
 	}
 
+	// Sync countdown to game variable before saving it to file
+	syncCountdown();
+
 	// Write save name
 	char saveNameC[SAVE_DESCRIPTION_LEN];
 	memset(saveNameC, 0, sizeof(saveNameC));
@@ -292,6 +295,7 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 	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
@@ -307,8 +311,6 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 		placeIt->state = placesStates[i];
 	}
 
-	// TODO: countdown
-
 	return true;
 }
 
diff --git a/engines/cryomni3d/versailles/toolbar.cpp b/engines/cryomni3d/versailles/toolbar.cpp
index e0168e2..2f9426b 100644
--- a/engines/cryomni3d/versailles/toolbar.cpp
+++ b/engines/cryomni3d/versailles/toolbar.cpp
@@ -410,9 +410,6 @@ bool Toolbar::displayToolbar(const Graphics::Surface *original) {
 	                                 _bgSurface.w, original->h));
 	_engine->makeTranslucent(_bgSurface, subset);
 
-	// Draw the original surface on the surface to use for toolbar
-	g_system->copyRectToScreen(original->getPixels(), original->pitch, 0, 0, original->w, original->h);
-
 	// WORKAROUND: Reset the inventory status at init to let sprites highlighted until toolbar is hidden
 	_inventorySelected = -1;
 	_inventoryHovered = -1;
@@ -479,8 +476,6 @@ void Toolbar::handleToolbarEvents(const Graphics::Surface *original) {
 	// No need of original surface because the toolbar is fully displayed
 	drawToolbar(original);
 
-	// TODO: countdown
-
 	g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
 	                           original->h - _destSurface.h, _destSurface.w, _destSurface.h);
 	g_system->updateScreen();


Commit: 48ad952e50cdee734873f848f6f483a5078586ce
    https://github.com/scummvm/scummvm/commit/48ad952e50cdee734873f848f6f483a5078586ce
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Save some space

Changed paths:
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index abfb1a4..743bdf5 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -462,8 +462,8 @@ private:
 	IMG_CB(34174e);
 	IMG_CB(34174f);
 	static const unsigned int kSafeDigitsCount = 12;
-	static const unsigned int kSafeDigitsX[];
-	static const unsigned int kSafeDigitsY[];
+	static const unsigned short kSafeDigitsX[];
+	static const unsigned short kSafeDigitsY[];
 	static const char *kSafeDates[];
 	bool handleSafe(ZonFixedImage *fimg);
 	void drawSafeDigits(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpDigits)[10],
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index af20e9c..7ef87c0 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -1242,8 +1242,8 @@ bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) {
 	return success;
 }
 
-const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 };
-const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 };
+const unsigned short CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 };
+const unsigned short CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 };
 
 void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surface,
         const Graphics::Surface(&bmpDigits)[10], const unsigned char (&safeDigits)[kSafeDigitsCount]) {


Commit: f7c7707d15898a0f54880ea27f2abc8432300501
    https://github.com/scummvm/scummvm/commit/f7c7707d15898a0f54880ea27f2abc8432300501
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix objects order to keep savegame compat

That's easier to debug

Changed paths:
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 7ef87c0..b3acea0 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -113,13 +113,13 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 	SET_OBJECT(28, 133);
 	SET_OBJECT_GENERIC_CB(22, 134, 21);
 	SET_OBJECT(92, 135); // 40
-	SET_OBJECT(115, 136); // Out of order in EXE
 	SET_OBJECT_GENERIC_CB(16, 137, 22);
 	SET_OBJECT_GENERIC_CB(237, 138, 23);
 	SET_OBJECT_GENERIC_CB(0, 139, 24);
-	SET_OBJECT(31, 140); // 45
-	SET_OBJECT_GENERIC_CB(87, 141, 25);
+	SET_OBJECT(31, 140);
+	SET_OBJECT_GENERIC_CB(87, 141, 25); // 45
 	SET_OBJECT_CB(95, 142);
+	SET_OBJECT(115, 136); // Out of order in EXE
 	SET_OBJECT(157, 143);
 	SET_OBJECT(168, 144);
 	SET_OBJECT(65, 145); // 50


Commit: e791122c594cbd3e9c262fce58d6d7a4247093ab
    https://github.com/scummvm/scummvm/commit/e791122c594cbd3e9c262fce58d6d7a4247093ab
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Implement (final) level 7

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index d2e733f..a11b1ab 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -680,27 +680,26 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(43, nullptr, nullptr, "VS33");
 		SET_PLACE_STATE(44, nullptr, nullptr, "VS33");
 	} else if (_currentLevel == 7) {
-		// TODO: implement functions
 		SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(2, 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);
+		SET_PLACE_STATE(7, nullptr, nullptr, nullptr); // Filter is a leftover
 		SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(9, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(10, nullptr, nullptr, "VS33");
-		SET_PLACE_STATE(11, nullptr, nullptr, "VS33");
+		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, nullptr, "VS33");
+		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, 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);
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index fd88f8e..e3e91b8 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -614,10 +614,8 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 		}
 		initCountdown();
 		_inventory.clear();
-	} else if (_currentLevel <= 6) {
-		// TODO: remove this when we implemented all levels
-	} else {
-		error("New level %d is not implemented (yet)", level);
+	} else if (_currentLevel > 7) {
+		error("New level %d is not implemented", level);
 	}
 
 	_gameVariables[GameVariables::kCurrentTime] = 1;
@@ -693,7 +691,8 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 		error("Invalid level %d", level);
 	}
 
-	// TODO: countdown
+	// Level 7 starts countdown
+	_countingDown = (level == 7);
 	initPlacesStates();
 	initWhoSpeaksWhere();
 	setupLevelWarps(level);
@@ -1469,6 +1468,7 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 
 void CryOmni3DEngine_Versailles::executeSeeAction(unsigned int actionId) {
 	if (_currentLevel == 7 && _currentPlaceId != 20) {
+		// Don't display fixed images unless it's the bomb
 		// Not enough time for paintings
 		displayMessageBoxWarp(14);
 		return;
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 743bdf5..0b60dce 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -139,8 +139,8 @@ struct GameVariables {
 		kLoweredChandelier, // OK
 		kCombedOrangeTree, // OK
 		kMaineTalked, // OK
-		kUsedBougieAllumee,
-		kStateBombe,
+		kUsedLitCandle, // OK
+		kBombState, // OK
 		kInkSpilled, // OK
 		kCollectedPaperOnTable, // OK  // 30
 		kSafeUnlocked, // OK
@@ -505,23 +505,38 @@ private:
 	IMG_CB(44161d);
 	IMG_CB(44161e);
 	IMG_CB(44161f);
-	IMG_CB(45130);
-	IMG_CB(45270);
-	IMG_CB(45270b);
-	IMG_CB(45270c);
-	IMG_CB(45270d);
-	IMG_CB(45280);
 	static const unsigned int kEpigraphMaxLetters = 32;
 	static const char *kEpigraphContent;
 	static const char *kEpigraphPassword;
 	bool handleEpigraph(ZonFixedImage *fimg);
 	void drawEpigraphLetters(Graphics::ManagedSurface &surface,
 	                         const Graphics::Surface(&bmpLetters)[26], 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);
+	static const unsigned int kBombPasswordSmallLength = 40;
+	static const unsigned int kBombPasswordMaxLength = 60;
+	static const unsigned short kBombLettersPos[2][kBombPasswordMaxLength][2];
+	static const char *kBombPassword;
+	bool handleBomb(ZonFixedImage *fimg);
+	void drawBombLetters(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpLetters)[26],
+	                     const unsigned int kBombPasswordLength,
+	                     const unsigned char (&bombPossibilites)[kBombPasswordMaxLength][5],
+	                     const unsigned char (&bombCurrentLetters)[kBombPasswordMaxLength]);
 	IMG_CB(88004);
 	IMG_CB(88004b);
 #undef IMG_CB
@@ -583,6 +598,10 @@ private:
 	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
 
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index b3acea0..55608cd 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -418,7 +418,7 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 	SET_SCRIPT_BY_ID(45280);
 	SET_SCRIPT_BY_ID(88001);
 	SET_SCRIPT_BY_ID(88002);
-	//SET_SCRIPT_BY_ID(88003); // TODO: implement it
+	SET_SCRIPT_BY_ID(88003);
 	SET_SCRIPT_BY_ID(88004);
 #undef SET_SCRIPT_BY_ID
 }
@@ -2675,6 +2675,381 @@ IMG_CB(88002) {
 	}
 }
 
+IMG_CB(88003) {
+	// Dispatch to the correct state
+	if (_gameVariables[GameVariables::kBombState] >= 1 &&
+	        _gameVariables[GameVariables::kBombState] <= 5) {
+		FixedImgCallback callback;
+		switch (_gameVariables[GameVariables::kBombState]) {
+		case 1:
+			callback = &CryOmni3DEngine_Versailles::img_88003b;
+			break;
+		case 2:
+			callback = &CryOmni3DEngine_Versailles::img_88003c;
+			break;
+		case 3:
+			callback = &CryOmni3DEngine_Versailles::img_88003d;
+			break;
+		case 4:
+			callback = &CryOmni3DEngine_Versailles::img_88003e;
+			break;
+		case 5:
+			callback = &CryOmni3DEngine_Versailles::img_88003f;
+			break;
+		}
+		ZonFixedImage::CallbackFunctor *functor =
+		    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, callback);
+		fimg->changeCallback(functor);
+		return;
+	}
+
+	fimg->load("70Z_10.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_currentZone == 0 && fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 145) {
+			// Now we know how to reach the bomb
+			_gameVariables[GameVariables::kBombState] = 1;
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88003b);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (_currentLevel == 7) {
+				// You will need something to reach the bomb
+				displayMessageBox(kFixedimageMsgBoxParameters, fimg->surface(), 10,
+				                  fimg->getZoneCenter(fimg->_currentZone),
+				                  Common::Functor0Mem<void, ZonFixedImage>(fimg, &ZonFixedImage::manage));
+			}
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+IMG_CB(88003b) {
+	fimg->load("70Z_11.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_currentZone == 0 && fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 97) {
+			// Unlock first line with key 1
+			_gameVariables[GameVariables::kBombState] = 2;
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88003c);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+IMG_CB(88003c) {
+	fimg->load("70Z_12.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_currentZone == 1 && fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 116) {
+			// Unlock second line with key 2
+			_gameVariables[GameVariables::kBombState] = 3;
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88003d);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+IMG_CB(88003d) {
+	fimg->load("70Z_13.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_currentZone == 2 && fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 135) {
+			// Unlock third line with key 3
+			_gameVariables[GameVariables::kBombState] = 4;
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88003e);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+IMG_CB(88003e) {
+	fimg->load("70Z_14.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_currentZone == 3 && fimg->_usedObject &&
+		        fimg->_usedObject->idOBJ() == 136) {
+			// Unlock fourth line with key 4
+			_gameVariables[GameVariables::kBombState] = 5;
+			ZonFixedImage::CallbackFunctor *functor =
+			    new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this,
+			            &CryOmni3DEngine_Versailles::img_88003f);
+			fimg->changeCallback(functor);
+			break;
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+IMG_CB(88003f) {
+	fimg->load("70Z_15.GIF");
+
+	// Draw countdown there and not in fixed image class directly
+	Graphics::ManagedSurface tempSurf;
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			fimg->_exit = true;
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (handleBomb(fimg)) {
+				playInGameVideo("COFFRE");
+				_forcePaletteUpdate = true;
+				// Force reload of the place
+				if (_nextPlaceId == -1u) {
+					_nextPlaceId = _currentPlaceId;
+				}
+				playTransitionEndLevel(7);
+				break;
+			}
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+}
+
+bool CryOmni3DEngine_Versailles::handleBomb(ZonFixedImage *fimg) {
+	bool success = false;
+	Common::RandomSource rnd("VersaillesBomb");
+	Graphics::Surface bmpLetters[26];
+	unsigned char bombPossibilites[60][5];
+	unsigned char bombCurrentLetters[60];
+	Graphics::ManagedSurface tempSurf;
+
+	const unsigned int kBombPasswordLength = strlen(kBombPassword);
+	if (kBombPasswordLength >= kBombPasswordMaxLength) {
+		error("Bomb password is too long");
+	}
+
+	loadBMPs("bomb_%02d.bmp", bmpLetters, 26);
+	for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+		bombPossibilites[i][0] = toupper(kBombPassword[i]);
+		for (unsigned int j = 1; j < 5; j++) {
+			bool foundSameLetter;
+			do {
+				foundSameLetter = false;
+				bombPossibilites[i][j] = rnd.getRandomNumberRng('A', 'Z');
+				for (unsigned int k = 0; k < j; k++) {
+					if (bombPossibilites[i][k] == bombPossibilites[i][j]) {
+						foundSameLetter = true;
+					}
+				}
+			} while (foundSameLetter);
+		}
+		bombCurrentLetters[i] = rnd.getRandomNumber(4);
+	}
+
+	if (kBombPasswordLength <= kBombPasswordSmallLength) {
+		fimg->load("70z_16.GIF");
+	} else {
+		fimg->load("70z_17.GIF");
+	}
+	const Graphics::Surface *fimgSurface = fimg->surface();
+	tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format);
+	tempSurf.blitFrom(*fimgSurface);
+	drawBombLetters(tempSurf, bmpLetters, kBombPasswordLength, bombPossibilites, bombCurrentLetters);
+	drawCountdown(&tempSurf);
+	fimg->updateSurface(&tempSurf.rawSurface());
+
+	while (1) {
+		fimg->manage();
+		if (fimg->_exit || fimg->_zoneLow) {
+			break;
+		}
+		if (fimg->_zoneUse) {
+			if (fimg->_currentZone < kBombPasswordLength) {
+				// Safe digit
+				bombCurrentLetters[fimg->_currentZone] = (bombCurrentLetters[fimg->_currentZone] + 1) % 5;
+				// Reset the surface and redraw letters on it
+				tempSurf.blitFrom(*fimgSurface);
+				drawBombLetters(tempSurf, bmpLetters, kBombPasswordLength, bombPossibilites, bombCurrentLetters);
+				drawCountdown(&tempSurf);
+				fimg->updateSurface(&tempSurf.rawSurface());
+
+				waitMouseRelease();
+
+				// Check if password is OK
+				success = true;
+				for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+					unsigned char letterChar = bombPossibilites[i][bombCurrentLetters[i]];
+					if (letterChar != kBombPassword[i]) {
+						success = false;
+						break;
+					}
+				}
+				if (success) {
+					break;
+				}
+			}
+		}
+		if (countDown()) {
+			// Countdown has changed: refresh surface
+			drawCountdown(&tempSurf);
+			fimg->updateSurface(&tempSurf.rawSurface());
+		}
+	}
+
+	for (unsigned int i = 0; i < 26; i++) {
+		bmpLetters[i].free();
+	}
+	return success;
+}
+
+const char *CryOmni3DEngine_Versailles::kBombPassword = "JEMENVAISMAISLETATDEMEURERATOUJOURS";
+// We use brace elision here because it's dumped from the EXE
+const unsigned short CryOmni3DEngine_Versailles::kBombLettersPos[2][kBombPasswordMaxLength][2] = {
+	{
+		26, 91, 84, 89, 141, 89, 202, 88, 261, 87, 322, 86, 384, 85, 448, 84,
+		512, 83, 576, 83, 26, 175, 84, 175, 142, 174, 202, 174, 260, 174, 322,
+		174, 384, 173, 448, 173, 512, 173, 576, 172, 26, 261, 84, 261, 141,
+		261, 202, 261, 261, 262, 322, 262, 383, 262, 447, 263, 512, 263, 576,
+		263, 26, 344, 84, 345, 142, 346, 202, 347, 260, 348, 322, 349, 384,
+		350, 448, 351, 512, 352, 576, 352
+	},
+	{
+		42, 26, 100, 24, 155, 22, 214, 19, 271, 18, 330, 15, 389, 14, 451, 11,
+		515, 8, 576, 6, 45, 102, 100, 102, 156, 101, 215, 100, 272, 99, 331,
+		98, 391, 97, 453, 96, 515, 94, 578, 94, 44, 184, 101, 184, 157, 184,
+		215, 183, 272, 183, 331, 183, 391, 182, 453, 182, 515, 182, 577, 181,
+		44, 267, 101, 267, 157, 267, 215, 268, 272, 268, 331, 268, 390, 269,
+		453, 269, 515, 269, 578, 269, 45, 348, 101, 349, 156, 349, 215, 351,
+		271, 351, 331, 351, 391, 353, 453, 354, 515, 355, 577, 356, 44, 434,
+		101, 435, 156, 436, 215, 437, 272, 437, 331, 437, 391, 439, 453, 440,
+		515, 441, 578, 442
+	},
+};
+
+void CryOmni3DEngine_Versailles::drawBombLetters(Graphics::ManagedSurface &surface,
+        const Graphics::Surface(&bmpLetters)[26], const unsigned int kBombPasswordLength,
+        const unsigned char (&bombPossibilites)[kBombPasswordMaxLength][5],
+        const unsigned char (&bombCurrentLetters)[kBombPasswordMaxLength]) {
+	unsigned int table = kBombPasswordLength <= kBombPasswordSmallLength ? 0 : 1;
+	for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+		unsigned char letterChar = bombPossibilites[i][bombCurrentLetters[i]];
+		unsigned int letterId = 0;
+		if (letterChar >= 'A' && letterChar <= 'Z') {
+			letterId = letterChar - 'A';
+		}
+		const Graphics::Surface &letter = bmpLetters[letterId];
+		Common::Point dst(kBombLettersPos[table][i][0], kBombLettersPos[table][i][1]);
+		surface.transBlitFrom(letter, dst);
+	}
+}
+
 IMG_CB(88004) {
 	fimg->load("31j31.gif");
 	while (1) {
@@ -4082,6 +4457,112 @@ FILTER_EVENT(6, 19) {
 	return true;
 }
 
+FILTER_EVENT(7, 2) {
+	if (*event == 37021) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 103) {
+			// Light the candle
+			_inventory.removeByNameID(103);
+			collectObject(102);
+		}
+		// Handled here
+		return false;
+	} else if (*event == 37022) {
+		if (!_inventory.inInventoryByNameID(97)) {
+			collectObject(97);
+			_inventory.deselectObject();
+		} else {
+			// Jar is empty
+			displayMessageBoxWarp(11);
+		}
+		// Handled here
+		return false;
+	} else if (*event == 7) {
+		// Stairs
+		if (_gameVariables[GameVariables::kUsedLitCandle]) {
+			return true;
+		}
+
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 102) {
+			// Now you can go
+			displayMessageBoxWarp(12);
+			_inventory.removeByNameID(102);
+			_inventory.deselectObject();
+			// Save it for later
+			_gameVariables[GameVariables::kUsedLitCandle] = 1;
+
+			return true;
+		}
+
+		// Didn't used lit candle and not using it now: denied
+		// Too dark
+		displayMessageBoxWarp(7);
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(7, 9) {
+	if (*event == 37090) {
+		if (_placeStates[9].state == 0) {
+			// Get the candle snuffer
+			collectObject(145);
+			_inventory.deselectObject();
+			setPlaceState(9, 1);
+		}
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(7, 10_11_13) {
+	if (*event == 37131) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 143 &&
+		        !_inventory.inInventoryByNameID(136)) {
+			collectObject(136);
+			// WORKAROUND: Deselect the tool
+			_inventory.deselectObject();
+		}
+		// Handled here
+		return false;
+	} else if (*event == 37132) {
+		if (_inventory.selectedObject() &&
+		        _inventory.selectedObject()->idOBJ() == 143) {
+			// Nothing in this orange tree
+			displayMessageBoxWarp(5);
+		}
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
+FILTER_EVENT(7, 20) {
+	if (*event == 21) {
+		fakeTransition(*event);
+
+		playInGameVideo("70z_10");
+
+		executeSeeAction(88003);
+
+		_forcePaletteUpdate = true;
+		// Force reload of the place
+		if (_nextPlaceId == -1u) {
+			_nextPlaceId = _currentPlaceId;
+		}
+		// Handled here
+		return false;
+	}
+
+	return true;
+}
+
 #undef FILTER_EVENT
 #undef INIT_PLACE
 


Commit: 4e955c4776e3a4a8a73704fb04c90674bdac001f
    https://github.com/scummvm/scummvm/commit/4e955c4776e3a4a8a73704fb04c90674bdac001f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove outdated TODOs

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index e3e91b8..07fcd9c 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -795,10 +795,8 @@ void CryOmni3DEngine_Versailles::setGameTime(unsigned int newTime, unsigned int
 void CryOmni3DEngine_Versailles::gameStep() {
 	while (!_abortCommand) {
 		if (_nextPlaceId != -1u) {
-			// TODO: check selected object == -2 if needed
 			if (_placeStates[_nextPlaceId].initPlace) {
 				(this->*_placeStates[_nextPlaceId].initPlace)();
-				// TODO: check selected object == -2 if needed
 			}
 			doPlaceChange();
 			musicUpdate();
@@ -871,7 +869,6 @@ void CryOmni3DEngine_Versailles::gameStep() {
 			// Click on nothing with an object: deselect it
 			_inventory.setSelectedObject(nullptr);
 		}
-		// TODO: selected_object == -2 if needed
 	}
 }
 
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 0b60dce..fc94787 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -111,51 +111,50 @@ enum AbortCommand {
 
 struct GameVariables {
 	enum Var {
-		// TODO: make these enum members more correct
-		kCollectScore = 0, // OK       // 0
-		kUnlockHiddenDoor, // OK
-		kAlreadyWent3_19, // OK
-		kMedalsDrawerStatus, // OK
-		kCurrentTime, // OK
-		kGotMedalsSolution, // OK
-		kCabinetDrawerStatus, // OK
-		kDecipherScore, // OK
-		kCollectLampoonArchitecture, // OK
-		kGotRevealedPaper, // OK
-		kCollectKey, // OK             // 10
-		kCollectPortfolio, // OK
-		kSketchState, // OK
-		kFakeSketchChatState, // OK
-		kCollectFood, // OK
-		kCollectQuill, // OK
-		kStateLampoonReligion, // OK
-		kCollectSmallKey3, // OK
-		kCollectEngraving, // OK
-		kCollectCord, // OK
-		kCollectVaubanBlueprint1, // OK// 20
-		kCollectVaubanBlueprint2, // OK
-		kLadderState, // OK
-		kOpenedCurtain, // OK
-		kLoweredChandelier, // OK
-		kCombedOrangeTree, // OK
-		kMaineTalked, // OK
-		kUsedLitCandle, // OK
-		kBombState, // OK
-		kInkSpilled, // OK
-		kCollectedPaperOnTable, // OK  // 30
-		kSafeUnlocked, // OK
+		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, // OK
-		kBrushColor, // OK
-		kUsedScissors, // OK
-		kUnlockedAttic, // OK
-		kHasPlayedLebrun, // OK
+		kCollectedPaperInTrunk = 33,
+		kBrushColor,
+		kUsedScissors,
+		kUnlockedAttic,
+		kHasPlayedLebrun,
 		kWarnedIncomplete,
-		kUsedVaubanBlueprint1, // OK
-		kUsedVaubanBlueprint2, // OK   // 40
-		kSeenMemorandum, // OK
-		kCollectScissors, // OK
-		kSavedCountdown, // OK
+		kUsedVaubanBlueprint1,
+		kUsedVaubanBlueprint2,         // 40
+		kSeenMemorandum,
+		kCollectScissors,
+		kSavedCountdown,
 		kMax
 	};
 };


Commit: 0e0cdbee245dba78d35fab497ba16489fc9e561f
    https://github.com/scummvm/scummvm/commit/0e0cdbee245dba78d35fab497ba16489fc9e561f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix cursor shown too soon in transitions

It had then invalid colors.
Using previous palette in videos improved the situation but it's not
perfect though.

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 07fcd9c..4088749 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1000,6 +1000,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 	Common::String warpFile = nextPlace->warps[nextState];
 	warpFile.toUppercase();
 	if (warpFile.hasPrefix("NOT_STOP")) {
+		debug("Got not stop");
 		unsigned int transitionNum;
 		// Determine transition to take
 		if (nextPlace->getNumTransitions() == 1) {
@@ -1015,8 +1016,9 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 
 		animationId = determineTransitionAnimation(nextPlaceId, nextNextPlaceId, &transition);
 		animation = animationId == -1u ? "" : transition->animations[animationId];
-
 		animation.toUppercase();
+
+		debug("Transition animation: %s", animation.c_str());
 		if (animation.hasPrefix("NOT_FLI")) {
 			return;
 		}
@@ -1544,7 +1546,10 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
 		return;
 	}
 
-	g_system->showMouse(false);
+	if (restoreCursorPalette) {
+		// WORKAROUND: Don't mess with mouse when not restoring cursors palette
+		g_system->showMouse(false);
+	}
 	lockPalette(0, 241);
 	// Videos are like music because if you mute music in game it will mute videos soundtracks
 	playHNM(filename, Audio::Mixer::kMusicSoundType, nullptr,
@@ -1554,8 +1559,9 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
 	if (restoreCursorPalette) {
 		// Restore cursors colors as 2 first ones may have been erased by the video
 		setPalette(&_cursorPalette[3 * 240], 240, 248);
+		// WORKAROUND: Don't mess with mouse when not restoring cursors palette
+		g_system->showMouse(true);
 	}
-	g_system->showMouse(true);
 }
 
 void CryOmni3DEngine_Versailles::loadBMPs(const char *pattern, Graphics::Surface *bmps,


Commit: dae772f496c0eaa2df40b65292dddc850263f2cf
    https://github.com/scummvm/scummvm/commit/dae772f496c0eaa2df40b65292dddc850263f2cf
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Make sure toolbar is displayed on colored screen

If toolbar is triggered before warp first draw and after a FADE_PAL
transition, screen stays black until user leaves toolbar (in blind).

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 4088749..8401a78 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1208,6 +1208,12 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
 		g_system->copyRectToScreen(original->getPixels(), original->pitch, 0, 0, original->w, original->h);
 		drawCountdown();
 
+		// Fade in palette to avoid displaying toolbar on a black screen
+		if (_fadedPalette) {
+			fadeInPalette(_mainPalette);
+			_fadedPalette = false;
+		}
+
 		bool mustRedraw = displayToolbar(original);
 		// Don't redraw if we abort game
 		if (_abortCommand != AbortNoAbort) {


Commit: 57074300caf0340e31308fd7dc7bf3cd78e4e882
    https://github.com/scummvm/scummvm/commit/57074300caf0340e31308fd7dc7bf3cd78e4e882
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Remove superflous header

Changed paths:
    engines/cryomni3d/cryomni3d.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index bd27ea7..92c6314 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -38,8 +38,6 @@
 #include "cryomni3d/image/hlz.h"
 #include "cryomni3d/video/hnm_decoder.h"
 
-#include <stdarg.h> // For va_list etc.
-
 namespace CryOmni3D {
 
 CryOmni3DEngine::CryOmni3DEngine(OSystem *syst,


Commit: 222f6b0e4cd5afc3d6aae8210b71908b111fca19
    https://github.com/scummvm/scummvm/commit/222f6b0e4cd5afc3d6aae8210b71908b111fca19
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add assert where needed

Changed paths:
    engines/cryomni3d/cryomni3d.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 92c6314..edf4377 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -347,6 +347,8 @@ bool CryOmni3DEngine::checkKeysPressed(unsigned int numKeys, ...) {
 }
 
 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));
 }
 


Commit: ff197718c239e10209d8eaf26c90c11af5ed1c80
    https://github.com/scummvm/scummvm/commit/ff197718c239e10209d8eaf26c90c11af5ed1c80
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Rename unsigned int to uint

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/cryomni3d.h
    engines/cryomni3d/dialogs_manager.cpp
    engines/cryomni3d/dialogs_manager.h
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/fixed_image.h
    engines/cryomni3d/font_manager.cpp
    engines/cryomni3d/font_manager.h
    engines/cryomni3d/mouse_boxes.cpp
    engines/cryomni3d/mouse_boxes.h
    engines/cryomni3d/objects.cpp
    engines/cryomni3d/objects.h
    engines/cryomni3d/omni3d.cpp
    engines/cryomni3d/sprites.cpp
    engines/cryomni3d/sprites.h
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/dialogs_manager.cpp
    engines/cryomni3d/versailles/dialogs_manager.h
    engines/cryomni3d/versailles/documentation.cpp
    engines/cryomni3d/versailles/documentation.h
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp
    engines/cryomni3d/versailles/menus.cpp
    engines/cryomni3d/versailles/music.cpp
    engines/cryomni3d/versailles/saveload.cpp
    engines/cryomni3d/versailles/toolbar.cpp
    engines/cryomni3d/versailles/toolbar.h
    engines/cryomni3d/video/hnm_decoder.cpp
    engines/cryomni3d/video/hnm_decoder.h
    engines/cryomni3d/wam_parser.cpp
    engines/cryomni3d/wam_parser.h


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index edf4377..f1ac389 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -136,7 +136,7 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 	uint16 height = videoDecoder->getHeight();
 
 	bool skipVideo = false;
-	unsigned int frameNum = 0;
+	uint frameNum = 0;
 	while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
 		if (videoDecoder->needsUpdate()) {
 			const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
@@ -224,7 +224,7 @@ void CryOmni3DEngine::setCursor(const Graphics::Cursor &cursor) const {
 	                         cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor());
 }
 
-void CryOmni3DEngine::setCursor(unsigned int cursorId) const {
+void CryOmni3DEngine::setCursor(uint cursorId) const {
 	const Graphics::Cursor &cursor = _sprites.getCursor(cursorId);
 	g_system->setMouseCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(),
 	                         cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor());
@@ -234,7 +234,7 @@ bool CryOmni3DEngine::pollEvents() {
 	Common::Event event;
 	bool hasEvents = false;
 
-	unsigned int oldMouseButton = getCurrentMouseButton();
+	uint oldMouseButton = getCurrentMouseButton();
 
 	while (g_system->getEventManager()->pollEvent(event)) {
 		if (event.type == Common::EVENT_KEYDOWN) {
@@ -245,7 +245,7 @@ bool CryOmni3DEngine::pollEvents() {
 	g_system->delayMillis(10);
 
 	_dragStatus = kDragStatus_NoDrag;
-	unsigned int currentMouseButton = getCurrentMouseButton();
+	uint currentMouseButton = getCurrentMouseButton();
 	if (!oldMouseButton && currentMouseButton == 1) {
 		// Starting the drag
 		_dragStatus = kDragStatus_Pressed;
@@ -276,11 +276,11 @@ bool CryOmni3DEngine::pollEvents() {
 	return hasEvents;
 }
 
-void CryOmni3DEngine::setAutoRepeatClick(unsigned int millis) {
+void CryOmni3DEngine::setAutoRepeatClick(uint millis) {
 	_autoRepeatNextEvent = g_system->getMillis() + millis;
 }
 
-unsigned int CryOmni3DEngine::getCurrentMouseButton() {
+uint CryOmni3DEngine::getCurrentMouseButton() {
 	int mask = g_system->getEventManager()->getButtonState();
 	if (mask & 0x1) {
 		return 1;
@@ -325,13 +325,13 @@ bool CryOmni3DEngine::checkKeysPressed() {
 	}
 }
 
-bool CryOmni3DEngine::checkKeysPressed(unsigned int numKeys, ...) {
+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 (unsigned int i = 0; i < numKeys; i++) {
+		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) {
@@ -372,19 +372,19 @@ void CryOmni3DEngine::fadeOutPalette() {
 	uint16 delta[256 * 3];
 
 	g_system->getPaletteManager()->grabPalette(palOut, 0, 256);
-	for (unsigned int i = 0; i < 256 * 3; i++) {
+	for (uint i = 0; i < 256 * 3; i++) {
 		palWork[i] = palOut[i] << 8;
 		delta[i] = palWork[i] / 25;
 	}
 
-	for (unsigned int step = 0; step < 25 && !g_engine->shouldQuit(); step++) {
-		for (unsigned int i = 0; i < 256 * 3; i++) {
+	for (uint step = 0; step < 25 && !g_engine->shouldQuit(); 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 (unsigned int i = 0; i < 5; i++) {
+		for (uint i = 0; i < 5; i++) {
 			g_system->updateScreen();
 			g_system->delayMillis(10);
 		}
@@ -399,19 +399,19 @@ void CryOmni3DEngine::fadeInPalette(const byte *palette) {
 
 	memset(palOut, 0, sizeof(palOut));
 	memset(palWork, 0, sizeof(palWork));
-	for (unsigned int i = 0; i < 256 * 3; i++) {
+	for (uint i = 0; i < 256 * 3; i++) {
 		delta[i] = (palette[i] << 8) / 25;
 	}
 
 	setBlackPalette();
-	for (unsigned int step = 0; step < 25 && !g_engine->shouldQuit(); step++) {
-		for (unsigned int i = 0; i < 256 * 3; i++) {
+	for (uint step = 0; step < 25 && !g_engine->shouldQuit(); 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 (unsigned int i = 0; i < 5; i++) {
+		for (uint i = 0; i < 5; i++) {
 			g_system->updateScreen();
 			g_system->delayMillis(10);
 		}
diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index 17e9cd3..12d4299 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -107,8 +107,8 @@ public:
 
 	void fillSurface(byte color);
 	void setCursor(const Graphics::Cursor &cursor) const;
-	void setCursor(unsigned int cursorId) const;
-	typedef void (CryOmni3DEngine::*HNMCallback)(unsigned int frameNum);
+	void setCursor(uint cursorId) const;
+	typedef void (CryOmni3DEngine::*HNMCallback)(uint frameNum);
 	void playHNM(const Common::String &filename,
 	             Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
 	             HNMCallback beforeDraw = nullptr, HNMCallback afterDraw = nullptr);
@@ -117,13 +117,13 @@ public:
 	bool pollEvents();
 	Common::Point getMousePos();
 	void setMousePos(const Common::Point &point);
-	unsigned int getCurrentMouseButton();
+	uint getCurrentMouseButton();
 	Common::KeyState getNextKey();
 	bool checkKeysPressed();
-	bool checkKeysPressed(unsigned int numKeys, ...);
+	bool checkKeysPressed(uint numKeys, ...);
 	void clearKeys() { _keysPressed.clear(); }
 	void waitMouseRelease();
-	void setAutoRepeatClick(unsigned int millis);
+	void setAutoRepeatClick(uint millis);
 	DragStatus getDragStatus() { return _dragStatus; }
 
 	Common::String prepareFileName(const Common::String &baseName, const char *extension) const {
@@ -136,7 +136,7 @@ public:
 	virtual bool displayToolbar(const Graphics::Surface *original) = 0;
 	virtual bool hasPlaceDocumentation() = 0;
 	virtual bool displayPlaceDocumentation() = 0;
-	virtual unsigned int displayOptions() = 0;
+	virtual uint displayOptions() = 0;
 	virtual bool shouldAbort() { return g_engine->shouldQuit(); }
 
 	virtual void makeTranslucent(Graphics::Surface &dst, const Graphics::Surface &src) const = 0;
@@ -161,11 +161,11 @@ protected:
 
 	DragStatus _dragStatus;
 	Common::Point _dragStart;
-	unsigned int _autoRepeatNextEvent;
+	uint _autoRepeatNextEvent;
 
 private:
-	unsigned int _lockPaletteStartRW;
-	unsigned int _lockPaletteEndRW;
+	uint _lockPaletteStartRW;
+	uint _lockPaletteEndRW;
 };
 
 } // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/dialogs_manager.cpp b/engines/cryomni3d/dialogs_manager.cpp
index ef68495..fc40b14 100644
--- a/engines/cryomni3d/dialogs_manager.cpp
+++ b/engines/cryomni3d/dialogs_manager.cpp
@@ -42,7 +42,7 @@ void DialogsManager::loadGTO(const Common::String &gtoFileName) {
 	delete[] _gtoBuffer;
 	_gtoBuffer = nullptr;
 
-	unsigned int gtoSize = gtoFile.size();
+	uint gtoSize = gtoFile.size();
 	_gtoBuffer = new char[gtoSize];
 	gtoFile.read(_gtoBuffer, gtoSize);
 	gtoFile.close();
@@ -54,7 +54,7 @@ void DialogsManager::loadGTO(const Common::String &gtoFileName) {
 
 void DialogsManager::populateLabels() {
 	/* Get labels count and populate the labels array */
-	unsigned int numLabels;
+	uint numLabels;
 	const char *labelsP = strstr(_gtoBuffer, "LABELS=");
 	if (labelsP) {
 		labelsP += sizeof("LABELS=") - 1;
@@ -77,7 +77,7 @@ void DialogsManager::populateLabels() {
 }
 
 const char *DialogsManager::findLabel(const char *label, const char **realLabel) const {
-	unsigned int labelLen = 0;
+	uint labelLen = 0;
 	/* Truncate input label */
 	for (const char *labelP = label;
 	        *labelP != '\0' &&
@@ -115,7 +115,7 @@ Common::String DialogsManager::getLabelSound(const char *label) const {
 }
 
 const char *DialogsManager::findSequence(const char *sequence) const {
-	unsigned int sequenceLen = strlen(sequence);
+	uint sequenceLen = strlen(sequence);
 
 	const char *lineP;
 	for (lineP = _gtoBuffer; lineP != nullptr; lineP = nextLine(lineP)) {
@@ -226,7 +226,7 @@ const char *DialogsManager::previousMatch(const char *currentPtr, const char *st
 		return nullptr;
 	}
 
-	unsigned int matchLen = strlen(str);
+	uint matchLen = strlen(str);
 	for (; currentPtr >= _gtoBuffer; currentPtr--) {
 		if (*currentPtr == str[0]) {
 			if (!strncmp(currentPtr, str, matchLen)) {
@@ -308,7 +308,7 @@ bool DialogsManager::play(const Common::String &sequence, bool &slowStop) {
 			for (; *questionEnd != '>'; questionEnd++) { }
 			questions.push_back(Common::String(questionStart, questionEnd));
 		}
-		unsigned int eocInserted = -1;
+		uint eocInserted = -1;
 		if (!endOfConversationFound && questions.size() > 0) {
 			eocInserted = questions.size();
 			questions.push_back(_endOfConversationText);
@@ -321,7 +321,7 @@ bool DialogsManager::play(const Common::String &sequence, bool &slowStop) {
 
 		if (gotoList[0].label.hasPrefix("JOU")) {
 			// We must give a subject
-			unsigned int playerChoice = askPlayerQuestions(video, questions);
+			uint playerChoice = askPlayerQuestions(video, questions);
 			didSomething = true;
 			// -1 when shouldQuit
 			if (playerChoice == -1u || playerChoice == eocInserted) {
diff --git a/engines/cryomni3d/dialogs_manager.h b/engines/cryomni3d/dialogs_manager.h
index da1ccdb..7a3eefb 100644
--- a/engines/cryomni3d/dialogs_manager.h
+++ b/engines/cryomni3d/dialogs_manager.h
@@ -48,14 +48,14 @@ public:
 		_ignoreNoEndOfConversation(false) { }
 	virtual ~DialogsManager();
 
-	void init(unsigned int size, const Common::String &endOfConversationText) { _dialogsVariables.resize(size); _endOfConversationText = endOfConversationText; }
+	void init(uint size, const Common::String &endOfConversationText) { _dialogsVariables.resize(size); _endOfConversationText = endOfConversationText; }
 	void loadGTO(const Common::String &gtoFile);
 
-	void setupVariable(unsigned int id, const Common::String &variable) { _dialogsVariables[id] = DialogVariable(variable, 'N'); }
+	void setupVariable(uint id, const Common::String &variable) { _dialogsVariables[id] = DialogVariable(variable, 'N'); }
 	void reinitVariables();
-	unsigned int size() const { return _dialogsVariables.size(); }
-	byte &operator[](unsigned int idx) { return _dialogsVariables[idx].value; }
-	const byte &operator[](unsigned int idx) const { return _dialogsVariables[idx].value; }
+	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; }
 
@@ -69,8 +69,8 @@ protected:
 	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 unsigned int askPlayerQuestions(const Common::String &video,
-	                                        const Common::StringArray &questions) = 0;
+	virtual uint askPlayerQuestions(const Common::String &video,
+	                                const Common::StringArray &questions) = 0;
 
 private:
 	struct Goto {
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index f5f354a..c519eb9 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -163,7 +163,7 @@ void ZonFixedImage::loadZones(const Common::String &image) {
 	}
 }
 
-Common::Point ZonFixedImage::getZoneCenter(unsigned int zoneId) const {
+Common::Point ZonFixedImage::getZoneCenter(uint zoneId) const {
 	if (zoneId >= _zones.size()) {
 		error("Invalid zoneId %u/%u", zoneId, _zones.size());
 	}
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 7321a30..92445ed 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -35,16 +35,16 @@ struct Surface;
 namespace CryOmni3D {
 
 struct FixedImageConfiguration {
-	unsigned int spriteNothing;
-	unsigned int spriteLow;
-	unsigned int spriteHigh;
-	unsigned int spriteLeft;
-	unsigned int spriteRight;
-	unsigned int spriteQuestion;
-	unsigned int spriteListen;
-	unsigned int spriteSee;
-	unsigned int spriteUse;
-	unsigned int spriteSpeak;
+	uint spriteNothing;
+	uint spriteLow;
+	uint spriteHigh;
+	uint spriteLeft;
+	uint spriteRight;
+	uint spriteQuestion;
+	uint spriteListen;
+	uint spriteSee;
+	uint spriteUse;
+	uint spriteSpeak;
 
 	int16 toolbarTriggerY;
 };
@@ -74,13 +74,13 @@ public:
 	void updateSurface(const Graphics::Surface *newSurface);
 	const Graphics::Surface *surface() const { return _imageSurface; }
 	void changeCallback(CallbackFunctor *callback) { delete _callback; _callback = callback; }
-	Common::Point getZoneCenter(unsigned int zoneId) const;
-	void disableZone(unsigned int zoneId) { _zones[zoneId].valid = false; }
+	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 */
-	unsigned int _currentZone;
+	uint _currentZone;
 	bool _exit;
 	bool _zoneLow;
 	bool _zoneHigh;
diff --git a/engines/cryomni3d/font_manager.cpp b/engines/cryomni3d/font_manager.cpp
index 0b3b1a5..bf24061 100644
--- a/engines/cryomni3d/font_manager.cpp
+++ b/engines/cryomni3d/font_manager.cpp
@@ -73,10 +73,10 @@ void FontManager::loadFont(Common::ReadStream &font_fl) {
 	font_fl.read(font->comment, sizeof(font->comment));
 	//debug("Comment %s", font.comment);
 
-	for (unsigned int i = 0; i < Font::kCharactersCount; i++) {
+	for (uint i = 0; i < Font::kCharactersCount; i++) {
 		uint16 h = font_fl.readUint16BE();
 		uint16 w = font_fl.readUint16BE();
-		unsigned int sz = font->chars[i].setup(w, h);
+		uint sz = font->chars[i].setup(w, h);
 		//debug("Char %d sz %dx%d %d", i, w, h, sz);
 		font->chars[i].offX = font_fl.readSint16BE();
 		font->chars[i].offY = font_fl.readSint16BE();
@@ -100,7 +100,7 @@ void FontManager::setCurrentFont(int currentFont) {
 	setSpaceWidth(0);
 }
 
-void FontManager::setSpaceWidth(unsigned int additionalSpace) {
+void FontManager::setSpaceWidth(uint additionalSpace) {
 	if (_currentFont) {
 		_spaceWidth = additionalSpace + _currentFont->chars[0].printedWidth;
 	} else {
@@ -108,16 +108,16 @@ void FontManager::setSpaceWidth(unsigned int additionalSpace) {
 	}
 }
 
-unsigned int FontManager::displayStr_(unsigned int x, unsigned int y,
-                                      const Common::String &text) const {
-	unsigned int offset = 0;
+uint FontManager::displayStr_(uint x, uint y,
+                              const Common::String &text) const {
+	uint offset = 0;
 	for (Common::String::const_iterator it = text.begin(); it != text.end(); it++) {
 		offset += displayChar(x + offset, y, *it);
 	}
 	return offset;
 }
 
-unsigned int FontManager::displayChar(unsigned int x, unsigned int y, unsigned char c) const {
+uint FontManager::displayChar(uint x, uint y, unsigned char c) const {
 	if (!_currentFont) {
 		error("There is no current font");
 	}
@@ -154,8 +154,8 @@ unsigned int FontManager::displayChar(unsigned int x, unsigned int y, unsigned c
 #endif
 }
 
-unsigned int FontManager::getStrWidth(const Common::String &text) const {
-	unsigned int width = 0;
+uint FontManager::getStrWidth(const Common::String &text) const {
+	uint width = 0;
 	for (Common::String::const_iterator it = text.begin(); it != text.end(); it++) {
 		unsigned char c = *it;
 		if (c == ' ') {
@@ -181,12 +181,12 @@ bool FontManager::displayBlockText(const Common::String &text,
 	if (begin != text.end()) {
 		_blockTextRemaining = nullptr;
 		while (ptr != text.end() && !notEnoughSpace) {
-			unsigned int finalPos;
+			uint finalPos;
 			bool has_cr;
 			calculateWordWrap(text, &ptr, &finalPos, &has_cr, words);
-			unsigned int spacesWidth = (words.size() - 1) * _spaceWidth;
-			unsigned int remainingSpace = (_blockRect.right - finalPos);
-			unsigned int spaceConsumed = 0;
+			uint spacesWidth = (words.size() - 1) * _spaceWidth;
+			uint remainingSpace = (_blockRect.right - finalPos);
+			uint spaceConsumed = 0;
 			double spaceWidthPerWord;
 			if (words.size() == 1) {
 				spaceWidthPerWord = _spaceWidth;
@@ -194,7 +194,7 @@ bool FontManager::displayBlockText(const Common::String &text,
 				spaceWidthPerWord = (double)spacesWidth / (double)words.size();
 			}
 			Common::Array<Common::String>::const_iterator word;
-			unsigned int word_i;
+			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) {
@@ -218,7 +218,7 @@ bool FontManager::displayBlockText(const Common::String &text,
 	return notEnoughSpace;
 }
 
-unsigned int FontManager::getLinesCount(const Common::String &text, unsigned int width) {
+uint FontManager::getLinesCount(const Common::String &text, uint width) {
 	if (text.size() == 0) {
 		// One line even if it's empty
 		return 1;
@@ -228,13 +228,13 @@ unsigned int FontManager::getLinesCount(const Common::String &text, unsigned int
 		return getStrWidth(text) / width + 3;
 	}
 
-	unsigned int lineCount = 0;
+	uint lineCount = 0;
 	Common::String::const_iterator textP = text.begin();
-	unsigned int len = text.size();
+	uint len = text.size();
 
 	while (len > 0) {
 		Common::String buffer;
-		unsigned int lineWidth = 0;
+		uint lineWidth = 0;
 		lineCount++;
 		while (lineWidth < width && len > 0 && *textP != '\r') {
 			buffer += *(textP++);
@@ -277,12 +277,12 @@ unsigned int FontManager::getLinesCount(const Common::String &text, unsigned int
 }
 
 void FontManager::calculateWordWrap(const Common::String &text,
-                                    Common::String::const_iterator *position, unsigned int *finalPos, bool *hasCr,
+                                    Common::String::const_iterator *position, uint *finalPos, bool *hasCr,
                                     Common::Array<Common::String> &words) const {
 	*hasCr = false;
-	unsigned int offset = 0;
+	uint offset = 0;
 	bool wordWrap = false;
-	unsigned int lineWidth = _blockRect.right - _blockRect.left;
+	uint lineWidth = _blockRect.right - _blockRect.left;
 	Common::String::const_iterator ptr = *position;
 
 	words.clear();
@@ -299,7 +299,7 @@ void FontManager::calculateWordWrap(const Common::String &text,
 		Common::String::const_iterator begin = ptr;
 		for (; ptr != text.end() && *ptr != '\r' && *ptr != ' '; ptr++) { }
 		Common::String word(begin, ptr);
-		unsigned int width = getStrWidth(word);
+		uint width = getStrWidth(word);
 		if (width + offset >= lineWidth) {
 			wordWrap = true;
 			// word is too long: just put pointer back at begining
@@ -329,10 +329,10 @@ FontManager::Character::~Character() {
 	delete[] data;
 }
 
-unsigned int FontManager::Character::setup(uint16 width, uint16 height) {
+uint FontManager::Character::setup(uint16 width, uint16 height) {
 	w = width;
 	h = height;
-	unsigned int sz = w * h;
+	uint sz = w * h;
 	data = new byte[sz];
 	return sz;
 }
diff --git a/engines/cryomni3d/font_manager.h b/engines/cryomni3d/font_manager.h
index 24b45f5..0ac4fe3 100644
--- a/engines/cryomni3d/font_manager.h
+++ b/engines/cryomni3d/font_manager.h
@@ -44,22 +44,22 @@ public:
 
 	void loadFonts(const Common::Array<Common::String> &fontFiles);
 	void setCurrentFont(int currentFont);
-	unsigned int getCurrentFont() { return _currentFontId; }
+	uint getCurrentFont() { return _currentFontId; }
 	void setTransparentBackground(bool transparent) { _transparentBackground = transparent; }
-	void setSpaceWidth(unsigned int additionalSpace);
+	void setSpaceWidth(uint additionalSpace);
 	void setForeColor(byte color) { _foreColor = color; }
 	void setLineHeight(int h) { _lineHeight = h; }
 	int lineHeight() { return _lineHeight; }
-	void setCharSpacing(unsigned int w) { _charSpacing = w; }
+	void setCharSpacing(uint w) { _charSpacing = w; }
 	void setSurface(Graphics::ManagedSurface *surface) { _currentSurface = surface; }
 
 	int getFontMaxHeight() { return _currentFont->maxHeight; }
 
-	void displayInt(unsigned int x, unsigned int y, int value) const { displayStr_(x, y, Common::String::format("%d", value)); }
-	void displayStr(unsigned int x, unsigned int y, const Common::String &text) const { displayStr_(x, y, text); }
-	unsigned int getStrWidth(const Common::String &text) const;
+	void displayInt(uint x, uint y, int value) const { displayStr_(x, y, Common::String::format("%d", value)); }
+	void displayStr(uint x, uint y, const Common::String &text) const { displayStr_(x, y, text); }
+	uint getStrWidth(const Common::String &text) const;
 
-	unsigned int getLinesCount(const Common::String &text, unsigned int width);
+	uint getLinesCount(const Common::String &text, uint 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) { return displayBlockText(text, text.begin()); }
@@ -69,10 +69,10 @@ public:
 
 private:
 	void loadFont(Common::ReadStream &font_fl);
-	unsigned int displayStr_(unsigned int x, unsigned int y, const Common::String &text) const;
-	unsigned int displayChar(unsigned int x, unsigned int y, unsigned char c) const;
+	uint displayStr_(uint x, uint y, const Common::String &text) const;
+	uint displayChar(uint x, uint y, unsigned char c) const;
 	void calculateWordWrap(const Common::String &text, Common::String::const_iterator *position,
-	                       unsigned int *finalPos, bool *has_br, Common::Array<Common::String> &words) const;
+	                       uint *finalPos, bool *has_br, Common::Array<Common::String> &words) const;
 
 	struct Character {
 		uint16 h;
@@ -86,7 +86,7 @@ private:
 		Character();
 		~Character();
 
-		unsigned int setup(uint16 width, uint16 height);
+		uint setup(uint16 width, uint16 height);
 	};
 
 	struct Font {
@@ -99,10 +99,10 @@ private:
 
 	Common::Array<Font *> _fonts;
 	const Font *_currentFont;
-	unsigned int _currentFontId;
+	uint _currentFontId;
 	bool _transparentBackground;
-	unsigned int _spaceWidth;
-	unsigned int _charSpacing;
+	uint _spaceWidth;
+	uint _charSpacing;
 
 	byte _foreColor;
 
diff --git a/engines/cryomni3d/mouse_boxes.cpp b/engines/cryomni3d/mouse_boxes.cpp
index 6e8887d..85c4cd7 100644
--- a/engines/cryomni3d/mouse_boxes.cpp
+++ b/engines/cryomni3d/mouse_boxes.cpp
@@ -28,7 +28,7 @@
 
 namespace CryOmni3D {
 
-MouseBoxes::MouseBoxes(unsigned int size) {
+MouseBoxes::MouseBoxes(uint size) {
 	_boxes.resize(size);
 }
 
@@ -36,7 +36,7 @@ MouseBoxes::~MouseBoxes() {
 }
 
 void MouseBoxes::reset() {
-	unsigned int sz = _boxes.size();
+	uint sz = _boxes.size();
 	_boxes.clear();
 	_boxes.resize(sz);
 }
diff --git a/engines/cryomni3d/mouse_boxes.h b/engines/cryomni3d/mouse_boxes.h
index 66ddc4a..bda8115 100644
--- a/engines/cryomni3d/mouse_boxes.h
+++ b/engines/cryomni3d/mouse_boxes.h
@@ -37,7 +37,7 @@ class FontManager;
 
 class MouseBoxes {
 public:
-	MouseBoxes(unsigned int size);
+	MouseBoxes(uint size);
 	virtual ~MouseBoxes();
 
 	void reset();
diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
index 1559680..7829664 100644
--- a/engines/cryomni3d/objects.cpp
+++ b/engines/cryomni3d/objects.cpp
@@ -25,7 +25,7 @@
 
 namespace CryOmni3D {
 
-Object *Objects::findObjectByNameID(unsigned int nameID) {
+Object *Objects::findObjectByNameID(uint nameID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if (it->valid() && it->idOBJ() == nameID) {
 			return it;
@@ -34,7 +34,7 @@ Object *Objects::findObjectByNameID(unsigned int nameID) {
 	error("nameID not found %u", nameID);
 }
 
-Object *Objects::findObjectByIconID(unsigned int iconID) {
+Object *Objects::findObjectByIconID(uint iconID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if (it->valid() && it->idCA() == iconID) {
 			return it;
@@ -60,12 +60,12 @@ void Inventory::add(Object *obj) {
 	error("No more room in inventory");
 }
 
-void Inventory::remove(unsigned int position) {
+void Inventory::remove(uint position) {
 	(*this)[position] = nullptr;
 	(*_changeCallback)(-1u);
 }
 
-void Inventory::removeByIconID(unsigned int iconID) {
+void Inventory::removeByIconID(uint iconID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idCA() == iconID) {
 			deselectObject();
@@ -76,7 +76,7 @@ void Inventory::removeByIconID(unsigned int iconID) {
 	// Don't bail out
 }
 
-void Inventory::removeByNameID(unsigned int nameID) {
+void Inventory::removeByNameID(uint nameID) {
 	for (iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idOBJ() == nameID) {
 			deselectObject();
@@ -87,7 +87,7 @@ void Inventory::removeByNameID(unsigned int nameID) {
 	// Don't bail out
 }
 
-bool Inventory::inInventoryByIconID(unsigned int iconID) const {
+bool Inventory::inInventoryByIconID(uint iconID) const {
 	for (const_iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idCA() == iconID) {
 			return true;
@@ -96,7 +96,7 @@ bool Inventory::inInventoryByIconID(unsigned int iconID) const {
 	return false;
 }
 
-bool Inventory::inInventoryByNameID(unsigned int nameID) const {
+bool Inventory::inInventoryByNameID(uint nameID) const {
 	for (const_iterator it = begin(); it != end(); it++) {
 		if ((*it) && (*it)->idOBJ() == nameID) {
 			return true;
diff --git a/engines/cryomni3d/objects.h b/engines/cryomni3d/objects.h
index c34f30d..d680b6a 100644
--- a/engines/cryomni3d/objects.h
+++ b/engines/cryomni3d/objects.h
@@ -38,39 +38,39 @@ public:
 	Object() : _valid(false), _idCA(-1), _idCl(-1), _idSA(-1), _idSl(-1), _idOBJ(-1),
 		_viewCallback(nullptr) {}
 
-	Object(const Sprites &sprites, unsigned int idCA, unsigned int idOBJ) : _idCA(idCA),
+	Object(const Sprites &sprites, uint idCA, uint idOBJ) : _idCA(idCA),
 		_idCl(sprites.calculateSpriteId(idCA, 1)), _idSA(sprites.calculateSpriteId(idCA, 2)),
 		_idSl(sprites.calculateSpriteId(idCA, 3)),
 		_valid(true), _idOBJ(idOBJ), _viewCallback(nullptr) {}
 
 	~Object() { delete _viewCallback; }
 
-	unsigned int valid() const { return _valid; }
-	unsigned int idCA() const { return _idCA; }
-	unsigned int idCl() const { return _idCl; }
-	unsigned int idSA() const { return _idSA; }
-	unsigned int idSl() const { return _idSl; }
-	unsigned int idOBJ() const { return _idOBJ; }
+	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(unsigned int newIdOBJ) { _idOBJ = newIdOBJ; }
+	void rename(uint newIdOBJ) { _idOBJ = newIdOBJ; }
 
 private:
-	unsigned int _idOBJ;
-	unsigned int _idCA;
-	unsigned int _idCl;
-	unsigned int _idSA;
-	unsigned int _idSl;
+	uint _idOBJ;
+	uint _idCA;
+	uint _idCl;
+	uint _idSA;
+	uint _idSl;
 	bool _valid;
 	ViewCallback _viewCallback;
 };
 
 class Objects : public Common::Array<Object> {
 public:
-	Object *findObjectByNameID(unsigned int nameID);
-	Object *findObjectByIconID(unsigned int iconID);
+	Object *findObjectByNameID(uint nameID);
+	Object *findObjectByIconID(uint iconID);
 private:
 };
 
@@ -78,15 +78,15 @@ class Inventory : public Common::Array<Object *> {
 public:
 	Inventory() : _selectedObject(nullptr), _changeCallback(nullptr) { }
 	~Inventory() { delete _changeCallback; }
-	void init(unsigned int count, Common::Functor1<unsigned int, void> *changeCallback) { _changeCallback = changeCallback; resize(count); }
+	void init(uint count, Common::Functor1<uint, void> *changeCallback) { _changeCallback = changeCallback; resize(count); }
 
 	void clear();
 	void add(Object *);
-	void remove(unsigned int position);
-	void removeByNameID(unsigned int nameID);
-	void removeByIconID(unsigned int iconID);
-	bool inInventoryByNameID(unsigned int nameID) const;
-	bool inInventoryByIconID(unsigned int iconID) const;
+	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; }
@@ -94,7 +94,7 @@ public:
 
 private:
 	Object *_selectedObject;
-	Common::Functor1<unsigned int, void> *_changeCallback;
+	Common::Functor1<uint, void> *_changeCallback;
 };
 
 } // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/omni3d.cpp b/engines/cryomni3d/omni3d.cpp
index d0169a4..e02b521 100644
--- a/engines/cryomni3d/omni3d.cpp
+++ b/engines/cryomni3d/omni3d.cpp
@@ -142,14 +142,14 @@ void Omni3DManager::updateImageCoords() {
 
 	double tmp = (2048 * 65536) - 2048 * 65536 / (2. * M_PI) * _alpha;
 
-	unsigned int k = 0;
-	for (unsigned int i = 0; i < 31; i++) {
+	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];
 
-		unsigned int offset = 80;
-		unsigned int j;
+		uint offset = 80;
+		uint j;
 		for (j = 0; j < 20; j++) {
 			double v16 = atan2(_oppositeV[j], v25);
 			double v17 = v16 * _helperValue;
@@ -187,12 +187,12 @@ const Graphics::Surface *Omni3DManager::getSurface() {
 	}
 
 	if (_dirty) {
-		unsigned int off = 2;
+		uint off = 2;
 		byte *dst = (byte *)_surface.getBasePtr(0, 0);
 		const byte *src = (const byte *)_sourceSurface->getBasePtr(0, 0);
 
-		for (unsigned int i = 0; i < 30; i++) {
-			for (unsigned int j = 0; j < 40; j++) {
+		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;
@@ -208,14 +208,14 @@ const Graphics::Surface *Omni3DManager::getSurface() {
 				int x2 = (((_imageCoords[off + 0] >> 0) * 2) + dx2) >> 1;
 				int y2 = (((_imageCoords[off + 1] >> 5) * 2) + dy2) >> 1;
 
-				for (unsigned int y = 0; y < 16; y++) {
-					unsigned int px = (x2 * 2 + x1) * 16;
-					unsigned int py = (y2 * 2 + y1) / 2;
-					unsigned int deltaX = x1 * 32;
-					unsigned int deltaY = y1;
+				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 (unsigned int x = 0; x < 16; x++) {
-						unsigned int srcOff = (py & 0x1ff800) | (px >> 21);
+					for (uint x = 0; x < 16; x++) {
+						uint srcOff = (py & 0x1ff800) | (px >> 21);
 						dst[x] = src[srcOff];
 						px += deltaX;
 						py += deltaY;
@@ -257,7 +257,7 @@ Common::Point Omni3DManager::mapMouseCoords(const Common::Point &mouse) {
 	int smallX = mouse.x & 0xf, squareX = mouse.x >> 4;
 	int smallY = mouse.y & 0xf, squareY = mouse.y >> 4;
 
-	unsigned int off = 82 * squareY + 2 * squareX;
+	uint off = 82 * squareY + 2 * squareX;
 
 	pt.x = ((_imageCoords[off + 2] +
 	         smallY * ((_imageCoords[off + 84] - _imageCoords[off + 2]) >> 4) +
diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
index df09afb..473cd8a 100644
--- a/engines/cryomni3d/sprites.cpp
+++ b/engines/cryomni3d/sprites.cpp
@@ -72,7 +72,7 @@ void Sprites::loadSprites(Common::ReadStream &spr_fl) {
 
 		uint16 w = spr_fl.readUint16BE();
 		uint16 h = spr_fl.readUint16BE();
-		unsigned int sz = cursor->setup(w, h);
+		uint sz = cursor->setup(w, h);
 		cursor->_offX = spr_fl.readUint32BE();
 		cursor->_offY = spr_fl.readUint32BE();
 
@@ -81,7 +81,7 @@ void Sprites::loadSprites(Common::ReadStream &spr_fl) {
 	}
 }
 
-void Sprites::setupMapTable(const unsigned int *table, unsigned int size) {
+void Sprites::setupMapTable(const uint *table, uint size) {
 	delete _map;
 	_map = nullptr;
 	// Reset the reverse mapping
@@ -89,11 +89,11 @@ void Sprites::setupMapTable(const unsigned int *table, unsigned int size) {
 		(*it)->_constantId = -1;
 	}
 	if (table) {
-		_map = new Common::Array<unsigned int>(table, size);
+		_map = new Common::Array<uint>(table, size);
 
 		// Sweep all the mapping and set its reverse values
-		unsigned int i = 0;
-		for (Common::Array<unsigned int>::const_iterator it = _map->begin(); it != _map->end(); it++, i++) {
+		uint i = 0;
+		for (Common::Array<uint>::const_iterator it = _map->begin(); it != _map->end(); it++, i++) {
 			_cursors[*it]->_constantId = i;
 		}
 
@@ -101,7 +101,7 @@ void Sprites::setupMapTable(const unsigned int *table, unsigned int size) {
 		// 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
-		unsigned int unswept = 0;
+		uint unswept = 0;
 		for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
 			if ((*it)->_constantId == -1u) {
 				unswept++;
@@ -128,13 +128,13 @@ void Sprites::setupMapTable(const unsigned int *table, unsigned int size) {
 	}
 }
 
-void Sprites::setSpriteHotspot(unsigned int spriteId, unsigned int x, unsigned int y) {
+void Sprites::setSpriteHotspot(uint spriteId, uint x, uint y) {
 	MAP_ID(spriteId);
 	_cursors[spriteId]->_offX = x;
 	_cursors[spriteId]->_offY = y;
 }
 
-void Sprites::replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId) {
+void Sprites::replaceSprite(uint oldSpriteId, uint newSpriteId) {
 	MAP_ID(oldSpriteId);
 	MAP_ID(newSpriteId);
 	if (_cursors[oldSpriteId]->refCnt > 1) {
@@ -146,11 +146,11 @@ void Sprites::replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId)
 	_cursors[oldSpriteId]->refCnt++;
 }
 
-void Sprites::replaceSpriteColor(unsigned int spriteId, byte currentColor, byte newColor) {
+void Sprites::replaceSpriteColor(uint spriteId, byte currentColor, byte newColor) {
 	MAP_ID(spriteId);
 
 	byte *data = _cursors[spriteId]->_data;
-	unsigned int size = _cursors[spriteId]->_width * _cursors[spriteId]->_height;
+	uint size = _cursors[spriteId]->_width * _cursors[spriteId]->_height;
 	for (; size > 0; size--, data++) {
 		if (*data == currentColor) {
 			*data = newColor;
@@ -158,7 +158,7 @@ void Sprites::replaceSpriteColor(unsigned int spriteId, byte currentColor, byte
 	}
 }
 
-unsigned int Sprites::getSpritesCount() const {
+uint Sprites::getSpritesCount() const {
 	if (_map) {
 		return _map->size();
 	} else {
@@ -166,7 +166,7 @@ unsigned int Sprites::getSpritesCount() const {
 	}
 }
 
-unsigned int Sprites::revMapSpriteId(unsigned int id) const {
+uint Sprites::revMapSpriteId(uint id) const {
 	if (_map) {
 		if (id >= _cursors.size()) {
 			error("revMapSpriteId is out of bounds: %d/%d", id, _cursors.size());
@@ -177,14 +177,14 @@ unsigned int Sprites::revMapSpriteId(unsigned int id) const {
 	return id;
 }
 
-unsigned int Sprites::calculateSpriteId(unsigned int baseId, unsigned int offset) const {
+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());
 		}
-		unsigned int spriteId = _cursors[baseId]->_constantId;
+		uint spriteId = _cursors[baseId]->_constantId;
 		if (spriteId == -1u) {
 			error("Sprite %d is unreachable", baseId);
 		}
@@ -194,7 +194,7 @@ unsigned int Sprites::calculateSpriteId(unsigned int baseId, unsigned int offset
 	}
 }
 
-const Graphics::Surface &Sprites::getSurface(unsigned int spriteId) const {
+const Graphics::Surface &Sprites::getSurface(uint spriteId) const {
 	MAP_ID(spriteId);
 
 	CryoCursor *cursor = _cursors[spriteId];
@@ -204,7 +204,7 @@ const Graphics::Surface &Sprites::getSurface(unsigned int spriteId) const {
 	return *_surface;
 }
 
-const Graphics::Cursor &Sprites::getCursor(unsigned int spriteId) const {
+const Graphics::Cursor &Sprites::getCursor(uint spriteId) const {
 	MAP_ID(spriteId);
 
 	return *_cursors[spriteId];
@@ -219,10 +219,10 @@ Sprites::CryoCursor::~CryoCursor() {
 	delete[] _data;
 }
 
-unsigned int Sprites::CryoCursor::setup(uint16 width, uint16 height) {
+uint Sprites::CryoCursor::setup(uint16 width, uint16 height) {
 	_width = width;
 	_height = height;
-	unsigned int sz = _width * _height;
+	uint sz = _width * _height;
 	_data = new byte[sz];
 	return sz;
 }
diff --git a/engines/cryomni3d/sprites.h b/engines/cryomni3d/sprites.h
index bd4a867..8713da1 100644
--- a/engines/cryomni3d/sprites.h
+++ b/engines/cryomni3d/sprites.h
@@ -44,23 +44,23 @@ public:
 	virtual ~Sprites();
 
 	void loadSprites(Common::ReadStream &spr_fl);
-	void setupMapTable(const unsigned int *table, unsigned int size);
+	void setupMapTable(const uint *table, uint size);
 
-	void setSpriteHotspot(unsigned int spriteId, unsigned int x, unsigned int y);
+	void setSpriteHotspot(uint spriteId, uint x, uint y);
 
-	void replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId);
+	void replaceSprite(uint oldSpriteId, uint newSpriteId);
 
-	unsigned int getSpritesCount() const;
+	uint getSpritesCount() const;
 
-	void replaceSpriteColor(unsigned int spriteId, byte currentColor, byte newColor);
+	void replaceSpriteColor(uint spriteId, byte currentColor, byte newColor);
 
-	const Graphics::Surface &getSurface(unsigned int spriteId) const;
-	const Graphics::Cursor &getCursor(unsigned int spriteId) const;
+	const Graphics::Surface &getSurface(uint spriteId) const;
+	const Graphics::Cursor &getCursor(uint spriteId) const;
 
-	unsigned int revMapSpriteId(unsigned int id) const;
-	unsigned int calculateSpriteId(unsigned int baseId, unsigned int offset) const;
+	uint revMapSpriteId(uint id) const;
+	uint calculateSpriteId(uint baseId, uint offset) const;
 
-	byte getKeyColor(unsigned int spriteId) const { return 0; }
+	byte getKeyColor(uint spriteId) const { return 0; }
 
 private:
 	class CryoCursor : public Graphics::Cursor {
@@ -77,17 +77,17 @@ private:
 		virtual byte getPaletteStartIndex() const override { return 0; }
 		virtual uint16 getPaletteCount() const override { return 0; }
 
-		unsigned int setup(uint16 width, uint16 height);
+		uint setup(uint16 width, uint16 height);
 
 		uint16 _width;
 		uint16 _height;
 		int16 _offX;
 		int16 _offY;
-		unsigned int _constantId;
+		uint _constantId;
 
 		byte *_data;
 
-		unsigned int refCnt;
+		uint refCnt;
 
 		CryoCursor();
 		virtual ~CryoCursor();
@@ -96,7 +96,7 @@ private:
 	// Pointer to avoid to mutate Sprites when asking for a cursor
 	Graphics::Surface *_surface;
 	Common::Array<CryoCursor *> _cursors;
-	Common::Array<unsigned int> *_map;
+	Common::Array<uint> *_map;
 };
 
 } // End of namespace CryOmni3D
diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index a11b1ab..61ed9e4 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -25,7 +25,7 @@
 namespace CryOmni3D {
 namespace Versailles {
 
-const unsigned int CryOmni3DEngine_Versailles::kSpritesMapTable[] = {
+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,
@@ -43,7 +43,7 @@ const unsigned int CryOmni3DEngine_Versailles::kSpritesMapTable[] = {
 	/* 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 unsigned int CryOmni3DEngine_Versailles::kSpritesMapTableSize = ARRAYSIZE(kSpritesMapTable);
+const uint CryOmni3DEngine_Versailles::kSpritesMapTableSize = ARRAYSIZE(kSpritesMapTable);
 
 const LevelInitialState CryOmni3DEngine_Versailles::kLevelInitialStates[] = {
 	{  1, M_PI,   0. }, // Level 1
@@ -504,7 +504,7 @@ void CryOmni3DEngine_Versailles::setupDialogVariables() {
 	SET_DIAL_VARIABLE(136, "{CURRENT_GAME_TIME5}");
 	SET_DIAL_VARIABLE(137, "{JOUEUR_POSSEDE_EPIGRAPHE}");
 #undef SET_DIAL_VARIABLE
-	for (unsigned int i = 0; i < ARRAYSIZE(videoSubSettings); i++) {
+	for (uint i = 0; i < ARRAYSIZE(videoSubSettings); i++) {
 		const VideoSubSetting &vss = videoSubSettings[i];
 		_dialogsMan.registerSubtitlesSettings(
 		    vss.videoName,
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index f7a2146..27bcbb6 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -52,7 +52,7 @@ bool Versailles_DialogsManager::play(const Common::String &sequence) {
 	if (didSth && slowStop) {
 		if (_engine->showSubtitles()) {
 			bool skip = false;
-			unsigned int end = g_system->getMillis() + 2000;
+			uint end = g_system->getMillis() + 2000;
 			while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skip) {
 				g_system->updateScreen();
 				if (_engine->pollEvents() &&
@@ -150,11 +150,11 @@ void Versailles_DialogsManager::playDialog(const Common::String &video, const Co
 	if (_engine->showSubtitles()) {
 		Common::Rect block = settings.textRect;
 
-		unsigned int lines = fontManager.getLinesCount(text, block.width() - 8);
+		uint lines = fontManager.getLinesCount(text, block.width() - 8);
 		if (lines == 0) {
 			lines = 5;
 		}
-		unsigned int blockHeight = fontManager.lineHeight() * lines + 6;
+		uint blockHeight = fontManager.lineHeight() * lines + 6;
 		block.setHeight(blockHeight);
 
 		if (block.bottom >= 480) {
@@ -181,13 +181,13 @@ void Versailles_DialogsManager::playDialog(const Common::String &video, const Co
 		// Empty wave file
 		delete audioDecoder;
 
-		unsigned int duration = 100 * text.size();
+		uint duration = 100 * text.size();
 		if (duration < 1000) {
 			duration = 1000;
 		}
 
 		bool skipWait = false;
-		unsigned int end = g_system->getMillis() + duration;
+		uint end = g_system->getMillis() + duration;
 		while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skipWait) {
 			if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
 				skipWait = true;
@@ -238,7 +238,7 @@ void Versailles_DialogsManager::displayMessage(const Common::String &text) {
 	_engine->displayMessageBoxWarp(text);
 }
 
-unsigned int Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
+uint Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
         const Common::StringArray &questions) {
 	if (_lastImage.empty()) {
 		loadFrame(video);
@@ -258,11 +258,11 @@ unsigned int Versailles_DialogsManager::askPlayerQuestions(const Common::String
 	int16 tops[5];
 	int16 bottoms[5];
 	int16 currentHeight = 0;
-	unsigned int questionId = 0;
+	uint questionId = 0;
 	for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
 	        it++, questionId++) {
 		tops[questionId] = currentHeight;
-		unsigned int lines = fontManager.getLinesCount(*it, 598);
+		uint lines = fontManager.getLinesCount(*it, 598);
 		if (lines == 0) {
 			lines = 1;
 		}
@@ -288,7 +288,7 @@ unsigned int Versailles_DialogsManager::askPlayerQuestions(const Common::String
 
 	bool finished = false;
 	bool update = true;
-	unsigned int selectedQuestion = -1;
+	uint selectedQuestion = -1;
 	while (!finished) {
 		if (update) {
 			update = false;
diff --git a/engines/cryomni3d/versailles/dialogs_manager.h b/engines/cryomni3d/versailles/dialogs_manager.h
index 3c5028f..9c41fc4 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.h
+++ b/engines/cryomni3d/versailles/dialogs_manager.h
@@ -50,8 +50,8 @@ protected:
 	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;
-	unsigned int askPlayerQuestions(const Common::String &video,
-	                                const Common::StringArray &questions) override;
+	uint askPlayerQuestions(const Common::String &video,
+	                        const Common::StringArray &questions) override;
 
 private:
 	CryOmni3DEngine_Versailles *_engine;
diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
index 79c6001..abdbc63 100644
--- a/engines/cryomni3d/versailles/documentation.cpp
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -97,7 +97,7 @@ void Versailles_Documentation::init(const Sprites *sprites, FontManager *fontMan
 		error("Can't open %s", kAllDocsFile);
 	}
 
-	unsigned int allDocsSize = allDocsFile.size();
+	uint allDocsSize = allDocsFile.size();
 	char *allDocs = new char[allDocsSize + 1];
 	char *end = allDocs + allDocsSize;
 	allDocsFile.read(allDocs, allDocsSize);
@@ -188,7 +188,7 @@ void Versailles_Documentation::handleDocInGame(const Common::String &record) {
 	bool end = false;
 	while (!end) {
 		inGamePrepareRecord(docSurface, boxes);
-		unsigned int action = inGameHandleRecord(docSurface, boxes, nextRecord);
+		uint action = inGameHandleRecord(docSurface, boxes, nextRecord);
 		switch (action) {
 		case 0:
 			// Back
@@ -280,7 +280,7 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 	Image::BitmapDecoder bmpDecoder;
 	Common::File file;
 
-	for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
+	for (uint i = 0; i < ARRAYSIZE(categories); i++) {
 		if (!categories[i].bmp) {
 			// No BMP to load
 			continue;
@@ -330,14 +330,14 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 	g_system->showMouse(true);
 
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int selectedBox = -1;
+	uint hoveredBox = -1;
+	uint selectedBox = -1;
 
 	while (selectedBox == -1u) {
 		if (redraw) {
 			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
-			for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
-				unsigned int foreColor = 243;
+			for (uint i = 0; i < ARRAYSIZE(categories); i++) {
+				uint foreColor = 243;
 				if (i == hoveredBox) {
 					foreColor = 241;
 					if (categories[hoveredBox].highlightedImg.getPixels() != nullptr) {
@@ -347,8 +347,8 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 				}
 				_fontManager->setForeColor(foreColor);
 				if (categories[i].title) {
-					unsigned int x = categories[i].linesPos.right - _fontManager->getStrWidth(*categories[i].title);
-					unsigned int y = categories[i].linesPos.bottom - _fontManager->getFontMaxHeight() - 5;
+					uint x = categories[i].linesPos.right - _fontManager->getStrWidth(*categories[i].title);
+					uint y = categories[i].linesPos.bottom - _fontManager->getFontMaxHeight() - 5;
 					_fontManager->displayStr(x, y, *categories[i].title);
 
 					// Draw line to text
@@ -373,7 +373,7 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 				// Don't change highlighted icon when clicking
 				Common::Point mouse = _engine->getMousePos();
 				bool foundBox = false;
-				for (unsigned int i = 0; i < ARRAYSIZE(categories); i++) {
+				for (uint i = 0; i < ARRAYSIZE(categories); i++) {
 					if (boxes.hitTest(i, mouse)) {
 						foundBox = true;
 						if (i != hoveredBox) {
@@ -446,11 +446,11 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 	_fontManager->setCurrentFont(0);
 
 	MouseBoxes boxes(ARRAYSIZE(kTimelineEntries) + 1);
-	for (unsigned int box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
+	for (uint box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
 		boxes.setupBox(box_id, kTimelineEntries[box_id].x, kTimelineEntries[box_id].y,
 		               kTimelineEntries[box_id].x + 30, kTimelineEntries[box_id].y + 20);
 	}
-	const unsigned int leaveBoxId = ARRAYSIZE(kTimelineEntries);
+	const uint leaveBoxId = ARRAYSIZE(kTimelineEntries);
 	boxes.setupBox(leaveBoxId, 639 - _sprites->getCursor(105).getWidth(),
 	               479 - _sprites->getCursor(105).getHeight(), 640, 480);
 
@@ -458,13 +458,13 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 	g_system->showMouse(true);
 
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int selectedBox = -1;
+	uint hoveredBox = -1;
+	uint selectedBox = -1;
 
 	while (selectedBox == -1u) {
 		if (redraw) {
 			// Draw without worrying of already modified areas, that's handled when recomputing hoveredBox
-			for (unsigned int i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
+			for (uint i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
 				_fontManager->setForeColor(i == hoveredBox ? 241 : 243);
 				_fontManager->displayStr(kTimelineEntries[i].x, kTimelineEntries[i].y, kTimelineEntries[i].year);
 			}
@@ -482,7 +482,7 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 			if (!_engine->getCurrentMouseButton()) {
 				// Don't change highlighted date when clicking
 				bool foundBox = false;
-				for (unsigned int i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
+				for (uint i = 0; i < ARRAYSIZE(kTimelineEntries); i++) {
 					if (boxes.hitTest(i, mouse)) {
 						foundBox = true;
 						if (i != hoveredBox) {
@@ -526,8 +526,8 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 	}
 }
 
-unsigned int Versailles_Documentation::docAreaHandleRecords(const Common::String &record) {
-	unsigned int action = -1;
+uint Versailles_Documentation::docAreaHandleRecords(const Common::String &record) {
+	uint action = -1;
 
 	_currentRecord = record;
 	_visitTrace.clear();
@@ -639,7 +639,7 @@ void Versailles_Documentation::docAreaPrepareNavigation() {
 		_categoryStartRecord = "VS00";
 		_categoryEndRecord = "VS37";
 		_categoryTitle = (*_messages)[72];
-		unsigned int id = atoi(_currentRecord.c_str() + 2);
+		uint id = atoi(_currentRecord.c_str() + 2);
 		if (id >= 16 && id <= 40) {
 			_currentMapLayout = true;
 		}
@@ -681,7 +681,7 @@ void Versailles_Documentation::docAreaPrepareRecord(Graphics::ManagedSurface &su
 		_fontManager->setCharSpacing(1);
 		_fontManager->setSurface(&surface);
 		_fontManager->setForeColor(243);
-		for (unsigned int box_id = 10; box_id < ARRAYSIZE(kTimelineEntries) + 10; box_id++) {
+		for (uint box_id = 10; box_id < ARRAYSIZE(kTimelineEntries) + 10; box_id++) {
 			boxes.display(box_id, *_fontManager);
 		}
 	}
@@ -689,7 +689,7 @@ void Versailles_Documentation::docAreaPrepareRecord(Graphics::ManagedSurface &su
 	drawRecordBoxes(surface, true, boxes);
 }
 
-unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurface &surface,
+uint Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurface &surface,
         MouseBoxes &boxes, Common::String &nextRecord) {
 	// Hovering is only handled for timeline entries
 	_engine->setCursor(181);
@@ -697,8 +697,8 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 
 	bool first = true;
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int action = -1;
+	uint hoveredBox = -1;
+	uint action = -1;
 
 	while (action == -1u) {
 		if (redraw) {
@@ -716,7 +716,7 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 			Common::Point mouse = _engine->getMousePos();
 			if (_currentInTimeline) {
 				bool foundBox = false;
-				for (unsigned int i = 10; i < 10 + ARRAYSIZE(kTimelineEntries); i++) {
+				for (uint i = 10; i < 10 + ARRAYSIZE(kTimelineEntries); i++) {
 					if (boxes.hitTest(i, mouse)) {
 						foundBox = true;
 						if (i != hoveredBox) {
@@ -764,8 +764,8 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 						items.push_back(it->title);
 					}
 					Common::Rect iconRect = boxes.getBoxRect(2);
-					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
-					                            true, 20, items);
+					uint selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                                    true, 20, items);
 					if (selectedItem != -1u) {
 						nextRecord = _currentLinks[selectedItem].record;
 						action = 2;
@@ -776,8 +776,8 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 						items.push_back(it->title);
 					}
 					Common::Rect iconRect = boxes.getBoxRect(3);
-					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
-					                            true, 20, items);
+					uint selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                                    true, 20, items);
 					if (selectedItem != -1u) {
 						nextRecord = _allLinks[selectedItem].record;
 						action = 3;
@@ -792,7 +792,7 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 					Common::StringArray items;
 					items.push_back((*_messages)[61]);
 					items.push_back((*_messages)[62]);
-					unsigned int selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(1), false, 20, items);
+					uint selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(1), false, 20, items);
 					if (selectedItem == 0) {
 						action = 1;
 					} else if (selectedItem == 1) {
@@ -808,7 +808,7 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 					// Handle quit menu
 					Common::StringArray items;
 					items.push_back((*_messages)[60]);
-					unsigned int selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(6), false, 20, items);
+					uint selectedItem = handlePopupMenu(surface, boxes.getBoxOrigin(6), false, 20, items);
 					if (selectedItem == 0) {
 						action = 6;
 					}
@@ -841,7 +841,7 @@ unsigned int Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurf
 					action = -1;
 					continue;
 				}
-				unsigned int recordId = hmIt->_value.id;
+				uint recordId = hmIt->_value.id;
 				if (action == 4) {
 					recordId++;
 				} else if (action == 5) {
@@ -865,16 +865,16 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 		Common::Rect areaPos;
 		const char *record;
 		const char *bmp;
-		unsigned int messageId;
+		uint messageId;
 		const Common::String *message;
 		Common::Point messagePos;
 		Graphics::Surface highlightedImg;
 
-		Area(const Common::Point &areaPos_, const char *bmp_, unsigned int messageId_,
+		Area(const Common::Point &areaPos_, const char *bmp_, uint messageId_,
 		     const char *record_ = nullptr) :
 			areaPos(areaPos_.x, areaPos_.y, areaPos_.x, areaPos_.y), record(record_), bmp(bmp_),
 			messageId(messageId_), message(nullptr) { }
-		Area(const Common::Rect &areaPos_, unsigned int messageId_, const char *record_ = nullptr) :
+		Area(const Common::Rect &areaPos_, uint messageId_, const char *record_ = nullptr) :
 			areaPos(areaPos_), record(record_), bmp(nullptr), messageId(messageId_), message(nullptr) { }
 	} areas[] = {
 		Area(Common::Point(174, 181), "APL.bmp", 74),
@@ -905,7 +905,7 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 	Image::BitmapDecoder bmpDecoder;
 	Common::File file;
 
-	for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+	for (uint i = 0; i < ARRAYSIZE(areas); i++) {
 		if (areas[i].bmp) {
 			if (!file.open(areas[i].bmp)) {
 				error("Failed to open BMP file: %s", areas[i].bmp);
@@ -920,7 +920,7 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 			areas[i].areaPos.setHeight(areas[i].highlightedImg.h);
 		}
 		areas[i].message = &(*_messages)[areas[i].messageId];
-		unsigned int lineWidth = _fontManager->getStrWidth(*areas[i].message);
+		uint lineWidth = _fontManager->getStrWidth(*areas[i].message);
 		areas[i].messagePos.x = (areas[i].areaPos.left + areas[i].areaPos.right) / 2 - lineWidth / 2;
 		areas[i].messagePos.y = areas[i].areaPos.top - 40;
 		if (areas[i].messagePos.x < 8) {
@@ -956,8 +956,8 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 	g_system->showMouse(true);
 
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int selectedBox = -1;
+	uint hoveredBox = -1;
+	uint selectedBox = -1;
 
 	while (selectedBox == -1u) {
 		if (redraw) {
@@ -967,10 +967,10 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 					mapSurface.transBlitFrom(areas[hoveredBox].highlightedImg,
 					                         Common::Point(areas[hoveredBox].areaPos.left, areas[hoveredBox].areaPos.top));
 				} else {
-					unsigned int middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
-					unsigned int middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
-					unsigned int spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
-					unsigned int spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
+					uint middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
+					uint middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
+					uint spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
+					uint spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
 					mapSurface.transBlitFrom(_sprites->getSurface(163), Common::Point(spriteX, spriteY),
 					                         _sprites->getKeyColor(163));
 				}
@@ -988,7 +988,7 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 			                         _sprites->getKeyColor(105));
 			/*
 			// For debugging only
-			for(unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+			for(uint i = 0; i < ARRAYSIZE(areas); i++) {
 			    mapSurface.frameRect(areas[i].areaPos, 0);
 			}
 			*/
@@ -1005,8 +1005,8 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 			if (!_engine->getCurrentMouseButton()) {
 				// Don't change highlighted icon when clicking
 				bool foundBox = false;
-				unsigned int oldHoveredBox = hoveredBox;
-				for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+				uint oldHoveredBox = hoveredBox;
+				for (uint i = 0; i < ARRAYSIZE(areas); i++) {
 					if (boxes.hitTest(i, mouse)) {
 						if (i != hoveredBox) {
 							hoveredBox = i;
@@ -1064,18 +1064,18 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 		Common::Rect areaPos;
 		bool fillArea;
 		const char *record;
-		unsigned int messageId;
+		uint messageId;
 		Common::String message;
 		Common::Point messagePos;
 		Common::Rect areaPos1;
 		Common::Rect areaPos2;
 
 		Area(const Common::Rect &areaPos_, const char *record_, bool fillArea_ = true,
-		     unsigned int messageId_ = -1) :
+		     uint messageId_ = -1) :
 			areaPos(areaPos_), record(record_), fillArea(fillArea_), messageId(messageId_) { }
 		Area(const Common::Rect &areaPos_, const Common::Rect &areaPos1_,
 		     const Common::Rect &areaPos2_, const char *record_, bool fillArea_ = true,
-		     unsigned int messageId_ = -1) :
+		     uint messageId_ = -1) :
 			areaPos(areaPos_), areaPos1(areaPos1_), areaPos2(areaPos2_),
 			record(record_), fillArea(fillArea_), messageId(messageId_) { }
 	} areas[] = {
@@ -1117,14 +1117,14 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 
 	MouseBoxes boxes(ARRAYSIZE(areas) + 1);
 
-	for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+	for (uint i = 0; i < ARRAYSIZE(areas); i++) {
 		if (areas[i].messageId != -1u) {
 			areas[i].message = (*_messages)[areas[i].messageId];
 		} else {
 			areas[i].message = getRecordTitle(areas[i].record);
 		}
-		unsigned int lineWidth = _fontManager->getStrWidth(areas[i].message);
-		unsigned int right;
+		uint lineWidth = _fontManager->getStrWidth(areas[i].message);
+		uint right;
 		if (areas[i].areaPos2.right) {
 			right = areas[i].areaPos2.right;
 		} else {
@@ -1173,8 +1173,8 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 	g_system->showMouse(true);
 
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int selectedBox = -1;
+	uint hoveredBox = -1;
+	uint selectedBox = -1;
 
 	while (selectedBox == -1u) {
 		if (redraw) {
@@ -1198,10 +1198,10 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 						mapSurface.fillRect(rect, 243);
 					}
 				} else {
-					unsigned int middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
-					unsigned int middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
-					unsigned int spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
-					unsigned int spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
+					uint middleX = (areas[hoveredBox].areaPos.left + areas[hoveredBox].areaPos.right) / 2;
+					uint middleY = (areas[hoveredBox].areaPos.top + areas[hoveredBox].areaPos.bottom) / 2;
+					uint spriteX = middleX - _sprites->getCursor(163).getWidth() / 2;
+					uint spriteY = middleY - _sprites->getCursor(163).getHeight() / 2;
 					mapSurface.transBlitFrom(_sprites->getSurface(163), Common::Point(spriteX, spriteY),
 					                         _sprites->getKeyColor(163));
 				}
@@ -1218,7 +1218,7 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 			                         _sprites->getKeyColor(105));
 			/*
 			// For debugging only
-			for(unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+			for(uint i = 0; i < ARRAYSIZE(areas); i++) {
 			    mapSurface.frameRect(areas[i].areaPos, 0);
 			    if (areas[i].areaPos1.right) {
 			        mapSurface.frameRect(areas[i].areaPos1, 0);
@@ -1241,8 +1241,8 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 			if (!_engine->getCurrentMouseButton()) {
 				// Don't change highlighted icon when clicking
 				bool foundBox = false;
-				unsigned int oldHoveredBox = hoveredBox;
-				for (unsigned int i = 0; i < ARRAYSIZE(areas); i++) {
+				uint oldHoveredBox = hoveredBox;
+				for (uint i = 0; i < ARRAYSIZE(areas); i++) {
 					if (boxes.hitTest(i, mouse)) {
 						if (i != hoveredBox) {
 							hoveredBox = i;
@@ -1313,7 +1313,7 @@ void Versailles_Documentation::inGamePrepareRecord(Graphics::ManagedSurface &sur
 	_currentHasMap = false;
 
 	if (_currentRecord.hasPrefix("VS")) {
-		unsigned int id = atoi(_currentRecord.c_str() + 2);
+		uint id = atoi(_currentRecord.c_str() + 2);
 		if (id >= 16 && id <= 40) {
 			_currentMapLayout = true;
 		}
@@ -1334,12 +1334,12 @@ void Versailles_Documentation::inGamePrepareRecord(Graphics::ManagedSurface &sur
 	drawRecordBoxes(surface, false, boxes);
 }
 
-unsigned int Versailles_Documentation::inGameHandleRecord(Graphics::ManagedSurface &surface,
+uint Versailles_Documentation::inGameHandleRecord(Graphics::ManagedSurface &surface,
         MouseBoxes &boxes, Common::String &nextRecord) {
 	_engine->setCursor(181);
 	g_system->showMouse(true);
 
-	unsigned int action = -1;
+	uint action = -1;
 
 	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.w, surface.h);
 
@@ -1360,8 +1360,8 @@ unsigned int Versailles_Documentation::inGameHandleRecord(Graphics::ManagedSurfa
 						items.push_back(it->title);
 					}
 					Common::Rect iconRect = boxes.getBoxRect(2);
-					unsigned int selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
-					                            true, 20, items);
+					uint selectedItem = handlePopupMenu(surface, Common::Point(iconRect.right, iconRect.top),
+					                                    true, 20, items);
 					if (selectedItem != -1u) {
 						nextRecord = _currentLinks[selectedItem].record;
 						action = 2;
@@ -1464,7 +1464,7 @@ void Versailles_Documentation::drawRecordData(Graphics::ManagedSurface &surface,
 
 	Common::String text = getRecordData(_currentRecord, title, subtitle, caption, hyperlinks);*/
 
-	unsigned int lineHeight = 21;
+	uint lineHeight = 21;
 	_fontManager->setCurrentFont(4);
 	_fontManager->setTransparentBackground(true);
 	_fontManager->setSpaceWidth(1);
@@ -1539,22 +1539,22 @@ void Versailles_Documentation::drawRecordData(Graphics::ManagedSurface &surface,
 void Versailles_Documentation::setupRecordBoxes(bool inDocArea, MouseBoxes &boxes) {
 	// Layout of bar in doc area is Quit | Back |   | Previous | Category | Next |   | Trace | Hyperlinks | All records
 	// Layout of bar in game is ==> Trace | Hyperlinks | Quit
-	unsigned int allRecordsX = 640 - _sprites->getCursor(19).getWidth();
-	unsigned int hyperlinksX = allRecordsX - _sprites->getCursor(242).getWidth() - 10;
-	unsigned int traceX = hyperlinksX - _sprites->getCursor(105).getWidth() - 10;
+	uint allRecordsX = 640 - _sprites->getCursor(19).getWidth();
+	uint hyperlinksX = allRecordsX - _sprites->getCursor(242).getWidth() - 10;
+	uint traceX = hyperlinksX - _sprites->getCursor(105).getWidth() - 10;
 
 	if (_visitTrace.size()) {
 		boxes.setupBox(0, traceX, 480 - _sprites->getCursor(105).getHeight() - 3,
 		               traceX + _sprites->getCursor(105).getWidth(), 480);
 	}
 	if (inDocArea) {
-		unsigned int backX = _sprites->getCursor(225).getWidth() + 10; //Right to quit button
+		uint backX = _sprites->getCursor(225).getWidth() + 10; //Right to quit button
 
 		_fontManager->setCurrentFont(0);
 		_fontManager->setTransparentBackground(true);
 		_fontManager->setSpaceWidth(0);
 		_fontManager->setCharSpacing(1);
-		unsigned int categoryHalfWidth = _fontManager->getStrWidth(_categoryTitle) / 2;
+		uint categoryHalfWidth = _fontManager->getStrWidth(_categoryTitle) / 2;
 		unsigned nextX = 320 + categoryHalfWidth + 20;
 		unsigned prevX = 320 - categoryHalfWidth - 20 - _sprites->getCursor(76).getWidth();
 
@@ -1574,13 +1574,13 @@ void Versailles_Documentation::setupRecordBoxes(bool inDocArea, MouseBoxes &boxe
 		// Map
 		boxes.setupBox(8, 403, 305, 622, 428);
 		if (_currentInTimeline) {
-			for (unsigned int box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
+			for (uint box_id = 0; box_id < ARRAYSIZE(kTimelineEntries); box_id++) {
 				boxes.setupBox(10 + box_id, kTimelineEntries[box_id].x, kTimelineEntries[box_id].y,
 				               kTimelineEntries[box_id].x + 30, kTimelineEntries[box_id].y + 15, kTimelineEntries[box_id].year);
 			}
 		}
 	} else {
-		unsigned int quitInGameX = 640 - _sprites->getCursor(105).getWidth();
+		uint quitInGameX = 640 - _sprites->getCursor(105).getWidth();
 		boxes.setupBox(1, quitInGameX, 480 - _sprites->getCursor(105).getHeight(),
 		               quitInGameX + _sprites->getCursor(105).getWidth(), 480);
 	}
@@ -1629,28 +1629,28 @@ void Versailles_Documentation::drawRecordBoxes(Graphics::ManagedSurface &surface
 	}
 }
 
-unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSurface
+uint Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSurface
         &originalSurface,
-        const Common::Point &anchor, bool rightAligned, unsigned int itemHeight,
+        const Common::Point &anchor, bool rightAligned, uint itemHeight,
         const Common::StringArray &items) {
 
-	unsigned int maxTextWidth = 0;
+	uint maxTextWidth = 0;
 
 	_fontManager->setCurrentFont(4);
 	_fontManager->setTransparentBackground(true);
 	_fontManager->setCharSpacing(1);
 
 	for (Common::StringArray::const_iterator it = items.begin(); it != items.end(); it++) {
-		unsigned int width = _fontManager->getStrWidth(*it);
+		uint width = _fontManager->getStrWidth(*it);
 		if (width > maxTextWidth) {
 			maxTextWidth = width;
 		}
 	}
 
-	unsigned int width = maxTextWidth + 2 * kPopupMenuMargin;
-	unsigned int height = itemHeight * items.size() + 2 * kPopupMenuMargin;
+	uint width = maxTextWidth + 2 * kPopupMenuMargin;
+	uint height = itemHeight * items.size() + 2 * kPopupMenuMargin;
 
-	unsigned int hiddenItems = 0;
+	uint hiddenItems = 0;
 	int top = anchor.y - height;
 	while (top < 0) {
 		hiddenItems++;
@@ -1669,7 +1669,7 @@ unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSu
 	surface.copyFrom(originalSurface);
 
 	MouseBoxes boxes(shownItems);
-	for (unsigned int i = 0; i < shownItems; i++) {
+	for (uint i = 0; i < shownItems; i++) {
 		boxes.setupBox(i, popupRect.left + kPopupMenuMargin,
 		               popupRect.top + kPopupMenuMargin + i * itemHeight,
 		               popupRect.right - kPopupMenuMargin,
@@ -1680,12 +1680,12 @@ unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSu
 
 	bool fullRedraw = true;
 	bool redraw = true;
-	unsigned int hoveredBox = -1;
-	unsigned int action = -1;
-	unsigned int lastShownItem = items.size() - 1;
-	unsigned int firstShownItem = lastShownItem - shownItems + 1;
+	uint hoveredBox = -1;
+	uint action = -1;
+	uint lastShownItem = items.size() - 1;
+	uint firstShownItem = lastShownItem - shownItems + 1;
 
-	unsigned int slowScrollNextEvent = g_system->getMillis() + 250;
+	uint slowScrollNextEvent = g_system->getMillis() + 250;
 
 	Common::Point mouse;
 
@@ -1695,7 +1695,7 @@ unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSu
 				surface.fillRect(popupRect, 247);
 				fullRedraw = false;
 			}
-			for (unsigned int i = 0; i < shownItems; i++) {
+			for (uint i = 0; i < shownItems; i++) {
 				if (i == 0 && firstShownItem != 0) {
 					// There are items before the first one: display an arrow
 					surface.transBlitFrom(_sprites->getSurface(162),
@@ -1727,8 +1727,8 @@ unsigned int Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSu
 			}
 			mouse = _engine->getMousePos();
 
-			unsigned int newHovered = -1;
-			for (unsigned int i = 0; i < shownItems; i++) {
+			uint newHovered = -1;
+			for (uint i = 0; i < shownItems; i++) {
 				if (boxes.hitTest(i, mouse)) {
 					newHovered = i;
 					break;
@@ -1808,7 +1808,7 @@ char *Versailles_Documentation::getDocPartAddress(char *start, char *end, const
 	}
 	char *foundPos = nullptr;
 	const char *pattern;
-	unsigned int patternLen;
+	uint patternLen;
 	for (const char **patternP = patterns; *patternP && !foundPos; patternP++) {
 		pattern = *patternP;
 		patternLen = strlen(pattern);
@@ -1886,7 +1886,7 @@ const char *Versailles_Documentation::getRecordSubtitle(char *start, char *end)
 		return nullptr;
 	}
 
-	unsigned int ln = strlen(ret);
+	uint ln = strlen(ret);
 	char *p = ret + ln + 1; // Got to end of line and check next line
 	for (; p < end && *p && *p != '\r' && *p != '=' ; p++) { }
 	if (*p == '=') {
@@ -1907,7 +1907,7 @@ void Versailles_Documentation::getRecordHyperlinks(char *start, char *end,
 	const char *const hyperlinksPatterns[] = { "SAVOIR-PLUS 1=", "SAVOIR-PLUS 2=", "SAVOIR-PLUS 3=" };
 
 	hyperlinks.clear();
-	for (unsigned int hyperlinkId = 0; hyperlinkId < ARRAYSIZE(hyperlinksPatterns); hyperlinkId++) {
+	for (uint hyperlinkId = 0; hyperlinkId < ARRAYSIZE(hyperlinksPatterns); hyperlinkId++) {
 		const char *patterns[] = { hyperlinksPatterns[hyperlinkId], nullptr };
 		const char *ret = getDocPartAddress(start, end, patterns);
 		if (ret) {
diff --git a/engines/cryomni3d/versailles/documentation.h b/engines/cryomni3d/versailles/documentation.h
index 0a581d9..a1559f8 100644
--- a/engines/cryomni3d/versailles/documentation.h
+++ b/engines/cryomni3d/versailles/documentation.h
@@ -53,16 +53,16 @@ private:
 	Common::String docAreaHandleTimeline();
 	Common::String docAreaHandleGeneralMap();
 	Common::String docAreaHandleCastleMap();
-	unsigned int docAreaHandleRecords(const Common::String &record);
+	uint docAreaHandleRecords(const Common::String &record);
 
 	void docAreaPrepareNavigation();
 	void docAreaPrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
-	unsigned int docAreaHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
-	                                 Common::String &nextRecord);
+	uint docAreaHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
+	                         Common::String &nextRecord);
 
 	void inGamePrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
-	unsigned int inGameHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
-	                                Common::String &nextRecord);
+	uint inGameHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
+	                        Common::String &nextRecord);
 
 	void setupRecordBoxes(bool inDocArea, MouseBoxes &boxes);
 	void setupTimelineBoxes(MouseBoxes &boxes);
@@ -71,14 +71,14 @@ private:
 	                    const Common::String &subtitle, const Common::String &caption);
 	void drawRecordBoxes(Graphics::ManagedSurface &surface, bool inDocArea, MouseBoxes &boxes);
 
-	unsigned int handlePopupMenu(const Graphics::ManagedSurface &surface,
-	                             const Common::Point &anchor, bool rightAligned, unsigned int itemHeight,
-	                             const Common::StringArray &items);
+	uint handlePopupMenu(const Graphics::ManagedSurface &surface,
+	                     const Common::Point &anchor, bool rightAligned, uint itemHeight,
+	                     const Common::StringArray &items);
 
 	struct RecordInfo {
-		unsigned int id;
-		unsigned int position;
-		unsigned int size;
+		uint id;
+		uint position;
+		uint size;
 	};
 
 	struct LinkInfo {
@@ -88,8 +88,8 @@ private:
 
 	struct TimelineEntry {
 		char year[8];
-		unsigned int x;
-		unsigned int y;
+		uint x;
+		uint y;
 	};
 	static const TimelineEntry kTimelineEntries[];
 
@@ -112,7 +112,7 @@ private:
 	static const char *kAllDocsFile;
 	static const char *kLinksDocsFile;
 
-	static const unsigned int kPopupMenuMargin = 5;
+	static const uint kPopupMenuMargin = 5;
 
 	CryOmni3DEngine *_engine;
 	FontManager *_fontManager;
@@ -122,7 +122,7 @@ private:
 	Common::StringArray _recordsOrdered;
 	Common::HashMap<Common::String, RecordInfo> _records;
 	char *_linksData;
-	unsigned int _linksSize;
+	uint _linksSize;
 
 	Common::Array<LinkInfo> _allLinks;
 
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 8401a78..2ab47c0 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -116,7 +116,7 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	_transparentNewStop = 254;
 
 	// Inventory has a size of 50
-	_inventory.init(50, new Common::Functor1Mem<unsigned int, void, Toolbar>(&_toolbar,
+	_inventory.init(50, new Common::Functor1Mem<uint, void, Toolbar>(&_toolbar,
 	                &Toolbar::inventoryChanged));
 
 	// Init toolbar after we have setup sprites and fonts
@@ -152,7 +152,7 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	bool stopGame = false;
 	while (!stopGame) {
 		bool exitLoop = false;
-		unsigned int nextStep = 0;
+		uint nextStep = 0;
 #if defined(DEBUG_FAST_START) && DEBUG_FAST_START>=2
 		nextStep = 27;
 		// Called in options
@@ -300,7 +300,7 @@ void CryOmni3DEngine_Versailles::setupSprites() {
 	}
 	_sprites.loadSprites(file);
 
-	for (unsigned int i = 0; i < _sprites.getSpritesCount(); i++) {
+	for (uint i = 0; i < _sprites.getSpritesCount(); i++) {
 		const Graphics::Cursor &cursor = _sprites.getCursor(i);
 		if (cursor.getWidth() != 32 || cursor.getHeight() != 32) {
 			_sprites.setSpriteHotspot(i, 8, 8);
@@ -367,7 +367,7 @@ void CryOmni3DEngine_Versailles::setMainPaletteColor(byte color, byte red, byte
 }
 
 struct transparentScore {
-	unsigned int score;
+	uint score;
 	byte redScaled;
 	byte greenScaled;
 
@@ -380,8 +380,8 @@ static transparentScore transparentCalculateScore(byte red, byte green, byte blu
 	transparentScore ret;
 	ret.score = 10 * (blue + 3 * (red + 2 * green)) / 30;
 	if (ret.score) {
-		ret.redScaled = ((unsigned int)red) * 256 / ret.score;
-		ret.greenScaled = ((unsigned int)green) * 256 / ret.score;
+		ret.redScaled = ((uint)red) * 256 / ret.score;
+		ret.greenScaled = ((uint)green) * 256 / ret.score;
 	} else {
 		ret.redScaled = 0;
 		ret.greenScaled = 0;
@@ -393,26 +393,26 @@ void CryOmni3DEngine_Versailles::calculateTransparentMapping() {
 	// Calculate colors proximity array
 	transparentScore *proximities = new transparentScore[256];
 
-	for (unsigned int i = _transparentSrcStart; i < _transparentSrcStop; i++) {
+	for (uint i = _transparentSrcStart; i < _transparentSrcStop; i++) {
 		proximities[i] = transparentCalculateScore(_mainPalette[3 * i + 0], _mainPalette[3 * i + 1],
 		                 _mainPalette[3 * i + 2]);
 	}
 
-	unsigned int newColorsNextId = _transparentNewStart;
-	unsigned int newColorsCount = 0;
-	for (unsigned int i = _transparentDstStart; i < _transparentDstStop; i++) {
-		byte transparentRed = ((unsigned int)_mainPalette[3 * i + 0]) * 60 / 128;
-		byte transparentGreen = ((unsigned int)_mainPalette[3 * i + 1]) * 50 / 128;
-		byte transparentBlue = ((unsigned int)_mainPalette[3 * i + 2]) * 35 / 128;
+	uint newColorsNextId = _transparentNewStart;
+	uint newColorsCount = 0;
+	for (uint i = _transparentDstStart; i < _transparentDstStop; i++) {
+		byte transparentRed = ((uint)_mainPalette[3 * i + 0]) * 60 / 128;
+		byte transparentGreen = ((uint)_mainPalette[3 * i + 1]) * 50 / 128;
+		byte transparentBlue = ((uint)_mainPalette[3 * i + 2]) * 35 / 128;
 
 		// Find nearest color
 		transparentScore newColorScore = transparentCalculateScore(transparentRed, transparentGreen,
 		                                 transparentBlue);
-		unsigned int distanceMin = -1u;
-		unsigned int nearestId = -1u;
-		for (unsigned int j = _transparentSrcStart; j < _transparentSrcStop; j++) {
+		uint distanceMin = -1u;
+		uint nearestId = -1u;
+		for (uint j = _transparentSrcStart; j < _transparentSrcStop; j++) {
 			if (j != i && newColorScore.dScore(proximities[j]) < 15) {
-				unsigned int distance = newColorScore.dRed(proximities[j]) + newColorScore.dGreen(proximities[j]);
+				uint distance = newColorScore.dRed(proximities[j]) + newColorScore.dGreen(proximities[j]);
 				if (distance < distanceMin) {
 					distanceMin = distance;
 					nearestId = j;
@@ -450,8 +450,8 @@ void CryOmni3DEngine_Versailles::makeTranslucent(Graphics::Surface &dst,
 
 	const byte *srcP = (const byte *) src.getPixels();
 	byte *dstP = (byte *) dst.getPixels();
-	for (unsigned int y = 0; y < dst.h; y++) {
-		for (unsigned int x = 0; x < dst.w; x++) {
+	for (uint y = 0; y < dst.h; y++) {
+		for (uint x = 0; x < dst.w; x++) {
 			dstP[x] = _transparentPaletteMap[srcP[x]];
 		}
 		dstP += dst.pitch;
@@ -608,7 +608,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) {
 
 	if (_currentLevel == 1) {
 		_dialogsMan.reinitVariables();
-		for (Common::Array<unsigned int>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
+		for (Common::Array<uint>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
 		        it++) {
 			*it = 0;
 		}
@@ -667,7 +667,7 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 		// Create a first SearchSet in which we will add all others to easily cleanup the mess
 		Common::SearchSet *visitFiles = new Common::SearchSet();
 
-		for (unsigned int lvl = 1; lvl <= 7; lvl++) {
+		for (uint lvl = 1; lvl <= 7; lvl++) {
 			Common::SearchSet *visitFilesAnimacti = new Common::SearchSet();
 			Common::SearchSet *visitFilesWarp = new Common::SearchSet();
 			Common::SearchSet *visitFilesImgFix = new Common::SearchSet();
@@ -719,7 +719,7 @@ void CryOmni3DEngine_Versailles::setupLevelWarps(int level) {
 	_omni3dMan.setBeta(initialState.beta);
 }
 
-void CryOmni3DEngine_Versailles::setGameTime(unsigned int newTime, unsigned int level) {
+void CryOmni3DEngine_Versailles::setGameTime(uint newTime, uint level) {
 	if (_currentLevel != level) {
 		error("Level %u != current level %u", level, _currentLevel);
 	}
@@ -804,7 +804,7 @@ void CryOmni3DEngine_Versailles::gameStep() {
 		if (_forcePaletteUpdate) {
 			redrawWarp();
 		}
-		unsigned int actionId = handleWarp();
+		uint actionId = handleWarp();
 		debug("handleWarp returned %u", actionId);
 		// Don't handle keyboard for levels 4 and 5, it was a debug leftover
 
@@ -888,7 +888,7 @@ void CryOmni3DEngine_Versailles::doGameOver() {
 
 void CryOmni3DEngine_Versailles::doPlaceChange() {
 	const Place *nextPlace = _wam.findPlaceById(_nextPlaceId);
-	unsigned int state = _placeStates[_nextPlaceId].state;
+	uint state = _placeStates[_nextPlaceId].state;
 	if (state == -1u) {
 		state = 0;
 	}
@@ -942,9 +942,9 @@ void CryOmni3DEngine_Versailles::doPlaceChange() {
 	}
 }
 
-void CryOmni3DEngine_Versailles::setPlaceState(unsigned int placeId, unsigned int newState) {
-	unsigned int numStates = _wam.findPlaceById(placeId)->getNumStates();
-	unsigned int oldState = _placeStates[placeId].state;
+void CryOmni3DEngine_Versailles::setPlaceState(uint placeId, uint newState) {
+	uint numStates = _wam.findPlaceById(placeId)->getNumStates();
+	uint oldState = _placeStates[placeId].state;
 
 	if (newState > numStates) {
 		warning("CryOmni3DEngine_Versailles::setPlaceState: newState '%d' > numStates '%d'",
@@ -959,9 +959,9 @@ void CryOmni3DEngine_Versailles::setPlaceState(unsigned int placeId, unsigned in
 	}
 }
 
-void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
+void CryOmni3DEngine_Versailles::executeTransition(uint nextPlaceId) {
 	const Transition *transition;
-	unsigned int animationId = determineTransitionAnimation(_currentPlaceId, nextPlaceId, &transition);
+	uint animationId = determineTransitionAnimation(_currentPlaceId, nextPlaceId, &transition);
 
 	_nextPlaceId = nextPlaceId;
 
@@ -992,7 +992,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 	_omni3dMan.setAlpha(transition->dstAlpha);
 	_omni3dMan.setBeta(-transition->dstBeta);
 
-	unsigned int nextState = _placeStates[nextPlaceId].state;
+	uint nextState = _placeStates[nextPlaceId].state;
 	if (nextState == -1u) {
 		nextState = 0;
 	}
@@ -1001,7 +1001,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 	warpFile.toUppercase();
 	if (warpFile.hasPrefix("NOT_STOP")) {
 		debug("Got not stop");
-		unsigned int transitionNum;
+		uint transitionNum;
 		// Determine transition to take
 		if (nextPlace->getNumTransitions() == 1) {
 			// Only one
@@ -1012,7 +1012,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 		} else {
 			transitionNum = 0;
 		}
-		unsigned int nextNextPlaceId = nextPlace->transitions[transitionNum].dstId;
+		uint nextNextPlaceId = nextPlace->transitions[transitionNum].dstId;
 
 		animationId = determineTransitionAnimation(nextPlaceId, nextNextPlaceId, &transition);
 		animation = animationId == -1u ? "" : transition->animations[animationId];
@@ -1038,7 +1038,7 @@ void CryOmni3DEngine_Versailles::executeTransition(unsigned int nextPlaceId) {
 	}
 }
 
-void CryOmni3DEngine_Versailles::fakeTransition(unsigned int dstPlaceId) {
+void CryOmni3DEngine_Versailles::fakeTransition(uint dstPlaceId) {
 	// No need of animation, caller will take care
 	// We just setup the camera in good place for the caller
 	const Place *srcPlace = _wam.findPlaceById(_currentPlaceId);
@@ -1050,8 +1050,8 @@ void CryOmni3DEngine_Versailles::fakeTransition(unsigned int dstPlaceId) {
 	_omni3dMan.setBeta(-transition->dstBeta);
 }
 
-unsigned int CryOmni3DEngine_Versailles::determineTransitionAnimation(unsigned int srcPlaceId,
-        unsigned int dstPlaceId, const Transition **transition_) {
+uint CryOmni3DEngine_Versailles::determineTransitionAnimation(uint srcPlaceId,
+        uint dstPlaceId, const Transition **transition_) {
 	const Place *srcPlace = _wam.findPlaceById(srcPlaceId);
 	const Place *dstPlace = _wam.findPlaceById(dstPlaceId);
 	const Transition *transition = srcPlace->findTransition(dstPlaceId);
@@ -1060,12 +1060,12 @@ unsigned int CryOmni3DEngine_Versailles::determineTransitionAnimation(unsigned i
 		*transition_ = transition;
 	}
 
-	unsigned int srcNumStates = srcPlace->getNumStates();
-	unsigned int dstNumStates = dstPlace->getNumStates();
-	unsigned int animsNum = transition->getNumAnimations();
+	uint srcNumStates = srcPlace->getNumStates();
+	uint dstNumStates = dstPlace->getNumStates();
+	uint animsNum = transition->getNumAnimations();
 
-	unsigned int srcState = _placeStates[srcPlaceId].state;
-	unsigned int dstState = _placeStates[dstPlaceId].state;
+	uint srcState = _placeStates[srcPlaceId].state;
+	uint dstState = _placeStates[dstPlaceId].state;
 
 	if (srcState >= srcNumStates) {
 		error("Invalid src state");
@@ -1108,11 +1108,11 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 	bool leftButtonPressed = false;
 	bool firstDraw = true;
 	bool moving = true;
-	unsigned int actionId;
+	uint actionId;
 	g_system->showMouse(true);
 	while (!leftButtonPressed && !exit) {
 		int xDelta = 0, yDelta = 0;
-		unsigned int movingCursor = -1;
+		uint movingCursor = -1;
 
 		pollEvents();
 		Common::Point mouse = getMousePos();
@@ -1195,8 +1195,8 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 	return actionId;
 }
 
-bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
-        unsigned int movingCursor) {
+bool CryOmni3DEngine_Versailles::handleWarpMouse(uint *actionId,
+        uint movingCursor) {
 	fixActionId(actionId);
 
 	if (getCurrentMouseButton() == 2 ||
@@ -1265,10 +1265,10 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId,
 	return false;
 }
 
-void CryOmni3DEngine_Versailles::fixActionId(unsigned int *actionId) const {
+void CryOmni3DEngine_Versailles::fixActionId(uint *actionId) const {
 	PlaceStateActionKey mask = PlaceStateActionKey(_currentPlaceId, _placeStates[_currentPlaceId].state,
 	                           *actionId);
-	Common::HashMap<PlaceStateActionKey, unsigned int>::const_iterator it = _actionMasks.find(mask);
+	Common::HashMap<PlaceStateActionKey, uint>::const_iterator it = _actionMasks.find(mask);
 	if (it != _actionMasks.end()) {
 		*actionId = it->_value;
 		return;
@@ -1382,9 +1382,9 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 
 	bool cursorWasVisible = g_system->showMouse(true);
 
-	for (unsigned int i = 4; i > 0; i--) {
+	for (uint i = 4; i > 0; i--) {
 		// Wait 100ms
-		for (unsigned int j = 10; j > 0; j--) {
+		for (uint j = 10; j > 0; j--) {
 			// pollEvents sleeps 10ms
 			pollEvents();
 			g_system->updateScreen();
@@ -1392,7 +1392,7 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 		setCursor(obj->idSA());
 		g_system->updateScreen();
 		// Wait 100ms
-		for (unsigned int j = 10; j > 0; j--) {
+		for (uint j = 10; j > 0; j--) {
 			// pollEvents sleeps 10ms
 			pollEvents();
 			g_system->updateScreen();
@@ -1471,7 +1471,7 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 	setMousePos(Common::Point(320, 240)); // Center of screen
 }
 
-void CryOmni3DEngine_Versailles::executeSeeAction(unsigned int actionId) {
+void CryOmni3DEngine_Versailles::executeSeeAction(uint actionId) {
 	if (_currentLevel == 7 && _currentPlaceId != 20) {
 		// Don't display fixed images unless it's the bomb
 		// Not enough time for paintings
@@ -1487,7 +1487,7 @@ void CryOmni3DEngine_Versailles::executeSeeAction(unsigned int actionId) {
 	}
 }
 
-void CryOmni3DEngine_Versailles::executeSpeakAction(unsigned int actionId) {
+void CryOmni3DEngine_Versailles::executeSpeakAction(uint actionId) {
 	PlaceActionKey key(_currentPlaceId, actionId);
 	Common::HashMap<PlaceActionKey, Common::String>::iterator it = _whoSpeaksWhere.find(key);
 	g_system->showMouse(true);
@@ -1502,14 +1502,14 @@ void CryOmni3DEngine_Versailles::executeSpeakAction(unsigned int actionId) {
 	}
 }
 
-void CryOmni3DEngine_Versailles::executeDocAction(unsigned int actionId) {
+void CryOmni3DEngine_Versailles::executeDocAction(uint actionId) {
 	if (_currentLevel == 7) {
 		// Not enough time for doc
 		displayMessageBoxWarp(13);
 		return;
 	}
 
-	Common::HashMap<unsigned int, const char *>::iterator it = _docPeopleRecord.find(actionId);
+	Common::HashMap<uint, const char *>::iterator it = _docPeopleRecord.find(actionId);
 	if (it == _docPeopleRecord.end() || !it->_value) {
 		warning("Missing documentation record for action %u", actionId);
 		return;
@@ -1537,7 +1537,7 @@ void CryOmni3DEngine_Versailles::handleFixedImg(const FixedImgCallback &callback
 	}
 }
 
-unsigned int CryOmni3DEngine_Versailles::getFakeTransition(unsigned int actionId) const {
+uint CryOmni3DEngine_Versailles::getFakeTransition(uint actionId) const {
 	for (const FakeTransitionActionPlace *ft = kFakeTransitions; ft->actionId != 0; ft++) {
 		if (ft->actionId == actionId) {
 			return ft->placeId;
@@ -1571,11 +1571,11 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename,
 }
 
 void CryOmni3DEngine_Versailles::loadBMPs(const char *pattern, Graphics::Surface *bmps,
-        unsigned int count) {
+        uint count) {
 	Image::BitmapDecoder bmpDecoder;
 	Common::File file;
 
-	for (unsigned int i = 0; i < count; i++) {
+	for (uint i = 0; i < count; i++) {
 		Common::String bmp = Common::String::format(pattern, i);
 
 		if (!file.open(bmp)) {
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index fc94787..8411451 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -51,10 +51,10 @@ class ZonFixedImage;
 namespace CryOmni3D {
 namespace Versailles {
 struct PlaceStateActionKey {
-	unsigned int placeId;
-	unsigned int placeState;
-	unsigned int actionId;
-	PlaceStateActionKey(unsigned int placeId_, unsigned int placeState_, unsigned int actionId_) :
+	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 {
@@ -63,9 +63,9 @@ struct PlaceStateActionKey {
 };
 
 struct PlaceActionKey {
-	unsigned int placeId;
-	unsigned int actionId;
-	PlaceActionKey(unsigned int placeId_, unsigned int actionId_) :
+	uint placeId;
+	uint actionId;
+	PlaceActionKey(uint placeId_, uint actionId_) :
 		placeId(placeId_), actionId(actionId_) {}
 
 	bool operator==(const PlaceActionKey &other) const {
@@ -170,7 +170,7 @@ struct SoundIds {
 
 struct PlaceState {
 	typedef void (CryOmni3DEngine_Versailles::*InitFunc)();
-	typedef bool (CryOmni3DEngine_Versailles::*FilterEventFunc)(unsigned int *event);
+	typedef bool (CryOmni3DEngine_Versailles::*FilterEventFunc)(uint *event);
 
 	PlaceState() : initPlace(nullptr), filterEvent(nullptr), docImage(nullptr), state(0) {}
 	PlaceState(InitFunc initPlace_, FilterEventFunc filterEvent_, const char *docImage_) :
@@ -179,18 +179,18 @@ struct PlaceState {
 	InitFunc initPlace;
 	FilterEventFunc filterEvent;
 	const char *docImage;
-	unsigned int state;
+	uint state;
 };
 
 struct LevelInitialState {
-	unsigned int placeId;
+	uint placeId;
 	double alpha;
 	double beta;
 };
 
 struct FakeTransitionActionPlace {
-	unsigned int actionId;
-	unsigned int placeId;
+	uint actionId;
+	uint placeId;
 };
 
 typedef void (CryOmni3DEngine_Versailles::*FixedImgCallback)(ZonFixedImage *);
@@ -198,14 +198,14 @@ typedef void (CryOmni3DEngine_Versailles::*FixedImgCallback)(ZonFixedImage *);
 struct MsgBoxParameters {
 	int font;
 	byte foreColor;
-	unsigned int lineHeight;
-	unsigned int spaceWidth;
-	unsigned int charSpacing;
-	unsigned int initialWidth;
-	unsigned int incrementWidth;
-	unsigned int initialHeight;
-	unsigned int incrementHeight;
-	unsigned int timeoutChar;
+	uint lineHeight;
+	uint spaceWidth;
+	uint charSpacing;
+	uint initialWidth;
+	uint incrementWidth;
+	uint initialHeight;
+	uint incrementHeight;
+	uint timeoutChar;
 };
 
 class CryOmni3DEngine_Versailles : public CryOmni3DEngine {
@@ -230,7 +230,7 @@ public:
 	virtual bool displayToolbar(const Graphics::Surface *original) override { return _toolbar.displayToolbar(original); };
 	virtual bool hasPlaceDocumentation() override;
 	virtual bool displayPlaceDocumentation() override;
-	virtual unsigned int displayOptions() override;
+	virtual uint displayOptions() override;
 	virtual bool shouldAbort() override { return g_engine->shouldQuit() || _abortCommand != AbortNoAbort; }
 
 private:
@@ -256,65 +256,65 @@ private:
 	void initDocPeopleRecord();
 	void setupLevelActionsMask();
 
-	unsigned int currentGameTime() const { return _gameVariables[GameVariables::kCurrentTime]; }
-	void setGameTime(unsigned int newTime, unsigned int level);
+	uint currentGameTime() const { return _gameVariables[GameVariables::kCurrentTime]; }
+	void setGameTime(uint newTime, uint level);
 	void updateGameTimeDialVariables();
 
 	void gameStep();
 	void doGameOver();
 
-	void setPlaceState(unsigned int placeId, unsigned int newState);
+	void setPlaceState(uint placeId, uint newState);
 	void doPlaceChange();
-	void executeTransition(unsigned int nextPlaceId);
-	void fakeTransition(unsigned int dstPlaceId);
-	unsigned int determineTransitionAnimation(unsigned int srcId, unsigned int dstId,
-	        const Transition **transition);
+	void executeTransition(uint nextPlaceId);
+	void fakeTransition(uint dstPlaceId);
+	uint determineTransitionAnimation(uint srcId, uint dstId,
+	                                  const Transition **transition);
 
-	unsigned int getFakeTransition(unsigned int actionId) const;
-	void fixActionId(unsigned int *actionId) const;
+	uint getFakeTransition(uint actionId) const;
+	void fixActionId(uint *actionId) const;
 
 	int handleWarp();
-	bool handleWarpMouse(unsigned int *actionId, unsigned int movingCuror);
+	bool handleWarpMouse(uint *actionId, uint movingCuror);
 	void animateWarpTransition(const Transition *transition);
 	void redrawWarp();
 
 	void handleFixedImg(const FixedImgCallback &callback);
-	void executeSeeAction(unsigned int actionId);
+	void executeSeeAction(uint actionId);
 
-	void executeSpeakAction(unsigned int actionId);
+	void executeSpeakAction(uint actionId);
 	void setupDialogShows();
 	bool preprocessDialog(const Common::String &sequence);
 	void postprocessDialog(const Common::String &sequence);
 
-	void executeDocAction(unsigned int actionId);
+	void executeDocAction(uint actionId);
 
 	void drawMenuTitle(Graphics::ManagedSurface *surface, byte color);
-	unsigned int displayFilePicker(const Graphics::Surface *bgFrame, bool saveMode,
-	                               Common::String &saveName);
-	unsigned int displayYesNoBox(Graphics::ManagedSurface &surface, const Common::Rect &position,
-	                             unsigned int msg_id);
+	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 &params, const Graphics::Surface *surface,
-	                       unsigned int msg_id, const Common::Point &position,
+	                       uint msg_id, const Common::Point &position,
 	                       const Common::Functor0<void> &callback) { displayMessageBox(params, surface, _messages[msg_id], position, callback); }
 	void displayMessageBox(const MsgBoxParameters &params, 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(unsigned int msg_id) { displayMessageBoxWarp(_messages[msg_id]); }
+	void displayMessageBoxWarp(uint msg_id) { displayMessageBoxWarp(_messages[msg_id]); }
 	void displayCredits();
 
 	void warpMsgBoxCB();
 
 	bool canVisit() const;
-	Common::String getSaveFileName(bool visit, unsigned int saveNum) const;
+	Common::String getSaveFileName(bool visit, uint saveNum) const;
 	void getSavesList(bool visit, Common::Array<Common::String> &saveNames);
-	void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName);
-	bool loadGame(bool visit, unsigned int saveNum);
+	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(unsigned int nameID, const ZonFixedImage *fimg = nullptr,
+	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);
@@ -326,10 +326,10 @@ private:
 
 	void playInGameVideo(const Common::String &filename, bool restoreCursorPalette = true);
 
-	void loadBMPs(const char *pattern, Graphics::Surface *bmps, unsigned int count);
+	void loadBMPs(const char *pattern, Graphics::Surface *bmps, uint count);
 
-	unsigned int getMusicId(unsigned int level, unsigned int placeId) const;
-	bool musicWouldChange(unsigned int level, unsigned int placeId) const;
+	uint getMusicId(uint level, uint placeId) const;
+	bool musicWouldChange(uint level, uint placeId) const;
 	void musicUpdate();
 	void musicPause();
 	void musicResume();
@@ -337,11 +337,11 @@ private:
 	void musicSetQuiet(bool quiet);
 
 	Common::StringArray _messages;
-	static const unsigned int kSpritesMapTable[];
-	static const unsigned int kSpritesMapTableSize;
+	static const uint kSpritesMapTable[];
+	static const uint kSpritesMapTableSize;
 	static const LevelInitialState kLevelInitialStates[];
 	static const FakeTransitionActionPlace kFakeTransitions[];
-	Common::HashMap<unsigned int, FixedImgCallback> _imgScripts;
+	Common::HashMap<uint, FixedImgCallback> _imgScripts;
 	Common::Array<Common::String> _paintingsTitles;
 
 	Toolbar _toolbar;
@@ -353,35 +353,35 @@ private:
 	bool _forceRedrawWarp;
 
 	byte *_transparentPaletteMap;
-	unsigned int _transparentSrcStart;
-	unsigned int _transparentSrcStop;
-	unsigned int _transparentDstStart;
-	unsigned int _transparentDstStop;
-	unsigned int _transparentNewStart;
-	unsigned int _transparentNewStop;
+	uint _transparentSrcStart;
+	uint _transparentSrcStop;
+	uint _transparentDstStart;
+	uint _transparentDstStop;
+	uint _transparentNewStart;
+	uint _transparentNewStop;
 
 	bool _isPlaying;
 	bool _isVisiting;
 	AbortCommand _abortCommand;
-	unsigned int _loadedSave;
+	uint _loadedSave;
 
 	int _omni3dSpeed;
 
-	unsigned int _currentLevel;
+	uint _currentLevel;
 	Versailles_DialogsManager _dialogsMan;
 
 	Omni3DManager _omni3dMan;
 	ZonFixedImage *_fixedImage;
 
-	Common::Array<unsigned int> _gameVariables;
+	Common::Array<uint> _gameVariables;
 	Common::Array<PlaceState> _placeStates;
-	Common::HashMap<PlaceStateActionKey, unsigned int> _actionMasks;
+	Common::HashMap<PlaceStateActionKey, uint> _actionMasks;
 	Common::HashMap<PlaceActionKey, Common::String> _whoSpeaksWhere;
-	Common::HashMap<unsigned int, const char *> _docPeopleRecord;
+	Common::HashMap<uint, const char *> _docPeopleRecord;
 	bool _transitionAnimateWarp;
-	unsigned int _nextPlaceId;
+	uint _nextPlaceId;
 	WAMParser _wam;
-	unsigned int _currentPlaceId;
+	uint _currentPlaceId;
 	const Place *_currentPlace;
 	const Image::ImageDecoder *_currentWarpImage;
 
@@ -401,17 +401,17 @@ private:
 	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(unsigned int frameNum) { drawCountdown(); }
+	void drawCountdownVideo(uint frameNum) { drawCountdown(); }
 
 	bool _countingDown;
-	unsigned int _countdownNextEvent;
+	uint _countdownNextEvent;
 	char _countdownValue[6];
 	Graphics::ManagedSurface _countdownSurface;
 	bool doCountDown();
 	void doDrawCountdown(Graphics::ManagedSurface *surface);
 
 	// Objects
-	template<unsigned int ID>
+	template<uint ID>
 	void genericDisplayObject();
 	void obj_105();
 	void obj_106();
@@ -425,9 +425,9 @@ private:
 	void obj_142hk(Graphics::ManagedSurface &surface);
 
 	// Fixed image
-	template<unsigned int ID>
+	template<uint ID>
 	void genericDumbImage(ZonFixedImage *fimg);
-	template<unsigned int ID>
+	template<uint ID>
 	void genericPainting(ZonFixedImage *fimg);
 #define IMG_CB(name) void img_ ## name(ZonFixedImage *fimg)
 	IMG_CB(31101);
@@ -460,7 +460,7 @@ private:
 	IMG_CB(34174d);
 	IMG_CB(34174e);
 	IMG_CB(34174f);
-	static const unsigned int kSafeDigitsCount = 12;
+	static const uint kSafeDigitsCount = 12;
 	static const unsigned short kSafeDigitsX[];
 	static const unsigned short kSafeDigitsY[];
 	static const char *kSafeDates[];
@@ -504,7 +504,7 @@ private:
 	IMG_CB(44161d);
 	IMG_CB(44161e);
 	IMG_CB(44161f);
-	static const unsigned int kEpigraphMaxLetters = 32;
+	static const uint kEpigraphMaxLetters = 32;
 	static const char *kEpigraphContent;
 	static const char *kEpigraphPassword;
 	bool handleEpigraph(ZonFixedImage *fimg);
@@ -527,20 +527,20 @@ private:
 	IMG_CB(88003d);
 	IMG_CB(88003e);
 	IMG_CB(88003f);
-	static const unsigned int kBombPasswordSmallLength = 40;
-	static const unsigned int kBombPasswordMaxLength = 60;
+	static const uint kBombPasswordSmallLength = 40;
+	static const uint kBombPasswordMaxLength = 60;
 	static const unsigned short kBombLettersPos[2][kBombPasswordMaxLength][2];
 	static const char *kBombPassword;
 	bool handleBomb(ZonFixedImage *fimg);
 	void drawBombLetters(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpLetters)[26],
-	                     const unsigned int kBombPasswordLength,
+	                     const uint kBombPasswordLength,
 	                     const unsigned char (&bombPossibilites)[kBombPasswordMaxLength][5],
 	                     const unsigned char (&bombCurrentLetters)[kBombPasswordMaxLength]);
 	IMG_CB(88004);
 	IMG_CB(88004b);
 #undef IMG_CB
 
-#define FILTER_EVENT(level, place) bool filterEventLevel ## level ## Place ## place(unsigned int *event)
+#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);
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 55608cd..559f296 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -129,7 +129,7 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 #undef SET_OBJECT
 }
 
-template<unsigned int ID>
+template<uint ID>
 void CryOmni3DEngine_Versailles::genericDisplayObject() {
 	displayObject(imagesObjects[ID]);
 }
@@ -189,7 +189,7 @@ void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) {
 
 	drawEpigraphLetters(surface, bmpLetters, kEpigraphPassword);
 
-	for (unsigned int i = 0; i < 26; i++) {
+	for (uint i = 0; i < 26; i++) {
 		bmpLetters[i].free();
 	}
 }
@@ -238,7 +238,7 @@ void CryOmni3DEngine_Versailles::obj_142hk(Graphics::ManagedSurface &surface) {
 		Common::Point(448, 356),
 	};
 
-	unsigned int id = _currentPlaceId - 14;
+	uint id = _currentPlaceId - 14;
 	assert(id < ARRAYSIZE(markers));
 
 	/*
@@ -249,8 +249,8 @@ void CryOmni3DEngine_Versailles::obj_142hk(Graphics::ManagedSurface &surface) {
 	for(id = 0; id < ARRAYSIZE(markers); id++) {
 	*/
 	// Why - 20? Ask to game creators, it's like that in the code
-	unsigned int spriteX = markers[id].x - _sprites.getCursor(4).getWidth() / 2 - 20;
-	unsigned int spriteY = markers[id].y - _sprites.getCursor(4).getHeight() / 2;
+	uint spriteX = markers[id].x - _sprites.getCursor(4).getWidth() / 2 - 20;
+	uint spriteY = markers[id].y - _sprites.getCursor(4).getHeight() / 2;
 	surface.transBlitFrom(_sprites.getSurface(4), Common::Point(spriteX, spriteY),
 	                      _sprites.getKeyColor(4));
 	/*
@@ -424,7 +424,7 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 }
 
 // Generic handler for dumb fixed images
-template<unsigned int ID>
+template<uint ID>
 void CryOmni3DEngine_Versailles::genericDumbImage(ZonFixedImage *fimg) {
 	fimg->load(imagesPaintings[ID]);
 	while (1) {
@@ -446,7 +446,7 @@ void CryOmni3DEngine_Versailles::genericDumbImage(ZonFixedImage *fimg) {
     } while (false)
 
 // Generic handler for paintings fixed images
-template<unsigned int ID>
+template<uint ID>
 void CryOmni3DEngine_Versailles::genericPainting(ZonFixedImage *fimg) {
 	fimg->load(imagesPaintings[ID]);
 	while (1) {
@@ -1189,7 +1189,7 @@ bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) {
 	Graphics::ManagedSurface tempSurf;
 
 	loadBMPs("coff_%02d.bmp", bmpDigits, 10);
-	for (unsigned int i = 0; i < kSafeDigitsCount; i++) {
+	for (uint i = 0; i < kSafeDigitsCount; i++) {
 		safeDigits[i] = rnd.getRandomNumber(9);
 	}
 
@@ -1236,7 +1236,7 @@ bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) {
 		}
 	}
 
-	for (unsigned int i = 0; i < 10; i++) {
+	for (uint i = 0; i < 10; i++) {
 		bmpDigits[i].free();
 	}
 	return success;
@@ -1247,7 +1247,7 @@ const unsigned short CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 31
 
 void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surface,
         const Graphics::Surface(&bmpDigits)[10], const unsigned char (&safeDigits)[kSafeDigitsCount]) {
-	for (unsigned int i = 0; i < ARRAYSIZE(safeDigits); i++) {
+	for (uint i = 0; i < ARRAYSIZE(safeDigits); i++) {
 		const Graphics::Surface &digit = bmpDigits[safeDigits[i]];
 		Common::Point dst(kSafeDigitsX[i % 4], kSafeDigitsY[i / 4]);
 		surface.transBlitFrom(digit, dst);
@@ -1256,13 +1256,13 @@ void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surfac
 
 const char *CryOmni3DEngine_Versailles::kSafeDates[] = { "1643", "1668", "1674" };
 bool CryOmni3DEngine_Versailles::checkSafeDigits(unsigned char (&safeDigits)[kSafeDigitsCount]) {
-	unsigned int dateChecked;
+	uint dateChecked;
 	for (dateChecked = 0; dateChecked < ARRAYSIZE(kSafeDates); dateChecked++) {
 		const char *checkDate = kSafeDates[dateChecked];
 		// Find the date in one of safe digits lines
-		unsigned int line;
+		uint line;
 		for (line = 0; line < kSafeDigitsCount; line += 4) {
-			unsigned int digit;
+			uint digit;
 			for (digit = 0; digit < 4; digit++) {
 				if (safeDigits[line + digit] != checkDate[digit] - '0') {
 					break;
@@ -1506,7 +1506,7 @@ IMG_CB(41802) {
 			break;
 		}
 		if (fimg->_usedObject && fimg->_currentZone == 0) {
-			unsigned int objID = fimg->_usedObject->idOBJ();
+			uint objID = fimg->_usedObject->idOBJ();
 			if (objID == 100) {
 				playInGameVideo("12E2_24");
 				// Force reload of the place
@@ -1553,7 +1553,7 @@ IMG_CB(41802b) {
 			break;
 		}
 		if (fimg->_usedObject && fimg->_currentZone == 0) {
-			unsigned int objID = fimg->_usedObject->idOBJ();
+			uint objID = fimg->_usedObject->idOBJ();
 			if (objID == 100) {
 				playInGameVideo("12E2_24");
 				// Force reload of the place
@@ -1598,7 +1598,7 @@ IMG_CB(41802c) {
 			break;
 		}
 		if (fimg->_usedObject && fimg->_currentZone == 0) {
-			unsigned int objID = fimg->_usedObject->idOBJ();
+			uint objID = fimg->_usedObject->idOBJ();
 			if (objID == 100) {
 				playInGameVideo("12E2_24");
 				// Force reload of the place
@@ -1633,7 +1633,7 @@ IMG_CB(41802d) {
 			break;
 		}
 		if (fimg->_usedObject && fimg->_currentZone == 0) {
-			unsigned int objID = fimg->_usedObject->idOBJ();
+			uint objID = fimg->_usedObject->idOBJ();
 			if (objID == 100) {
 				playInGameVideo("12E2_24");
 				// Force reload of the place
@@ -2397,7 +2397,7 @@ bool CryOmni3DEngine_Versailles::handleEpigraph(ZonFixedImage *fimg) {
 		}
 	}
 
-	for (unsigned int i = 0; i < 26; i++) {
+	for (uint i = 0; i < 26; i++) {
 		bmpLetters[i].free();
 	}
 	return success;
@@ -2408,8 +2408,8 @@ const char *CryOmni3DEngine_Versailles::kEpigraphPassword = "LELOUPETLATETE";
 
 void CryOmni3DEngine_Versailles::drawEpigraphLetters(Graphics::ManagedSurface &surface,
         const Graphics::Surface(&bmpLetters)[26], const Common::String &letters) {
-	for (unsigned int i = 0; i < letters.size() && i < kEpigraphMaxLetters; i++) {
-		unsigned int letterId = 0;
+	for (uint i = 0; i < letters.size() && i < kEpigraphMaxLetters; i++) {
+		uint letterId = 0;
 		if (letters[i] >= 'A' && letters[i] <= 'Z') {
 			letterId = letters[i] - 'A';
 		}
@@ -2930,20 +2930,20 @@ bool CryOmni3DEngine_Versailles::handleBomb(ZonFixedImage *fimg) {
 	unsigned char bombCurrentLetters[60];
 	Graphics::ManagedSurface tempSurf;
 
-	const unsigned int kBombPasswordLength = strlen(kBombPassword);
+	const uint kBombPasswordLength = strlen(kBombPassword);
 	if (kBombPasswordLength >= kBombPasswordMaxLength) {
 		error("Bomb password is too long");
 	}
 
 	loadBMPs("bomb_%02d.bmp", bmpLetters, 26);
-	for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+	for (uint i = 0; i < kBombPasswordLength; i++) {
 		bombPossibilites[i][0] = toupper(kBombPassword[i]);
-		for (unsigned int j = 1; j < 5; j++) {
+		for (uint j = 1; j < 5; j++) {
 			bool foundSameLetter;
 			do {
 				foundSameLetter = false;
 				bombPossibilites[i][j] = rnd.getRandomNumberRng('A', 'Z');
-				for (unsigned int k = 0; k < j; k++) {
+				for (uint k = 0; k < j; k++) {
 					if (bombPossibilites[i][k] == bombPossibilites[i][j]) {
 						foundSameLetter = true;
 					}
@@ -2984,7 +2984,7 @@ bool CryOmni3DEngine_Versailles::handleBomb(ZonFixedImage *fimg) {
 
 				// Check if password is OK
 				success = true;
-				for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+				for (uint i = 0; i < kBombPasswordLength; i++) {
 					unsigned char letterChar = bombPossibilites[i][bombCurrentLetters[i]];
 					if (letterChar != kBombPassword[i]) {
 						success = false;
@@ -3003,7 +3003,7 @@ bool CryOmni3DEngine_Versailles::handleBomb(ZonFixedImage *fimg) {
 		}
 	}
 
-	for (unsigned int i = 0; i < 26; i++) {
+	for (uint i = 0; i < 26; i++) {
 		bmpLetters[i].free();
 	}
 	return success;
@@ -3034,13 +3034,13 @@ const unsigned short CryOmni3DEngine_Versailles::kBombLettersPos[2][kBombPasswor
 };
 
 void CryOmni3DEngine_Versailles::drawBombLetters(Graphics::ManagedSurface &surface,
-        const Graphics::Surface(&bmpLetters)[26], const unsigned int kBombPasswordLength,
+        const Graphics::Surface(&bmpLetters)[26], const uint kBombPasswordLength,
         const unsigned char (&bombPossibilites)[kBombPasswordMaxLength][5],
         const unsigned char (&bombCurrentLetters)[kBombPasswordMaxLength]) {
-	unsigned int table = kBombPasswordLength <= kBombPasswordSmallLength ? 0 : 1;
-	for (unsigned int i = 0; i < kBombPasswordLength; i++) {
+	uint table = kBombPasswordLength <= kBombPasswordSmallLength ? 0 : 1;
+	for (uint i = 0; i < kBombPasswordLength; i++) {
 		unsigned char letterChar = bombPossibilites[i][bombCurrentLetters[i]];
-		unsigned int letterId = 0;
+		uint letterId = 0;
 		if (letterChar >= 'A' && letterChar <= 'Z') {
 			letterId = letterChar - 'A';
 		}
@@ -3103,7 +3103,7 @@ IMG_CB(88004b) {
 #undef IMG_CB
 
 // Init place and filter event
-#define FILTER_EVENT(level, place) bool CryOmni3DEngine_Versailles::filterEventLevel ## level ## Place ## place(unsigned int *event)
+#define FILTER_EVENT(level, place) bool CryOmni3DEngine_Versailles::filterEventLevel ## level ## Place ## place(uint *event)
 #define INIT_PLACE(level, place) void CryOmni3DEngine_Versailles::initPlaceLevel ## level ## Place ## place()
 
 FILTER_EVENT(1, 1) {
@@ -3194,7 +3194,7 @@ FILTER_EVENT(1, 7) {
 FILTER_EVENT(1, 14) {
 	if (*event == 31141 && _placeStates[14].state == 0) {
 		// Open the curtain
-		unsigned int fakePlaceId = getFakeTransition(*event);
+		uint fakePlaceId = getFakeTransition(*event);
 		fakeTransition(fakePlaceId);
 		playInGameVideo("10D2_1");
 		setPlaceState(14, 1);
@@ -3236,7 +3236,7 @@ FILTER_EVENT(1, 14) {
 		      _placeStates[14].state);
 	}
 
-	unsigned int fakePlaceId = getFakeTransition(*event);
+	uint fakePlaceId = getFakeTransition(*event);
 	fakeTransition(fakePlaceId);
 
 	playInGameVideo(video);
@@ -3257,7 +3257,7 @@ FILTER_EVENT(2, 1) {
 		_dialogsMan["{JOUEUR-MONTRE-UN-PAMPHLET}"] = 'N';
 		_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N';
 		_dialogsMan["{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}"] = 'N';
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 96  || idOBJ == 101 || idOBJ == 115 ||
 		        idOBJ == 125 || idOBJ == 127) {
 			_dialogsMan["{JOUEUR-MONTRE-UN-PAMPHLET}"] = 'Y';
@@ -3373,7 +3373,7 @@ FILTER_EVENT(2, 2) {
 	assert(callback != nullptr);
 
 	// Adjust viewpoint for video
-	unsigned int fakePlaceId = getFakeTransition(*event);
+	uint fakePlaceId = getFakeTransition(*event);
 	fakeTransition(fakePlaceId);
 
 	playInGameVideo(video);
@@ -3395,7 +3395,7 @@ FILTER_EVENT(2, 2) {
 
 FILTER_EVENT(2, 5) {
 	if (*event == 22501 && _inventory.selectedObject()) {
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 96) {
 			if (!_inventory.inInventoryByNameID(101)) {
 				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARTS}"] = 'Y';
@@ -3480,7 +3480,7 @@ FILTER_EVENT(2, 9) {
 FILTER_EVENT(2, 11) {
 	if (*event == 22111 && _inventory.selectedObject()) {
 		bool gameOver = false;
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 107) {
 			_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] = 'Y';
 		} else if (idOBJ == 109) {
@@ -3510,7 +3510,7 @@ FILTER_EVENT(2, 11) {
 
 FILTER_EVENT(2, 12) {
 	if (*event == 22121 && _inventory.selectedObject()) {
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 105) {
 			_dialogsMan["{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}"] = 'Y';
 			_dialogsMan["{JOUEUR-A-MONTRE-ESQUISSES-NON-TRIEES-LEBRUN}"] = 'Y';
@@ -3967,7 +3967,7 @@ FILTER_EVENT(4, 15) {
 
 FILTER_EVENT(4, 16) {
 	if (*event == 24161 && _inventory.selectedObject()) {
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 124) {
 			_dialogsMan["{JOUEUR-DONNE-REPAS}"] = 'Y';
 		} else {
@@ -4012,7 +4012,7 @@ FILTER_EVENT(4, 17) {
 		setPlaceState(17, 1);
 		return false;
 	} else if (*event == 34172) {
-		unsigned int fakePlaceId = getFakeTransition(*event);
+		uint fakePlaceId = getFakeTransition(*event);
 		fakeTransition(fakePlaceId);
 		handleFixedImg(&CryOmni3DEngine_Versailles::img_34172);
 		return false;
@@ -4035,7 +4035,7 @@ INIT_PLACE(5, 6) {
 
 FILTER_EVENT(5, 9) {
 	if (*event == 25090 && _inventory.selectedObject()) {
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (currentGameTime() < 4) {
 			if (idOBJ == 125 && _gameVariables[GameVariables::kStateLampoonReligion] == 3) {
 				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
@@ -4096,7 +4096,7 @@ FILTER_EVENT(5, 9) {
 
 FILTER_EVENT(5, 14) {
 	if (*event == 25142 && _inventory.selectedObject()) {
-		unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+		uint idOBJ = _inventory.selectedObject()->idOBJ();
 		if (idOBJ == 125) {
 			_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y';
 		} else {
@@ -4263,7 +4263,7 @@ FILTER_EVENT(5, 23) {
 FILTER_EVENT(5, 27) {
 	if (*event == 25270) {
 		if (_inventory.selectedObject()) {
-			unsigned int idOBJ = _inventory.selectedObject()->idOBJ();
+			uint idOBJ = _inventory.selectedObject()->idOBJ();
 			if (idOBJ == 115) {
 				_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'Y';
 			} else if (idOBJ == 125) {
@@ -4328,7 +4328,7 @@ FILTER_EVENT(5, 29) {
 
 FILTER_EVENT(5, 33) {
 	if (*event == 35330 && !_gameVariables[GameVariables::kLoweredChandelier]) {
-		unsigned int fakePlaceId = getFakeTransition(*event);
+		uint fakePlaceId = getFakeTransition(*event);
 		fakeTransition(fakePlaceId);
 
 		playInGameVideo("LUSTRE");
@@ -4571,7 +4571,7 @@ FILTER_EVENT(7, 20) {
 void CryOmni3DEngine_Versailles::initCountdown() {
 	strcpy(_countdownValue, "05:00");
 	if (_gameVariables[GameVariables::kSavedCountdown]) {
-		unsigned int counter = _gameVariables[GameVariables::kSavedCountdown];
+		uint counter = _gameVariables[GameVariables::kSavedCountdown];
 		_countdownValue[4] = counter;
 		counter >>= 8;
 		_countdownValue[3] = counter;
@@ -4583,7 +4583,7 @@ void CryOmni3DEngine_Versailles::initCountdown() {
 }
 
 void CryOmni3DEngine_Versailles::syncCountdown() {
-	unsigned int counter = 0;
+	uint counter = 0;
 	counter |= _countdownValue[0];
 	counter <<= 8;
 	counter |= _countdownValue[1];
diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index 9a44478..7e88d67 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -60,7 +60,7 @@ void CryOmni3DEngine_Versailles::drawMenuTitle(Graphics::ManagedSurface *surface
 	_fontManager.setCurrentFont(oldFont);
 }
 
-unsigned int CryOmni3DEngine_Versailles::displayOptions() {
+uint CryOmni3DEngine_Versailles::displayOptions() {
 	Common::Array<int> menuEntries;
 	menuEntries.push_back(26);
 	menuEntries.push_back(27);
@@ -84,9 +84,9 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 
 	int drawState = 1;
 
-	unsigned int volumeCursorMiddleY = _sprites.getCursor(102).getHeight() / 2;
-	unsigned int volume = CLIP(ConfMan.getInt("sfx_volume"), 0, 256);
-	unsigned int soundVolumeY = ((283 * (256 - volume)) >> 8) + 101;
+	uint volumeCursorMiddleY = _sprites.getCursor(102).getHeight() / 2;
+	uint volume = CLIP(ConfMan.getInt("sfx_volume"), 0, 256);
+	uint soundVolumeY = ((283 * (256 - volume)) >> 8) + 101;
 	byte volumeForeColor = 243;
 
 	Graphics::ManagedSurface optionsSurface;
@@ -98,10 +98,10 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 	setCursor(181);
 	g_system->showMouse(true);
 
-	unsigned int hoveredBox = -1;
-	unsigned int selectedBox;
+	uint hoveredBox = -1;
+	uint selectedBox;
 	int selectedMsg = 0;
-	unsigned int volumeBox;
+	uint volumeBox;
 	bool resetScreen = true;
 	bool forceEvents = true;
 
@@ -132,10 +132,10 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 			optionsSurface.hLine(544, 429, 613, volumeForeColor); // minus 1 because hLine draws inclusive
 
 			boxes.reset();
-			unsigned int boxId = 0;
-			unsigned int top = 195;
-			unsigned int bottom;
-			unsigned int width;
+			uint boxId = 0;
+			uint top = 195;
+			uint bottom;
+			uint width;
 
 			for (Common::Array<int>::iterator it = menuEntries.begin(); it != menuEntries.end(); it++) {
 				if (*it == 30 && !ConfMan.getBool("subtitles")) {
@@ -156,7 +156,7 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 				} else if (*it == -42 && canVisit()) {
 					*it = 42;
 				} else if (*it == 48) {
-					unsigned int omni3D_speed = ConfMan.getInt("omni3d_speed");
+					uint omni3D_speed = ConfMan.getInt("omni3d_speed");
 					switch (omni3D_speed) {
 					case 1:
 						*it = 51;
@@ -215,7 +215,7 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 		if (pollEvents() || forceEvents) { // always call pollEvents
 			forceEvents = false;
 			Common::Point mouse = getMousePos();
-			unsigned int boxId = 0;
+			uint boxId = 0;
 			Common::Array<int>::iterator it;
 			for (it = menuEntries.begin(); it != menuEntries.end(); it++) {
 				if (boxes.hitTest(boxId, mouse)) {
@@ -319,7 +319,7 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 				Common::String saveName;
 				bool wasVisiting = _isVisiting;
 				_isVisiting = false;
-				unsigned int saveNumber = displayFilePicker(bgFrame, false, saveName);
+				uint saveNumber = displayFilePicker(bgFrame, false, saveName);
 				if (saveNumber == -1u) {
 					_isVisiting = wasVisiting;
 					drawState = 1;
@@ -334,7 +334,7 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 				Common::String saveName;
 				bool wasVisiting = _isVisiting;
 				_isVisiting = true;
-				unsigned int saveNumber = displayFilePicker(bgFrame, false, saveName);
+				uint saveNumber = displayFilePicker(bgFrame, false, saveName);
 				if (saveNumber == -1u) {
 					_isVisiting = wasVisiting;
 					drawState = 1;
@@ -347,7 +347,7 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 				waitMouseRelease();
 			} else if (selectedMsg == 29) {
 				Common::String saveName;
-				unsigned int saveNumber = displayFilePicker(bgFrame, true, saveName);
+				uint saveNumber = displayFilePicker(bgFrame, true, saveName);
 				if (saveNumber != -1u) {
 					saveGame(_isVisiting, saveNumber, saveName);
 				}
@@ -475,11 +475,11 @@ unsigned int CryOmni3DEngine_Versailles::displayOptions() {
 	return selectedMsg;
 }
 
-unsigned int CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurface &surface,
-        const Common::Rect &position, unsigned int msg_id) {
-	unsigned int confirmWidth = _fontManager.getStrWidth(_messages[53]);
-	unsigned int cancelWidth = _fontManager.getStrWidth(_messages[54]);
-	unsigned int oldFont = _fontManager.getCurrentFont();
+uint CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurface &surface,
+        const Common::Rect &position, uint msg_id) {
+	uint confirmWidth = _fontManager.getStrWidth(_messages[53]);
+	uint cancelWidth = _fontManager.getStrWidth(_messages[54]);
+	uint oldFont = _fontManager.getCurrentFont();
 
 	_fontManager.setSurface(&surface);
 	_fontManager.setForeColor(240);
@@ -500,11 +500,11 @@ unsigned int CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurfac
 
 	bool end = false;
 	bool redraw = true;
-	unsigned int result = -1u;
+	uint result = -1u;
 
 	while (!end || redraw) {
 		if (redraw) {
-			for (unsigned int boxId = 0; boxId < 2; boxId++) {
+			for (uint boxId = 0; boxId < 2; boxId++) {
 				if (boxId == result) {
 					_fontManager.setForeColor(240);
 				} else {
@@ -520,7 +520,7 @@ unsigned int CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurfac
 
 		if (pollEvents()) {
 			Common::Point mouse = getMousePos();
-			unsigned int hit_result = -1u;
+			uint hit_result = -1u;
 			if (boxes.hitTest(1, mouse)) {
 				hit_result = 1;
 			} else if (boxes.hitTest(0, mouse)) {
@@ -549,7 +549,7 @@ unsigned int CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurfac
 	return result;
 }
 
-unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surface *bgFrame,
+uint CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surface *bgFrame,
         bool saveMode, Common::String &saveName) {
 	Graphics::ManagedSurface surface(bgFrame->w, bgFrame->h, bgFrame->format);
 	surface.blitFrom(*bgFrame);
@@ -579,10 +579,10 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 
 	// Yes/No buttons
 	const Common::String &okMsg = _messages[53];
-	unsigned int okWidth = _fontManager.getStrWidth(okMsg);
+	uint okWidth = _fontManager.getStrWidth(okMsg);
 	boxes.setupBox(6, 246, 430, 246 + okWidth, 450, &okMsg);
 	const Common::String &cancelMsg = _messages[54];
-	unsigned int cancelWidth = _fontManager.getStrWidth(cancelMsg);
+	uint cancelWidth = _fontManager.getStrWidth(cancelMsg);
 	boxes.setupBox(7, 146, 430, 146 + cancelWidth, 450, &cancelMsg);
 
 	// Up/Down buttons
@@ -593,19 +593,19 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 
 	setCursor(181);
 
-	unsigned int fileListOffset = CLIP(ConfMan.getInt(_isVisiting ? "visits_list_off" :
-	                                   "saves_list_off"), 0, 100 - 6);
+	uint fileListOffset = CLIP(ConfMan.getInt(_isVisiting ? "visits_list_off" :
+	                           "saves_list_off"), 0, 100 - 6);
 
-	unsigned int boxHovered = -1;
-	unsigned int boxSelected = -1;
+	uint boxHovered = -1;
+	uint boxSelected = -1;
 
 	bool textCursorState = false;
-	unsigned int textCursorNextState = 0;
-	unsigned int textCursorPos = -1;
+	uint textCursorNextState = 0;
+	uint textCursorPos = -1;
 
 	bool autoRepeatInhibit = false;
-	unsigned int autoRepeatDelay = 250;
-	unsigned int autoRepeatEndInhibit = 0;
+	uint autoRepeatDelay = 250;
+	uint autoRepeatEndInhibit = 0;
 
 	bool finished = false;
 	bool filesListChanged = true;
@@ -613,7 +613,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 	while (!finished) {
 		if (filesListChanged || redraw) {
 			if (filesListChanged) {
-				for (unsigned int file = 0, fileY = 280; file < 6; file++, fileY += 20) {
+				for (uint file = 0, fileY = 280; file < 6; file++, fileY += 20) {
 					boxes.setupBox(file, 146, fileY, 408, fileY + 14, &savesList[file + fileListOffset]);
 				}
 				// Redraw background as file list changed
@@ -621,7 +621,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 				filesListChanged = false;
 			}
 			// Don't redraw the scroll buttons
-			for (unsigned int box = 0; box < 8; box++) {
+			for (uint box = 0; box < 8; box++) {
 				if (box == boxSelected) {
 					// Selected
 					_fontManager.setForeColor(240);
@@ -661,12 +661,12 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 		g_system->updateScreen();
 		pollEvents();
 		Common::KeyState key = getNextKey();
-		unsigned int mousePressed = getCurrentMouseButton();
+		uint mousePressed = getCurrentMouseButton();
 
 		if (!mousePressed) {
 			bool boxFound = false;
 			// Don't handle scroll arrows hovering
-			for (unsigned int box = 0; box < 8; box++) {
+			for (uint box = 0; box < 8; box++) {
 				if (boxes.hitTest(box, getMousePos())) {
 					boxFound = true;
 					if (boxHovered != box) {
@@ -733,7 +733,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 			}
 			if (g_system->getMillis() > textCursorNextState) {
 				textCursorNextState = g_system->getMillis() + 200; // Blink at 200ms period
-				unsigned int width = _fontManager.getStrWidth(savesList[boxSelected + fileListOffset]);
+				uint width = _fontManager.getStrWidth(savesList[boxSelected + fileListOffset]);
 				Common::Rect boxRct = boxes.getBoxRect(boxSelected);
 				textCursorPos = boxRct.left + width;
 				textCursorState = !textCursorState;
@@ -742,7 +742,7 @@ unsigned int CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surfa
 		}
 		if (!autoRepeatInhibit) {
 			bool autoRepeatTrigger = false;
-			unsigned int oldFileListOffset = fileListOffset;
+			uint oldFileListOffset = fileListOffset;
 			if (mousePressed) {
 				if (boxes.hitTest(8, getMousePos()) && fileListOffset > 0) {
 					fileListOffset--;
@@ -827,9 +827,9 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters &param
 	_fontManager.setSpaceWidth(params.spaceWidth);
 	_fontManager.setCharSpacing(params.charSpacing);
 
-	unsigned int width = params.initialWidth;
-	unsigned int height = params.initialHeight;
-	unsigned int lineCount = 0;
+	uint width = params.initialWidth;
+	uint height = params.initialHeight;
+	uint lineCount = 0;
 	Common::Point pt = position;
 	Common::Rect rct;
 
@@ -868,7 +868,7 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters &param
 			tooLarge = true;
 		}
 		lineCount = _fontManager.getLinesCount(msg, rct.width() - 12);
-		if (lineCount && lineCount * _fontManager.lineHeight() + 18 < (unsigned int)rct.height()) {
+		if (lineCount && lineCount * _fontManager.lineHeight() + 18 < (uint)rct.height()) {
 			notEnough = false;
 		}
 	}
@@ -889,7 +889,7 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters &param
 	                           dstSurface.w, dstSurface.h);
 
 	waitMouseRelease();
-	unsigned int disappearTime = g_system->getMillis() + msg.size() * params.timeoutChar * 10;
+	uint disappearTime = g_system->getMillis() + msg.size() * params.timeoutChar * 10;
 	bool finished = false;
 	while (!finished) {
 		g_system->updateScreen();
@@ -962,8 +962,8 @@ void CryOmni3DEngine_Versailles::displayCredits() {
 	char line[256];
 	bool end = false;
 	bool calculatedScreen = false;
-	unsigned int lineHeight = 20;
-	unsigned int currentY = 0;
+	uint lineHeight = 20;
+	uint currentY = 0;
 	int32 fileOffset = 0;
 	bool skipScreen = false;
 
@@ -985,7 +985,7 @@ void CryOmni3DEngine_Versailles::displayCredits() {
 					}
 					skipScreen = false;
 					// Wait
-					unsigned int endScreenTime = g_system->getMillis() + 6000;
+					uint endScreenTime = g_system->getMillis() + 6000;
 					while (g_system->getMillis() < endScreenTime && !skipScreen) {
 						g_system->updateScreen();
 						if (pollEvents()) {
@@ -1054,7 +1054,7 @@ void CryOmni3DEngine_Versailles::displayCredits() {
 		} else {
 			// Text
 			if (calculatedScreen) {
-				unsigned int width = _fontManager.getStrWidth(line);
+				uint width = _fontManager.getStrWidth(line);
 				// Center around 315
 				_fontManager.displayStr(315 - width / 2, currentY, line);
 			}
diff --git a/engines/cryomni3d/versailles/music.cpp b/engines/cryomni3d/versailles/music.cpp
index a19e82a..2fa60be 100644
--- a/engines/cryomni3d/versailles/music.cpp
+++ b/engines/cryomni3d/versailles/music.cpp
@@ -52,7 +52,7 @@ void CryOmni3DEngine_Versailles::musicUpdate() {
 		return;
 	}
 
-	unsigned int musicId = getMusicId(_currentLevel, _currentPlaceId);
+	uint musicId = getMusicId(_currentLevel, _currentPlaceId);
 	const char *musicBName = kMusicFiles[_currentLevel - 1][musicId];
 	assert(musicBName != nullptr);
 
@@ -131,15 +131,15 @@ void CryOmni3DEngine_Versailles::musicSetQuiet(bool quiet) {
 	}
 }
 
-bool CryOmni3DEngine_Versailles::musicWouldChange(unsigned int level, unsigned int placeId) const {
-	unsigned int musicId = getMusicId(level, placeId);
+bool CryOmni3DEngine_Versailles::musicWouldChange(uint level, uint placeId) const {
+	uint musicId = getMusicId(level, placeId);
 	const char *musicFile = kMusicFiles[_currentLevel - 1][musicId];
 
 	return musicFile != _musicCurrentFile;
 }
 
-unsigned int CryOmni3DEngine_Versailles::getMusicId(unsigned int level,
-        unsigned int placeId) const {
+uint CryOmni3DEngine_Versailles::getMusicId(uint level,
+        uint placeId) const {
 	// No need of place state
 	switch (level) {
 	case 1:
diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index 752cb76..a6620a3 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -34,7 +34,7 @@ namespace Versailles {
 
 #define SAVE_DESCRIPTION_LEN 20
 
-Common::String CryOmni3DEngine_Versailles::getSaveFileName(bool visit, unsigned int saveNum) const {
+Common::String CryOmni3DEngine_Versailles::getSaveFileName(bool visit, uint saveNum) const {
 	return Common::String::format("%s%s.%04u", _targetName.c_str(), visit ? "_visit" : "", saveNum);
 }
 
@@ -108,12 +108,12 @@ void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &s
 		}
 	}
 
-	for (unsigned int i = saveNames.size(); i < 100; i++) {
+	for (uint i = saveNames.size(); i < 100; i++) {
 		saveNames.push_back(_messages[55]);
 	}
 }
 
-void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
+void CryOmni3DEngine_Versailles::saveGame(bool visit, uint saveNum,
         const Common::String &saveName) {
 	if (visit && saveNum == 1) {
 		error("Can't erase bootstrap visit");
@@ -149,17 +149,17 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
 
 	// Dialog variables
 	assert(_dialogsMan.size() < 200);
-	for (unsigned int i = 0; i < _dialogsMan.size(); i++) {
+	for (uint i = 0; i < _dialogsMan.size(); i++) {
 		out->writeByte(_dialogsMan[i]);
 	}
-	for (unsigned int i = _dialogsMan.size(); i < 200; 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++) {
-		unsigned int objId = -1;
+		uint objId = -1;
 		if (*it != nullptr) {
 			// Inventory contains pointers to objects stored in _objects
 			objId = *it - _objects.begin();
@@ -178,20 +178,20 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
 	// Places states
 	assert(_placeStates.size() <= 100);
 	Common::Array<PlaceState>::const_iterator placeIt = _placeStates.begin();
-	for (unsigned int i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
+	for (uint i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
 		out->writeUint32BE(placeIt->state);
 	}
-	for (unsigned int i = _placeStates.size(); i < 100; i++) {
+	for (uint i = _placeStates.size(); i < 100; i++) {
 		out->writeUint32BE(0);
 	}
 
 	// Game variables
 	assert(_gameVariables.size() < 100);
-	for (Common::Array<unsigned int>::const_iterator it = _gameVariables.begin();
+	for (Common::Array<uint>::const_iterator it = _gameVariables.begin();
 	        it != _gameVariables.end(); it++) {
 		out->writeUint32BE(*it);
 	}
-	for (unsigned int i = _gameVariables.size(); i < 100; i++) {
+	for (uint i = _gameVariables.size(); i < 100; i++) {
 		out->writeUint32BE(0);
 	}
 
@@ -200,7 +200,7 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum,
 	delete out;
 }
 
-bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
+bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
 	Common::SeekableReadStream *in;
 
 	if (visit && saveNum == 1) {
@@ -241,17 +241,17 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 
 	// Dialog variables
 	assert(_dialogsMan.size() < 200);
-	for (unsigned int i = 0; i < _dialogsMan.size(); i++) {
+	for (uint i = 0; i < _dialogsMan.size(); i++) {
 		_dialogsMan[i] = in->readByte();
 	}
-	for (unsigned int i = _dialogsMan.size(); i < 200; i++) {
+	for (uint i = _dialogsMan.size(); i < 200; i++) {
 		in->readByte();
 	}
 
 	// Inventory
 	assert(_inventory.size() == 50);
 	for (Inventory::iterator it = _inventory.begin(); it != _inventory.end(); it++) {
-		unsigned int objId = in->readUint32BE();
+		uint objId = in->readUint32BE();
 		if (objId >= _objects.size()) {
 			objId = -1;
 		}
@@ -276,17 +276,17 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 	// 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 (unsigned int i = 0; i < 100; i++) {
+	for (uint i = 0; i < 100; i++) {
 		placesStates[i] = in->readUint32BE();
 	}
 
 	// Game variables
 	assert(_gameVariables.size() < 100);
-	for (Common::Array<unsigned int>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
+	for (Common::Array<uint>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
 	        it++) {
 		*it = in->readUint32BE();
 	}
-	for (unsigned int i = _gameVariables.size(); i < 100; i++) {
+	for (uint i = _gameVariables.size(); i < 100; i++) {
 		in->readUint32BE();
 	}
 
@@ -305,7 +305,7 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) {
 	_omni3dMan.setBeta(beta);
 
 	// _placeStates has just been resized in initNewLevel
-	unsigned int i = 0;
+	uint i = 0;
 	for (Common::Array<PlaceState>::iterator placeIt = _placeStates.begin();
 	        placeIt != _placeStates.end() && i < ARRAYSIZE(placesStates); placeIt++, i++) {
 		placeIt->state = placesStates[i];
diff --git a/engines/cryomni3d/versailles/toolbar.cpp b/engines/cryomni3d/versailles/toolbar.cpp
index 2f9426b..f6884bd 100644
--- a/engines/cryomni3d/versailles/toolbar.cpp
+++ b/engines/cryomni3d/versailles/toolbar.cpp
@@ -73,7 +73,7 @@ Toolbar::~Toolbar() {
 	_destSurface.free();
 }
 
-void Toolbar::inventoryChanged(unsigned int newPosition) {
+void Toolbar::inventoryChanged(uint newPosition) {
 	if (newPosition != -1u && newPosition > _inventoryOffset) {
 		_inventoryOffset = newPosition - 7;
 	}
@@ -103,8 +103,8 @@ const {
 	return it;
 }
 
-unsigned int Toolbar::captureEvent(const Common::Point &mousePos, unsigned int dragStatus) {
-	unsigned int result = 0;
+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);
@@ -162,7 +162,7 @@ void Toolbar::updateZones() {
 	}
 }
 
-unsigned int Toolbar::callbackInventory(unsigned int invId, unsigned int dragStatus) {
+uint Toolbar::callbackInventory(uint invId, uint dragStatus) {
 	if (!_inventoryEnabled) {
 		return 0;
 	}
@@ -206,7 +206,7 @@ unsigned int Toolbar::callbackInventory(unsigned int invId, unsigned int dragSta
 
 }
 
-unsigned int Toolbar::callbackInventoryPrev(unsigned int dragStatus) {
+uint Toolbar::callbackInventoryPrev(uint dragStatus) {
 	if (!_inventoryEnabled) {
 		return 0;
 	}
@@ -221,7 +221,7 @@ unsigned int Toolbar::callbackInventoryPrev(unsigned int dragStatus) {
 	return 0;
 }
 
-unsigned int Toolbar::callbackInventoryNext(unsigned int dragStatus) {
+uint Toolbar::callbackInventoryNext(uint dragStatus) {
 	if (!_inventoryEnabled) {
 		return 0;
 	}
@@ -235,7 +235,7 @@ unsigned int Toolbar::callbackInventoryNext(unsigned int dragStatus) {
 	return 0;
 }
 
-unsigned int Toolbar::callbackViewObject(unsigned int dragStatus) {
+uint Toolbar::callbackViewObject(uint dragStatus) {
 	if (!_inventoryEnabled) {
 		return 0;
 	}
@@ -274,7 +274,7 @@ unsigned int Toolbar::callbackViewObject(unsigned int dragStatus) {
 	}
 }
 
-unsigned int Toolbar::callbackOptions(unsigned int dragStatus) {
+uint Toolbar::callbackOptions(uint dragStatus) {
 	_mouse_in_options = true;
 
 	switch (dragStatus) {
@@ -300,7 +300,7 @@ unsigned int Toolbar::callbackOptions(unsigned int dragStatus) {
 	}
 }
 
-unsigned int Toolbar::callbackDocumentation(unsigned int dragStatus) {
+uint Toolbar::callbackDocumentation(uint dragStatus) {
 	_mouse_in_options = true;
 
 	switch (dragStatus) {
@@ -372,7 +372,7 @@ void Toolbar::drawToolbar(const Graphics::Surface *original) {
 	if (_inventoryEnabled && _inventoryHovered != -1u) {
 		Object *obj = (*_inventory)[_inventoryHovered];
 
-		unsigned int zoneId = _inventoryHovered - _inventoryOffset;
+		uint zoneId = _inventoryHovered - _inventoryOffset;
 		if (zoneId >= 8) {
 			// The object is hidden: huh?
 			return;
@@ -383,8 +383,8 @@ void Toolbar::drawToolbar(const Graphics::Surface *original) {
 		_fontManager->setCurrentFont(5);
 		_fontManager->setTransparentBackground(true);
 		const Common::String &objName = (*_messages)[obj->idOBJ()];
-		unsigned int x = 195 - _fontManager->getStrWidth(objName);
-		unsigned int startX = _zones[zoneId].rect.left + kTextOffset;
+		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);
@@ -546,8 +546,8 @@ void Toolbar::handleToolbarEvents(const Graphics::Surface *original) {
 			// 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);
-			unsigned int zoneId = zoneIt - _zones.begin();
-			unsigned int inventoryId = zoneId + _inventoryOffset;
+			uint zoneId = zoneIt - _zones.begin();
+			uint inventoryId = zoneId + _inventoryOffset;
 			if (zoneId < 8 && inventoryId < _inventory->size() && (*_inventory)[inventoryId] != nullptr) {
 				// It's the inventory
 				shouldHover = true;
diff --git a/engines/cryomni3d/versailles/toolbar.h b/engines/cryomni3d/versailles/toolbar.h
index 11517cc..e65d161 100644
--- a/engines/cryomni3d/versailles/toolbar.h
+++ b/engines/cryomni3d/versailles/toolbar.h
@@ -51,13 +51,13 @@ public:
 
 	Graphics::Surface &getBackgroundSurface() { return _bgSurface; }
 	bool displayToolbar(const Graphics::Surface *original);
-	void inventoryChanged(unsigned int newPosition);
-	unsigned int inventoryOffset() const { return _inventoryOffset; }
-	void setInventoryOffset(unsigned int offset) { _inventoryOffset = offset; }
+	void inventoryChanged(uint newPosition);
+	uint inventoryOffset() const { return _inventoryOffset; }
+	void setInventoryOffset(uint offset) { _inventoryOffset = offset; }
 	void setInventoryEnabled(bool enabled) { _inventoryEnabled = enabled; }
 
 private:
-	typedef unsigned int (Toolbar::*ZoneCallback)(unsigned int dragStatus);
+	typedef uint(Toolbar::*ZoneCallback)(uint dragStatus);
 	struct Zone {
 		Common::Rect rect;
 		uint16 imageMain;
@@ -73,21 +73,21 @@ private:
 	Inventory *_inventory;
 	CryOmni3DEngine *_engine;
 
-	static const unsigned int kTextOffset = 13;
+	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;
-	unsigned int captureEvent(const Common::Point &mousePos, unsigned int dragStatus);
+	uint captureEvent(const Common::Point &mousePos, uint dragStatus);
 	void drawToolbar(const Graphics::Surface *original);
 	void handleToolbarEvents(const Graphics::Surface *original);
 
 	bool _inventoryEnabled;
-	unsigned int _inventoryMaxOffset;
-	unsigned int _inventoryOffset;
-	unsigned int _inventoryHovered;
-	unsigned int _inventorySelected;
+	uint _inventoryMaxOffset;
+	uint _inventoryOffset;
+	uint _inventoryHovered;
+	uint _inventorySelected;
 
 	Object *_backup_selected_object;
 	bool _mouse_in_options;
@@ -96,19 +96,19 @@ private:
 
 	bool _parentMustRedraw;
 	bool _shortExit;
-	unsigned int _position;
+	uint _position;
 
 	Graphics::Surface _bgSurface;
 	Graphics::ManagedSurface _destSurface;
 
-	template<unsigned int N>
-	unsigned int callbackInventory(unsigned int dragStatus) { return callbackInventory(N, dragStatus); }
-	unsigned int callbackInventory(unsigned int invId, unsigned int dragStatus);
-	unsigned int callbackInventoryPrev(unsigned int dragStatus);
-	unsigned int callbackInventoryNext(unsigned int dragStatus);
-	unsigned int callbackViewObject(unsigned int dragStatus);
-	unsigned int callbackOptions(unsigned int dragStatus);
-	unsigned int callbackDocumentation(unsigned int dragStatus);
+	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
diff --git a/engines/cryomni3d/video/hnm_decoder.cpp b/engines/cryomni3d/video/hnm_decoder.cpp
index 0451828..7d4c84e 100644
--- a/engines/cryomni3d/video/hnm_decoder.cpp
+++ b/engines/cryomni3d/video/hnm_decoder.cpp
@@ -82,7 +82,8 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
 		frameCount = 0;
 	}
 
-	_videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay, _initialPalette);
+	_videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay,
+	                                 _initialPalette);
 	if (soundBits != 0 && soundChannels != 0) {
 		// HNM4 is 22050Hz
 		_audioTrack = new DPCMAudioTrack(soundChannels, soundBits, 22050, getSoundType());
@@ -202,8 +203,8 @@ void HNMDecoder::HNM4VideoTrack::decodePalette(Common::SeekableReadStream *strea
 		if (size < 2) {
 			break;
 		}
-		unsigned int start = stream->readByte();
-		unsigned int count = stream->readByte();
+		uint start = stream->readByte();
+		uint count = stream->readByte();
 		size -= 2;
 
 		if (start == 255 && count == 255) {
@@ -244,7 +245,7 @@ void HNMDecoder::HNM4VideoTrack::decodeInterframe(Common::SeekableReadStream *st
 	uint16 width = _surface.w;
 	bool eop = false;
 
-	unsigned int currentPos = 0;
+	uint currentPos = 0;
 
 	while (!eop) {
 		if (size < 1) {
@@ -344,7 +345,7 @@ void HNMDecoder::HNM4VideoTrack::decodeIntraframe(Common::SeekableReadStream *st
 	_nextNextFrameDelay = -1u;
 }
 
-HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, unsigned int sampleRate,
+HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
         Audio::Mixer::SoundType soundType) : AudioTrack(soundType), _audioStream(nullptr),
 	_gotLUT(false), _lastSample(0) {
 	if (bits != 16) {
@@ -369,7 +370,7 @@ Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(Common::SeekableReadStr
 		stream->read(_lut, 256 * sizeof(*_lut));
 		size -= 256 * sizeof(*_lut);
 #ifndef SCUMM_LITTLE_ENDIAN
-		for (unsigned int i = 0; i < 256; i++) {
+		for (uint i = 0; i < 256; i++) {
 			_lut[i] = FROM_LE_16(_lut[i]);
 		}
 #endif
diff --git a/engines/cryomni3d/video/hnm_decoder.h b/engines/cryomni3d/video/hnm_decoder.h
index c5d9307..993638e 100644
--- a/engines/cryomni3d/video/hnm_decoder.h
+++ b/engines/cryomni3d/video/hnm_decoder.h
@@ -98,7 +98,7 @@ private:
 
 	class DPCMAudioTrack : public AudioTrack {
 	public:
-		DPCMAudioTrack(uint16 channels, uint16 bits, unsigned int sampleRate,
+		DPCMAudioTrack(uint16 channels, uint16 bits, uint sampleRate,
 		               Audio::Mixer::SoundType soundType);
 		~DPCMAudioTrack();
 
diff --git a/engines/cryomni3d/wam_parser.cpp b/engines/cryomni3d/wam_parser.cpp
index a27e3ab..bce98cb 100644
--- a/engines/cryomni3d/wam_parser.cpp
+++ b/engines/cryomni3d/wam_parser.cpp
@@ -37,13 +37,13 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 	stream.read(str, 16);
 	stream.readUint32LE();
 
-	unsigned int nPlaces = stream.readByte();
+	uint nPlaces = stream.readByte();
 	//debug("nPlaces = %u", nPlaces);
-	for (unsigned int i = 0; i < nPlaces; i++) {
+	for (uint i = 0; i < nPlaces; i++) {
 		Place place;
-		unsigned int nWarps = stream.readByte();
+		uint nWarps = stream.readByte();
 		//debug("nWarps = %u", nWarps);
-		for (unsigned int k = 0; k < 8; k++) {
+		for (uint k = 0; k < 8; k++) {
 			stream.read(str, 16);
 			//debug("Warp: %.16s", str);
 			if (nWarps > 0) {
@@ -58,20 +58,20 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 		Place *oldPlace = findPlaceById_(place.placeId);
 		if (oldPlace) {
 			debug("Found duplicate place %u at %u, removing it", place.placeId,
-			      (unsigned int)(oldPlace - _places.begin()));
+			      (uint)(oldPlace - _places.begin()));
 			_places.erase(oldPlace);
 		}
 		//debug("nPlaceId = %u", place.placeId);
 		stream.readUint32LE();
-		unsigned int nTransitions = stream.readByte();
+		uint nTransitions = stream.readByte();
 		//debug("nTransitions = %u", nTransitions);
-		unsigned int nZones = stream.readByte();
+		uint nZones = stream.readByte();
 		//debug("nZones = %u", nZones);
-		for (unsigned int j = 0; j < nTransitions; j++) {
+		for (uint j = 0; j < nTransitions; j++) {
 			Transition trans;
 			stream.readUint32LE();
-			unsigned int nAnimations = stream.readByte();
-			for (unsigned int k = 0; k < 8; k++) {
+			uint nAnimations = stream.readByte();
+			for (uint k = 0; k < 8; k++) {
 				stream.read(str, 16);
 				if (nAnimations > 0) {
 					trans.animations.push_back(str);
@@ -87,7 +87,7 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 			trans.dstBeta = stream.readDoubleLE();
 			place.transitions.push_back(trans);
 		}
-		for (unsigned int j = 0; j < nZones; j++) {
+		for (uint j = 0; j < nZones; j++) {
 			Zone zone;
 			zone.zoneId = stream.readSint32LE();
 			zone.rct.left = stream.readSint32LE();
@@ -101,7 +101,7 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 	}
 }
 
-const Place *WAMParser::findPlaceById(unsigned int placeId) const {
+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;
@@ -110,7 +110,7 @@ const Place *WAMParser::findPlaceById(unsigned int placeId) const {
 	return nullptr;
 }
 
-Place *WAMParser::findPlaceById_(unsigned int placeId) {
+Place *WAMParser::findPlaceById_(uint placeId) {
 	for (Common::Array<Place>::iterator it = _places.begin(); it != _places.end(); it++) {
 		if (it->placeId == placeId) {
 			return it;
@@ -179,7 +179,7 @@ void Place::setupWarpConstraints(Omni3DManager &omni3d) const {
 	}
 }
 
-unsigned int Place::hitTest(const Common::Point &point) const {
+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)) {
@@ -203,7 +203,7 @@ unsigned int Place::hitTest(const Common::Point &point) const {
 	return 0;
 }
 
-const Transition *Place::findTransition(unsigned int nextPlaceId) const {
+const Transition *Place::findTransition(uint nextPlaceId) const {
 	for (Common::Array<Transition>::const_iterator it = transitions.begin(); it != transitions.end();
 	        it++) {
 		if (it->dstId == nextPlaceId) {
diff --git a/engines/cryomni3d/wam_parser.h b/engines/cryomni3d/wam_parser.h
index 6f678af..c8a904f 100644
--- a/engines/cryomni3d/wam_parser.h
+++ b/engines/cryomni3d/wam_parser.h
@@ -36,43 +36,43 @@ namespace CryOmni3D {
 class Omni3DManager;
 
 struct Zone {
-	unsigned int zoneId;
-	unsigned int action;
+	uint zoneId;
+	uint action;
 	Common::Rect rct;
 };
 
 struct Transition {
-	unsigned int dstId;
+	uint dstId;
 	double srcAlpha;
 	double srcBeta;
 	double dstAlpha;
 	double dstBeta;
 	Common::Array<Common::String> animations;
-	unsigned int getNumAnimations() const { return animations.size(); }
+	uint getNumAnimations() const { return animations.size(); }
 };
 
 struct Place {
-	unsigned int placeId;
+	uint placeId;
 	Common::Array<Common::String> warps;
 	Common::Array<Transition> transitions;
 	Common::Array<Zone> zones;
 
-	unsigned int getNumStates() const { return warps.size(); }
-	unsigned int getNumTransitions() const { return transitions.size(); }
+	uint getNumStates() const { return warps.size(); }
+	uint getNumTransitions() const { return transitions.size(); }
 	void setupWarpConstraints(Omni3DManager &omni3d) const;
-	unsigned int hitTest(const Common::Point &point) const;
-	const Transition *findTransition(unsigned int nextPlaceId) 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(unsigned int placeId) const;
+	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_(unsigned int placeId);
+	Place *findPlaceById_(uint placeId);
 	Common::Array<Place> _places;
 };
 


Commit: 28206dd554d38ca154b78bf0c349d1a966c31826
    https://github.com/scummvm/scummvm/commit/28206dd554d38ca154b78bf0c349d1a966c31826
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix include paths

Changed paths:
    engines/cryomni3d/cryomni3d.h
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/fixed_image.h
    engines/cryomni3d/font_manager.cpp
    engines/cryomni3d/objects.cpp
    engines/cryomni3d/omni3d.cpp
    engines/cryomni3d/sprites.cpp
    engines/cryomni3d/wam_parser.cpp


diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index 12d4299..6d6faff 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -33,9 +33,9 @@
 
 #include "engines/engine.h"
 
-#include "font_manager.h"
-#include "objects.h"
-#include "sprites.h"
+#include "cryomni3d/font_manager.h"
+#include "cryomni3d/objects.h"
+#include "cryomni3d/sprites.h"
 
 class OSystem;
 
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index c519eb9..b3ea5f3 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "engines/cryomni3d/fixed_image.h"
+#include "cryomni3d/fixed_image.h"
 
 #include "common/file.h"
 #include "common/system.h"
diff --git a/engines/cryomni3d/fixed_image.h b/engines/cryomni3d/fixed_image.h
index 92445ed..c1e7fd4 100644
--- a/engines/cryomni3d/fixed_image.h
+++ b/engines/cryomni3d/fixed_image.h
@@ -25,8 +25,8 @@
 
 #include "common/func.h"
 
-#include "engines/cryomni3d/cryomni3d.h"
-#include "engines/cryomni3d/objects.h"
+#include "cryomni3d/cryomni3d.h"
+#include "cryomni3d/objects.h"
 
 namespace Graphics {
 struct Surface;
diff --git a/engines/cryomni3d/font_manager.cpp b/engines/cryomni3d/font_manager.cpp
index bf24061..2cf3f7b 100644
--- a/engines/cryomni3d/font_manager.cpp
+++ b/engines/cryomni3d/font_manager.cpp
@@ -24,7 +24,7 @@
 #include "common/file.h"
 #include "graphics/managed_surface.h"
 
-#include "engines/cryomni3d/font_manager.h"
+#include "cryomni3d/font_manager.h"
 
 namespace CryOmni3D {
 
diff --git a/engines/cryomni3d/objects.cpp b/engines/cryomni3d/objects.cpp
index 7829664..3a29948 100644
--- a/engines/cryomni3d/objects.cpp
+++ b/engines/cryomni3d/objects.cpp
@@ -21,7 +21,7 @@
  */
 
 
-#include "engines/cryomni3d/objects.h"
+#include "cryomni3d/objects.h"
 
 namespace CryOmni3D {
 
diff --git a/engines/cryomni3d/omni3d.cpp b/engines/cryomni3d/omni3d.cpp
index e02b521..5672a3f 100644
--- a/engines/cryomni3d/omni3d.cpp
+++ b/engines/cryomni3d/omni3d.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "engines/cryomni3d/omni3d.h"
+#include "cryomni3d/omni3d.h"
 
 #include "common/rect.h"
 
diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
index 473cd8a..309c36f 100644
--- a/engines/cryomni3d/sprites.cpp
+++ b/engines/cryomni3d/sprites.cpp
@@ -24,7 +24,7 @@
 #include "common/file.h"
 #include "graphics/surface.h"
 
-#include "engines/cryomni3d/sprites.h"
+#include "cryomni3d/sprites.h"
 
 // #define SPRTIES_DEBUG
 
diff --git a/engines/cryomni3d/wam_parser.cpp b/engines/cryomni3d/wam_parser.cpp
index bce98cb..75bbfb0 100644
--- a/engines/cryomni3d/wam_parser.cpp
+++ b/engines/cryomni3d/wam_parser.cpp
@@ -22,8 +22,8 @@
 
 #include "common/stream.h"
 
-#include "engines/cryomni3d/wam_parser.h"
-#include "engines/cryomni3d/omni3d.h"
+#include "cryomni3d/wam_parser.h"
+#include "cryomni3d/omni3d.h"
 
 namespace CryOmni3D {
 


Commit: 8dceff30ea50a46b9260a0a8e34d42fc45e2a274
    https://github.com/scummvm/scummvm/commit/8dceff30ea50a46b9260a0a8e34d42fc45e2a274
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix indentation of preproc blocks

Changed paths:
    engines/cryomni3d/detection.cpp


diff --git a/engines/cryomni3d/detection.cpp b/engines/cryomni3d/detection.cpp
index 62bdebd..80d43f2 100644
--- a/engines/cryomni3d/detection.cpp
+++ b/engines/cryomni3d/detection.cpp
@@ -31,7 +31,7 @@
 #include "cryomni3d/cryomni3d.h"
 
 #ifdef ENABLE_VERSAILLES
-	#include "cryomni3d/versailles/engine.h"
+#include "cryomni3d/versailles/engine.h"
 #endif
 
 namespace CryOmni3D {
@@ -249,7 +249,7 @@ bool CryOmni3DMetaEngine::createInstance(OSystem *syst, Engine **engine,
 }
 
 #if PLUGIN_ENABLED_DYNAMIC(CRYOMNI3D)
-	REGISTER_PLUGIN_DYNAMIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
+REGISTER_PLUGIN_DYNAMIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
 #else
-	REGISTER_PLUGIN_STATIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
+REGISTER_PLUGIN_STATIC(CRYOMNI3D, PLUGIN_TYPE_ENGINE, CryOmni3DMetaEngine);
 #endif


Commit: 257a788e08fc396592f05eb688250b6948075fba
    https://github.com/scummvm/scummvm/commit/257a788e08fc396592f05eb688250b6948075fba
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Cleanup

Changed paths:
    engines/cryomni3d/detection.cpp
    engines/cryomni3d/image/hlz.h


diff --git a/engines/cryomni3d/detection.cpp b/engines/cryomni3d/detection.cpp
index 80d43f2..00f8480 100644
--- a/engines/cryomni3d/detection.cpp
+++ b/engines/cryomni3d/detection.cpp
@@ -70,22 +70,8 @@ Common::Language CryOmni3DEngine::getLanguage() const {
 
 bool CryOmni3DEngine::hasFeature(EngineFeature f) const {
 	return false;
-//		(f == kSupportsRTL);
 }
 
-/*
-#ifdef ENABLE_MYST
-
-bool MohawkEngine_Myst::hasFeature(EngineFeature f) const {
-    return
-        MohawkEngine::hasFeature(f)
-        || (f == kSupportsLoadingDuringRuntime)
-        || (f == kSupportsSavingDuringRuntime);
-}
-
-#endif
-*/
-
 } // End of Namespace CryOmni3D
 
 static const PlainGameDescriptor cryomni3DGames[] = {
@@ -95,29 +81,7 @@ static const PlainGameDescriptor cryomni3DGames[] = {
 
 #include "cryomni3d/detection_tables.h"
 
-/*
-static const char *directoryGlobs[] = {
-    "all",
-    "assets1",
-    "data",
-    "program",
-    "95instal",
-    "Rugrats Adventure Game",
-    0
-};
-*/
-
 static const ADExtraGuiOptionsMap optionsList[] = {
-	/*{
-	        GAMEOPTION_PLAY_MYST_FLYBY,
-	        {
-	                _s("Play the Myst fly by movie"),
-	                _s("The Myst fly by movie was not played by the original engine."),
-	                "playmystflyby",
-	                false
-	        }
-	},*/
-
 	AD_EXTRA_GUI_OPTIONS_TERMINATOR
 };
 
@@ -127,7 +91,6 @@ public:
 		        sizeof(CryOmni3D::CryOmni3DGameDescription), cryomni3DGames, optionsList) {
 		//_singleId = "cryomni3d";
 		_maxScanDepth = 2;
-		//_directoryGlobs = directoryGlobs;
 	}
 
 	ADDetectedGame fallbackDetect(const FileMap &allFiles,
@@ -192,37 +155,14 @@ SaveStateList CryOmni3DMetaEngine::listSavesForPrefix(const char *prefix,
 SaveStateList CryOmni3DMetaEngine::listSaves(const char *target) const {
 	SaveStateList saveList;
 
-	/*
-	// Loading games is only supported in Myst/Riven currently.
-	saveList = listSavesForPrefix("myst", "mys");
-
-	for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
-	    // Read the description from the save
-	    int slot = save->getSaveSlot();
-	    Common::String description = Mohawk::MystGameState::querySaveDescription(slot);
-	    save->setDescription(description);
-	}
-	*/
-
 	return saveList;
 }
 
 void CryOmni3DMetaEngine::removeSaveState(const char *target, int slot) const {
 
-	/*
-	// Removing saved games is only supported in Myst/Riven currently.
-	if (strstr(target, "myst")) {
-	    Mohawk::MystGameState::deleteSave(slot);
-	}
-	*/
 }
 
 SaveStateDescriptor CryOmni3DMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
-	/*
-	if (strstr(target, "myst")) {
-	    return Mohawk::MystGameState::querySaveMetaInfos(slot);
-	}
-	*/
 	return SaveStateDescriptor();
 }
 
diff --git a/engines/cryomni3d/image/hlz.h b/engines/cryomni3d/image/hlz.h
index 831632f..411f752 100644
--- a/engines/cryomni3d/image/hlz.h
+++ b/engines/cryomni3d/image/hlz.h
@@ -20,14 +20,6 @@
  *
  */
 
-/**
- * @file
- * Image decoder used in engines:
- *  - hugo
- *  - mohawk
- *  - wintermute
- */
-
 #ifndef CRYOMNI3D_IMAGE_HLZ_H
 #define CRYOMNI3D_IMAGE_HLZ_H
 


Commit: d3c33364d7fe18cfd330a7510f2fa5ef96a48307
    https://github.com/scummvm/scummvm/commit/d3c33364d7fe18cfd330a7510f2fa5ef96a48307
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Sort files

Changed paths:
    engines/cryomni3d/module.mk


diff --git a/engines/cryomni3d/module.mk b/engines/cryomni3d/module.mk
index 637cf34..30dd767 100644
--- a/engines/cryomni3d/module.mk
+++ b/engines/cryomni3d/module.mk
@@ -1,19 +1,19 @@
 MODULE := engines/cryomni3d
 
 MODULE_OBJS = \
+	image/codecs/hlz.o \
+	image/hlz.o \
+	video/hnm_decoder.o \
 	cryomni3d.o \
-	omni3d.o \
 	detection.o \
-	mouse_boxes.o \
 	dialogs_manager.o \
 	fixed_image.o \
 	font_manager.o \
+	mouse_boxes.o \
 	objects.o \
+	omni3d.o \
 	sprites.o \
-	wam_parser.o \
-	video/hnm_decoder.o \
-	image/hlz.o \
-	image/codecs/hlz.o
+	wam_parser.o
 
 ifdef ENABLE_VERSAILLES
 MODULE_OBJS += \


Commit: bd8698897dbcba425a63255ebc2edf9c48cfb814
    https://github.com/scummvm/scummvm/commit/bd8698897dbcba425a63255ebc2edf9c48cfb814
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Better check of sprites magic

Changed paths:
    engines/cryomni3d/sprites.cpp


diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
index 309c36f..23f8c43 100644
--- a/engines/cryomni3d/sprites.cpp
+++ b/engines/cryomni3d/sprites.cpp
@@ -54,13 +54,13 @@ Sprites::~Sprites() {
 }
 
 void Sprites::loadSprites(Common::ReadStream &spr_fl) {
-	byte magic[4];
-
 	while (true) {
-		if (spr_fl.read(magic, sizeof(magic)) == 0) {
+		uint32 magic = spr_fl.readUint32BE();
+		if (spr_fl.eos()) {
+			// We are EOS so last read likely failed
 			break;
 		}
-		if (memcmp(magic, "SPRI", sizeof(magic))) {
+		if (magic != MKTAG('S', 'P', 'R', 'I')) {
 			error("Invalid sprite magic");
 		}
 


Commit: 5ed893bb6ab73384d647f3b20defa87e81a4c970
    https://github.com/scummvm/scummvm/commit/5ed893bb6ab73384d647f3b20defa87e81a4c970
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Move break to be clear it's not a fall through

Changed paths:
    engines/cryomni3d/versailles/documentation.cpp


diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
index abdbc63..38328f2 100644
--- a/engines/cryomni3d/versailles/documentation.cpp
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -596,15 +596,13 @@ uint Versailles_Documentation::docAreaHandleRecords(const Common::String &record
 			nextRecord = docAreaHandleCastleMap();
 			if (nextRecord == "") {
 				// Go back to current record
-				break;
 			} else if (nextRecord != "planG") {
 				_currentRecord = nextRecord;
-				break;
 			} else {
 				// We can't go up to previous case, so let's do a round
 				action = 7;
-				break;
 			}
+			break;
 		case 9:
 			action = -1;
 			// Start of category


Commit: d5a6c1c9cbf071c6b5a8f23334bdfb87808a4ab3
    https://github.com/scummvm/scummvm/commit/d5a6c1c9cbf071c6b5a8f23334bdfb87808a4ab3
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix abort constants names

Changed paths:
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp
    engines/cryomni3d/versailles/menus.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 2ab47c0..d03bd95 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -191,33 +191,33 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 				_isPlaying = true;
 				_toolbar.setInventoryEnabled(!_isVisiting);
 				nextStep = 0;
-				_abortCommand = AbortNoAbort;
+				_abortCommand = kAbortNoAbort;
 
 				gameStep();
 
 				// We shouldn't return from gameStep without an abort command
-				assert(_abortCommand != AbortNoAbort);
+				assert(_abortCommand != kAbortNoAbort);
 				switch (_abortCommand) {
 				default:
 					error("Invalid abortCommand: %d", _abortCommand);
 					// Shouldn't return
 					return Common::kUnknownError;
-				case AbortFinished:
-				case AbortGameOver:
+				case kAbortFinished:
+				case kAbortGameOver:
 					// Go back to menu
 					exitLoop = true;
 					break;
-				case AbortQuit:
+				case kAbortQuit:
 					exitLoop = true;
 					stopGame = true;
 					break;
-				case AbortNewGame:
+				case kAbortNewGame:
 					nextStep = 27;
 					break;
-				case AbortLoadGame:
+				case kAbortLoadGame:
 					nextStep = 28;
 					break;
-				case AbortNextLevel:
+				case kAbortNextLevel:
 					nextStep = 65;
 					break;
 				}
@@ -564,7 +564,7 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 
 	fadeOutPalette();
 	if (g_engine->shouldQuit()) {
-		_abortCommand = AbortQuit;
+		_abortCommand = kAbortQuit;
 		return;
 	}
 
@@ -578,13 +578,13 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 
 	clearKeys();
 	if (g_engine->shouldQuit()) {
-		_abortCommand = AbortQuit;
+		_abortCommand = kAbortQuit;
 		return;
 	}
 
 	fadeOutPalette();
 	if (g_engine->shouldQuit()) {
-		_abortCommand = AbortQuit;
+		_abortCommand = kAbortQuit;
 		return;
 	}
 
@@ -594,9 +594,9 @@ void CryOmni3DEngine_Versailles::playTransitionEndLevel(int level) {
 	fillSurface(0);
 
 	if (level == 7 || level == 8) {
-		_abortCommand = AbortFinished;
+		_abortCommand = kAbortFinished;
 	} else {
-		_abortCommand = AbortNextLevel;
+		_abortCommand = kAbortNextLevel;
 	}
 }
 
@@ -862,7 +862,7 @@ void CryOmni3DEngine_Versailles::gameStep() {
 				}
 			} else if (actionId == 66666) {
 				// Abort
-				assert(_abortCommand != AbortNoAbort);
+				assert(_abortCommand != kAbortNoAbort);
 				return;
 			}
 		} else if (!actionId) {
@@ -883,7 +883,7 @@ void CryOmni3DEngine_Versailles::doGameOver() {
 		playInGameVideo("4gameove");
 	}
 	fillSurface(0);
-	_abortCommand = AbortGameOver;
+	_abortCommand = kAbortGameOver;
 }
 
 void CryOmni3DEngine_Versailles::doPlaceChange() {
@@ -1150,7 +1150,7 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 
 		exit = handleWarpMouse(&actionId, movingCursor);
 		if (g_engine->shouldQuit()) {
-			_abortCommand = AbortQuit;
+			_abortCommand = kAbortQuit;
 			exit = true;
 		}
 		if (exit) {
@@ -1216,7 +1216,7 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(uint *actionId,
 
 		bool mustRedraw = displayToolbar(original);
 		// Don't redraw if we abort game
-		if (_abortCommand != AbortNoAbort) {
+		if (_abortCommand != kAbortNoAbort) {
 			return true;
 		}
 		if (mustRedraw) {
@@ -1230,7 +1230,7 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(uint *actionId,
 	if (countDown()) {
 		// Time has changed: need redraw
 		// Don't redraw if we abort game
-		if (_abortCommand != AbortNoAbort) {
+		if (_abortCommand != kAbortNoAbort) {
 			return true;
 		}
 
diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 8411451..1d92d38 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -100,13 +100,13 @@ namespace Versailles {
 class CryOmni3DEngine_Versailles;
 
 enum AbortCommand {
-	AbortNoAbort = 0,
-	AbortQuit = 1,
-	AbortLoadGame = 2,
-	AbortNewGame = 3,
-	AbortNextLevel = 5,
-	AbortFinished = 6,
-	AbortGameOver = 7
+	kAbortNoAbort = 0,
+	kAbortQuit = 1,
+	kAbortLoadGame = 2,
+	kAbortNewGame = 3,
+	kAbortNextLevel = 5,
+	kAbortFinished = 6,
+	kAbortGameOver = 7
 };
 
 struct GameVariables {
@@ -231,7 +231,7 @@ public:
 	virtual bool hasPlaceDocumentation() override;
 	virtual bool displayPlaceDocumentation() override;
 	virtual uint displayOptions() override;
-	virtual bool shouldAbort() override { return g_engine->shouldQuit() || _abortCommand != AbortNoAbort; }
+	virtual bool shouldAbort() override { return g_engine->shouldQuit() || _abortCommand != kAbortNoAbort; }
 
 private:
 	void setupFonts();
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 559f296..5d0eea2 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -4612,7 +4612,7 @@ bool CryOmni3DEngine_Versailles::doCountDown() {
 						// Finished!
 						_countingDown = false;
 						playTransitionEndLevel(8);
-						_abortCommand = AbortGameOver;
+						_abortCommand = kAbortGameOver;
 					}
 				}
 			}
diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index 7e88d67..79d7aa2 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -451,20 +451,20 @@ uint CryOmni3DEngine_Versailles::displayOptions() {
 	g_system->showMouse(false);
 
 	if (selectedMsg == 42) {
-		_abortCommand = AbortLoadGame;
+		_abortCommand = kAbortLoadGame;
 		// For return value
 		selectedMsg = 28;
 	} else if (selectedMsg == 28) {
-		_abortCommand = AbortLoadGame;
+		_abortCommand = kAbortLoadGame;
 	} else if (selectedMsg == 40) {
-		_abortCommand = AbortQuit;
+		_abortCommand = kAbortQuit;
 	} else if (selectedMsg == 27) {
-		_abortCommand = AbortNewGame;
+		_abortCommand = kAbortNewGame;
 		_isVisiting = false;
 	} else if (g_engine->shouldQuit()) {
 		// Fake a quit
 		selectedMsg = 40;
-		_abortCommand = AbortQuit;
+		_abortCommand = kAbortQuit;
 	}
 
 	ConfMan.flushToDisk();


Commit: b81f477ac1828862ba8c30cec90679606f64de3c
    https://github.com/scummvm/scummvm/commit/b81f477ac1828862ba8c30cec90679606f64de3c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Convert short to int16

Changed paths:
    engines/cryomni3d/versailles/engine.h
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h
index 1d92d38..66f4663 100644
--- a/engines/cryomni3d/versailles/engine.h
+++ b/engines/cryomni3d/versailles/engine.h
@@ -461,8 +461,8 @@ private:
 	IMG_CB(34174e);
 	IMG_CB(34174f);
 	static const uint kSafeDigitsCount = 12;
-	static const unsigned short kSafeDigitsX[];
-	static const unsigned short kSafeDigitsY[];
+	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],
@@ -529,7 +529,7 @@ private:
 	IMG_CB(88003f);
 	static const uint kBombPasswordSmallLength = 40;
 	static const uint kBombPasswordMaxLength = 60;
-	static const unsigned short kBombLettersPos[2][kBombPasswordMaxLength][2];
+	static const uint16 kBombLettersPos[2][kBombPasswordMaxLength][2];
 	static const char *kBombPassword;
 	bool handleBomb(ZonFixedImage *fimg);
 	void drawBombLetters(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpLetters)[26],
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 5d0eea2..2f18f96 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -1242,8 +1242,8 @@ bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) {
 	return success;
 }
 
-const unsigned short CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 };
-const unsigned short CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 };
+const uint16 CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 };
+const uint16 CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 };
 
 void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surface,
         const Graphics::Surface(&bmpDigits)[10], const unsigned char (&safeDigits)[kSafeDigitsCount]) {
@@ -3011,7 +3011,7 @@ bool CryOmni3DEngine_Versailles::handleBomb(ZonFixedImage *fimg) {
 
 const char *CryOmni3DEngine_Versailles::kBombPassword = "JEMENVAISMAISLETATDEMEURERATOUJOURS";
 // We use brace elision here because it's dumped from the EXE
-const unsigned short CryOmni3DEngine_Versailles::kBombLettersPos[2][kBombPasswordMaxLength][2] = {
+const uint16 CryOmni3DEngine_Versailles::kBombLettersPos[2][kBombPasswordMaxLength][2] = {
 	{
 		26, 91, 84, 89, 141, 89, 202, 88, 261, 87, 322, 86, 384, 85, 448, 84,
 		512, 83, 576, 83, 26, 175, 84, 175, 142, 174, 202, 174, 260, 174, 322,


Commit: 2d82abdaf5e1dbfd08291f0e70b5b971f791bc07
    https://github.com/scummvm/scummvm/commit/2d82abdaf5e1dbfd08291f0e70b5b971f791bc07
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Add a comment to clarify

Changed paths:
    engines/cryomni3d/versailles/menus.cpp


diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index 79d7aa2..dd95540 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -170,6 +170,9 @@ uint CryOmni3DEngine_Versailles::displayOptions() {
 					case 4:
 						*it = 50;
 						break;
+					default:
+						// If it is another value, menu text is 48 (normal speed) and there is nothing to do
+						break;
 					}
 				}
 


Commit: 7ae6e1af1e2fb190cf3ae4ce82b08fb3cddb868e
    https://github.com/scummvm/scummvm/commit/7ae6e1af1e2fb190cf3ae4ce82b08fb3cddb868e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Use byte instead of char

Changed paths:
    engines/cryomni3d/video/hnm_decoder.cpp


diff --git a/engines/cryomni3d/video/hnm_decoder.cpp b/engines/cryomni3d/video/hnm_decoder.cpp
index 7d4c84e..15e86da 100644
--- a/engines/cryomni3d/video/hnm_decoder.cpp
+++ b/engines/cryomni3d/video/hnm_decoder.cpp
@@ -72,8 +72,8 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
 	uint16 soundChannels = stream->readUint16LE();
 	uint32 frameSize = stream->readUint32LE();
 
-	char unknownStr[16];
-	char copyright[16];
+	byte unknownStr[16];
+	byte copyright[16];
 	stream->read(unknownStr, sizeof(unknownStr));
 	stream->read(copyright, sizeof(copyright));
 


Commit: f20d33f1305ace5f7cc9c7cf9c2a299c35bc0c77
    https://github.com/scummvm/scummvm/commit/f20d33f1305ace5f7cc9c7cf9c2a299c35bc0c77
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Make ignored reads explicit

Changed paths:
    engines/cryomni3d/font_manager.cpp
    engines/cryomni3d/sprites.cpp
    engines/cryomni3d/versailles/saveload.cpp
    engines/cryomni3d/wam_parser.cpp


diff --git a/engines/cryomni3d/font_manager.cpp b/engines/cryomni3d/font_manager.cpp
index 2cf3f7b..9b37d27 100644
--- a/engines/cryomni3d/font_manager.cpp
+++ b/engines/cryomni3d/font_manager.cpp
@@ -61,9 +61,9 @@ void FontManager::loadFont(Common::ReadStream &font_fl) {
 	}
 
 	// 3 unknown uint16
-	font_fl.readUint16BE();
-	font_fl.readUint16BE();
-	font_fl.readUint16BE();
+	(void) font_fl.readUint16BE();
+	(void) font_fl.readUint16BE();
+	(void) font_fl.readUint16BE();
 
 	Font *font = new Font();
 
diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
index 23f8c43..36cd439 100644
--- a/engines/cryomni3d/sprites.cpp
+++ b/engines/cryomni3d/sprites.cpp
@@ -65,8 +65,8 @@ void Sprites::loadSprites(Common::ReadStream &spr_fl) {
 		}
 
 		// 2 unknown uint32
-		spr_fl.readUint32BE();
-		spr_fl.readUint32BE();
+		(void) spr_fl.readUint32BE();
+		(void) spr_fl.readUint32BE();
 
 		CryoCursor *cursor = new CryoCursor();
 
diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp
index a6620a3..afade64 100644
--- a/engines/cryomni3d/versailles/saveload.cpp
+++ b/engines/cryomni3d/versailles/saveload.cpp
@@ -235,9 +235,9 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
 	in->read(saveNameC, sizeof(saveNameC));
 
 	// dummy values
-	in->readUint32LE();
-	in->readUint32BE();
-	in->readUint32BE();
+	(void) in->readUint32LE();
+	(void) in->readUint32BE();
+	(void) in->readUint32BE();
 
 	// Dialog variables
 	assert(_dialogsMan.size() < 200);
@@ -245,7 +245,8 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
 		_dialogsMan[i] = in->readByte();
 	}
 	for (uint i = _dialogsMan.size(); i < 200; i++) {
-		in->readByte();
+		// Read the remaining bytes but don't use them
+		(void) in->readByte();
 	}
 
 	// Inventory
@@ -287,7 +288,8 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
 		*it = in->readUint32BE();
 	}
 	for (uint i = _gameVariables.size(); i < 100; i++) {
-		in->readUint32BE();
+		// Read the remaining variables but don't use them
+		(void) in->readUint32BE();
 	}
 
 	delete in;
diff --git a/engines/cryomni3d/wam_parser.cpp b/engines/cryomni3d/wam_parser.cpp
index 75bbfb0..8119cda 100644
--- a/engines/cryomni3d/wam_parser.cpp
+++ b/engines/cryomni3d/wam_parser.cpp
@@ -32,10 +32,11 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 
 	_places.clear();
 
-	stream.readByte();
-	stream.readByte();
-	stream.read(str, 16);
-	stream.readUint32LE();
+	// 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);
@@ -62,14 +63,14 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 			_places.erase(oldPlace);
 		}
 		//debug("nPlaceId = %u", place.placeId);
-		stream.readUint32LE();
+		(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;
-			stream.readUint32LE();
+			(void) stream.readUint32LE();
 			uint nAnimations = stream.readByte();
 			for (uint k = 0; k < 8; k++) {
 				stream.read(str, 16);
@@ -78,9 +79,10 @@ void WAMParser::loadStream(Common::ReadStream &stream) {
 					nAnimations--;
 				}
 			}
-			stream.readUint32LE();
+			(void) stream.readUint32LE();
 			trans.dstId = stream.readUint32LE();
-			stream.readByte();
+			// Unused byte
+			(void) stream.readByte();
 			trans.srcAlpha = stream.readDoubleLE();
 			trans.srcBeta = stream.readDoubleLE();
 			trans.dstAlpha = stream.readDoubleLE();


Commit: e07844e06b56c3d299c5c7f88c5910dd0c882f3c
    https://github.com/scummvm/scummvm/commit/e07844e06b56c3d299c5c7f88c5910dd0c882f3c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix constants names

Changed paths:
    engines/cryomni3d/versailles/data.cpp
    engines/cryomni3d/versailles/logic.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index 61ed9e4..cbfe190 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -301,7 +301,7 @@ struct VideoSubSetting {
 	int16 drawBottom;
 };
 
-static const VideoSubSetting videoSubSettings[] = {
+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},
@@ -504,8 +504,8 @@ void CryOmni3DEngine_Versailles::setupDialogVariables() {
 	SET_DIAL_VARIABLE(136, "{CURRENT_GAME_TIME5}");
 	SET_DIAL_VARIABLE(137, "{JOUEUR_POSSEDE_EPIGRAPHE}");
 #undef SET_DIAL_VARIABLE
-	for (uint i = 0; i < ARRAYSIZE(videoSubSettings); i++) {
-		const VideoSubSetting &vss = videoSubSettings[i];
+	for (uint i = 0; i < ARRAYSIZE(kVideoSubSettings); i++) {
+		const VideoSubSetting &vss = kVideoSubSettings[i];
 		_dialogsMan.registerSubtitlesSettings(
 		    vss.videoName,
 		    DialogsManager::SubtitlesSettings(
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index 2f18f96..d39d531 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -33,7 +33,7 @@
 namespace CryOmni3D {
 namespace Versailles {
 
-static const char *imagesObjects[] = {
+static const char *kImagesObjects[] = {
 	"PAMP.gif",   //  0:  96
 	"PAPT_2.gif", //  1:  98
 	"PAML.gif",   //  2: 101
@@ -131,56 +131,56 @@ void CryOmni3DEngine_Versailles::setupObjects() {
 
 template<uint ID>
 void CryOmni3DEngine_Versailles::genericDisplayObject() {
-	displayObject(imagesObjects[ID]);
+	displayObject(kImagesObjects[ID]);
 }
 
 void CryOmni3DEngine_Versailles::obj_105() {
-	displayObject(imagesObjects[3]);
-	displayObject(imagesObjects[4]);
-	displayObject(imagesObjects[5]);
-	displayObject(imagesObjects[6]);
+	displayObject(kImagesObjects[3]);
+	displayObject(kImagesObjects[4]);
+	displayObject(kImagesObjects[5]);
+	displayObject(kImagesObjects[6]);
 }
 
 void CryOmni3DEngine_Versailles::obj_106() {
-	displayObject(imagesObjects[6]);
-	displayObject(imagesObjects[3]);
-	displayObject(imagesObjects[4]);
+	displayObject(kImagesObjects[6]);
+	displayObject(kImagesObjects[3]);
+	displayObject(kImagesObjects[4]);
 }
 
 void CryOmni3DEngine_Versailles::obj_107() {
 	if (_gameVariables[GameVariables::kSketchState] == 3) {
-		displayObject(imagesObjects[7]);
+		displayObject(kImagesObjects[7]);
 	} else {
-		displayObject(imagesObjects[6]);
+		displayObject(kImagesObjects[6]);
 	}
 }
 
 void CryOmni3DEngine_Versailles::obj_118() {
 	if (_gameVariables[GameVariables::kDecipherScore]) {
-		displayObject(imagesObjects[11]);
+		displayObject(kImagesObjects[11]);
 	} else {
-		displayObject(imagesObjects[10]);
+		displayObject(kImagesObjects[10]);
 	}
 }
 
 void CryOmni3DEngine_Versailles::obj_121() {
 	if (_gameVariables[GameVariables::kGotMedalsSolution]) {
-		displayObject(imagesObjects[13]);
+		displayObject(kImagesObjects[13]);
 	} else {
-		displayObject(imagesObjects[12]);
+		displayObject(kImagesObjects[12]);
 	}
 }
 
 void CryOmni3DEngine_Versailles::obj_125() {
 	if (_gameVariables[GameVariables::kStateLampoonReligion]) {
-		displayObject(imagesObjects[15]);
+		displayObject(kImagesObjects[15]);
 	} else {
-		displayObject(imagesObjects[14]);
+		displayObject(kImagesObjects[14]);
 	}
 }
 
 void CryOmni3DEngine_Versailles::obj_126() {
-	displayObject(imagesObjects[16], &CryOmni3DEngine_Versailles::obj_126hk);
+	displayObject(kImagesObjects[16], &CryOmni3DEngine_Versailles::obj_126hk);
 }
 
 void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) {
@@ -197,9 +197,9 @@ void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) {
 void CryOmni3DEngine_Versailles::obj_142() {
 	// Display a marker only when in maze
 	if (_currentLevel == 6 && _currentPlaceId >= 14 && _currentPlaceId <= 44) {
-		displayObject(imagesObjects[26], &CryOmni3DEngine_Versailles::obj_142hk);
+		displayObject(kImagesObjects[26], &CryOmni3DEngine_Versailles::obj_142hk);
 	} else {
-		displayObject(imagesObjects[26]);
+		displayObject(kImagesObjects[26]);
 	}
 }
 
@@ -260,7 +260,7 @@ void CryOmni3DEngine_Versailles::obj_142hk(Graphics::ManagedSurface &surface) {
 }
 
 // This array contains images for all paintings it must be kept in sync with _paintingsTitles
-static const char *imagesPaintings[] = {
+static const char *kImagesPaintings[] = {
 	"10E_1.GIF",      //  0: 41201
 	nullptr,          //  1: 41202
 	"10E_3.GIF",      //  2: 41203
@@ -426,7 +426,7 @@ void CryOmni3DEngine_Versailles::setupImgScripts() {
 // Generic handler for dumb fixed images
 template<uint ID>
 void CryOmni3DEngine_Versailles::genericDumbImage(ZonFixedImage *fimg) {
-	fimg->load(imagesPaintings[ID]);
+	fimg->load(kImagesPaintings[ID]);
 	while (1) {
 		fimg->manage();
 		if (fimg->_exit || fimg->_zoneLow) {
@@ -448,7 +448,7 @@ void CryOmni3DEngine_Versailles::genericDumbImage(ZonFixedImage *fimg) {
 // Generic handler for paintings fixed images
 template<uint ID>
 void CryOmni3DEngine_Versailles::genericPainting(ZonFixedImage *fimg) {
-	fimg->load(imagesPaintings[ID]);
+	fimg->load(kImagesPaintings[ID]);
 	while (1) {
 		fimg->manage();
 		if (fimg->_exit || fimg->_zoneLow) {


Commit: f25102ac76ffe7f5f2196f5fa260cfb9eb26e2c2
    https://github.com/scummvm/scummvm/commit/f25102ac76ffe7f5f2196f5fa260cfb9eb26e2c2
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Put delayMillis out of pollEvents

This let's improve reaction times

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/fixed_image.cpp
    engines/cryomni3d/versailles/dialogs_manager.cpp
    engines/cryomni3d/versailles/documentation.cpp
    engines/cryomni3d/versailles/engine.cpp
    engines/cryomni3d/versailles/logic.cpp
    engines/cryomni3d/versailles/menus.cpp
    engines/cryomni3d/versailles/music.cpp
    engines/cryomni3d/versailles/toolbar.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index f1ac389..193d105 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -159,6 +159,7 @@ void CryOmni3DEngine::playHNM(const Common::String &filename, Audio::Mixer::Soun
 			}
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (pollEvents() && checkKeysPressed()) {
 			skipVideo = true;
@@ -214,6 +215,7 @@ void CryOmni3DEngine::displayHLZ(const Common::String &filename) {
 			}
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 	}
 
 	delete imageDecoder;
@@ -242,7 +244,6 @@ bool CryOmni3DEngine::pollEvents() {
 		}
 		hasEvents = true;
 	}
-	g_system->delayMillis(10);
 
 	_dragStatus = kDragStatus_NoDrag;
 	uint currentMouseButton = getCurrentMouseButton();
@@ -294,6 +295,8 @@ uint CryOmni3DEngine::getCurrentMouseButton() {
 void CryOmni3DEngine::waitMouseRelease() {
 	while (g_system->getEventManager()->getButtonState() != 0 && !g_engine->shouldQuit()) {
 		pollEvents();
+		g_system->updateScreen();
+		g_system->delayMillis(10);
 	}
 }
 
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp
index b3ea5f3..f00b309 100644
--- a/engines/cryomni3d/fixed_image.cpp
+++ b/engines/cryomni3d/fixed_image.cpp
@@ -191,6 +191,7 @@ void ZonFixedImage::manage() {
 	// Force poll events even when we must refresh the cursor
 	if (!_engine.pollEvents() && !_refreshCursor) {
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 		return;
 	}
 	_refreshCursor = false;
@@ -266,6 +267,7 @@ void ZonFixedImage::manage() {
 	}
 
 	g_system->updateScreen();
+	g_system->delayMillis(10);
 }
 
 void ZonFixedImage::handleMouseZones(const Common::Array<Zone>::const_iterator &currentZone) {
diff --git a/engines/cryomni3d/versailles/dialogs_manager.cpp b/engines/cryomni3d/versailles/dialogs_manager.cpp
index 27bcbb6..2b9d38e 100644
--- a/engines/cryomni3d/versailles/dialogs_manager.cpp
+++ b/engines/cryomni3d/versailles/dialogs_manager.cpp
@@ -55,6 +55,7 @@ bool Versailles_DialogsManager::play(const Common::String &sequence) {
 			uint end = g_system->getMillis() + 2000;
 			while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skip) {
 				g_system->updateScreen();
+				g_system->delayMillis(10);
 				if (_engine->pollEvents() &&
 				        (_engine->checkKeysPressed(1, Common::KEYCODE_SPACE) ||
 				         _engine->getCurrentMouseButton() == 1)) {
@@ -189,6 +190,8 @@ void Versailles_DialogsManager::playDialog(const Common::String &video, const Co
 		bool skipWait = false;
 		uint end = g_system->getMillis() + duration;
 		while (!g_engine->shouldQuit() && g_system->getMillis() < end && !skipWait) {
+			g_system->updateScreen();
+			g_system->delayMillis(10);
 			if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
 				skipWait = true;
 			}
@@ -224,6 +227,7 @@ void Versailles_DialogsManager::playDialog(const Common::String &video, const Co
 				}
 			}
 			g_system->updateScreen();
+			g_system->delayMillis(10);
 		}
 		_engine->_mixer->stopHandle(audioHandle);
 	}
@@ -303,6 +307,7 @@ uint Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
 			                           _lastImage.h);
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			_engine->clearKeys();
diff --git a/engines/cryomni3d/versailles/documentation.cpp b/engines/cryomni3d/versailles/documentation.cpp
index 38328f2..b830b0c 100644
--- a/engines/cryomni3d/versailles/documentation.cpp
+++ b/engines/cryomni3d/versailles/documentation.cpp
@@ -367,6 +367,7 @@ Common::String Versailles_Documentation::docAreaHandleSummary() {
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			if (!_engine->getCurrentMouseButton()) {
@@ -476,6 +477,7 @@ Common::String Versailles_Documentation::docAreaHandleTimeline() {
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			Common::Point mouse = _engine->getMousePos();
@@ -704,6 +706,7 @@ uint Versailles_Documentation::docAreaHandleRecord(Graphics::ManagedSurface &sur
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents() || first) {
 			first = false;
@@ -997,6 +1000,7 @@ Common::String Versailles_Documentation::docAreaHandleGeneralMap() {
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			Common::Point mouse = _engine->getMousePos();
@@ -1233,6 +1237,7 @@ Common::String Versailles_Documentation::docAreaHandleCastleMap() {
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			Common::Point mouse = _engine->getMousePos();
@@ -1343,6 +1348,7 @@ uint Versailles_Documentation::inGameHandleRecord(Graphics::ManagedSurface &surf
 
 	while (action == -1u) {
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			if (g_engine->shouldQuit()) {
@@ -1717,6 +1723,7 @@ uint Versailles_Documentation::handlePopupMenu(const Graphics::ManagedSurface
 			redraw = false;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (_engine->pollEvents()) {
 			if (g_engine->shouldQuit()) {
diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index d03bd95..7ec18a7 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -1190,6 +1190,9 @@ int CryOmni3DEngine_Versailles::handleWarp() {
 				g_system->updateScreen();
 			}
 		}
+
+		// Slow down loop but after updating screen
+		g_system->delayMillis(10);
 	}
 	g_system->showMouse(false);
 	return actionId;
@@ -1346,6 +1349,9 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit
 		drawCountdown();
 		g_system->updateScreen();
 
+		// Slow down transition
+		g_system->delayMillis(10);
+
 		if (fabs(oldDeltaAlpha - deltaAlpha) < 0.001 && fabs(oldDeltaBeta - deltaBeta) < 0.001) {
 			exit = true;
 		}
@@ -1373,6 +1379,9 @@ void CryOmni3DEngine_Versailles::redrawWarp() {
 
 void CryOmni3DEngine_Versailles::warpMsgBoxCB() {
 	pollEvents();
+
+	g_system->updateScreen();
+	g_system->delayMillis(10);
 }
 
 void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
@@ -1385,17 +1394,17 @@ void CryOmni3DEngine_Versailles::animateCursor(const Object *obj) {
 	for (uint i = 4; i > 0; i--) {
 		// Wait 100ms
 		for (uint j = 10; j > 0; j--) {
-			// pollEvents sleeps 10ms
 			pollEvents();
 			g_system->updateScreen();
+			g_system->delayMillis(10);
 		}
 		setCursor(obj->idSA());
 		g_system->updateScreen();
 		// Wait 100ms
 		for (uint j = 10; j > 0; j--) {
-			// pollEvents sleeps 10ms
 			pollEvents();
 			g_system->updateScreen();
+			g_system->delayMillis(10);
 		}
 		setCursor(obj->idSl());
 		g_system->updateScreen();
@@ -1463,6 +1472,7 @@ void CryOmni3DEngine_Versailles::displayObject(const Common::String &imgName,
 			}
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 	}
 	waitMouseRelease();
 	clearKeys();
diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp
index d39d531..02592ee 100644
--- a/engines/cryomni3d/versailles/logic.cpp
+++ b/engines/cryomni3d/versailles/logic.cpp
@@ -3165,6 +3165,7 @@ FILTER_EVENT(1, 3) {
 	if (*event == 11301) {
 		while (!g_engine->shouldQuit() && _mixer->isSoundIDActive(SoundIds::kLeb001)) {
 			g_system->updateScreen();
+			g_system->delayMillis(10);
 			pollEvents();
 		}
 		clearKeys();
diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp
index dd95540..031739d 100644
--- a/engines/cryomni3d/versailles/menus.cpp
+++ b/engines/cryomni3d/versailles/menus.cpp
@@ -214,6 +214,7 @@ uint CryOmni3DEngine_Versailles::displayOptions() {
 			drawState = 0;
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (pollEvents() || forceEvents) { // always call pollEvents
 			forceEvents = false;
@@ -520,6 +521,7 @@ uint CryOmni3DEngine_Versailles::displayYesNoBox(Graphics::ManagedSurface &surfa
 			g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, surface.w, surface.h);
 		}
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 
 		if (pollEvents()) {
 			Common::Point mouse = getMousePos();
@@ -662,6 +664,8 @@ uint CryOmni3DEngine_Versailles::displayFilePicker(const Graphics::Surface *bgFr
 		}
 
 		g_system->updateScreen();
+		g_system->delayMillis(10);
+
 		pollEvents();
 		Common::KeyState key = getNextKey();
 		uint mousePressed = getCurrentMouseButton();
@@ -895,8 +899,6 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters &param
 	uint disappearTime = g_system->getMillis() + msg.size() * params.timeoutChar * 10;
 	bool finished = false;
 	while (!finished) {
-		g_system->updateScreen();
-
 		callback();
 
 		if (g_system->getMillis() > disappearTime) {
@@ -991,6 +993,8 @@ void CryOmni3DEngine_Versailles::displayCredits() {
 					uint endScreenTime = g_system->getMillis() + 6000;
 					while (g_system->getMillis() < endScreenTime && !skipScreen) {
 						g_system->updateScreen();
+						g_system->delayMillis(10);
+
 						if (pollEvents()) {
 							if (getCurrentMouseButton() == 1) {
 								skipScreen = true;
diff --git a/engines/cryomni3d/versailles/music.cpp b/engines/cryomni3d/versailles/music.cpp
index 2fa60be..22d1dd8 100644
--- a/engines/cryomni3d/versailles/music.cpp
+++ b/engines/cryomni3d/versailles/music.cpp
@@ -26,6 +26,7 @@
 #include "common/config-manager.h"
 #include "common/error.h"
 #include "common/file.h"
+#include "common/system.h"
 
 #include "cryomni3d/versailles/engine.h"
 
@@ -110,13 +111,13 @@ void CryOmni3DEngine_Versailles::musicStop() {
 		int realVolume = (musicVol * channelVol) / Audio::Mixer::kMaxChannelVolume;
 		bool skip = false;
 		while (realVolume > 0 && !skip) {
-			// pollEvents waits for 10ms
 			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);
diff --git a/engines/cryomni3d/versailles/toolbar.cpp b/engines/cryomni3d/versailles/toolbar.cpp
index f6884bd..23b94b8 100644
--- a/engines/cryomni3d/versailles/toolbar.cpp
+++ b/engines/cryomni3d/versailles/toolbar.cpp
@@ -423,7 +423,10 @@ bool Toolbar::displayToolbar(const Graphics::Surface *original) {
 		g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
 		                           original->h - _destSurface.h, _destSurface.w, _destSurface.h);
 		g_system->updateScreen();
-		// pollEvents will slow down the animation because it waits 10ms
+
+		// Slow down animation
+		g_system->delayMillis(10);
+
 		_engine->pollEvents();
 		if (g_engine->shouldQuit()) {
 			return false;
@@ -449,7 +452,10 @@ bool Toolbar::displayToolbar(const Graphics::Surface *original) {
 		g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
 		                           original->h - _destSurface.h, _destSurface.w, _destSurface.h);
 		g_system->updateScreen();
-		// pollEvents will slow down the animation because it waits 10ms
+
+		// Slow down animation
+		g_system->delayMillis(10);
+
 		_engine->pollEvents();
 		if (g_engine->shouldQuit()) {
 			return false;
@@ -584,6 +590,7 @@ void Toolbar::handleToolbarEvents(const Graphics::Surface *original) {
 		}
 
 		g_system->updateScreen();
+		g_system->delayMillis(10);
 	}
 
 	// Hide description when finished and selected object


Commit: b72fdaf8a2f97a04ecb14c693d9a994f169a9b0f
    https://github.com/scummvm/scummvm/commit/b72fdaf8a2f97a04ecb14c693d9a994f169a9b0f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix search path of files

Without that, when images are reused from one level to another, they are
not found. For example in level 2 when displaying images in The Bassano
Antechamber.

Changed paths:
    engines/cryomni3d/versailles/engine.cpp


diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp
index 7ec18a7..6417a9b 100644
--- a/engines/cryomni3d/versailles/engine.cpp
+++ b/engines/cryomni3d/versailles/engine.cpp
@@ -86,6 +86,35 @@ Common::Error CryOmni3DEngine_Versailles::run() {
 	SearchMan.addSubDirectoryMatching(gameDataDir, "music", 1);
 	SearchMan.addSubDirectoryMatching(gameDataDir, "sound", 1);
 
+	// Sometimes files are taken from other levels
+	// Original game has a logic based on the first character of the file name.
+	// We can't do this here so we put in lower priority all the levels as a fallback
+
+	// Create a first SearchSet in which we will add all others to group everything
+	Common::SearchSet *fallbackFiles = new Common::SearchSet();
+
+	for (uint lvl = 1; lvl <= 7; lvl++) {
+		Common::SearchSet *fallbackFilesAnimacti = new Common::SearchSet();
+		Common::SearchSet *fallbackFilesWarp = new Common::SearchSet();
+		Common::SearchSet *fallbackFilesImgFix = new Common::SearchSet();
+
+		fallbackFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "animacti/level%d", lvl), 2);
+		fallbackFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "warp/level%d/cyclo", lvl), 2);
+		fallbackFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "warp/level%d/hnm", lvl), 2);
+		fallbackFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
+		            "img_fix/level%d", lvl), 2);
+
+		fallbackFiles->add(Common::String::format("__fallbackFiles_animacti_%d", lvl),
+		                   fallbackFilesAnimacti);
+		fallbackFiles->add(Common::String::format("__fallbackFiles_warp_%d", lvl), fallbackFilesWarp);
+		fallbackFiles->add(Common::String::format("__fallbackFiles_img_fix_%d", lvl), fallbackFilesImgFix);
+	}
+
+	SearchMan.add("__fallbackFiles", fallbackFiles);
+
 	setupMessages();
 
 	_dialogsMan.init(138, _messages[22]);
@@ -637,15 +666,15 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 	// SearchMan can't add several times the same basename
 	// We create several SearchSet with different names that we add to SearchMan instead
 
-	// Visiting uses all levels
-	SearchMan.remove("__visitFiles");
-
 	SearchMan.remove("__levelFiles_animacti");
 	SearchMan.remove("__levelFiles_warp");
 	SearchMan.remove("__levelFiles_img_fix");
 
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
 	if (level >= 1 && level <= 7) {
+		// Add current level directories to the search set to be looked up first
+		// If a file is not found in the current level, find it with the fallback
+
 		Common::SearchSet *levelFilesAnimacti = new Common::SearchSet();
 		Common::SearchSet *levelFilesWarp = new Common::SearchSet();
 		Common::SearchSet *levelFilesImgFix = new Common::SearchSet();
@@ -663,30 +692,7 @@ void CryOmni3DEngine_Versailles::initNewLevel(int level) {
 		SearchMan.add("__levelFiles_warp", levelFilesWarp);
 		SearchMan.add("__levelFiles_img_fix", levelFilesImgFix);
 	} else if (level == 8 && _isVisiting) {
-		// In visit mode, we take files from all levels, happily they have unique names
-		// Create a first SearchSet in which we will add all others to easily cleanup the mess
-		Common::SearchSet *visitFiles = new Common::SearchSet();
-
-		for (uint lvl = 1; lvl <= 7; lvl++) {
-			Common::SearchSet *visitFilesAnimacti = new Common::SearchSet();
-			Common::SearchSet *visitFilesWarp = new Common::SearchSet();
-			Common::SearchSet *visitFilesImgFix = new Common::SearchSet();
-
-			visitFilesAnimacti->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			            "animacti/level%d", lvl), 1);
-			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			        "warp/level%d/cyclo", lvl), 1);
-			visitFilesWarp->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			        "warp/level%d/hnm", lvl), 1);
-			visitFilesImgFix->addSubDirectoryMatching(gameDataDir, Common::String::format(
-			            "img_fix/level%d", lvl), 1);
-
-			visitFiles->add(Common::String::format("__visitFiles_animacti_%d", lvl), visitFilesAnimacti);
-			visitFiles->add(Common::String::format("__visitFiles_warp_%d", lvl), visitFilesWarp);
-			visitFiles->add(Common::String::format("__visitFiles_img_fix_%d", lvl), visitFilesImgFix);
-		}
-
-		SearchMan.add("__visitFiles", visitFiles);
+		// In visit mode, we take files from all levels so we use the fallback mechanism
 	} else {
 		error("Invalid level %d", level);
 	}


Commit: e707e312da9979664c9a853457269c39e04e0aca
    https://github.com/scummvm/scummvm/commit/e707e312da9979664c9a853457269c39e04e0aca
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Handle cursor moves during fading

Changed paths:
    engines/cryomni3d/cryomni3d.cpp


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 193d105..9cabf54 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -388,11 +388,15 @@ void CryOmni3DEngine::fadeOutPalette() {
 		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) {
@@ -415,12 +419,15 @@ void CryOmni3DEngine::fadeInPalette(const byte *palette) {
 		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() {


Commit: 475f9ea293331537c84cbc4d6f57647ba1820378
    https://github.com/scummvm/scummvm/commit/475f9ea293331537c84cbc4d6f57647ba1820378
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix missed clicks when occuring beteen two pollEvent

Changed paths:
    engines/cryomni3d/cryomni3d.cpp
    engines/cryomni3d/cryomni3d.h


diff --git a/engines/cryomni3d/cryomni3d.cpp b/engines/cryomni3d/cryomni3d.cpp
index 9cabf54..b7d3a9d 100644
--- a/engines/cryomni3d/cryomni3d.cpp
+++ b/engines/cryomni3d/cryomni3d.cpp
@@ -234,17 +234,44 @@ void CryOmni3DEngine::setCursor(uint cursorId) const {
 
 bool CryOmni3DEngine::pollEvents() {
 	Common::Event event;
+	int buttonMask;
 	bool hasEvents = false;
 
-	uint oldMouseButton = getCurrentMouseButton();
+	// 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) {
@@ -281,19 +308,8 @@ void CryOmni3DEngine::setAutoRepeatClick(uint millis) {
 	_autoRepeatNextEvent = g_system->getMillis() + millis;
 }
 
-uint CryOmni3DEngine::getCurrentMouseButton() {
-	int mask = g_system->getEventManager()->getButtonState();
-	if (mask & 0x1) {
-		return 1;
-	} else if (mask & 0x2) {
-		return 2;
-	} else {
-		return 0;
-	}
-}
-
 void CryOmni3DEngine::waitMouseRelease() {
-	while (g_system->getEventManager()->getButtonState() != 0 && !g_engine->shouldQuit()) {
+	while (getCurrentMouseButton() != 0 && !g_engine->shouldQuit()) {
 		pollEvents();
 		g_system->updateScreen();
 		g_system->delayMillis(10);
diff --git a/engines/cryomni3d/cryomni3d.h b/engines/cryomni3d/cryomni3d.h
index 6d6faff..003d508 100644
--- a/engines/cryomni3d/cryomni3d.h
+++ b/engines/cryomni3d/cryomni3d.h
@@ -117,7 +117,7 @@ public:
 	bool pollEvents();
 	Common::Point getMousePos();
 	void setMousePos(const Common::Point &point);
-	uint getCurrentMouseButton();
+	uint getCurrentMouseButton() { return _lastMouseButton; }
 	Common::KeyState getNextKey();
 	bool checkKeysPressed();
 	bool checkKeysPressed(uint numKeys, ...);
@@ -161,6 +161,7 @@ protected:
 
 	DragStatus _dragStatus;
 	Common::Point _dragStart;
+	uint _lastMouseButton;
 	uint _autoRepeatNextEvent;
 
 private:


Commit: 3e61864ad8f007c36c3e568361a422baf2666a9c
    https://github.com/scummvm/scummvm/commit/3e61864ad8f007c36c3e568361a422baf2666a9c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2019-06-01T22:43:48+02:00

Commit Message:
CRYOMNI3D: Fix places documentation

Changed paths:
    engines/cryomni3d/versailles/data.cpp


diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp
index cbfe190..af3dae4 100644
--- a/engines/cryomni3d/versailles/data.cpp
+++ b/engines/cryomni3d/versailles/data.cpp
@@ -534,7 +534,8 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		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);
+		// 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");
@@ -549,7 +550,8 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(5, nullptr, FILTER_EVENT(2, 5), nullptr);
 		SET_PLACE_STATE(6, nullptr, nullptr, "VS19");
 		SET_PLACE_STATE(7, nullptr, nullptr, nullptr);
-		SET_PLACE_STATE(8, 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");
@@ -715,7 +717,8 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		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);
+		// 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");
@@ -748,7 +751,8 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		SET_PLACE_STATE(36, nullptr, nullptr, "VS23");
 		SET_PLACE_STATE(37, nullptr, nullptr, "VS22");
 		SET_PLACE_STATE(38, nullptr, nullptr, "VS20");
-		SET_PLACE_STATE(39, nullptr, nullptr, nullptr);
+		// 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");
@@ -758,7 +762,7 @@ void CryOmni3DEngine_Versailles::initPlacesStates() {
 		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, "VS19");
+		SET_PLACE_STATE(49, nullptr, nullptr, nullptr);
 	}
 #undef INIT_PLACE
 #undef FILTER_EVENT





More information about the Scummvm-git-logs mailing list