[Scummvm-git-logs] scummvm master -> c0eaf1227d983af02bd8acac18101711b0ca7e7b

mduggan noreply at scummvm.org
Fri Apr 7 12:54:28 UTC 2023


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

Summary:
c4fc5f9922 TETRAEDGE: Slight cleanups for Game and Application class interfaces
443a14f80e TETRAEDGE: Fixes to get Amerzone as far as main menu.
ba318b8283 TETRAEDGE: Refactor game class to split out Syberia-specific parts
9baaeee37f TETRAEDGE: Starting to add classes needed for Amerzone
0b90939b9f TETRAEDGE: Fix crash in Syberia 1
c0eaf1227d TETRAEDGE: Add more implementation for Amerzone support


Commit: c4fc5f99222290a4ef3b6b3cd2a49567ebc16bb4
    https://github.com/scummvm/scummvm/commit/c4fc5f99222290a4ef3b6b3cd2a49567ebc16bb4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Slight cleanups for Game and Application class interfaces

Changed paths:
    engines/tetraedge/game/application.h
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/lua_binds.cpp


diff --git a/engines/tetraedge/game/application.h b/engines/tetraedge/game/application.h
index 2fcb104ff18..3446496a8b3 100644
--- a/engines/tetraedge/game/application.h
+++ b/engines/tetraedge/game/application.h
@@ -63,18 +63,13 @@ public:
 	void showLoadingIcon(bool show);
 	void saveCorrupted(const Common::String &fname);
 
-	void drawBack();
-	void drawFront();
 	void performRender();
-	//void preloadTextrue(); does nothing..
+	//void preloadTextrue(); does nothing
 
 	void fade();
 	void blackFade();
 	void captureFade();
 	bool isFading();
-	bool onBlackFadeAnimationFinished();
-	bool onMainWindowSizeChanged();
-	bool onMousePositionChanged(const Common::Point &p);
 
 	bool isLockCursor();
 	bool isLockPad();
@@ -88,8 +83,6 @@ public:
 
 	Common::String getHelpText(const Common::String &key);
 
-	const char *inAppUnlockFullVersionID();
-
 	BonusMenu &bonusMenu() { return _bonusMenu; }
 	GlobalBonusMenu &globalBonusMenu() { return _globalBonusMenu; }
 	MainMenu &mainMenu() { return _mainMenu; }
@@ -120,6 +113,15 @@ public:
 	bool ratioStretched() const { return _ratioStretched; }
 
 private:
+	void drawBack();
+	void drawFront();
+
+	const char *inAppUnlockFullVersionID();
+
+	bool onBlackFadeAnimationFinished();
+	bool onMainWindowSizeChanged();
+	bool onMousePositionChanged(const Common::Point &p);
+
 	bool _finishedGame;
 	bool _finishedFremium;
 
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 79a98247426..eb3e22ad9b9 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -52,8 +52,8 @@ _sceneCharacterVisibleFromLoad(false), _isCharacterWalking(false),
 _lastCharMoveMousePos(0.0f, 0.0f), _randomSoundFinished(false),
 _previousMousePos(-1, -1), _markersVisible(true), _saveRequested(false),
 _gameLoadState(0), _luaShowOwnerError(false), _score(0), _warped(false),
-_firstInventory(true), _randomSource("SyberiaGameRandom"), _frameCounter(0),
-_warpFadeFlag(false), _dialogsTold(0), _runModeEnabled(true) {
+_firstInventory(true), _frameCounter(0), _warpFadeFlag(false),
+_dialogsTold(0), _runModeEnabled(true) {
 	for (int i = 0; i < NUM_OBJECTS_TAKEN_IDS; i++) {
 		_objectsTakenBits[i] = false;
 	}
@@ -1375,11 +1375,13 @@ bool Game::onVideoFinished() {
 	return false;
 }
 
+/* Unused
 void Game::pauseMovie() {
 	_music.pause();
 	TeSpriteLayout *sprite = _inGameGui.spriteLayoutChecked("video");
 	sprite->pause();
 }
+*/
 
 bool Game::playMovie(const Common::String &vidPath, const Common::String &musicPath, float volume /* = 1.0f */) {
 	Application *app = g_engine->getApplication();
@@ -1438,7 +1440,7 @@ void Game::playRandomSound(const Common::String &name) {
 
 	if (!_randomSoundFinished) {
 		_randomSoundTimer.start();
-		int r = _randomSource.getRandomNumber(RAND_MAX);
+		int r = g_engine->getRandomNumber(RAND_MAX);
 		float f = (r + 1 + (r / 100) * -100);
 		uint64 time = 1000000;
 		if (f >= 25.0) {
@@ -1454,7 +1456,7 @@ void Game::playRandomSound(const Common::String &name) {
 		for (auto *snd : sndlist) {
 			total += snd->_f1;
 		}
-		int r = _randomSource.getRandomNumber(RAND_MAX);
+		int r = g_engine->getRandomNumber(RAND_MAX);
 		float total2 = 0.0;
 		uint i = 0;
 		while (i < sndlist.size() && total2 <= r * 4.656613e-10 * total) {
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index bc2c50857a5..d91d2cb684a 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -83,23 +83,15 @@ public:
 
 	//enum EGameScoreID {}; // Not needed?
 
-	bool addAnimToSet(const Common::String &path);
 	void addArtworkUnlocked(const Common::String &name, bool notify);
 	void addNoScale2Child(TeLayout *layout);
-	void addNoScale2Children();
-	void addNoScaleChildren();
 	void addRandomSound(const Common::String &s1, const Common::String &s2, float f1, float f2);
 	void addToBag(const Common::String &objname);
 	void addToHand(const Common::String &objname);
 	void addToScore(int score);
-	void attachButtonsLayoutGoto() {}; // does nothing?
-	void createButtonsLayoutGoto() {}; // does nothing?
-	void deleteButtonsLayoutGoto() {}; // does nothing?
 
 	bool changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
-	bool changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag);
 
-	void deleteNoScale();
 	void draw();
 	void enter(); // will load game if _loadName is set.
 	// Note: game uses ILayouts here..
@@ -109,9 +101,6 @@ public:
 	void finishFreemium();
 	void finishGame();
 	void initLoadedBackupData();
-	void initNoScale();
-	void initScene(bool param_1, const Common::String &scenePath);
-	bool initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
 	bool isDocumentOpened();
 	bool isMouse() { return false; }
 	bool isMoviePlaying();
@@ -119,39 +108,18 @@ public:
 					  const Common::String &param_4, float param_5);
 	void leave(bool flag);
 	void loadBackup(const Common::String &path);
-	bool loadCharacter(const Common::String &name);
 	bool loadPlayerCharacter(const Common::String &name);
 	bool loadScene(const Common::String &name);
 
 	// Not in original. Load unlocked artwork from ScummVM config.
 	void loadUnlockedArtwork();
 
-	bool onAnswered(const Common::String &val);
-	bool onCallNumber(Common::String val);
-	bool onCharacterAnimationFinished(const Common::String &val);
-	bool onCharacterAnimationPlayerFinished(const Common::String &val);
-	bool onDialogFinished(const Common::String &val);
-	bool onDisplacementFinished();
-	bool onDisplacementPlayerFinished();
-	bool onFinishedCheckBackup(bool result);
-	bool onFinishedLoadingBackup(const Common::String &val);
-	bool onFinishedSavingBackup(int something);
-	bool onInventoryButtonValidated();
-	bool onLockVideoButtonValidated();
-	bool onMarkersVisible(TeCheckboxLayout::State state);
-	bool onMouseClick(const Common::Point &pt);
-	bool onMouseMove();
-	bool onSkipVideoButtonValidated();
-	bool onVideoFinished();
-
-	void pauseMovie();
-	void pauseSounds() {}; // does nothing?
+	//void pauseMovie(); // Unused
+	//void pauseSounds() {}; // Unused, does nothing?
 	bool playMovie(const Common::String &vidPath, const Common::String &musicPath, float volume = 1.0f);
 	void playRandomSound(const Common::String &name);
 	void playSound(const Common::String &name, int param_2, float volume);
 	void removeNoScale2Child(TeLayout *layout);
-	void removeNoScale2Children();
-	void removeNoScaleChildren();
 	void resetPreviousMousePos();
 	void resumeMovie();
 	void resumeSounds() {}; // does nothing?
@@ -160,7 +128,7 @@ public:
 	void setCurrentObjectSprite(const Common::String &spritePath);
 	bool showMarkers(bool val);
 	bool startAnimation(const Common::String &animName, int loopcount, bool reversed);
-	void startAnimationPart(const Common::String &param_1, int param_2, int param_3, int param_4, bool param_5) {};
+	// void startAnimationPart(const Common::String &param_1, int param_2, int param_3, int param_4, bool param_5) {}; // Unused.
 	void stopSound(const Common::String &name);
 	Common::Error syncGame(Common::Serializer &s); // Basically replaces saveBackup from original..
 	bool unloadCharacter(const Common::String &character);
@@ -200,7 +168,6 @@ public:
 	void setPosPlayer(const TeVector3f32 &pos) { _posPlayer = pos; }
 	TeTimer &walkTimer() { return _walkTimer; }
 	void setExitZone(const Common::String &zone) { _exitZone = zone; }
-	Common::RandomSource &randomSource() { return _randomSource; }
 	void setLoadName(const Common::String &loadName) { _loadName = loadName; }
 	bool hasLoadName() const { return !_loadName.empty(); }
 	bool isArtworkUnlocked(const Common::String &name) const;
@@ -210,6 +177,45 @@ public:
 	bool runModeEnabled() const { return _runModeEnabled; }
 
 private:
+	bool addAnimToSet(const Common::String &path);
+	void addNoScale2Children();
+	void addNoScaleChildren();
+
+	void attachButtonsLayoutGoto() {}; // does nothing?
+	void createButtonsLayoutGoto() {}; // does nothing?
+	void deleteButtonsLayoutGoto() {}; // does nothing?
+
+	bool changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag);
+
+	void deleteNoScale();
+
+	void initNoScale();
+	void initScene(bool param_1, const Common::String &scenePath);
+	bool initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
+
+	bool loadCharacter(const Common::String &name);
+
+	bool onAnswered(const Common::String &val);
+	bool onCallNumber(Common::String val);
+	bool onCharacterAnimationFinished(const Common::String &val);
+	bool onCharacterAnimationPlayerFinished(const Common::String &val);
+	bool onDialogFinished(const Common::String &val);
+	bool onDisplacementFinished();
+	bool onDisplacementPlayerFinished();
+	bool onFinishedCheckBackup(bool result);
+	bool onFinishedLoadingBackup(const Common::String &val);
+	bool onFinishedSavingBackup(int something);
+	bool onInventoryButtonValidated();
+	bool onLockVideoButtonValidated();
+	bool onMarkersVisible(TeCheckboxLayout::State state);
+	bool onMouseClick(const Common::Point &pt);
+	bool onMouseMove();
+	bool onSkipVideoButtonValidated();
+	bool onVideoFinished();
+
+	void removeNoScale2Children();
+	void removeNoScaleChildren();
+
 	bool _luaShowOwnerError;
 	bool _running;
 	bool _entered;
@@ -280,7 +286,6 @@ private:
 	bool _saveRequested;
 	bool _randomSoundFinished;
 
-	Common::RandomSource _randomSource;
 	RandomSound *_randomSound;
 	TeTimer _randomSoundTimer;
 
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index d4b129bd863..56c28ac9eff 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -1754,7 +1754,7 @@ static int tolua_ExportedFunctions_SetCharacterLookChar00(lua_State *L) {
 }
 
 static uint Random(uint max) {
-	return g_engine->getGame()->randomSource().getRandomNumber(max - 1);
+	return g_engine->getRandomNumber(max - 1);
 }
 
 static int tolua_ExportedFunctions_Random00(lua_State *L) {


Commit: 443a14f80e4e8a1665918d5cd419a0d0693e0fe8
    https://github.com/scummvm/scummvm/commit/443a14f80e4e8a1665918d5cd419a0d0693e0fe8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Fixes to get Amerzone as far as main menu.

Changed paths:
    engines/tetraedge/detection.cpp
    engines/tetraedge/detection_tables.h
    engines/tetraedge/game/application.cpp
    engines/tetraedge/game/application.h
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/inventory_menu.cpp
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/game/main_menu.cpp
    engines/tetraedge/te/te_core.cpp


diff --git a/engines/tetraedge/detection.cpp b/engines/tetraedge/detection.cpp
index e72aa1336b2..1e33c369493 100644
--- a/engines/tetraedge/detection.cpp
+++ b/engines/tetraedge/detection.cpp
@@ -54,14 +54,13 @@ DetectedGame TetraedgeMetaEngineDetection::toDetectedGame(const ADDetectedGame &
 	DetectedGame game = AdvancedMetaEngineDetection::toDetectedGame(adGame);
 
 	// The AdvancedDetector model only allows specifying a single supported
-	// game language. Both games support multiple languages
-	if (game.gameId == "syberia" || game.gameId == "syberia2") {
-		for (const Common::Language *language = getGameLanguages(); *language != Common::UNK_LANG; language++) {
-			// "ru" only present on syberia 1
-			if (game.gameId == "syberia2" && *language == Common::RU_RUS)
-				continue;
-			game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(*language));
-		}
+	// game language. All games support multiple languages.  Only Syberia 1
+	// supports RU.
+	for (const Common::Language *language = getGameLanguages(); *language != Common::UNK_LANG; language++) {
+		// "ru" only present on syberia 1
+		if (game.gameId != "syberia" && *language == Common::RU_RUS)
+			continue;
+		game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(*language));
 	}
 
 	return game;
diff --git a/engines/tetraedge/detection_tables.h b/engines/tetraedge/detection_tables.h
index e36394c1b69..0ff86557c3a 100644
--- a/engines/tetraedge/detection_tables.h
+++ b/engines/tetraedge/detection_tables.h
@@ -29,6 +29,17 @@ const PlainGameDescriptor GAME_NAMES[] = {
 };
 
 const ADGameDescription GAME_DESCRIPTIONS[] = {
+	// Amerzone GOG release
+	{
+		"amerzone",
+		nullptr,
+		AD_ENTRY1s("MacOS/Amerzone", "d:cde4144aeea5a99602ee903554585178", 6380272),
+		Common::UNK_LANG,
+		Common::kPlatformMacintosh,
+		ADGF_UNSTABLE,
+		GUIO0()
+	},
+
 	// GOG and Steam releases
 	// Note: Full sum of GOG and Steam are different,
 	// but size and first 5000 bytes are the same.
diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp
index 1f7a0a2515a..3da0e119a23 100644
--- a/engines/tetraedge/game/application.cpp
+++ b/engines/tetraedge/game/application.cpp
@@ -87,6 +87,11 @@ _drawShadows(true) {
 
 	// Note: original has an app run timer, but it's never used?
 
+	if (g_engine->gameType() == TetraedgeEngine::kAmerzone)
+		_defaultCursor = "2D/arrow6.png";
+	else
+		_defaultCursor = "pictures/cursor.png";
+
 	loadOptions("options.xml");
 }
 
@@ -168,21 +173,23 @@ void Application::create() {
 	_loc.load(textFileNode);
 	core->addLoc(&_loc);
 
-	const Common::Path helpMenuPath("menus/help/help_");
-	Common::Path helpMenuFilePath;
-	i = 0;
-	while (i < ARRAYSIZE(allLangs)) {
-		helpMenuFilePath = helpMenuPath.append(core->language() + ".xml");
-		if (Common::File::exists(helpMenuFilePath))
-			break;
-		core->language(allLangs[i]);
-		i++;
-	}
-	if (i == ARRAYSIZE(allLangs)) {
-		error("Couldn't find menus/help/help_[lang].xml for any language.");
-	}
+	if (g_engine->gameType() != TetraedgeEngine::kAmerzone) {
+		const Common::Path helpMenuPath("menus/help/help_");
+		Common::Path helpMenuFilePath;
+		i = 0;
+		while (i < ARRAYSIZE(allLangs)) {
+			helpMenuFilePath = helpMenuPath.append(core->language() + ".xml");
+			if (Common::File::exists(helpMenuFilePath))
+				break;
+			core->language(allLangs[i]);
+			i++;
+		}
+		if (i == ARRAYSIZE(allLangs)) {
+			error("Couldn't find menus/help/help_[lang].xml for any language.");
+		}
 
-	_helpGui.load(helpMenuFilePath);
+		_helpGui.load(helpMenuFilePath);
+	}
 
 	// TODO: set TeCore field 0x74 and 0x78 to true here? Do they do anything?");
 
@@ -229,7 +236,7 @@ void Application::create() {
 	g_system->showMouse(false);
 	//mainWindow->setNativeCursorVisible(false);
 
-	_mouseCursorLayout.load("pictures/cursor.png");
+	_mouseCursorLayout.load(_defaultCursor);
 	_mouseCursorLayout.setAnchor(TeVector3f32(0.3f, 0.1f, 0.0f));
 	_frontOrientationLayout.addChild(&_mouseCursorLayout);
 
diff --git a/engines/tetraedge/game/application.h b/engines/tetraedge/game/application.h
index 3446496a8b3..7a1bb59ff6a 100644
--- a/engines/tetraedge/game/application.h
+++ b/engines/tetraedge/game/application.h
@@ -106,6 +106,7 @@ public:
 	const Common::String &firstWarpPath() { return _firstWarpPath; }
 	const Common::String &firstZone() { return _firstZone; }
 	const Common::String &firstScene() { return _firstScene; }
+	const Common::String &defaultCursor() { return _defaultCursor; }
 	TeLayout &frontLayout() { return _frontLayout; };
 	TeLayout &frontOrientationLayout() { return _frontOrientationLayout; }
 	TeLayout &backLayout() { return _backLayout; }
@@ -146,6 +147,7 @@ private:
 	Common::String _firstWarpPath;
 	Common::String _firstZone;
 	Common::String _firstScene;
+	Common::String _defaultCursor;
 
 	Common::Array<Common::String> _unrecalAnims;
 
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index eb3e22ad9b9..0e1b50b8e38 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -1265,12 +1265,10 @@ bool Game::onMouseMove() {
 	if (!_entered)
 		return false;
 
-	const Common::String DEFAULT_CURSOR("pictures/cursor.png");
-
 	Application *app = g_engine->getApplication();
 
 	if (app->isLockCursor()) {
-		app->mouseCursorLayout().load(DEFAULT_CURSOR);
+		app->mouseCursorLayout().load(app->defaultCursor());
 		return false;
 	}
 
@@ -1292,7 +1290,7 @@ bool Game::onMouseMove() {
 	if (cellphone->isMouseIn(mouseLoc)) {
 		skipFullSearch = true;
 		if (!cellbg->visible() && _objectif.isMouseIn(mouseLoc)) {
-			app->mouseCursorLayout().load(DEFAULT_CURSOR);
+			app->mouseCursorLayout().load(app->defaultCursor());
 			return false;
 		}
 	}
diff --git a/engines/tetraedge/game/inventory_menu.cpp b/engines/tetraedge/game/inventory_menu.cpp
index 9dd250b5cc1..09d1b63a76c 100644
--- a/engines/tetraedge/game/inventory_menu.cpp
+++ b/engines/tetraedge/game/inventory_menu.cpp
@@ -31,7 +31,7 @@ InventoryMenu::InventoryMenu() {
 
 void InventoryMenu::enter() {
 	Application *app = g_engine->getApplication();
-	app->mouseCursorLayout().load("pictures/cursor.png");
+	app->mouseCursorLayout().load(app->defaultCursor());
 
 	_gui.layoutChecked("inventoryMenu")->setVisible(true);
 	onInventoryButton();
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index 56c28ac9eff..de23497c344 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -78,7 +78,7 @@ static int tolua_ExportedFunctions_LoadObjectMaterials01(lua_State *L) {
 
 static void PlayMovie(const Common::String &vidpath, const Common::String &musicpath) {
 	Application *app = g_engine->getApplication();
-	app->mouseCursorLayout().load("pictures/cursor.png");
+	app->mouseCursorLayout().load(app->defaultCursor());
 	Game *game = g_engine->getGame();
 	game->playMovie(vidpath, musicpath);
 }
diff --git a/engines/tetraedge/game/main_menu.cpp b/engines/tetraedge/game/main_menu.cpp
index 7f4ddf898ef..fa82bba68df 100644
--- a/engines/tetraedge/game/main_menu.cpp
+++ b/engines/tetraedge/game/main_menu.cpp
@@ -68,19 +68,27 @@ void MainMenu::enter() {
 	app->captureFade();
 
 	_entered = true;
-	load("menus/mainMenu/mainMenu.lua");
+	const char *luaFile = (g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/MainMenu.lua" : "menus/mainMenu/mainMenu.lua");
+	load(luaFile);
+
+	TeLayout *menuLayout = layoutChecked("menu");
+	appSpriteLayout.addChild(menuLayout);
 
 	//
 	// WORKAROUND: This is set to PanScan ratio 1.0, but with our code
 	// but that shrinks it down to pillarboxed.  Force back to full size.
 	//
-	layoutChecked("background")->setRatioMode(TeILayout::RATIO_MODE_NONE);
+	TeLayout *background;
+	if (layout("background"))
+		background = layoutChecked("background");
+	else
+		background = dynamic_cast<TeLayout *>(menuLayout->child(0));
+	assert(background);
+	background->setRatioMode(TeILayout::RATIO_MODE_NONE);
 
-	TeLayout *menuLayout = layoutChecked("menu");
-	appSpriteLayout.addChild(menuLayout);
 
 	app->mouseCursorLayout().setVisible(true);
-	app->mouseCursorLayout().load("pictures/cursor.png");
+	app->mouseCursorLayout().load(app->defaultCursor());
 
 	TeMusic &music = app->music();
 	if (music.isPlaying()) {
diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp
index 99be35c6159..26ffc5ae042 100644
--- a/engines/tetraedge/te/te_core.cpp
+++ b/engines/tetraedge/te/te_core.cpp
@@ -184,7 +184,8 @@ Common::FSNode TeCore::findFile(const Common::Path &path) const {
 		"DefaultDistributor-Freemium",			// iOS Syb 1 paid
 		"iPhone-iPad/DefaultDistributor",		// iOS Syb 1 paid
 		"Android-iPhone-iPad/iPhone-iPad",		// iOS Syb 2
-		"PC-MacOSX-Android-iPhone-iPad"			// iOS Syb 2
+		"PC-MacOSX-Android-iPhone-iPad",		// iOS Syb 2
+		"Full/HD"								// Amerzone
 	};
 
 	const Common::Path langs[] = {


Commit: ba318b82839305b6bdcebd110fd713b2fa80f0e5
    https://github.com/scummvm/scummvm/commit/ba318b82839305b6bdcebd110fd713b2fa80f0e5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Refactor game class to split out Syberia-specific parts

Changed paths:
  A engines/tetraedge/game/syberia_game.cpp
  A engines/tetraedge/game/syberia_game.h
    engines/tetraedge/game/billboard.cpp
    engines/tetraedge/game/bonus_menu.cpp
    engines/tetraedge/game/documents_browser.cpp
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/game_sound.cpp
    engines/tetraedge/game/in_game_scene.cpp
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/game/youki_manager.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/tetraedge.cpp


diff --git a/engines/tetraedge/game/billboard.cpp b/engines/tetraedge/game/billboard.cpp
index 94b36bec1e3..edf113ed5fe 100644
--- a/engines/tetraedge/game/billboard.cpp
+++ b/engines/tetraedge/game/billboard.cpp
@@ -23,7 +23,7 @@
 
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/billboard.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 
 #include "tetraedge/te/te_core.h"
 
@@ -35,7 +35,7 @@ Billboard::Billboard() : _hasPos2(false) {
 bool Billboard::load(const Common::String &path) {
 	_model = new TeModel();
 	TeIntrusivePtr<Te3DTexture> texture = Te3DTexture::makeInstance();
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
 	TeCore *core = g_engine->getCore();
 	Common::FSNode texnode = core->findFile(game->sceneZonePath().join(path));
 	texture->load(texnode);
diff --git a/engines/tetraedge/game/bonus_menu.cpp b/engines/tetraedge/game/bonus_menu.cpp
index 10daeb05664..61459b70bb3 100644
--- a/engines/tetraedge/game/bonus_menu.cpp
+++ b/engines/tetraedge/game/bonus_menu.cpp
@@ -24,7 +24,7 @@
 #include "common/textconsole.h"
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_input_mgr.h"
 
@@ -39,6 +39,8 @@ void BonusMenu::enter(const Common::String &scriptName) {
 		error("BonusMenu::enter: failed to load %s", scriptName.c_str());
 	Application *app = g_engine->getApplication();
 	app->frontLayout().addChild(layoutChecked("menu"));
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 
 	buttonLayoutChecked("quitButton")->onMouseClickValidated().add(this, &BonusMenu::onQuitButton);
 
@@ -65,7 +67,7 @@ void BonusMenu::enter(const Common::String &scriptName) {
 		if (btn->childCount() <= 4)
 			error("expected save button to have >4 children");
 		const Common::String artName = btn->child(4)->name();
-		btn->setEnable(g_engine->getGame()->isArtworkUnlocked(artName));
+		btn->setEnable(game->isArtworkUnlocked(artName));
 
 		btnNo++;
 	}
diff --git a/engines/tetraedge/game/documents_browser.cpp b/engines/tetraedge/game/documents_browser.cpp
index 533e928c31a..7921550242e 100644
--- a/engines/tetraedge/game/documents_browser.cpp
+++ b/engines/tetraedge/game/documents_browser.cpp
@@ -23,7 +23,7 @@
 
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_lua_thread.h"
 #include "tetraedge/te/te_scrolling_layout.h"
@@ -53,20 +53,23 @@ void DocumentsBrowser::hideDocument() {
 	Game *game = g_engine->getGame();
 
 	bool callFn = true;
-	Common::Array<Game::YieldedCallback> &yieldedcallbacks = game->yieldedCallbacks();
-	for (uint i = 0; i < yieldedcallbacks.size(); i++) {
-		if (yieldedcallbacks[i]._luaFnName == "OnDocumentClosed" &&
-			yieldedcallbacks[i]._luaParam == docName) {
-			yieldedcallbacks.remove_at(i);
-			if (yieldedcallbacks[i]._luaThread) {
-				yieldedcallbacks[i]._luaThread->resume();
-				callFn = false;
+	SyberiaGame *sybgame = dynamic_cast<SyberiaGame *>(game);
+	if (sybgame) {
+		Common::Array<SyberiaGame::YieldedCallback> &yieldedcallbacks = sybgame->yieldedCallbacks();
+		for (uint i = 0; i < yieldedcallbacks.size(); i++) {
+			if (yieldedcallbacks[i]._luaFnName == "OnDocumentClosed" &&
+				yieldedcallbacks[i]._luaParam == docName) {
+				yieldedcallbacks.remove_at(i);
+				if (yieldedcallbacks[i]._luaThread) {
+					yieldedcallbacks[i]._luaThread->resume();
+					callFn = false;
+				}
+				break;
 			}
-			break;
 		}
+		if (callFn)
+			game->luaScript().execute("OnDocumentClosed", docName);
 	}
-	if (callFn)
-		game->luaScript().execute("OnDocumentClosed", docName);
 
 	app->fade();
 }
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 0e1b50b8e38..7f0ab07c49d 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -46,27 +46,16 @@
 namespace Tetraedge {
 
 Game::Game() : _objectsTakenVal(0), _returnToMainMenu(false), _entered(false),
-_enteredFlag2(false), _running(false), _movePlayerCharacterDisabled(false),
-_noScaleLayout(nullptr), _noScaleLayout2(nullptr), _isCharacterIdle(true),
-_sceneCharacterVisibleFromLoad(false), _isCharacterWalking(false),
-_lastCharMoveMousePos(0.0f, 0.0f), _randomSoundFinished(false),
-_previousMousePos(-1, -1), _markersVisible(true), _saveRequested(false),
-_gameLoadState(0), _luaShowOwnerError(false), _score(0), _warped(false),
-_firstInventory(true), _frameCounter(0), _warpFadeFlag(false),
-_dialogsTold(0), _runModeEnabled(true) {
+_running(false), _noScaleLayout2(nullptr), _luaShowOwnerError(false),
+_firstInventory(true), _dialogsTold(0) {
 	for (int i = 0; i < NUM_OBJECTS_TAKEN_IDS; i++) {
 		_objectsTakenBits[i] = false;
 	}
-	_randomSound = new RandomSound();
 	_dialog2.onAnimationDownFinishedSignal().add(this, &Game::onDialogFinished);
 	_question2.onAnswerSignal().add(this, &Game::onAnswered);
 }
 
 Game::~Game() {
-	if (_entered) {
-		leave(true);
-	}
-	delete _randomSound;
 }
 
 /*static*/ const char *Game::OBJECTS_TAKEN_IDS[5] = {
@@ -77,303 +66,12 @@ Game::~Game() {
 	"VPoupeeMammouth"
 };
 
-bool Game::addAnimToSet(const Common::String &anim) {
-	// Get path to lua script, eg scenes/ValVoralberg/14040/Set14040.lua
-	const Common::Path animPath(Common::String("scenes/") + anim + "/");
-
-	if (Common::File::exists(animPath)) {
-		const Common::StringArray parts = TetraedgeEngine::splitString(anim, '/');
-		assert(parts.size() >= 2);
-
-		const Common::String layoutName = parts[1];
-		const Common::String path = Common::String("scenes/") + parts[0] + "/" + parts[1] + "/Set" + parts[1];
-
-		_setAnimGui.load(path + ".lua");
-
-		// Note: game makes this here, but never uses it..
-		// it seems like a random memory leak??
-		// TeSpriteLayout *spritelayout = new TeSpriteLayout();
-
-		TeSpriteLayout *spritelayout = findSpriteLayoutByName(_setAnimGui.layoutChecked("root"), layoutName);
-
-		_scene.bgGui().layoutChecked("root")->addChild(spritelayout);
-		return true;
-	}
-
-	return false;
-}
-
-/*static*/
-Common::String Game::artworkConfName(const Common::String &name) {
-	Common::String configName = Common::String::format("artwork_%s", name.c_str());
-	for (uint i = 0; i < configName.size(); i++) {
-		if (configName[i] == '/' || configName[i] == '.')
-			configName.setChar('_', i);
-	}
-	return configName;
-}
-
-void Game::addArtworkUnlocked(const Common::String &name, bool notify) {
-	const Common::String configName = artworkConfName(name);
-	if (_unlockedArtwork.contains(configName))
-		return;
-	ConfMan.setBool(configName, true);
-	ConfMan.flushToDisk();
-	_unlockedArtwork[configName] = true;
-	if (notify)
-		_notifier.push("BONUS!", "Inventory/Objects/VPapierCrayon.png");
-}
-
-bool Game::isArtworkUnlocked(const Common::String &name) const {
-	const Common::String configName = artworkConfName(name);
-	return _unlockedArtwork.getValOrDefault(configName, false);
-}
-
 void Game::addNoScale2Child(TeLayout *layout) {
 	if (_noScaleLayout2 && layout) {
 		_noScaleLayout2->addChild(layout);
 	}
 }
 
-void Game::addNoScale2Children() {
-	if (!_noScaleLayout2)
-		return;
-
-	TeLayout *vidbtn = _inGameGui.layout("videoButtonLayout");
-	if (vidbtn)
-		_noScaleLayout2->addChild(vidbtn);
-
-	TeLayout *bg = _inventory.cellphone()->gui().layout("background");
-	if (bg)
-		_noScaleLayout2->addChild(bg);
-
-	TeButtonLayout *bgbtn = _objectif.gui1().buttonLayout("background");
-	if (bgbtn)
-		_noScaleLayout2->addChild(bgbtn);
-}
-
-void Game::addNoScaleChildren() {
-	if (!_noScaleLayout)
-		return;
-	TeLayout *inGame = _inGameGui.layout("inGame");
-	if (inGame)
-		_noScaleLayout->addChild(inGame);
-
-	_noScaleLayout->addChild(&_question2);
-
-	Application *app = g_engine->getApplication();
-	app->frontLayout().addChild(&_dialog2);
-
-	_noScaleLayout->addChild(&_inventory);
-	_noScaleLayout->addChild(&_inventoryMenu);
-	_noScaleLayout->addChild(&_documentsBrowser);
-	_noScaleLayout->addChild(&_documentsBrowser.zoomedLayout());
-}
-
-void Game::addRandomSound(const Common::String &name, const Common::String &path, float f1, float volume) {
-	if (!_randomSounds.contains(name)) {
-		_randomSounds[name] = Common::Array<RandomSound*>();
-	}
-	RandomSound *randsound = new RandomSound();
-	randsound->_path = path;
-	randsound->_f1 = f1;
-	randsound->_volume = volume;
-	randsound->_name = name;
-	_randomSounds[name].push_back(randsound);
-}
-
-void Game::addToBag(const Common::String &objid) {
-	if (_inventory.objectCount(objid) != 0)
-		return;
-	_inventory.addObject(objid);
-	Common::String imgpath("Inventory/Objects/");
-	imgpath += objid;
-	imgpath += ".png";
-	_notifier.push(_inventory.objectName(objid), imgpath);
-	for (int i = 0; i < NUM_OBJECTS_TAKEN_IDS; i++) {
-		if (objid == OBJECTS_TAKEN_IDS[i] && !_objectsTakenBits[i]) {
-			_objectsTakenBits[i] = true;
-			_objectsTakenVal++;
-		}
-	}
-	// Seeems strange as we're already in Game, but that's what original does?
-	Game *game = g_engine->getGame();
-	game->_score += 10;
-	debug("Updated score: %d", game->_score);
-}
-
-void Game::addToHand(const Common::String &objname) {
-	_inventory.addObject(objname);
-	_inventory.selectedObject(objname);
-}
-
-void Game::addToScore(int score) {
-	_score += score;
-}
-
-bool Game::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
-	//debug("Game::changeWarp(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
-	Application *app = g_engine->getApplication();
-	if (fadeFlag && g_engine->gameType() == TetraedgeEngine::kSyberia) {
-		app->blackFade();
-	} else {
-		app->captureFade();
-	}
-	// Slight divergence from original.. free after capturing fade so characters don't disappear.
-	if (g_engine->gameType() == TetraedgeEngine::kSyberia2)
-		_scene.freeGeometry();
-
-	_warpZone = zone;
-	_warpScene = scene;
-	_warpFadeFlag = fadeFlag;
-	_warped = true;
-	return true;
-}
-
-bool Game::changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
-	//debug("Game::changeWarp2(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
-	_warped = false;
-	_movePlayerCharacterDisabled = false;
-	_sceneCharacterVisibleFromLoad = false;
-	// TODO? _charMoveMouseEventNo = -1?
-	_isCharacterIdle = true;
-	_isCharacterWalking = false;
-	Common::Path luapath("scenes");
-	luapath.joinInPlace(zone);
-	luapath.joinInPlace(scene);
-	luapath.joinInPlace("Logic");
-	luapath.appendInPlace(scene);
-	luapath.appendInPlace(".lua");
-
-	if (g_engine->getCore()->findFile(luapath).exists()) {
-		_luaScript.execute("OnLeave");
-		_luaContext.removeGlobal("On");
-		_luaContext.removeGlobal("OnEnter");
-		_luaContext.removeGlobal("OnWarpObjectHit");
-		_luaContext.removeGlobal("OnButtonDown");
-		_luaContext.removeGlobal("OnButtonUp");
-		_luaContext.removeGlobal("OnFinishedAnim");
-		_luaContext.removeGlobal("OnCharacterAnimationFinished");
-		_luaContext.removeGlobal("OnCharacterAnimationPlayerFinished");
-		_luaContext.removeGlobal("OnDisplacementFinished");
-		_luaContext.removeGlobal("OnFreeSoundFinished");
-		_luaContext.removeGlobal("OnDocumentClosed");
-		_luaContext.removeGlobal("OnSelectedObject");
-		_luaContext.removeGlobal("OnDialogFinished");
-		_luaContext.removeGlobal("OnAnswered");
-		_luaContext.removeGlobal("OnLeave");
-		_luaScript.unload();
-	}
-
-	_forGui.unload();
-	_prevSceneName = _currentScene;
-	if (!fadeFlag)
-		g_engine->getApplication()->fade();
-
-	return initWarp(zone, scene, false);
-}
-
-void Game::deleteNoScale() {
-	if (_noScaleLayout) {
-		removeNoScaleChildren();
-		delete _noScaleLayout;
-		_noScaleLayout = nullptr;
-	}
-	if (_noScaleLayout2) {
-		removeNoScale2Children();
-		delete _noScaleLayout2;
-		_noScaleLayout2 = nullptr;
-	}
-}
-
-void Game::draw() {
-	if (_running) {
-		_frameCounter++;
-		_scene.draw();
-	}
-}
-
-void Game::enter() {
-	_enteredFlag2 = true;
-	_entered = true;
-	_luaShowOwnerError = false;
-	_score = 0;
-	Application *app = g_engine->getApplication();
-	app->visualFade().init();
-	// TODO: Original puts this click handler at -10000.. but then it never gets hit?
-	Common::SharedPtr<TeCallback1Param<Game, const Common::Point &>> callbackptr(new TeCallback1Param<Game, const Common::Point &>(this, &Game::onMouseClick, 10000.0f));
-	g_engine->getInputMgr()->_mouseLUpSignal.push_back(callbackptr);
-	_movePlayerCharacterDisabled = false;
-	// TODO? Set _charMoveMouseEventNo = -1
-	_isCharacterIdle = true;
-	_sceneCharacterVisibleFromLoad = false;
-	Character::loadSettings("models/ModelsSettings.xml");
-	Object3D::loadSettings("objects/ObjectsSettings.xml");
-	if (_scene._character) {
-		_scene._character->onFinished().remove(this, &Game::onDisplacementPlayerFinished);
-		_scene.unloadCharacter(_scene._character->_model->name());
-	}
-	bool loaded = loadPlayerCharacter("Kate");
-	if (!loaded)
-		error("[Game::enter] Can't load player character");
-
-	_scene._character->_model->setVisible(true);
-	_running = true;
-	_luaContext.create();
-	GameAchievements::registerAchievements(_luaContext);
-
-	_luaContext.setGlobal("BUTTON_VALID", 1);
-	_luaContext.setGlobal("BUTTON_CANCEL", 2);
-	_luaContext.setGlobal("BUTTON_EXTRA1", 4);
-	_luaContext.setGlobal("BUTTON_EXTRA2", 8);
-	_luaContext.setGlobal("BUTTON_L1", 0x10);
-	_luaContext.setGlobal("BUTTON_R1", 0x20);
-	_luaContext.setGlobal("BUTTON_START", 0x40);
-	_luaContext.setGlobal("BUTTON_UP", 0x80);
-	_luaContext.setGlobal("BUTTON_DOWN", 0x100);
-	_luaContext.setGlobal("BUTTON_LEFT", 0x200);
-	_luaContext.setGlobal("BUTTON_RIGHT", 0x400);
-	_luaContext.setGlobal("BUTTON_LS_CLIC", 0x800);
-	_luaContext.setGlobal("BUTTON_RS_CLIC", 0x1000);
-	_luaContext.setGlobal("BUTTON_BACK", 0x2000);
-	_luaContext.setGlobal("BUTTON_SELECT", 0x4000);
-	_luaContext.setGlobal("BUTTON_L2", 0x8000);
-	_luaContext.setGlobal("BUTTON_R2", 0x10000);
-	_luaContext.setGlobal("BUTTON_LS_UP", 0x20000);
-	_luaContext.setGlobal("BUTTON_LS_DOWN", 0x40000);
-	_luaContext.setGlobal("BUTTON_LS_LEFT", 0x80000);
-	_luaContext.setGlobal("BUTTON_LS_RIGHT", 0x100000);
-	_luaContext.setGlobal("BUTTON_RS_UP", 0x200000);
-	_luaContext.setGlobal("BUTTON_RS_DOWN", 0x400000);
-	_luaContext.setGlobal("BUTTON_RS_LEFT", 0x800000);
-	_luaContext.setGlobal("BUTTON_RS_RIGHT", 0x1000000);
-
-	_gameEnterScript.attachToContext(&_luaContext);
-
-	if (!_objectif.gui1().loaded()) {
-		_objectif.load();
-	}
-	_question2.load();
-	_dialog2.load();
-	_documentsBrowser.load();
-	_documentsBrowser.loadZoomed();
-	_inventory.load();
-
-	_inventory.cellphone()->onCallNumber().add(this, &Game::onCallNumber);
-
-	if (hasLoadName()) {
-		loadBackup(_loadName);
-	} else {
-		_gameLoadState = 1;
-		onFinishedLoadingBackup("");
-	}
-	_sceneCharacterVisibleFromLoad = true;
-	_scene._character->onFinished().remove(this, &Game::onDisplacementPlayerFinished);
-	_scene._character->onFinished().add(this, &Game::onDisplacementPlayerFinished);
-	_prevSceneName.clear();
-	_notifier.load();
-}
-
 /*static*/
 TeI3DObject2 *Game::findLayoutByName(TeLayout *parent, const Common::String &name) {
 	// Seems like this is never used?
@@ -397,336 +95,6 @@ TeSpriteLayout *Game::findSpriteLayoutByName(TeLayout *parent, const Common::Str
 	return nullptr;
 }
 
-void Game::finishFreemium() {
-	Application *app = g_engine->getApplication();
-	app->setFinishedGame(true);
-	app->setFinishedFremium(true);
-}
-
-void Game::finishGame() {
-	Application *app = g_engine->getApplication();
-	// FIXME: The original sets this, but then Application::run immediately
-	// returns to the menu.. how does the original wait for the credits to end??
-	//app->_finishedGame = true;
-	_playedTimer.stop();
-	/* Game does this but does nothing with result?
-	if (app->difficulty() == 2) {
-		_playedTimer.getTimeFromStart();
-	} */
-	app->credits().enter(false);
-}
-
-void Game::initLoadedBackupData() {
-	bool warpFlag = true;
-	Application *app = g_engine->getApplication();
-	Common::String firstWarpPath;
-	if (!_loadName.empty()) {
-		warpFlag = false;
-		Common::InSaveFile *saveFile = g_engine->getSaveFileManager()->openForLoading(_loadName);
-		Common::Error result = g_engine->loadGameStream(saveFile);
-		if (result.getCode() == Common::kNoError) {
-			ExtendedSavegameHeader header;
-			if (MetaEngine::readSavegameHeader(saveFile, &header))
-				g_engine->setTotalPlayTime(header.playtime);
-		}
-	} else {
-		firstWarpPath = app->firstWarpPath();
-		_currentScene = app->firstScene();
-		_currentZone = app->firstZone();
-		_playedTimer.start();
-		_objectsTakenVal = 0;
-		for (int i = 0; i < ARRAYSIZE(_objectsTakenBits); i++) {
-			_objectsTakenBits[i] = 0;
-		}
-		_dialogsTold = 0;
-		if (_loadName == "NO_OWNER")
-			_luaShowOwnerError = true;
-	}
-	_gameLoadState = 0;
-	app->showLoadingIcon(false);
-	_loadName.clear();
-	initScene(warpFlag, firstWarpPath);
-}
-
-void Game::initNoScale() {
-	if (!_noScaleLayout) {
-		_noScaleLayout = new TeLayout();
-		_noScaleLayout->setName("noScaleLayout");
-		_noScaleLayout->setSizeType(TeILayout::RELATIVE_TO_PARENT);
-		_noScaleLayout->setSize(TeVector3f32(1.0f, 1.0f, 0.0f));
-	}
-
-	if (!_noScaleLayout2) {
-		_noScaleLayout2 = new TeLayout();
-		_noScaleLayout2->setName("noScaleLayout2");
-		_noScaleLayout2->setSizeType(TeILayout::RELATIVE_TO_PARENT);
-		_noScaleLayout2->setSize(TeVector3f32(1.0f, 1.0f, 0.0f));
-	}
-}
-
-void Game::initScene(bool fade, const Common::String &scenePath) {
-	_luaContext.setGlobal("SHOW_OWNER_ERROR", _luaShowOwnerError);
-	initWarp(_currentZone, _currentScene, fade);
-	loadScene(scenePath);
-	if (_scene._character->_model.get() && !_scene.findKate()) {
-		_scene.models().push_back(_scene._character->_model);
-	}
-	_scene._character->_model->setVisible(true);
-}
-
-bool Game::initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
-	debug("Game::initWarp(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
-	_inventoryMenu.unload();
-	_inGameGui.unload();
-	_movePlayerCharacterDisabled = false;
-	_sceneCharacterVisibleFromLoad = true;
-
-	if (_scene._character) {
-		_scene._character->_model->setVisible(true);
-		_scene._character->deleteAllCallback();
-		_scene._character->stop();
-		_scene._character->setAnimation(_scene._character->characterSettings()._idleAnimFileName, true);
-		if (!_scene.findKate()) {
-			_scene.models().push_back(_scene._character->_model);
-			if (_scene._character->_shadowModel[0]) {
-				_scene.models().push_back(_scene._character->_shadowModel[0]);
-				_scene.models().push_back(_scene._character->_shadowModel[1]);
-			}
-		}
-	}
-
-	_currentZone = zone;
-	_currentScene = scene;
-
-	_scene.loadBlockers();
-	Common::Path scenePath("scenes");
-	scenePath.joinInPlace(zone);
-	scenePath.joinInPlace(scene);
-	_sceneZonePath = scenePath;
-
-	TeCore *core = g_engine->getCore();
-
-	const Common::FSNode intLuaNode = core->findFile(scenePath.join(Common::String::format("Int%s.lua", scene.c_str())));
-	const Common::FSNode logicLuaNode = core->findFile(scenePath.join(Common::String::format("Logic%s.lua", scene.c_str())));
-	const Common::FSNode setLuaNode = core->findFile(scenePath.join(Common::String::format("Set%s.lua", scene.c_str())));
-	Common::FSNode forLuaNode = core->findFile(scenePath.join(Common::String::format("For%s.lua", scene.c_str())));
-	const Common::FSNode markerLuaNode = core->findFile(scenePath.join(Common::String::format("Marker%s.lua", scene.c_str())));
-
-	bool intLuaExists = intLuaNode.exists();
-	bool logicLuaExists = logicLuaNode.exists();
-	bool setLuaExists = setLuaNode.exists();
-	bool forLuaExists = forLuaNode.exists();
-	if (!forLuaExists) {
-		// slight hack.. try an alternate For lua path.
-		forLuaNode = core->findFile(scenePath.join("Android-MacOSX").join(Common::String::format("For%s.lua", scene.c_str())));
-		forLuaExists = forLuaNode.exists();
-		debug("searched for %s", forLuaNode.getName().c_str());
-	}
-	bool markerLuaExists = markerLuaNode.exists();
-
-	if (!intLuaExists && !logicLuaExists && !setLuaExists && !forLuaExists && !markerLuaExists) {
-		debug("No lua scripts for scene %s zone %s", scene.c_str(), zone.c_str());
-		return false;
-	}
-
-	for (auto &sound : _gameSounds) {
-		sound->setRetain(false);
-	}
-
-	if (logicLuaExists) {
-		_luaContext.addBindings(LuaBinds::LuaOpenBinds);
-		_luaScript.attachToContext(&_luaContext);
-		_luaScript.load(core->findFile("menus/help/help.lua"));
-		_luaScript.execute();
-		_luaScript.load(logicLuaNode);
-	}
-
-	if (_forGui.loaded())
-		_forGui.unload();
-
-	_scene.reset();
-	_scene.bgGui().unload();
-	_scene.markerGui().unload();
-	_scene.hitObjectGui().unload();
-	Common::Path geomPath(Common::String::format("scenes/%s/Geometry%s.bin",
-												 zone.c_str(), zone.c_str()));
-	Common::FSNode geomFile = core->findFile(geomPath);
-	if (geomFile.isReadable()) {
-		// Syberia 1, load geom bin
-		_scene.load(geomFile);
-	} else {
-		// Syberia 2, load from xml
-		_scene.loadXml(zone, scene);
-	}
-	_scene.loadBackground(setLuaNode);
-
-	Application *app = g_engine->getApplication();
-	if (forLuaExists) {
-		_forGui.load(forLuaNode);
-		TeLayout *bg = _forGui.layoutChecked("background");
-		bg->setRatioMode(TeILayout::RATIO_MODE_NONE);
-		app->frontLayout().addChild(bg);
-		// Note: Game also adds cellphone to both frontLayout *and* noScaleLayout2,
-		// so we reproduce the broken behavior exactly.
-		TeLayout *cellbg = _inventory.cellphone()->gui().buttonLayoutChecked("background");
-		app->frontLayout().removeChild(cellbg);
-		app->frontLayout().addChild(cellbg);
-		_objectif.reattachLayout(&app->frontLayout());
-	}
-
-	if (intLuaExists) {
-		_scene.loadInteractions(intLuaNode);
-		TeLuaGUI::StringMap<TeButtonLayout *> &blayouts = _scene.hitObjectGui().buttonLayouts();
-		for (auto &entry : blayouts) {
-			HitObject *hobj = new HitObject();
-			TeButtonLayout *btn = entry._value;
-			hobj->_game = this;
-			hobj->_button = btn;
-			hobj->_name = btn->name();
-			btn->onMouseClickValidated().add(hobj, &HitObject::onValidated);
-			btn->onButtonChangedToStateDownSignal().add(hobj, &HitObject::onDown);
-			btn->onButtonChangedToStateUpSignal().add(hobj, &HitObject::onUp);
-			_gameHitObjects.push_back(hobj);
-		}
-	}
-
-	_inventoryMenu.load();
-	_inGameGui.load("InGame.lua");
-
-	TeButtonLayout *skipbtn = _inGameGui.buttonLayoutChecked("skipVideoButton");
-	skipbtn->setVisible(false);
-	skipbtn->onMouseClickValidated().remove(this, &Game::onSkipVideoButtonValidated);
-	skipbtn->onMouseClickValidated().add(this, &Game::onSkipVideoButtonValidated);
-
-	TeButtonLayout *vidbgbtn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
-	vidbgbtn->setVisible(false);
-	vidbgbtn->onMouseClickValidated().remove(this, &Game::onLockVideoButtonValidated);
-	vidbgbtn->onMouseClickValidated().add(this, &Game::onLockVideoButtonValidated);
-
-	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
-	video->setVisible(false);
-	video->_tiledSurfacePtr->_frameAnim.onStop().remove(this, &Game::onVideoFinished);
-	video->_tiledSurfacePtr->_frameAnim.onStop().add(this, &Game::onVideoFinished);
-
-	TeButtonLayout *invbtn = _inGameGui.buttonLayoutChecked("inventoryButton");
-	invbtn->onMouseClickValidated().remove(this, &Game::onInventoryButtonValidated);
-	invbtn->onMouseClickValidated().add(this, &Game::onInventoryButtonValidated);
-	invbtn->setSizeType(TeILayout::RELATIVE_TO_PARENT);
-
-	const TeVector3f32 winSize = app->getMainWindow().size();
-	if (g_engine->getCore()->fileFlagSystemFlag("definition") == "SD") {
-		invbtn->setSize(TeVector3f32(0.12f, (4.0f / ((winSize.y() / winSize.x()) * 4.0f)) * 0.12f, 0.0));
-	} else {
-		invbtn->setSize(TeVector3f32(0.08f, (4.0f / ((winSize.y() / winSize.x()) * 4.0f)) * 0.08f, 0.0));
-	}
-
-	TeCheckboxLayout *markersCheckbox = _inGameGui.checkboxLayout("markersVisibleButton");
-	markersCheckbox->setState(_markersVisible ? TeCheckboxLayout::CheckboxStateActive : TeCheckboxLayout::CheckboxStateUnactive);
-	markersCheckbox->onStateChangedSignal().add(this, &Game::onMarkersVisible);
-
-	initNoScale();
-	removeNoScale2Children();
-	app->frontLayout().removeChild(_noScaleLayout2);
-
-	TeLayout *vidLayout = _inGameGui.layout("videoLayout");
-	app->frontLayout().removeChild(vidLayout);
-	removeNoScaleChildren();
-	app->frontLayout().removeChild(_noScaleLayout);
-
-	app->frontLayout().addChild(_noScaleLayout);
-	addNoScaleChildren();
-	app->frontLayout().addChild(vidLayout);
-	app->frontLayout().addChild(_noScaleLayout2);
-	addNoScale2Children();
-	if (!fadeFlag) {
-		if (_inventory.selectedObject().size()) {
-			_inventory.selectedObject(_inventory.selectedInventoryObject());
-		}
-		_inventory.setVisible(false);
-		_objectif.setVisibleObjectif(false);
-		_objectif.setVisibleButtonHelp(true);
-		_running = true;
-		loadScene("save.xml");
-	}
-
-	app->backLayout().addChild(_scene.background());
-
-	if (markerLuaExists) {
-		TeLayout *bg = _scene.markerGui().layout("background");
-		app->frontLayout().addChild(bg);
-	}
-
-	Common::String camname = Common::String("Camera") + scene;
-	_scene.setCurrentCamera(camname);
-
-	// Special hacks for certain scenes (don't blame me, original does this..)
-	if (g_engine->gameType() == TetraedgeEngine::kSyberia) {
-		if (scene == "14050") {
-			TeIntrusivePtr<TeCamera> curcamera = _scene.currentCamera();
-			const TeVector3f32 coords(1200.6f, -1937.5f, 1544.1f);
-			curcamera->setPosition(coords);
-		} else if (scene == "34610") {
-			TeIntrusivePtr<TeCamera> curcamera = _scene.currentCamera();
-			const TeVector3f32 coords(-328.243f, 340.303f, -1342.84f);
-			curcamera->setPosition(coords);
-			const TeQuaternion rot(0.003194f, 0.910923f, -0.009496f, -0.412389f);
-			curcamera->setRotation(rot);
-		}
-
-		//
-		// WORKAROUND: Fix the camera in the restored scenes
-		//
-		if (zone == "ValStreet" && scene == "11100") {
-			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
-			cam->setProjMatrixType(3);
-			cam->setFov(0.5f);
-		} else if (zone == "ValField" && scene == "11170") {
-			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
-			cam->setProjMatrixType(3);
-			// TODO: Is camera position right? Kate not visible..
-			// default values:
-			// -494.447998  -79.2976989  1408.5
-			// scene entrance and exit
-			// -184, -143, 1563
-			// -42, -147, 1534
-		} else if (zone == "BarRiverSide" && scene == "24020") {
-			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
-			cam->setProjMatrixType(3);
-			cam->setFov(0.5f);
-		}
-	}
-
-	if (logicLuaExists) {
-		_exitZone.clear();
-		_luaScript.execute();
-		_luaScript.execute("OnEnter", _prevSceneName);
-		_luaScript.execute("OnSelectedObject", _inventory.selectedObject());
-	}
-
-	for (uint i = 0; i < _gameSounds.size(); i++) {
-		if (_gameSounds[i]->retain())
-			continue;
-		_gameSounds[i]->stop();
-		_gameSounds[i]->deleteLater();
-		_gameSounds.remove_at(i);
-		i--;
-	}
-
-	// Take a copy and clear the global list first, as deleting a sound can cause the
-	// next sound to trigger (which might have been deleted already).
-	Common::HashMap<Common::String, Common::Array<RandomSound *>> rsounds = _randomSounds;
-	_randomSounds.clear();
-	for (auto &randsoundlist : rsounds) {
-		for (auto *randsound : randsoundlist._value) {
-			delete randsound;
-		}
-		randsoundlist._value.clear();
-	}
-
-	_scene.initScroll();
-	return true;
-}
-
 bool Game::isDocumentOpened() {
 	return _documentsBrowser.gui1().layoutChecked("zoomed")->visible();
 }
@@ -787,330 +155,11 @@ bool Game::launchDialog(const Common::String &dname, uint param_2, const Common:
 	return true;
 }
 
-void Game::leave(bool flag) {
-	if (!_enteredFlag2)
-		return;
-
-	Application *app = g_engine->getApplication();
-
-	deleteNoScale();
-	_entered = false;
-	_running = false;
-	_notifier.unload();
-	g_engine->getInputMgr()->_mouseLUpSignal.remove(this, &Game::onMouseClick);
-	_question2.unload();
-	TeLayout *cellbg = _inventory.cellphone()->gui().buttonLayout("background");
-	if (cellbg)
-		app->frontLayout().removeChild(cellbg);
-	_inventory.cellphone()->leave();
-	_dialog2.unload();
-	_inventory.unload();
-	_documentsBrowser.unload();
-	_inventoryMenu.unload();
-	_gui1.unload();
-	_objectif.unload(); // not done in original, but should be.
-	_scene.close();
-	_forGui.unload();
-	if (_scene._character) {
-		_scene._character->deleteAllCallback();
-		_scene._character->stop();
-		_scene.unloadCharacter(_scene._character->_model->name());
-	}
-
-	for (auto &sound : _gameSounds) {
-		delete sound;
-	}
-	_gameSounds.clear();
-
-	for (auto &randsoundlist : _randomSounds) {
-		for (auto *randsound : randsoundlist._value) {
-			delete randsound;
-		}
-		randsoundlist._value.clear();
-	}
-	_randomSounds.clear();
-
-	for (auto *hitobj : _gameHitObjects) {
-		delete hitobj;
-	}
-	_gameHitObjects.clear();
-
-	// TODO: clear Game::HitObject tree here?
-
-	_luaContext.destroy();
-	_running = false;
-	_inGameGui.buttonLayoutChecked("skipVideoButton")->onMouseClickValidated().remove(this, &Game::onSkipVideoButtonValidated);
-	_inGameGui.buttonLayoutChecked("videoBackgroundButton")->onMouseClickValidated().remove(this, &Game::onLockVideoButtonValidated);
-	_inGameGui.spriteLayoutChecked("video")->_tiledSurfacePtr->_frameAnim.onFinished().remove(this, &Game::onSkipVideoButtonValidated);
-	_inGameGui.buttonLayoutChecked("inventoryButton")->onMouseClickValidated().remove(this, &Game::onInventoryButtonValidated);
-	_inGameGui.unload();
-	_playedTimer.stop();
-	_enteredFlag2 = false;
-
-	app->lockCursor(false);
-	app->lockCursorFromAction(false);
-	// TODO: Set some inputmgr flag here?
-	Character::animCacheFreeAll();
-}
-
-void Game::loadBackup(const Common::String &path) {
-	if (_gameLoadState == 0) {
-		_gameLoadState = 1;
-		g_engine->getApplication()->showLoadingIcon(true);
-		onFinishedLoadingBackup(path);
-	}
-}
-
-void Game::loadUnlockedArtwork() {
-	Common::ConfigManager::Domain *domain = ConfMan.getActiveDomain();
-	for (auto &val : *domain) {
-		if (val._key.substr(0, 8) == "artwork_") {
-			_unlockedArtwork[val._key] = true;
-		}
-	}
-}
-
-bool Game::loadCharacter(const Common::String &name) {
-	bool result = true;
-	Character *character = _scene.character(name);
-	if (!character) {
-		result = _scene.loadCharacter(name);
-		if (result) {
-			character = _scene.character(name);
-			assert(character);
-			character->_onCharacterAnimFinishedSignal.remove(this, &Game::onCharacterAnimationFinished);
-			character->_onCharacterAnimFinishedSignal.add(this, &Game::onCharacterAnimationFinished);
-			// Syberia 2 uses a simplified callback here.
-			// We have made onDisplacementPlayerFinished more like Syberia 1's onDisplacementFinished.
-			if (g_engine->gameType() == TetraedgeEngine::kSyberia)
-				character->onFinished().add(this, &Game::onDisplacementPlayerFinished);
-			else
-				character->onFinished().add(this, &Game::onDisplacementFinished);
-		}
-	}
-	return result;
-}
-
-bool Game::loadPlayerCharacter(const Common::String &name) {
-	bool result = _scene.loadPlayerCharacter(name);
-	if (result) {
-		_scene._character->_characterAnimPlayerFinishedSignal.remove(this, &Game::onCharacterAnimationPlayerFinished);
-		_scene._character->_characterAnimPlayerFinishedSignal.add(this, &Game::onCharacterAnimationPlayerFinished);
-		_scene._character->onFinished().remove(this, &Game::onDisplacementPlayerFinished);
-		_scene._character->onFinished().add(this, &Game::onDisplacementPlayerFinished);
-	} else {
-		debug("failed to load player character %s", name.c_str());
-	}
-	return result;
-}
-
-bool Game::loadScene(const Common::String &name) {
-	TeCore *core = g_engine->getCore();
-	_gameEnterScript.load(core->findFile("scenes/OnGameEnter.lua"));
-	_gameEnterScript.execute();
-	Character *character = _scene._character;
-	if (character && character->_model->visible()) {
-		_sceneCharacterVisibleFromLoad = true;
-	}
-	return false;
-}
-
 bool Game::onAnswered(const Common::String &val) {
 	_luaScript.execute("OnAnswered", val);
 	return false;
 }
 
-bool Game::onCallNumber(Common::String val) {
-	_luaScript.execute("OnCallNumber", val);
-	return false;
-}
-
-bool Game::onCharacterAnimationFinished(const Common::String &charName) {
-	if (!_scene._character)
-		return false;
-
-	if (g_engine->gameType() == TetraedgeEngine::kSyberia2) {
-		Character *character = scene().character(charName);
-		if (character) {
-			const Common::String curAnimName = character->curAnimName();
-			if (curAnimName == character->walkAnim(Character::WalkPart_EndD)
-				|| curAnimName == character->walkAnim(Character::WalkPart_EndG)) {
-				character->updatePosition(1.0);
-				character->endMove();
-			}
-		}
-	}
-
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		if (cb._luaFnName == "OnCharacterAnimationFinished" && cb._luaParam == charName) {
-			TeLuaThread *lua = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			if (lua) {
-				lua->resume();
-				return false;
-			}
-			break;
-		}
-	}
-	_luaScript.execute("OnCharacterAnimationFinished", charName);
-	return false;
-}
-
-bool Game::onCharacterAnimationPlayerFinished(const Common::String &anim) {
-	if (_gameLoadState != 0)
-		return false;
-
-	bool callScripts = true;
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		// Yes, even Syberia2 checks for Kate here..
-		if (cb._luaFnName == "OnCharacterAnimationFinished" && cb._luaParam == "Kate") {
-			TeLuaThread *lua = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			if (lua) {
-				lua->resume();
-				callScripts = false;
-			}
-			break;
-		}
-	}
-	if (callScripts) {
-		if (g_engine->gameType() == TetraedgeEngine::kSyberia)
-			_luaScript.execute("OnCharacterAnimationFinished", "Kate");
-		else
-			_luaScript.execute("OnCharacterAnimationPlayerFinished", anim);
-		_luaScript.execute("OnCellCharacterAnimationPlayerFinished", anim);
-	}
-
-	Character *character = scene()._character;
-	assert(character);
-	// Note: the above callbacks can change the anim,
-	// so we have to fetch this *after* them.
-	const Common::String curAnimName = character->curAnimName();
-	if (_currentScene == _someSceneName) {
-		if (curAnimName == character->walkAnim(Character::WalkPart_Start)
-			|| curAnimName == character->walkAnim(Character::WalkPart_Loop)
-			|| curAnimName == character->walkAnim(Character::WalkPart_EndD)
-			|| curAnimName == character->walkAnim(Character::WalkPart_EndG))
-			character->stop();
-	} else {
-		if (!_sceneCharacterVisibleFromLoad && curAnimName == character->walkAnim(Character::WalkPart_Start)) {
-			character->setAnimation(character->walkAnim(Character::WalkPart_Loop), true);
-			return false;
-		}
-		if (curAnimName == character->walkAnim(Character::WalkPart_EndD)
-			|| curAnimName == character->walkAnim(Character::WalkPart_EndG)) {
-			character->updatePosition(1.0);
-			character->endMove();
-			// endMove can result in callbacks that change the animation. check again.
-			if (character->curAnimName() == character->walkAnim(Character::WalkPart_EndD)
-				|| character->curAnimName() == character->walkAnim(Character::WalkPart_EndG))
-				character->setAnimation(character->characterSettings()._idleAnimFileName, true);
-		}
-	}
-
-	return false;
-}
-
-bool Game::onDialogFinished(const Common::String &val) {
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		if (cb._luaFnName == "OnDialogFinished" && cb._luaParam == val) {
-			TeLuaThread *lua = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			if (lua) {
-				lua->resume();
-				return false;
-			}
-			break;
-		}
-	}
-
-	_luaScript.execute("OnDialogFinished", val);
-	_luaScript.execute("OnCellDialogFinished", val);
-	return false;
-}
-
-// This is the Syberia 2 version of this function, not used in Syb 1.
-// Syb 1 uses a function much more like onDisplacementPlayerFinished below.
-bool Game::onDisplacementFinished() {
-	TeLuaThread *thread = nullptr;
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		if (cb._luaFnName == "OnDisplacementFinished") {
-			thread = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			break;
-		}
-	}
-	if (thread) {
-		thread->resume();
-	} else {
-		_luaScript.execute("OnDisplacementFinished");
-	}
-	return false;
-}
-
-bool Game::onDisplacementPlayerFinished() {
-	_sceneCharacterVisibleFromLoad = true;
-	assert(_scene._character);
-	_scene._character->stop();
-	_scene._character->walkMode("Walk");
-	_scene._character->setAnimation(_scene._character->characterSettings()._idleAnimFileName, true);
-
-	if (_isCharacterWalking) {
-		_isCharacterWalking = false;
-		_isCharacterIdle = true;
-	} else {
-		_isCharacterIdle = false;
-	}
-
-	TeLuaThread *thread = nullptr;
-
-	const char *cbName = (g_engine->gameType() == TetraedgeEngine::kSyberia ?
-						"OnDisplacementFinished" : "OnDisplacementPlayerFinished");
-
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		if (cb._luaFnName == cbName) {
-			thread = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			break;
-		}
-	}
-	if (thread) {
-		thread->resume();
-	} else {
-		_luaScript.execute(cbName);
-	}
-	return false;
-}
-
-bool Game::onFinishedCheckBackup(bool result) {
-	if (_gameLoadState == 1) {
-		_gameLoadState = 0;
-		return true;
-	}
-	return false;
-}
-
-bool Game::onFinishedLoadingBackup(const Common::String &val) {
-	if (_gameLoadState == 1) {
-		_loadName = val;
-		_gameLoadState = 2;
-		return true;
-	}
-	return false;
-}
-
-bool Game::onFinishedSavingBackup(int something) {
-	if (something) {
-		g_engine->getGame()->_returnToMainMenu = true;
-	}
-	g_engine->getApplication()->showLoadingIcon(false);
-	return true;
-}
 
 bool Game::onInventoryButtonValidated() {
 	_inventoryMenu.enter();
@@ -1123,119 +172,6 @@ bool Game::onLockVideoButtonValidated() {
 	return true;
 }
 
-bool Game::onMarkersVisible(TeCheckboxLayout::State state) {
-	_markersVisible = (state == TeCheckboxLayout::CheckboxStateActive);
-	showMarkers(state == TeCheckboxLayout::CheckboxStateActive);
-	return false;
-}
-
-bool Game::onMouseClick(const Common::Point &pt) {
-	Application *app = g_engine->getApplication();
-
-	if (app->isFading())
-		return true;
-
-	// In case we capture a click during a video or dialog (shouldn't happen?)
-	if (!_scene.currentCamera() || _dialog2.isDialogPlaying() || _question2.isEntered())
-		return false;
-
-	_posPlayer = TeVector3f32(-1.0f, -1.0f, -1.0f);
-	if (_previousMousePos == TeVector2s32(-1, -1)) {
-		_previousMousePos = pt;
-	} else {
-		const TeVector3f32 winSize = app->getMainWindow().size();
-		const TeVector2s32 prevMousePos = _previousMousePos;
-		_previousMousePos = pt;
-		float xdist = (pt.x - prevMousePos._x) / winSize.x();
-		float ydist = (pt.y - prevMousePos._y) / winSize.y();
-		float sqrdist = xdist * xdist + ydist * ydist;
-		if (sqrdist < 0.0001 && (!_walkTimer.running() || _walkTimer.timeElapsed() > 300000.0
-						 || (_scene._character && _scene._character->walkModeStr() != "Walk"))) {
-			return false;
-			// Normal walk click
-		}
-	}
-
-	if (!app->frontLayout().isMouseIn(pt))
-		return false;
-
-	Common::String nearestMeshName = "None";
-	TeIntrusivePtr<TeCamera> curCamera = _scene.currentCamera();
-	Common::Array<TePickMesh2*> pickMeshes = _scene.clickMeshes();
-	TePickMesh2 *nearestMesh = TeFreeMoveZone::findNearestMesh(curCamera, pt, pickMeshes, nullptr, false);
-	if (nearestMesh) {
-		nearestMeshName = nearestMesh->name();
-		debug("Game::onMouseClick: Click near mesh %s", nearestMeshName.c_str());
-		_lastCharMoveMousePos = TeVector2s32();
-	}
-
-	Character *character = _scene._character;
-	if (app->isLockCursor() || _movePlayerCharacterDisabled || !character)
-		return false;
-
-	const Common::String &charAnim = character->curAnimName();
-
-	if (charAnim == character->characterSettings()._idleAnimFileName
-		|| charAnim == character->walkAnim(Character::WalkPart_Start)
-		|| charAnim == character->walkAnim(Character::WalkPart_Loop)
-		|| charAnim == character->walkAnim(Character::WalkPart_EndD)
-		|| charAnim == character->walkAnim(Character::WalkPart_EndG)) {
-		_luaScript.execute("On");
-		if (!_scene.isObjectBlocking(nearestMeshName) && character->freeMoveZone()) {
-			const TeVector3f32 charPos = character->_model->position();
-			TeIntrusivePtr<TeBezierCurve> curve = character->freeMoveZone()->curve(charPos, pt, 8.0, true);
-			if (!curve)
-				return false;
-
-			_scene.setCurve(curve);
-			character->setCurveStartLocation(TeVector3f32());
-			if (curve->controlPoints().size() == 1) {
-				character->endMove();
-			} else {
-				if (!_walkTimer.running() || _walkTimer.timeElapsed() > 300000 || !_runModeEnabled) {
-					_walkTimer.stop();
-					_walkTimer.start();
-					character->walkMode("Walk");
-				} else {
-					// Note: original checks the timer elapsed again here.. why?
-					_walkTimer.stop();
-					character->walkMode("Jog");
-				}
-				character->placeOnCurve(curve);
-				character->setCurveOffset(0.0);
-				if (charAnim != character->walkAnim(Character::WalkPart_Start)) {
-					character->setAnimation(character->walkAnim(Character::WalkPart_Start), false);
-				}
-				character->walkTo(1.0, false);
-				_sceneCharacterVisibleFromLoad = false;
-				_lastCharMoveMousePos = pt;
-			}
-		}
-		// FIXME: The original never checks for empty/null curve here..
-		// but it seems our curve can possibly become null.
-		if (_scene.curve() && _scene.curve()->length()) {
-			TeVector3f32 lastPoint = _scene.curve()->controlPoints().back();
-			character->setAnimation(character->walkAnim(Character::WalkPart_Loop), true);
-			character->walkTo(1.0, false);
-			_isCharacterWalking = true;
-			_posPlayer = lastPoint;
-		}
-	}
-
-	// Note: charAnim above may no longer be valid as anim may have changed.
-	if (_sceneCharacterVisibleFromLoad || (character->curAnimName() == character->characterSettings()._idleAnimFileName)) {
-		_lastCharMoveMousePos = TeVector2s32();
-		_movePlayerCharacterDisabled = false;
-		_isCharacterIdle = true;
-		_isCharacterWalking = false;
-		if (nearestMesh) {
-			character->stop();
-			_luaScript.execute("OnWarpObjectHit", nearestMeshName);
-		}
-	}
-
-	return false;
-}
 
 #ifdef TETRAEDGE_ENABLE_CUSTOM_CURSOR_CHECKS
 // Note: None of these cursor files seem to be actually shipped with the game
@@ -1330,46 +266,10 @@ bool Game::onMouseMove() {
 
 bool Game::onSkipVideoButtonValidated() {
 	TeSpriteLayout *sprite = _inGameGui.spriteLayoutChecked("video");
-	TeButtonLayout *btn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
 	sprite->stop();
-	btn->setVisible(false);
-	return false;
-}
-
-bool Game::onVideoFinished() {
-	if (!_inGameGui.loaded()) {
-		_music.stop();
-		return false;
-	}
-
-	Application *app = g_engine->getApplication();
-
-	app->captureFade();
-
-	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
-	Common::String vidPath = video->_tiledSurfacePtr->loadedPath();
-	TeButtonLayout *btn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
-	btn->setVisible(false);
-	btn = _inGameGui.buttonLayoutChecked("skipVideoButton");
-	btn->setVisible(false);
-	video->setVisible(false);
-	_music.stop();
-	_running = true;
-	bool resumed = false;
-	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
-		YieldedCallback &cb = _yieldedCallbacks[i];
-		if (cb._luaFnName == "OnMovieFinished" && cb._luaParam == vidPath) {
-			TeLuaThread *lua = cb._luaThread;
-			_yieldedCallbacks.remove_at(i);
-			resumed = true;
-			if (lua)
-				lua->resume();
-			break;
-		}
-	}
-	if (!resumed)
-		_luaScript.execute("OnMovieFinished", vidPath);
-	app->fade();
+	TeButtonLayout *btn = _inGameGui.buttonLayout("videoBackgroundButton");
+	if (btn)
+		btn->setVisible(false);
 	return false;
 }
 
@@ -1430,50 +330,6 @@ bool Game::playMovie(const Common::String &vidPath, const Common::String &musicP
 	}
 }
 
-void Game::playRandomSound(const Common::String &name) {
-	if (!_randomSounds.contains(name)) {
-		warning("Game::playRandomSound: can't find sound list %s", name.c_str());
-		return;
-	}
-
-	if (!_randomSoundFinished) {
-		_randomSoundTimer.start();
-		int r = g_engine->getRandomNumber(RAND_MAX);
-		float f = (r + 1 + (r / 100) * -100);
-		uint64 time = 1000000;
-		if (f >= 25.0) {
-			time = f * 45000.0;
-		}
-		_randomSoundTimer.setAlarmIn(time);
-		_randomSoundTimer.alarmSignal().remove(_randomSound, &RandomSound::onSoundFinished);
-		_randomSoundTimer.alarmSignal().add(_randomSound, &RandomSound::onSoundFinished);
-		_randomSound->_name = name;
-	} else {
-		Common::Array<RandomSound *> &sndlist = _randomSounds[name];
-		float total = 0.0;
-		for (auto *snd : sndlist) {
-			total += snd->_f1;
-		}
-		int r = g_engine->getRandomNumber(RAND_MAX);
-		float total2 = 0.0;
-		uint i = 0;
-		while (i < sndlist.size() && total2 <= r * 4.656613e-10 * total) {
-			total2 += sndlist[i]->_f1;
-			i++;
-		}
-		assert(i > 0);
-		i--;
-		RandomSound *sound = sndlist[i];
-		sound->_music.volume(sound->_volume);
-		sound->_music.onStopSignal().remove(sound, &RandomSound::onSoundFinished);
-		sound->_music.onStopSignal().add(sound, &RandomSound::onSoundFinished);
-		sound->_music.load(sound->_path.toString());
-		sound->_music.repeat(false);
-		sound->_music.play();
-		// TODO: set a flag that it's playing?
-	}
-}
-
 void Game::playSound(const Common::String &name, int repeats, float volume) {
 	Game *game = g_engine->getGame();
 
@@ -1525,43 +381,6 @@ void Game::removeNoScale2Child(TeLayout *layout) {
 	_noScaleLayout2->removeChild(layout);
 }
 
-void Game::removeNoScale2Children() {
-	if (!_noScaleLayout2)
-		return;
-
-	TeLayout *vidbtn = _inGameGui.layout("videoButtonLayout");
-	if (vidbtn)
-		_noScaleLayout2->removeChild(vidbtn);
-
-	TeLayout *bg = _inventory.cellphone()->gui().layout("background");
-	if (bg)
-		_noScaleLayout2->removeChild(bg);
-
-	TeButtonLayout *bgbtn = _objectif.gui1().buttonLayout("background");
-	if (bgbtn)
-		_noScaleLayout2->removeChild(bgbtn);
-
-	TeLayout *notifier = _notifier.gui().layout("notifier");
-	if (notifier)
-		_noScaleLayout2->removeChild(notifier);
-}
-
-void Game::removeNoScaleChildren() {
-	if (!_noScaleLayout)
-		return;
-	_noScaleLayout->removeChild(&_question2);
-	Application *app = g_engine->getApplication();
-	app->frontLayout().removeChild(&_dialog2);
-	_noScaleLayout->removeChild(&_inventory);
-	_noScaleLayout->removeChild(&_inventoryMenu);
-	_noScaleLayout->removeChild(&_documentsBrowser);
-	_noScaleLayout->removeChild(&_documentsBrowser.zoomedLayout());
-}
-
-void Game::resetPreviousMousePos() {
-	_previousMousePos = TeVector2s32(-1, -1);
-}
-
 void Game::resumeMovie() {
 	_music.play();
 	_inGameGui.spriteLayout("video")->play();
@@ -1674,189 +493,5 @@ Common::Error Game::syncGame(Common::Serializer &s) {
 	return Common::kNoError;
 }
 
-bool Game::unloadCharacter(const Common::String &charname) {
-	Character *c = _scene.character(charname);
-	if (!c)
-		return false;
-
-	for (uint i = 0; i < _scene.models().size(); i++) {
-		if (_scene.models()[i] == c->_model) {
-			_scene.models().remove_at(i);
-			break;
-		}
-	}
-	c->_onCharacterAnimFinishedSignal.remove(this, &Game::onCharacterAnimationFinished);
-	c->removeAnim();
-	// Syberia 2 uses a simplified callback here.
-	// We have made onDisplacementPlayerFinished more like Syberia 1's onDisplacementPlayerFinished.
-	if (g_engine->gameType() == TetraedgeEngine::kSyberia)
-		c->onFinished().remove(this, &Game::onDisplacementPlayerFinished);
-	else
-		c->onFinished().remove(this, &Game::onDisplacementFinished);
-	_scene.unloadCharacter(charname);
-	return true;
-}
-
-bool Game::unloadCharacters() {
-	// Loop will update the array, take a copy first.
-	Common::Array<Character *> chars = _scene._characters;
-	for (Character *c : chars) {
-		unloadCharacter(c->_model->name());
-	}
-	return true;
-}
-
-bool Game::unloadPlayerCharacter(const Common::String &charname) {
-	Character *c = _scene.character(charname);
-	if (c) {
-		c->_onCharacterAnimFinishedSignal.remove(this, &Game::onCharacterAnimationPlayerFinished);
-		c->onFinished().remove(this, &Game::onDisplacementPlayerFinished);
-		_scene.unloadCharacter(charname);
-	}
-	return c != nullptr;
-}
-
-void Game::update() {
-	if (!_entered)
-		return;
-
-	TeITextLayout *debugTimeTextLayout = _inGameGui.textLayout("debugTimeText1");
-	if (debugTimeTextLayout) {
-		warning("TODO: Game::update: Fill out debugTimeTextLayout");
-	}
-
-	if (!_warped) {
-		if (_gameLoadState == 2) {
-			initLoadedBackupData();
-			return;
-		} else if (_gameLoadState != 0) {
-			return;
-		}
-
-		Application *app = g_engine->getApplication();
-
-		if (_scene._character) {
-			if (!_scene._character->_model->visible())
-				app->lockCursor(false);
-		}
-
-		TeButtonLayout *invbtn = _inGameGui.buttonLayout("inventoryButton");
-		if (invbtn)
-			invbtn->setVisible(!app->isLockCursor() && !_dialog2.isDialogPlaying());
-
-		Character *player = _scene._character;
-		if (player) {
-			TeIntrusivePtr<TeModel> model = player->_model;
-			bool modelVisible = model->visible();
-			if (model->anim())
-				player->permanentUpdate();
-			if (modelVisible) {
-				if (player->needsSomeUpdate()) {
-					Game *game = g_engine->getGame();
-					game->_sceneCharacterVisibleFromLoad = false;
-					TeVector3f32 charPos = player->_model->position();
-					const Common::String charName = player->_model->name();
-					TeFreeMoveZone *zone = _scene.pathZone(player->freeMoveZoneName());
-					if (zone) {
-						TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
-						zone->setCamera(cam, false);
-						player->setFreeMoveZone(zone);
-						_scene.setPositionCharacter(charName, player->freeMoveZoneName(), charPos);
-						TeIntrusivePtr<TeBezierCurve> curve = zone->curve(model->position(), player->positionCharacter());
-						_scene.setCurve(curve);
-						player->setCurveStartLocation(TeVector3f32(0, 0, 0));
-						player->placeOnCurve(curve);
-						player->setCurveOffset(0.0f);
-						player->setAnimation(player->walkAnim(Character::WalkPart_Start), false);
-						player->walkTo(1.0f, false);
-						_isCharacterWalking = true;
-					}
-					player->setNeedsSomeUpdate(false);
-				}
-
-				const Common::String &charAnim = _scene._character->curAnimName();
-				bool unlockCursor = (charAnim == _scene._character->walkAnim(Character::WalkPart_Start) ||
-						charAnim == _scene._character->walkAnim(Character::WalkPart_Loop) ||
-						charAnim == _scene._character->walkAnim(Character::WalkPart_EndD) ||
-						charAnim == _scene._character->walkAnim(Character::WalkPart_EndG) ||
-						charAnim == _scene._character->characterSettings()._idleAnimFileName);
-				app->lockCursor(!unlockCursor);
-			}
-		}
-
-		Common::Array<Character *> characters = _scene._characters;
-		for (Character *c : characters) {
-			if (c->_model->anim())
-				c->permanentUpdate();
-		}
-
-		Common::Point mousePos = g_engine->getInputMgr()->lastMousePos();
-		if (_lastUpdateMousePos != mousePos) {
-			onMouseMove();
-			_lastUpdateMousePos = mousePos;
-		}
-		if (_saveRequested) {
-			_saveRequested = false;
-			saveBackup("save.xml");
-		}
-
-		_luaScript.execute("Update");
-		_objectif.update();
-		_scene.update();
-	} else {
-		TeSoundManager *soundmgr = g_engine->getSoundManager();
-		// Take a copy in case the active music objects changes as we iterate.
-		Common::Array<TeMusic *> musics = soundmgr->musics();
-		for (TeMusic *music : musics) {
-			const Common::String &chanName = music->channelName();
-			if (chanName != "music" && chanName != "sfx" && chanName != "dialog")
-				music->stop();
-		}
-		changeWarp2(_warpZone, _warpScene, _warpFadeFlag);
-	}
-}
-
-
-bool Game::HitObject::onChangeWarp() {
-	// Seems like this function is never used?
-	error("TODO: Implement Game::HitObject::onChangeWarp");
-	return false;
-}
-
-bool Game::HitObject::onDown() {
-	_game->luaScript().execute("OnButtonDown", _name);
-	_game->_isCharacterIdle = true;
-	return false;
-}
-
-bool Game::HitObject::onUp() {
-	// debug("Game::HitObject mouseup: %s", _name.c_str());
-	_game->luaScript().execute("OnButtonUp", _name);
-	_game->_isCharacterIdle = true;
-	return false;
-}
-
-bool Game::HitObject::onValidated() {
-	if (!g_engine->getApplication()->isLockCursor()) {
-		_game->luaScript().execute("OnWarpObjectHit", _name);
-		_game->_isCharacterIdle = true;
-	}
-	return false;
-}
-
-bool Game::RandomSound::onSoundFinished() {
-	Game *game = g_engine->getGame();
-	_music.onStopSignal().remove(this, &RandomSound::onSoundFinished);
-	if (game->_randomSoundFinished) {
-		game->_randomSoundFinished = false;
-	} else {
-		game->_randomSoundFinished = true;
-		game->_randomSound->_music.onStopSignal().remove(this, &RandomSound::onSoundFinished);
-		game->_randomSoundTimer.stop();
-	}
-	game->playRandomSound(_name);
-	return false;
-}
-
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index d91d2cb684a..b8502db1659 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -49,29 +49,7 @@ class TeLuaThread;
 class Game {
 public:
 	Game();
-	~Game();
-
-	struct HitObject {
-		bool onChangeWarp();
-		bool onDown();
-		bool onUp();
-		bool onValidated();
-		//byte OnVisible(); empty never used?
-
-		Common::String _name;
-		Game *_game;
-		TeButtonLayout *_button;
-	};
-
-	class RandomSound {
-	public:
-		Common::Path _path;
-		Common::String _name;
-		TeMusic _music;
-		float _f1;
-		float _volume;
-		bool onSoundFinished();
-	};
+	virtual ~Game();
 
 	struct YieldedCallback {
 		TeLuaThread *_luaThread;
@@ -81,46 +59,34 @@ public:
 		// Note: original game long, and int fields.. unused?
 	};
 
-	//enum EGameScoreID {}; // Not needed?
-
-	void addArtworkUnlocked(const Common::String &name, bool notify);
 	void addNoScale2Child(TeLayout *layout);
-	void addRandomSound(const Common::String &s1, const Common::String &s2, float f1, float f2);
-	void addToBag(const Common::String &objname);
-	void addToHand(const Common::String &objname);
-	void addToScore(int score);
+	virtual void addToBag(const Common::String &objname) = 0;
 
-	bool changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
+	virtual bool changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) = 0;
 
-	void draw();
-	void enter(); // will load game if _loadName is set.
+	virtual void draw() = 0;
+	virtual void enter() = 0; // will load game if _loadName is set.
 	// Note: game uses ILayouts here..
 	static TeI3DObject2 *findLayoutByName(TeLayout *parent, const Common::String &name);
 	static TeSpriteLayout *findSpriteLayoutByName(TeLayout *parent, const Common::String &name);
 
-	void finishFreemium();
-	void finishGame();
-	void initLoadedBackupData();
+	virtual void finishGame() = 0;
+	virtual void initLoadedBackupData() = 0;
 	bool isDocumentOpened();
 	bool isMouse() { return false; }
 	bool isMoviePlaying();
-	bool launchDialog(const Common::String &param_1, uint param_2, const Common::String &param_3,
-					  const Common::String &param_4, float param_5);
-	void leave(bool flag);
-	void loadBackup(const Common::String &path);
-	bool loadPlayerCharacter(const Common::String &name);
-	bool loadScene(const Common::String &name);
+	bool launchDialog(const Common::String &param_1, uint param_2, const Common::String &charname,
+					  const Common::String &animfile, float animblend);
+	virtual void leave(bool flag) = 0;
 
 	// Not in original. Load unlocked artwork from ScummVM config.
-	void loadUnlockedArtwork();
+	virtual void loadUnlockedArtwork() {};
 
 	//void pauseMovie(); // Unused
 	//void pauseSounds() {}; // Unused, does nothing?
 	bool playMovie(const Common::String &vidPath, const Common::String &musicPath, float volume = 1.0f);
-	void playRandomSound(const Common::String &name);
 	void playSound(const Common::String &name, int param_2, float volume);
 	void removeNoScale2Child(TeLayout *layout);
-	void resetPreviousMousePos();
 	void resumeMovie();
 	void resumeSounds() {}; // does nothing?
 	void saveBackup(const Common::String &saveName);
@@ -131,10 +97,7 @@ public:
 	// void startAnimationPart(const Common::String &param_1, int param_2, int param_3, int param_4, bool param_5) {}; // Unused.
 	void stopSound(const Common::String &name);
 	Common::Error syncGame(Common::Serializer &s); // Basically replaces saveBackup from original..
-	bool unloadCharacter(const Common::String &character);
-	bool unloadCharacters();
-	bool unloadPlayerCharacter(const Common::String &character);
-	void update();
+	virtual void update() = 0;
 
 	InventoryMenu &inventoryMenu() { return _inventoryMenu; }
 	Inventory &inventory() { return _inventory; }
@@ -145,14 +108,9 @@ public:
 
 	bool _returnToMainMenu;
 	bool _firstInventory;
-	bool _movePlayerCharacterDisabled;
-	bool _sceneCharacterVisibleFromLoad;
-	bool _isCharacterWalking;
-	bool _isCharacterIdle;
 
 	const Common::String &currentZone() const { return _currentZone; }
 	const Common::String &currentScene() const { return _currentScene; }
-	const Common::Path &sceneZonePath() const { return _sceneZonePath; }
 	TeLuaScript &luaScript() { return _luaScript; }
 	TeLuaContext &luaContext() { return _luaContext; }
 	InGameScene &scene() { return _scene; }
@@ -160,108 +118,45 @@ public:
 	Question2 &question2() { return _question2; }
 	TeLuaGUI &forGui() { return _forGui; }
 	TeLuaGUI &inGameGui() { return _inGameGui; }
-	Objectif &objectif() { return _objectif; }
-	Common::Array<YieldedCallback> &yieldedCallbacks() { return _yieldedCallbacks; }
-	void setSaveRequested() { _saveRequested = true; }
-	bool markersVisible() const { return _markersVisible; }
-	const TeVector3f32 &posPlayer() const { return _posPlayer; }
-	void setPosPlayer(const TeVector3f32 &pos) { _posPlayer = pos; }
-	TeTimer &walkTimer() { return _walkTimer; }
-	void setExitZone(const Common::String &zone) { _exitZone = zone; }
-	void setLoadName(const Common::String &loadName) { _loadName = loadName; }
 	bool hasLoadName() const { return !_loadName.empty(); }
-	bool isArtworkUnlocked(const Common::String &name) const;
-	static Common::String artworkConfName(const Common::String &name);
-
-	void setRunModeEnabled(bool val) { _runModeEnabled = val; }
-	bool runModeEnabled() const { return _runModeEnabled; }
-
-private:
-	bool addAnimToSet(const Common::String &path);
-	void addNoScale2Children();
-	void addNoScaleChildren();
-
-	void attachButtonsLayoutGoto() {}; // does nothing?
-	void createButtonsLayoutGoto() {}; // does nothing?
-	void deleteButtonsLayoutGoto() {}; // does nothing?
-
-	bool changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag);
-
-	void deleteNoScale();
-
-	void initNoScale();
-	void initScene(bool param_1, const Common::String &scenePath);
-	bool initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
-
-	bool loadCharacter(const Common::String &name);
+	void setLoadName(const Common::String &loadName) { _loadName = loadName; }
 
 	bool onAnswered(const Common::String &val);
-	bool onCallNumber(Common::String val);
-	bool onCharacterAnimationFinished(const Common::String &val);
-	bool onCharacterAnimationPlayerFinished(const Common::String &val);
-	bool onDialogFinished(const Common::String &val);
-	bool onDisplacementFinished();
-	bool onDisplacementPlayerFinished();
-	bool onFinishedCheckBackup(bool result);
-	bool onFinishedLoadingBackup(const Common::String &val);
-	bool onFinishedSavingBackup(int something);
+	virtual bool onDialogFinished(const Common::String &val) = 0;
+	virtual bool onFinishedLoadingBackup(const Common::String &val) { return false; }
 	bool onInventoryButtonValidated();
 	bool onLockVideoButtonValidated();
-	bool onMarkersVisible(TeCheckboxLayout::State state);
-	bool onMouseClick(const Common::Point &pt);
 	bool onMouseMove();
 	bool onSkipVideoButtonValidated();
-	bool onVideoFinished();
-
-	void removeNoScale2Children();
-	void removeNoScaleChildren();
+	virtual bool onVideoFinished() = 0;
 
+protected:
 	bool _luaShowOwnerError;
 	bool _running;
 	bool _entered;
-	bool _enteredFlag2;
 
-	TeLuaGUI _gui1; // TODO: Is this ever used?
+	//TeLuaGUI _gui1; // Never used.
 	TeLuaGUI _setAnimGui;
 	TeLuaGUI _forGui;
 	TeLuaGUI _inGameGui;
 
 	Inventory _inventory;
 	InventoryMenu _inventoryMenu;
-	int _score;
-
-	int _frameCounter;
 
 	InGameScene _scene;
 
-	static char **_objectsTakenIDs;
-
-	TeVector2s32 _previousMousePos;
-	TeVector2s32 _lastCharMoveMousePos;
-
-	Common::String _warpZone;
-	Common::String _warpScene;
-	bool _warpFadeFlag;
-	bool _warped;
+	Common::String _loadName;
 
-	Common::String _currentZone;
 	Common::String _currentScene;
-	Common::String _exitZone;
+	Common::String _currentZone;
 	Common::String _prevSceneName;
-	Common::String _someSceneName;
-	Common::Path _sceneZonePath;
-
-	Common::String _loadName;
 
 	Common::Array<GameSound *> _gameSounds;
-	Common::Array<HitObject *> _gameHitObjects;
-	// These are static in original, but cleaner to keep here.
-	Common::Array<YieldedCallback> _yieldedCallbacks;
-
-	Common::HashMap<Common::String, bool> _unlockedArtwork;
-	Common::HashMap<Common::String, Common::Array<RandomSound *>> _randomSounds;
 
-	int _gameLoadState;
+	static const int NUM_OBJECTS_TAKEN_IDS = 5;
+	static const char *OBJECTS_TAKEN_IDS[NUM_OBJECTS_TAKEN_IDS];
+	bool _objectsTakenBits[NUM_OBJECTS_TAKEN_IDS];
+	int _objectsTakenVal;
 
 	TeTimer _playedTimer;
 	TeTimer _walkTimer;
@@ -274,30 +169,11 @@ private:
 
 	Question2 _question2;
 	Dialog2 _dialog2;
-	Objectif _objectif;
 
-	static const int NUM_OBJECTS_TAKEN_IDS = 5;
-	static const char *OBJECTS_TAKEN_IDS[NUM_OBJECTS_TAKEN_IDS];
-	bool _objectsTakenBits[NUM_OBJECTS_TAKEN_IDS];
-	int _objectsTakenVal;
 	int _dialogsTold;
 
-	bool _markersVisible;
-	bool _saveRequested;
-	bool _randomSoundFinished;
-
-	RandomSound *_randomSound;
-	TeTimer _randomSoundTimer;
-
-	TeLayout *_noScaleLayout;
 	TeLayout *_noScaleLayout2;
 
-	TeVector3f32 _posPlayer;
-
-	Common::Point _lastUpdateMousePos;
-
-	// Syberia 2 specific data
-	bool _runModeEnabled;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/game_sound.cpp b/engines/tetraedge/game/game_sound.cpp
index b7f45c3cee1..b0b0b6261a5 100644
--- a/engines/tetraedge/game/game_sound.cpp
+++ b/engines/tetraedge/game/game_sound.cpp
@@ -20,7 +20,7 @@
  */
 
 #include "tetraedge/game/game_sound.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/tetraedge.h"
 
 #include "tetraedge/te/te_lua_thread.h"
@@ -31,11 +31,12 @@ GameSound::GameSound() {
 }
 
 bool GameSound::onSoundStopped() {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	if (!game->luaContext().isCreated())
 		return false;
 
-	Common::Array<Game::YieldedCallback> &callbacks = game->yieldedCallbacks();
+	Common::Array<SyberiaGame::YieldedCallback> &callbacks = game->yieldedCallbacks();
 	for (uint i = 0; i < callbacks.size(); i++) {
 		if (callbacks[i]._luaFnName == "OnFreeSoundFinished" && callbacks[i]._luaParam == _name) {
 			TeLuaThread *thread = callbacks[i]._luaThread;
diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 32e4b39ec71..23134f6965f 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -26,7 +26,7 @@
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/game/billboard.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/game/in_game_scene.h"
 #include "tetraedge/game/in_game_scene_xml_parser.h"
 #include "tetraedge/game/character.h"
@@ -108,7 +108,8 @@ void InGameScene::addAnchorZone(const Common::String &s1, const Common::String &
 bool InGameScene::addMarker(const Common::String &markerName, const Common::String &imgPath, float x, float y, const Common::String &locType, const Common::String &markerVal, float anchorX, float anchorY) {
 	const TeMarker *marker = findMarker(markerName);
 	if (!marker) {
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		Application *app = g_engine->getApplication();
 		TeSpriteLayout *markerSprite = new TeSpriteLayout();
 		// Note: game checks paths here but seems to just use the original?
@@ -550,7 +551,8 @@ void InGameScene::freeSceneObjects() {
 		_characters[0]->deleteAllCallback();
 	}
 
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->unloadCharacters();
 
 	_characters.clear();
@@ -1456,7 +1458,8 @@ void InGameScene::loadInteractions(const Common::FSNode &node) {
 void InGameScene::moveCharacterTo(const Common::String &charName, const Common::String &curveName, float curveOffset, float curveEnd) {
 	Character *c = character(charName);
 	if (c != nullptr && c != _character) {
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		if (!game->_movePlayerCharacterDisabled) {
 			c->setCurveStartLocation(c->characterSettings()._cutSceneCurveDemiPosition);
 			TeIntrusivePtr<TeBezierCurve> crve = curve(curveName);
@@ -1657,7 +1660,8 @@ void InGameScene::unloadSpriteLayouts() {
 }
 
 void InGameScene::update() {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	if (_bgGui.loaded()) {
 		_bgGui.layoutChecked("background")->setZPosition(0.0f);
 	}
@@ -1730,7 +1734,7 @@ void InGameScene::update() {
 		_waitTimeTimer.stop();
 		bool resumed = false;
 		for (uint i = 0; i < game->yieldedCallbacks().size(); i++) {
-			Game::YieldedCallback &yc = game->yieldedCallbacks()[i];
+			SyberiaGame::YieldedCallback &yc = game->yieldedCallbacks()[i];
 			if (yc._luaFnName == "OnWaitFinished") {
 				TeLuaThread *thread = yc._luaThread;
 				game->yieldedCallbacks().remove_at(i);
@@ -1878,9 +1882,10 @@ void InGameScene::activateMask(const Common::String &name, bool val) {
 }
 
 bool InGameScene::AnimObject::onFinished() {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	for (uint i = 0; i < game->yieldedCallbacks().size(); i++) {
-		Game::YieldedCallback &yc = game->yieldedCallbacks()[i];
+		SyberiaGame::YieldedCallback &yc = game->yieldedCallbacks()[i];
 		if (yc._luaFnName == "OnFinishedAnim" && yc._luaParam == _name) {
 			TeLuaThread *thread = yc._luaThread;
 			game->yieldedCallbacks().remove_at(i);
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index de23497c344..ad5f50507ad 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -27,6 +27,7 @@
 #include "tetraedge/game/game.h"
 #include "tetraedge/game/lua_binds.h"
 #include "tetraedge/game/object3d.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/to_lua.h"
 #include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_lua_thread.h"
@@ -131,11 +132,12 @@ static int tolua_ExportedFunctions_PlayMovieAndWaitForEnd00(lua_State *L) {
 		Common::String s2(tolua_tostring(L, 2, nullptr));
 		PlayMovie(s1, s2);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnMovieFinished";
 		callback._luaParam = s1;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == s1)
 				warning("PlayMovieAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -147,7 +149,8 @@ static int tolua_ExportedFunctions_PlayMovieAndWaitForEnd00(lua_State *L) {
 }
 
 static void AddRandomSound(const Common::String &s1, const Common::String &s2, float f1, float f2){
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->addRandomSound(s1, s2, f1, f2);
 }
 
@@ -219,7 +222,8 @@ static int tolua_ExportedFunctions_TakeObject00(lua_State *L) {
 }
 
 static void TakeObjectInHand(const Common::String &obj) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	// TODO: Set global _lastHitObjectName?? How is it used?
 	//game->luaContext().setGlobal(_lastHitObjectName, true);
 	if (!obj.empty())
@@ -391,7 +395,8 @@ static int tolua_ExportedFunctions_AddUnrecalAnim00(lua_State *L) {
 }
 
 static void UnlockArtwork(const Common::String &name) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->addArtworkUnlocked(name, true);
 	Application *app = g_engine->getApplication();
 	app->saveOptions("options.xml");
@@ -442,7 +447,8 @@ static int tolua_ExportedFunctions_SetCharacterPlayerVisible00(lua_State *L) {
 }
 
 static void MoveCharacterPlayerDisabled(bool val) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->_movePlayerCharacterDisabled = val;
 }
 
@@ -714,11 +720,12 @@ int tolua_ExportedFunctions_StartAnimationAndWaitForEnd00(lua_State *L) {
 		bool b1 = tolua_toboolean(L, 3, false);
 		StartAnimation(s1, d1, b1);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnFinishedAnim";
 		callback._luaParam = s1;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == s1)
 				warning("StartAnimationAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -732,7 +739,8 @@ int tolua_ExportedFunctions_StartAnimationAndWaitForEnd00(lua_State *L) {
 }
 
 static void RequestAutoSave() {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->setSaveRequested();
 }
 
@@ -985,12 +993,13 @@ static int tolua_ExportedFunctions_SetCharacterAnimationAndWaitForEnd00(lua_Stat
 		double f4 = tolua_tonumber(L, 6, 9999.0);
 		SetCharacterAnimation(s1, s2, b1, b2, (int)f3, (int)f4);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnCharacterAnimationFinished";
 		callback._luaParam = s1;
 		callback._luaParam2 = s2;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == s1 && cb._luaParam2 == s2)
 				warning("SetCharacterAnimationAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -1039,12 +1048,13 @@ static int tolua_ExportedFunctions_BlendCharacterAnimationAndWaitForEnd00(lua_St
 		bool b2 = tolua_toboolean(L, 5, false);
 		BlendCharacterAnimation(s1, s2, f1, b1, b2);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnCharacterAnimationFinished";
 		callback._luaParam = s1;
 		callback._luaParam2 = s2;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == s1 && cb._luaParam2 == s2)
 				warning("BlendCharacterAnimationAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -1341,7 +1351,8 @@ static int tolua_ExportedFunctions_HideBillboard00(lua_State *L) {
 }
 
 static void UnlockAchievement(int val) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->addToScore(val);
 }
 
@@ -1394,10 +1405,11 @@ static int tolua_ExportedFunctions_WaitAndWaitForEnd00(lua_State *L) {
 		double d = tolua_tonumber(L, 1, 0.0);
 		Wait(d);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnWaitFinished";
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName)
 				warning("WaitAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -1488,11 +1500,12 @@ static int tolua_ExportedFunctions_LaunchDialogAndWaitForEnd00(lua_State *L) {
 		float f2 = tolua_tonumber(L, 5, 0.0);
 		LaunchDialog(s1, f1, s2, s3, f2);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnDialogFinished";
 		callback._luaParam = s1;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == callback._luaParam)
 				warning("LaunchDialogAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -1539,7 +1552,8 @@ static int tolua_ExportedFunctions_HideAnswers00(lua_State *L) {
 }
 
 static void PushTask(const Common::String &s1, const Common::String &s2) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->objectif().pushObjectif(s1, s2);
 }
 
@@ -1555,7 +1569,8 @@ static int tolua_ExportedFunctions_PushTask00(lua_State *L) {
 }
 
 static void DeleteTask(const Common::String &s1, const Common::String &s2) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->objectif().deleteObjectif(s1, s2);
 }
 
@@ -1574,7 +1589,8 @@ static int tolua_ExportedFunctions_DeleteTask00(lua_State *L) {
 }
 
 static void SetVisibleButtonHelp(bool val) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->objectif().setVisibleButtonHelp(val);
 }
 
@@ -1609,7 +1625,8 @@ static int tolua_ExportedFunctions_TestFileFlagSystemFlag00(lua_State *L) {
 }
 
 static void ExitZone(const Common::String &zone) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->setExitZone(zone);
 }
 
@@ -1915,11 +1932,12 @@ static int tolua_ExportedFunctions_PlaySoundAndWaitForEnd00(lua_State *L) {
 		double d2 = tolua_tonumber(L, 3, 1.0);
 		PlaySound(s1, d1, d2);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnFreeSoundFinished";
 		callback._luaParam = s1;
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName && cb._luaParam == s1)
 				warning("PlaySoundAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -1946,7 +1964,8 @@ static int tolua_ExportedFunctions_StopSound00(lua_State *L) {
 }
 
 static void PlayRandomSound(const Common::String &name) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->playRandomSound(name);
 }
 
@@ -2132,7 +2151,8 @@ static int tolua_ExportedFunctions_CurrentCharacterAnimation00(lua_State *L) {
 }
 
 static void LoadCharacter(const Common::String &name) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->loadCharacter(name);
 }
 
@@ -2147,7 +2167,8 @@ static int tolua_ExportedFunctions_LoadCharacter00(lua_State *L) {
 }
 
 static void UnloadCharacter(const Common::String &name) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->unloadCharacter(name);
 }
 
@@ -2192,10 +2213,11 @@ static int tolua_ExportedFunctions_MoveCharacterToAndWaitForEnd00(lua_State *L)
 		float f2 = tolua_tonumber(L, 4, 0.0);
 		MoveCharacterTo(s1, s2, f1, f2);
 
-		Game::YieldedCallback callback;
+		SyberiaGame::YieldedCallback callback;
 		callback._luaThread = TeLuaThread::threadFromState(L);
 		callback._luaFnName = "OnDisplacementFinished";
-		Game *game = g_engine->getGame();
+		SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+		assert(game);
 		for (const auto &cb : game->yieldedCallbacks()) {
 			if (cb._luaFnName == callback._luaFnName)
 				warning("MoveCharacterToAndWaitForEnd: Reentrency error, your are already in a yielded/sync function call");
@@ -2207,7 +2229,8 @@ static int tolua_ExportedFunctions_MoveCharacterToAndWaitForEnd00(lua_State *L)
 }
 
 static void MoveCharacterPlayerTo(float x, float y, float z, bool walkFlag) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	if (game->_movePlayerCharacterDisabled)
 		return;
 
@@ -2263,7 +2286,8 @@ static int tolua_ExportedFunctions_MoveCharacterPlayerTo00(lua_State *L) {
 }
 
 static void EnableRunMode(bool val) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	game->setRunModeEnabled(val);
 }
 
@@ -2278,7 +2302,8 @@ static int tolua_ExportedFunctions_EnableRunMode00(lua_State *L) {
 }
 
 static void SetModelPlayer(const Common::String &name) {
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	Character *character = game->scene()._character;
 
 	if (!character) {
diff --git a/engines/tetraedge/game/syberia_game.cpp b/engines/tetraedge/game/syberia_game.cpp
new file mode 100644
index 00000000000..f96c542cf18
--- /dev/null
+++ b/engines/tetraedge/game/syberia_game.cpp
@@ -0,0 +1,1458 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/file.h"
+#include "common/path.h"
+#include "common/str-array.h"
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "tetraedge/game/syberia_game.h"
+
+#include "tetraedge/tetraedge.h"
+#include "tetraedge/game/application.h"
+#include "tetraedge/game/character.h"
+#include "tetraedge/game/in_game_scene.h"
+#include "tetraedge/game/game_achievements.h"
+#include "tetraedge/game/lua_binds.h"
+#include "tetraedge/game/object3d.h"
+
+#include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_core.h"
+#include "tetraedge/te/te_input_mgr.h"
+#include "tetraedge/te/te_ray_intersection.h"
+#include "tetraedge/te/te_sound_manager.h"
+#include "tetraedge/te/te_variant.h"
+#include "tetraedge/te/te_lua_thread.h"
+
+namespace Tetraedge {
+
+SyberiaGame::SyberiaGame() : Game(),
+_enteredFlag2(false), _movePlayerCharacterDisabled(false),
+_noScaleLayout(nullptr), _isCharacterIdle(true),
+_sceneCharacterVisibleFromLoad(false), _isCharacterWalking(false),
+_lastCharMoveMousePos(0.0f, 0.0f), _randomSoundFinished(false),
+_previousMousePos(-1, -1), _markersVisible(true), _saveRequested(false),
+_gameLoadState(0), _score(0), _warped(false), _frameCounter(0),
+_warpFadeFlag(false), _runModeEnabled(true) {
+	_randomSound = new RandomSound();
+}
+
+SyberiaGame::~SyberiaGame() {
+	if (_entered) {
+		leave(true);
+	}
+	delete _randomSound;
+}
+
+bool SyberiaGame::addAnimToSet(const Common::String &anim) {
+	// Get path to lua script, eg scenes/ValVoralberg/14040/Set14040.lua
+	const Common::Path animPath(Common::String("scenes/") + anim + "/");
+
+	if (Common::File::exists(animPath)) {
+		const Common::StringArray parts = TetraedgeEngine::splitString(anim, '/');
+		assert(parts.size() >= 2);
+
+		const Common::String layoutName = parts[1];
+		const Common::String path = Common::String("scenes/") + parts[0] + "/" + parts[1] + "/Set" + parts[1];
+
+		_setAnimGui.load(path + ".lua");
+
+		// Note: game makes this here, but never uses it..
+		// it seems like a random memory leak??
+		// TeSpriteLayout *spritelayout = new TeSpriteLayout();
+
+		TeSpriteLayout *spritelayout = findSpriteLayoutByName(_setAnimGui.layoutChecked("root"), layoutName);
+
+		_scene.bgGui().layoutChecked("root")->addChild(spritelayout);
+		return true;
+	}
+
+	return false;
+}
+
+/*static*/
+Common::String SyberiaGame::artworkConfName(const Common::String &name) {
+	Common::String configName = Common::String::format("artwork_%s", name.c_str());
+	for (uint i = 0; i < configName.size(); i++) {
+		if (configName[i] == '/' || configName[i] == '.')
+			configName.setChar('_', i);
+	}
+	return configName;
+}
+
+void SyberiaGame::addArtworkUnlocked(const Common::String &name, bool notify) {
+	const Common::String configName = artworkConfName(name);
+	if (_unlockedArtwork.contains(configName))
+		return;
+	ConfMan.setBool(configName, true);
+	ConfMan.flushToDisk();
+	_unlockedArtwork[configName] = true;
+	if (notify)
+		_notifier.push("BONUS!", "Inventory/Objects/VPapierCrayon.png");
+}
+
+bool SyberiaGame::isArtworkUnlocked(const Common::String &name) const {
+	const Common::String configName = artworkConfName(name);
+	return _unlockedArtwork.getValOrDefault(configName, false);
+}
+
+void SyberiaGame::addNoScale2Children() {
+	if (!_noScaleLayout2)
+		return;
+
+	TeLayout *vidbtn = _inGameGui.layout("videoButtonLayout");
+	if (vidbtn)
+		_noScaleLayout2->addChild(vidbtn);
+
+	TeLayout *bg = _inventory.cellphone()->gui().layout("background");
+	if (bg)
+		_noScaleLayout2->addChild(bg);
+
+	TeButtonLayout *bgbtn = _objectif.gui1().buttonLayout("background");
+	if (bgbtn)
+		_noScaleLayout2->addChild(bgbtn);
+}
+
+void SyberiaGame::addNoScaleChildren() {
+	if (!_noScaleLayout)
+		return;
+	TeLayout *inGame = _inGameGui.layout("inGame");
+	if (inGame)
+		_noScaleLayout->addChild(inGame);
+
+	_noScaleLayout->addChild(&_question2);
+
+	Application *app = g_engine->getApplication();
+	app->frontLayout().addChild(&_dialog2);
+
+	_noScaleLayout->addChild(&_inventory);
+	_noScaleLayout->addChild(&_inventoryMenu);
+	_noScaleLayout->addChild(&_documentsBrowser);
+	_noScaleLayout->addChild(&_documentsBrowser.zoomedLayout());
+}
+
+void SyberiaGame::addRandomSound(const Common::String &name, const Common::String &path, float f1, float volume) {
+	if (!_randomSounds.contains(name)) {
+		_randomSounds[name] = Common::Array<RandomSound*>();
+	}
+	RandomSound *randsound = new RandomSound();
+	randsound->_path = path;
+	randsound->_f1 = f1;
+	randsound->_volume = volume;
+	randsound->_name = name;
+	_randomSounds[name].push_back(randsound);
+}
+
+void SyberiaGame::addToBag(const Common::String &objid) {
+	if (_inventory.objectCount(objid) != 0)
+		return;
+	_inventory.addObject(objid);
+	Common::String imgpath("Inventory/Objects/");
+	imgpath += objid;
+	imgpath += ".png";
+	_notifier.push(_inventory.objectName(objid), imgpath);
+	for (int i = 0; i < NUM_OBJECTS_TAKEN_IDS; i++) {
+		if (objid == OBJECTS_TAKEN_IDS[i] && !_objectsTakenBits[i]) {
+			_objectsTakenBits[i] = true;
+			_objectsTakenVal++;
+		}
+	}
+
+	_score += 10;
+	debug("Updated score: %d", _score);
+}
+
+void SyberiaGame::addToHand(const Common::String &objname) {
+	_inventory.addObject(objname);
+	_inventory.selectedObject(objname);
+}
+
+void SyberiaGame::addToScore(int score) {
+	_score += score;
+}
+
+bool SyberiaGame::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
+	//debug("Game::changeWarp(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
+	Application *app = g_engine->getApplication();
+	if (fadeFlag && g_engine->gameType() == TetraedgeEngine::kSyberia) {
+		app->blackFade();
+	} else {
+		app->captureFade();
+	}
+	// Slight divergence from original.. free after capturing fade so characters don't disappear.
+	if (g_engine->gameType() == TetraedgeEngine::kSyberia2)
+		_scene.freeGeometry();
+
+	_warpZone = zone;
+	_warpScene = scene;
+	_warpFadeFlag = fadeFlag;
+	_warped = true;
+	return true;
+}
+
+bool SyberiaGame::changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
+	//debug("Game::changeWarp2(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
+	_warped = false;
+	_movePlayerCharacterDisabled = false;
+	_sceneCharacterVisibleFromLoad = false;
+	// TODO? _charMoveMouseEventNo = -1?
+	_isCharacterIdle = true;
+	_isCharacterWalking = false;
+	Common::Path luapath("scenes");
+	luapath.joinInPlace(zone);
+	luapath.joinInPlace(scene);
+	luapath.joinInPlace("Logic");
+	luapath.appendInPlace(scene);
+	luapath.appendInPlace(".lua");
+
+	if (g_engine->getCore()->findFile(luapath).exists()) {
+		_luaScript.execute("OnLeave");
+		_luaContext.removeGlobal("On");
+		_luaContext.removeGlobal("OnEnter");
+		_luaContext.removeGlobal("OnWarpObjectHit");
+		_luaContext.removeGlobal("OnButtonDown");
+		_luaContext.removeGlobal("OnButtonUp");
+		_luaContext.removeGlobal("OnFinishedAnim");
+		_luaContext.removeGlobal("OnCharacterAnimationFinished");
+		_luaContext.removeGlobal("OnCharacterAnimationPlayerFinished");
+		_luaContext.removeGlobal("OnDisplacementFinished");
+		_luaContext.removeGlobal("OnFreeSoundFinished");
+		_luaContext.removeGlobal("OnDocumentClosed");
+		_luaContext.removeGlobal("OnSelectedObject");
+		_luaContext.removeGlobal("OnDialogFinished");
+		_luaContext.removeGlobal("OnAnswered");
+		_luaContext.removeGlobal("OnLeave");
+		_luaScript.unload();
+	}
+
+	_forGui.unload();
+	_prevSceneName = _currentScene;
+	if (!fadeFlag)
+		g_engine->getApplication()->fade();
+
+	return initWarp(zone, scene, false);
+}
+
+void SyberiaGame::deleteNoScale() {
+	if (_noScaleLayout) {
+		removeNoScaleChildren();
+		delete _noScaleLayout;
+		_noScaleLayout = nullptr;
+	}
+	if (_noScaleLayout2) {
+		removeNoScale2Children();
+		delete _noScaleLayout2;
+		_noScaleLayout2 = nullptr;
+	}
+}
+
+void SyberiaGame::draw() {
+	if (_running) {
+		_frameCounter++;
+		_scene.draw();
+	}
+}
+
+void SyberiaGame::enter() {
+	_enteredFlag2 = true;
+	_entered = true;
+	_luaShowOwnerError = false;
+	_score = 0;
+	Application *app = g_engine->getApplication();
+	app->visualFade().init();
+	// TODO: Original puts this click handler at -10000.. but then it never gets hit?
+	Common::SharedPtr<TeCallback1Param<SyberiaGame, const Common::Point &>> callbackptr(new TeCallback1Param<SyberiaGame, const Common::Point &>(this, &SyberiaGame::onMouseClick, 10000.0f));
+	g_engine->getInputMgr()->_mouseLUpSignal.push_back(callbackptr);
+	_movePlayerCharacterDisabled = false;
+	// TODO? Set _charMoveMouseEventNo = -1
+	_isCharacterIdle = true;
+	_sceneCharacterVisibleFromLoad = false;
+	Character::loadSettings("models/ModelsSettings.xml");
+	Object3D::loadSettings("objects/ObjectsSettings.xml");
+	if (_scene._character) {
+		_scene._character->onFinished().remove(this, &SyberiaGame::onDisplacementPlayerFinished);
+		_scene.unloadCharacter(_scene._character->_model->name());
+	}
+	bool loaded = loadPlayerCharacter("Kate");
+	if (!loaded)
+		error("[Game::enter] Can't load player character");
+
+	_scene._character->_model->setVisible(true);
+	_running = true;
+	_luaContext.create();
+	GameAchievements::registerAchievements(_luaContext);
+
+	_luaContext.setGlobal("BUTTON_VALID", 1);
+	_luaContext.setGlobal("BUTTON_CANCEL", 2);
+	_luaContext.setGlobal("BUTTON_EXTRA1", 4);
+	_luaContext.setGlobal("BUTTON_EXTRA2", 8);
+	_luaContext.setGlobal("BUTTON_L1", 0x10);
+	_luaContext.setGlobal("BUTTON_R1", 0x20);
+	_luaContext.setGlobal("BUTTON_START", 0x40);
+	_luaContext.setGlobal("BUTTON_UP", 0x80);
+	_luaContext.setGlobal("BUTTON_DOWN", 0x100);
+	_luaContext.setGlobal("BUTTON_LEFT", 0x200);
+	_luaContext.setGlobal("BUTTON_RIGHT", 0x400);
+	_luaContext.setGlobal("BUTTON_LS_CLIC", 0x800);
+	_luaContext.setGlobal("BUTTON_RS_CLIC", 0x1000);
+	_luaContext.setGlobal("BUTTON_BACK", 0x2000);
+	_luaContext.setGlobal("BUTTON_SELECT", 0x4000);
+	_luaContext.setGlobal("BUTTON_L2", 0x8000);
+	_luaContext.setGlobal("BUTTON_R2", 0x10000);
+	_luaContext.setGlobal("BUTTON_LS_UP", 0x20000);
+	_luaContext.setGlobal("BUTTON_LS_DOWN", 0x40000);
+	_luaContext.setGlobal("BUTTON_LS_LEFT", 0x80000);
+	_luaContext.setGlobal("BUTTON_LS_RIGHT", 0x100000);
+	_luaContext.setGlobal("BUTTON_RS_UP", 0x200000);
+	_luaContext.setGlobal("BUTTON_RS_DOWN", 0x400000);
+	_luaContext.setGlobal("BUTTON_RS_LEFT", 0x800000);
+	_luaContext.setGlobal("BUTTON_RS_RIGHT", 0x1000000);
+
+	_gameEnterScript.attachToContext(&_luaContext);
+
+	if (!_objectif.gui1().loaded()) {
+		_objectif.load();
+	}
+	_question2.load();
+	_dialog2.load();
+	_documentsBrowser.load();
+	_documentsBrowser.loadZoomed();
+	_inventory.load();
+
+	_inventory.cellphone()->onCallNumber().add(this, &SyberiaGame::onCallNumber);
+
+	if (hasLoadName()) {
+		loadBackup(_loadName);
+	} else {
+		_gameLoadState = 1;
+		onFinishedLoadingBackup("");
+	}
+	_sceneCharacterVisibleFromLoad = true;
+	_scene._character->onFinished().remove(this, &SyberiaGame::onDisplacementPlayerFinished);
+	_scene._character->onFinished().add(this, &SyberiaGame::onDisplacementPlayerFinished);
+	_prevSceneName.clear();
+	_notifier.load();
+}
+
+void SyberiaGame::finishFreemium() {
+	Application *app = g_engine->getApplication();
+	app->setFinishedGame(true);
+	app->setFinishedFremium(true);
+}
+
+void SyberiaGame::finishGame() {
+	Application *app = g_engine->getApplication();
+	// FIXME: The original sets this, but then Application::run immediately
+	// returns to the menu.. how does the original wait for the credits to end??
+	//app->_finishedGame = true;
+	_playedTimer.stop();
+	/* Game does this but does nothing with result?
+	if (app->difficulty() == 2) {
+		_playedTimer.getTimeFromStart();
+	} */
+	app->credits().enter(false);
+}
+
+void SyberiaGame::initLoadedBackupData() {
+	bool warpFlag = true;
+	Application *app = g_engine->getApplication();
+	Common::String firstWarpPath;
+	if (!_loadName.empty()) {
+		warpFlag = false;
+		Common::InSaveFile *saveFile = g_engine->getSaveFileManager()->openForLoading(_loadName);
+		Common::Error result = g_engine->loadGameStream(saveFile);
+		if (result.getCode() == Common::kNoError) {
+			ExtendedSavegameHeader header;
+			if (MetaEngine::readSavegameHeader(saveFile, &header))
+				g_engine->setTotalPlayTime(header.playtime);
+		}
+	} else {
+		firstWarpPath = app->firstWarpPath();
+		_currentScene = app->firstScene();
+		_currentZone = app->firstZone();
+		_playedTimer.start();
+		_objectsTakenVal = 0;
+		for (int i = 0; i < ARRAYSIZE(_objectsTakenBits); i++) {
+			_objectsTakenBits[i] = 0;
+		}
+		_dialogsTold = 0;
+		if (_loadName == "NO_OWNER")
+			_luaShowOwnerError = true;
+	}
+	_gameLoadState = 0;
+	app->showLoadingIcon(false);
+	_loadName.clear();
+	initScene(warpFlag, firstWarpPath);
+}
+
+void SyberiaGame::initNoScale() {
+	if (!_noScaleLayout) {
+		_noScaleLayout = new TeLayout();
+		_noScaleLayout->setName("noScaleLayout");
+		_noScaleLayout->setSizeType(TeILayout::RELATIVE_TO_PARENT);
+		_noScaleLayout->setSize(TeVector3f32(1.0f, 1.0f, 0.0f));
+	}
+
+	if (!_noScaleLayout2) {
+		_noScaleLayout2 = new TeLayout();
+		_noScaleLayout2->setName("noScaleLayout2");
+		_noScaleLayout2->setSizeType(TeILayout::RELATIVE_TO_PARENT);
+		_noScaleLayout2->setSize(TeVector3f32(1.0f, 1.0f, 0.0f));
+	}
+}
+
+void SyberiaGame::initScene(bool fade, const Common::String &scenePath) {
+	_luaContext.setGlobal("SHOW_OWNER_ERROR", _luaShowOwnerError);
+	initWarp(_currentZone, _currentScene, fade);
+	loadScene(scenePath);
+	if (_scene._character->_model.get() && !_scene.findKate()) {
+		_scene.models().push_back(_scene._character->_model);
+	}
+	_scene._character->_model->setVisible(true);
+}
+
+bool SyberiaGame::initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
+	debug("Game::initWarp(%s, %s, %s)", zone.c_str(), scene.c_str(), fadeFlag ? "true" : "false");
+	_inventoryMenu.unload();
+	_inGameGui.unload();
+	_movePlayerCharacterDisabled = false;
+	_sceneCharacterVisibleFromLoad = true;
+
+	if (_scene._character) {
+		_scene._character->_model->setVisible(true);
+		_scene._character->deleteAllCallback();
+		_scene._character->stop();
+		_scene._character->setAnimation(_scene._character->characterSettings()._idleAnimFileName, true);
+		if (!_scene.findKate()) {
+			_scene.models().push_back(_scene._character->_model);
+			if (_scene._character->_shadowModel[0]) {
+				_scene.models().push_back(_scene._character->_shadowModel[0]);
+				_scene.models().push_back(_scene._character->_shadowModel[1]);
+			}
+		}
+	}
+
+	_currentZone = zone;
+	_currentScene = scene;
+
+	_scene.loadBlockers();
+	Common::Path scenePath("scenes");
+	scenePath.joinInPlace(zone);
+	scenePath.joinInPlace(scene);
+	_sceneZonePath = scenePath;
+
+	TeCore *core = g_engine->getCore();
+
+	const Common::FSNode intLuaNode = core->findFile(scenePath.join(Common::String::format("Int%s.lua", scene.c_str())));
+	const Common::FSNode logicLuaNode = core->findFile(scenePath.join(Common::String::format("Logic%s.lua", scene.c_str())));
+	const Common::FSNode setLuaNode = core->findFile(scenePath.join(Common::String::format("Set%s.lua", scene.c_str())));
+	Common::FSNode forLuaNode = core->findFile(scenePath.join(Common::String::format("For%s.lua", scene.c_str())));
+	const Common::FSNode markerLuaNode = core->findFile(scenePath.join(Common::String::format("Marker%s.lua", scene.c_str())));
+
+	bool intLuaExists = intLuaNode.exists();
+	bool logicLuaExists = logicLuaNode.exists();
+	bool setLuaExists = setLuaNode.exists();
+	bool forLuaExists = forLuaNode.exists();
+	if (!forLuaExists) {
+		// slight hack.. try an alternate For lua path.
+		forLuaNode = core->findFile(scenePath.join("Android-MacOSX").join(Common::String::format("For%s.lua", scene.c_str())));
+		forLuaExists = forLuaNode.exists();
+		debug("searched for %s", forLuaNode.getName().c_str());
+	}
+	bool markerLuaExists = markerLuaNode.exists();
+
+	if (!intLuaExists && !logicLuaExists && !setLuaExists && !forLuaExists && !markerLuaExists) {
+		debug("No lua scripts for scene %s zone %s", scene.c_str(), zone.c_str());
+		return false;
+	}
+
+	for (auto &sound : _gameSounds) {
+		sound->setRetain(false);
+	}
+
+	if (logicLuaExists) {
+		_luaContext.addBindings(LuaBinds::LuaOpenBinds);
+		_luaScript.attachToContext(&_luaContext);
+		_luaScript.load(core->findFile("menus/help/help.lua"));
+		_luaScript.execute();
+		_luaScript.load(logicLuaNode);
+	}
+
+	if (_forGui.loaded())
+		_forGui.unload();
+
+	_scene.reset();
+	_scene.bgGui().unload();
+	_scene.markerGui().unload();
+	_scene.hitObjectGui().unload();
+	Common::Path geomPath(Common::String::format("scenes/%s/Geometry%s.bin",
+												 zone.c_str(), zone.c_str()));
+	Common::FSNode geomFile = core->findFile(geomPath);
+	if (geomFile.isReadable()) {
+		// Syberia 1, load geom bin
+		_scene.load(geomFile);
+	} else {
+		// Syberia 2, load from xml
+		_scene.loadXml(zone, scene);
+	}
+	_scene.loadBackground(setLuaNode);
+
+	Application *app = g_engine->getApplication();
+	if (forLuaExists) {
+		_forGui.load(forLuaNode);
+		TeLayout *bg = _forGui.layoutChecked("background");
+		bg->setRatioMode(TeILayout::RATIO_MODE_NONE);
+		app->frontLayout().addChild(bg);
+		// Note: Game also adds cellphone to both frontLayout *and* noScaleLayout2,
+		// so we reproduce the broken behavior exactly.
+		TeLayout *cellbg = _inventory.cellphone()->gui().buttonLayoutChecked("background");
+		app->frontLayout().removeChild(cellbg);
+		app->frontLayout().addChild(cellbg);
+		_objectif.reattachLayout(&app->frontLayout());
+	}
+
+	if (intLuaExists) {
+		_scene.loadInteractions(intLuaNode);
+		TeLuaGUI::StringMap<TeButtonLayout *> &blayouts = _scene.hitObjectGui().buttonLayouts();
+		for (auto &entry : blayouts) {
+			HitObject *hobj = new HitObject();
+			TeButtonLayout *btn = entry._value;
+			hobj->_game = this;
+			hobj->_button = btn;
+			hobj->_name = btn->name();
+			btn->onMouseClickValidated().add(hobj, &HitObject::onValidated);
+			btn->onButtonChangedToStateDownSignal().add(hobj, &HitObject::onDown);
+			btn->onButtonChangedToStateUpSignal().add(hobj, &HitObject::onUp);
+			_gameHitObjects.push_back(hobj);
+		}
+	}
+
+	_inventoryMenu.load();
+	_inGameGui.load("InGame.lua");
+
+	TeButtonLayout *skipbtn = _inGameGui.buttonLayoutChecked("skipVideoButton");
+	skipbtn->setVisible(false);
+	skipbtn->onMouseClickValidated().remove(this, &Game::onSkipVideoButtonValidated);
+	skipbtn->onMouseClickValidated().add(this, &Game::onSkipVideoButtonValidated);
+
+	TeButtonLayout *vidbgbtn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
+	vidbgbtn->setVisible(false);
+	vidbgbtn->onMouseClickValidated().remove(this, &SyberiaGame::onLockVideoButtonValidated);
+	vidbgbtn->onMouseClickValidated().add(this, &SyberiaGame::onLockVideoButtonValidated);
+
+	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
+	video->setVisible(false);
+	video->_tiledSurfacePtr->_frameAnim.onStop().remove(this, &Game::onVideoFinished);
+	video->_tiledSurfacePtr->_frameAnim.onStop().add(this, &Game::onVideoFinished);
+
+	TeButtonLayout *invbtn = _inGameGui.buttonLayoutChecked("inventoryButton");
+	invbtn->onMouseClickValidated().remove(this, &Game::onInventoryButtonValidated);
+	invbtn->onMouseClickValidated().add(this, &Game::onInventoryButtonValidated);
+	invbtn->setSizeType(TeILayout::RELATIVE_TO_PARENT);
+
+	const TeVector3f32 winSize = app->getMainWindow().size();
+	if (g_engine->getCore()->fileFlagSystemFlag("definition") == "SD") {
+		invbtn->setSize(TeVector3f32(0.12f, (4.0f / ((winSize.y() / winSize.x()) * 4.0f)) * 0.12f, 0.0));
+	} else {
+		invbtn->setSize(TeVector3f32(0.08f, (4.0f / ((winSize.y() / winSize.x()) * 4.0f)) * 0.08f, 0.0));
+	}
+
+	TeCheckboxLayout *markersCheckbox = _inGameGui.checkboxLayout("markersVisibleButton");
+	markersCheckbox->setState(_markersVisible ? TeCheckboxLayout::CheckboxStateActive : TeCheckboxLayout::CheckboxStateUnactive);
+	markersCheckbox->onStateChangedSignal().add(this, &SyberiaGame::onMarkersVisible);
+
+	initNoScale();
+	removeNoScale2Children();
+	app->frontLayout().removeChild(_noScaleLayout2);
+
+	TeLayout *vidLayout = _inGameGui.layout("videoLayout");
+	app->frontLayout().removeChild(vidLayout);
+	removeNoScaleChildren();
+	app->frontLayout().removeChild(_noScaleLayout);
+
+	app->frontLayout().addChild(_noScaleLayout);
+	addNoScaleChildren();
+	app->frontLayout().addChild(vidLayout);
+	app->frontLayout().addChild(_noScaleLayout2);
+	addNoScale2Children();
+	if (!fadeFlag) {
+		if (_inventory.selectedObject().size()) {
+			_inventory.selectedObject(_inventory.selectedInventoryObject());
+		}
+		_inventory.setVisible(false);
+		_objectif.setVisibleObjectif(false);
+		_objectif.setVisibleButtonHelp(true);
+		_running = true;
+		loadScene("save.xml");
+	}
+
+	app->backLayout().addChild(_scene.background());
+
+	if (markerLuaExists) {
+		TeLayout *bg = _scene.markerGui().layout("background");
+		app->frontLayout().addChild(bg);
+	}
+
+	Common::String camname = Common::String("Camera") + scene;
+	_scene.setCurrentCamera(camname);
+
+	// Special hacks for certain scenes (don't blame me, original does this..)
+	if (g_engine->gameType() == TetraedgeEngine::kSyberia) {
+		if (scene == "14050") {
+			TeIntrusivePtr<TeCamera> curcamera = _scene.currentCamera();
+			const TeVector3f32 coords(1200.6f, -1937.5f, 1544.1f);
+			curcamera->setPosition(coords);
+		} else if (scene == "34610") {
+			TeIntrusivePtr<TeCamera> curcamera = _scene.currentCamera();
+			const TeVector3f32 coords(-328.243f, 340.303f, -1342.84f);
+			curcamera->setPosition(coords);
+			const TeQuaternion rot(0.003194f, 0.910923f, -0.009496f, -0.412389f);
+			curcamera->setRotation(rot);
+		}
+
+		//
+		// WORKAROUND: Fix the camera in the restored scenes
+		//
+		if (zone == "ValStreet" && scene == "11100") {
+			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
+			cam->setProjMatrixType(3);
+			cam->setFov(0.5f);
+		} else if (zone == "ValField" && scene == "11170") {
+			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
+			cam->setProjMatrixType(3);
+			// TODO: Is camera position right? Kate not visible..
+			// default values:
+			// -494.447998  -79.2976989  1408.5
+			// scene entrance and exit
+			// -184, -143, 1563
+			// -42, -147, 1534
+		} else if (zone == "BarRiverSide" && scene == "24020") {
+			TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
+			cam->setProjMatrixType(3);
+			cam->setFov(0.5f);
+		}
+	}
+
+	if (logicLuaExists) {
+		_exitZone.clear();
+		_luaScript.execute();
+		_luaScript.execute("OnEnter", _prevSceneName);
+		_luaScript.execute("OnSelectedObject", _inventory.selectedObject());
+	}
+
+	for (uint i = 0; i < _gameSounds.size(); i++) {
+		if (_gameSounds[i]->retain())
+			continue;
+		_gameSounds[i]->stop();
+		_gameSounds[i]->deleteLater();
+		_gameSounds.remove_at(i);
+		i--;
+	}
+
+	// Take a copy and clear the global list first, as deleting a sound can cause the
+	// next sound to trigger (which might have been deleted already).
+	Common::HashMap<Common::String, Common::Array<RandomSound *>> rsounds = _randomSounds;
+	_randomSounds.clear();
+	for (auto &randsoundlist : rsounds) {
+		for (auto *randsound : randsoundlist._value) {
+			delete randsound;
+		}
+		randsoundlist._value.clear();
+	}
+
+	_scene.initScroll();
+	return true;
+}
+
+void SyberiaGame::leave(bool flag) {
+	if (!_enteredFlag2)
+		return;
+
+	Application *app = g_engine->getApplication();
+
+	deleteNoScale();
+	_entered = false;
+	_running = false;
+	_notifier.unload();
+	g_engine->getInputMgr()->_mouseLUpSignal.remove(this, &SyberiaGame::onMouseClick);
+	_question2.unload();
+	TeLayout *cellbg = _inventory.cellphone()->gui().buttonLayout("background");
+	if (cellbg)
+		app->frontLayout().removeChild(cellbg);
+	_inventory.cellphone()->leave();
+	_dialog2.unload();
+	_inventory.unload();
+	_documentsBrowser.unload();
+	_inventoryMenu.unload();
+	_objectif.unload(); // not done in original, but should be.
+	_scene.close();
+	_forGui.unload();
+	if (_scene._character) {
+		_scene._character->deleteAllCallback();
+		_scene._character->stop();
+		_scene.unloadCharacter(_scene._character->_model->name());
+	}
+
+	for (auto &sound : _gameSounds) {
+		delete sound;
+	}
+	_gameSounds.clear();
+
+	for (auto &randsoundlist : _randomSounds) {
+		for (auto *randsound : randsoundlist._value) {
+			delete randsound;
+		}
+		randsoundlist._value.clear();
+	}
+	_randomSounds.clear();
+
+	for (auto *hitobj : _gameHitObjects) {
+		delete hitobj;
+	}
+	_gameHitObjects.clear();
+
+	// TODO: clear SyberiaGame::HitObject tree here?
+
+	_luaContext.destroy();
+	_running = false;
+	_inGameGui.buttonLayoutChecked("skipVideoButton")->onMouseClickValidated().remove(this, &Game::onSkipVideoButtonValidated);
+	_inGameGui.buttonLayoutChecked("videoBackgroundButton")->onMouseClickValidated().remove(this, &Game::onLockVideoButtonValidated);
+	_inGameGui.spriteLayoutChecked("video")->_tiledSurfacePtr->_frameAnim.onFinished().remove(this, &Game::onSkipVideoButtonValidated);
+	_inGameGui.buttonLayoutChecked("inventoryButton")->onMouseClickValidated().remove(this, &Game::onInventoryButtonValidated);
+	_inGameGui.unload();
+	_playedTimer.stop();
+	_enteredFlag2 = false;
+
+	app->lockCursor(false);
+	app->lockCursorFromAction(false);
+	// TODO: Set some inputmgr flag here?
+	Character::animCacheFreeAll();
+}
+
+void SyberiaGame::loadBackup(const Common::String &path) {
+	if (_gameLoadState == 0) {
+		_gameLoadState = 1;
+		g_engine->getApplication()->showLoadingIcon(true);
+		onFinishedLoadingBackup(path);
+	}
+}
+
+void SyberiaGame::loadUnlockedArtwork() {
+	Common::ConfigManager::Domain *domain = ConfMan.getActiveDomain();
+	for (auto &val : *domain) {
+		if (val._key.substr(0, 8) == "artwork_") {
+			_unlockedArtwork[val._key] = true;
+		}
+	}
+}
+
+bool SyberiaGame::loadCharacter(const Common::String &name) {
+	bool result = true;
+	Character *character = _scene.character(name);
+	if (!character) {
+		result = _scene.loadCharacter(name);
+		if (result) {
+			character = _scene.character(name);
+			assert(character);
+			character->_onCharacterAnimFinishedSignal.remove(this, &SyberiaGame::onCharacterAnimationFinished);
+			character->_onCharacterAnimFinishedSignal.add(this, &SyberiaGame::onCharacterAnimationFinished);
+			// Syberia 2 uses a simplified callback here.
+			// We have made onDisplacementPlayerFinished more like Syberia 1's onDisplacementFinished.
+			if (g_engine->gameType() == TetraedgeEngine::kSyberia)
+				character->onFinished().add(this, &SyberiaGame::onDisplacementPlayerFinished);
+			else
+				character->onFinished().add(this, &SyberiaGame::onDisplacementFinished);
+		}
+	}
+	return result;
+}
+
+bool SyberiaGame::loadPlayerCharacter(const Common::String &name) {
+	bool result = _scene.loadPlayerCharacter(name);
+	if (result) {
+		_scene._character->_characterAnimPlayerFinishedSignal.remove(this, &SyberiaGame::onCharacterAnimationPlayerFinished);
+		_scene._character->_characterAnimPlayerFinishedSignal.add(this, &SyberiaGame::onCharacterAnimationPlayerFinished);
+		_scene._character->onFinished().remove(this, &SyberiaGame::onDisplacementPlayerFinished);
+		_scene._character->onFinished().add(this, &SyberiaGame::onDisplacementPlayerFinished);
+	} else {
+		debug("failed to load player character %s", name.c_str());
+	}
+	return result;
+}
+
+bool SyberiaGame::loadScene(const Common::String &name) {
+	TeCore *core = g_engine->getCore();
+	_gameEnterScript.load(core->findFile("scenes/OnGameEnter.lua"));
+	_gameEnterScript.execute();
+	Character *character = _scene._character;
+	if (character && character->_model->visible()) {
+		_sceneCharacterVisibleFromLoad = true;
+	}
+	return false;
+}
+
+bool SyberiaGame::onCallNumber(Common::String val) {
+	_luaScript.execute("OnCallNumber", val);
+	return false;
+}
+
+bool SyberiaGame::onCharacterAnimationFinished(const Common::String &charName) {
+	if (!_scene._character)
+		return false;
+
+	if (g_engine->gameType() == TetraedgeEngine::kSyberia2) {
+		Character *character = scene().character(charName);
+		if (character) {
+			const Common::String curAnimName = character->curAnimName();
+			if (curAnimName == character->walkAnim(Character::WalkPart_EndD)
+				|| curAnimName == character->walkAnim(Character::WalkPart_EndG)) {
+				character->updatePosition(1.0);
+				character->endMove();
+			}
+		}
+	}
+
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		if (cb._luaFnName == "OnCharacterAnimationFinished" && cb._luaParam == charName) {
+			TeLuaThread *lua = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			if (lua) {
+				lua->resume();
+				return false;
+			}
+			break;
+		}
+	}
+	_luaScript.execute("OnCharacterAnimationFinished", charName);
+	return false;
+}
+
+bool SyberiaGame::onCharacterAnimationPlayerFinished(const Common::String &anim) {
+	if (_gameLoadState != 0)
+		return false;
+
+	bool callScripts = true;
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		// Yes, even Syberia2 checks for Kate here..
+		if (cb._luaFnName == "OnCharacterAnimationFinished" && cb._luaParam == "Kate") {
+			TeLuaThread *lua = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			if (lua) {
+				lua->resume();
+				callScripts = false;
+			}
+			break;
+		}
+	}
+	if (callScripts) {
+		if (g_engine->gameType() == TetraedgeEngine::kSyberia)
+			_luaScript.execute("OnCharacterAnimationFinished", "Kate");
+		else
+			_luaScript.execute("OnCharacterAnimationPlayerFinished", anim);
+		_luaScript.execute("OnCellCharacterAnimationPlayerFinished", anim);
+	}
+
+	Character *character = scene()._character;
+	assert(character);
+	// Note: the above callbacks can change the anim,
+	// so we have to fetch this *after* them.
+	const Common::String curAnimName = character->curAnimName();
+	if (_currentScene == _someSceneName) {
+		if (curAnimName == character->walkAnim(Character::WalkPart_Start)
+			|| curAnimName == character->walkAnim(Character::WalkPart_Loop)
+			|| curAnimName == character->walkAnim(Character::WalkPart_EndD)
+			|| curAnimName == character->walkAnim(Character::WalkPart_EndG))
+			character->stop();
+	} else {
+		if (!_sceneCharacterVisibleFromLoad && curAnimName == character->walkAnim(Character::WalkPart_Start)) {
+			character->setAnimation(character->walkAnim(Character::WalkPart_Loop), true);
+			return false;
+		}
+		if (curAnimName == character->walkAnim(Character::WalkPart_EndD)
+			|| curAnimName == character->walkAnim(Character::WalkPart_EndG)) {
+			character->updatePosition(1.0);
+			character->endMove();
+			// endMove can result in callbacks that change the animation. check again.
+			if (character->curAnimName() == character->walkAnim(Character::WalkPart_EndD)
+				|| character->curAnimName() == character->walkAnim(Character::WalkPart_EndG))
+				character->setAnimation(character->characterSettings()._idleAnimFileName, true);
+		}
+	}
+
+	return false;
+}
+
+bool SyberiaGame::onDialogFinished(const Common::String &val) {
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		if (cb._luaFnName == "OnDialogFinished" && cb._luaParam == val) {
+			TeLuaThread *lua = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			if (lua) {
+				lua->resume();
+				return false;
+			}
+			break;
+		}
+	}
+
+	_luaScript.execute("OnDialogFinished", val);
+	_luaScript.execute("OnCellDialogFinished", val);
+	return false;
+}
+
+// This is the Syberia 2 version of this function, not used in Syb 1.
+// Syb 1 uses a function much more like onDisplacementPlayerFinished below.
+bool SyberiaGame::onDisplacementFinished() {
+	TeLuaThread *thread = nullptr;
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		if (cb._luaFnName == "OnDisplacementFinished") {
+			thread = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			break;
+		}
+	}
+	if (thread) {
+		thread->resume();
+	} else {
+		_luaScript.execute("OnDisplacementFinished");
+	}
+	return false;
+}
+
+bool SyberiaGame::onDisplacementPlayerFinished() {
+	_sceneCharacterVisibleFromLoad = true;
+	assert(_scene._character);
+	_scene._character->stop();
+	_scene._character->walkMode("Walk");
+	_scene._character->setAnimation(_scene._character->characterSettings()._idleAnimFileName, true);
+
+	if (_isCharacterWalking) {
+		_isCharacterWalking = false;
+		_isCharacterIdle = true;
+	} else {
+		_isCharacterIdle = false;
+	}
+
+	TeLuaThread *thread = nullptr;
+
+	const char *cbName = (g_engine->gameType() == TetraedgeEngine::kSyberia ?
+						"OnDisplacementFinished" : "OnDisplacementPlayerFinished");
+
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		if (cb._luaFnName == cbName) {
+			thread = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			break;
+		}
+	}
+	if (thread) {
+		thread->resume();
+	} else {
+		_luaScript.execute(cbName);
+	}
+	return false;
+}
+
+bool SyberiaGame::onFinishedCheckBackup(bool result) {
+	if (_gameLoadState == 1) {
+		_gameLoadState = 0;
+		return true;
+	}
+	return false;
+}
+
+bool SyberiaGame::onFinishedLoadingBackup(const Common::String &val) {
+	if (_gameLoadState == 1) {
+		_loadName = val;
+		_gameLoadState = 2;
+		return true;
+	}
+	return false;
+}
+
+bool SyberiaGame::onFinishedSavingBackup(int something) {
+	if (something) {
+		g_engine->getGame()->_returnToMainMenu = true;
+	}
+	g_engine->getApplication()->showLoadingIcon(false);
+	return true;
+}
+
+bool SyberiaGame::onMarkersVisible(TeCheckboxLayout::State state) {
+	_markersVisible = (state == TeCheckboxLayout::CheckboxStateActive);
+	showMarkers(state == TeCheckboxLayout::CheckboxStateActive);
+	return false;
+}
+
+bool SyberiaGame::onMouseClick(const Common::Point &pt) {
+	Application *app = g_engine->getApplication();
+
+	if (app->isFading())
+		return true;
+
+	// In case we capture a click during a video or dialog (shouldn't happen?)
+	if (!_scene.currentCamera() || _dialog2.isDialogPlaying() || _question2.isEntered())
+		return false;
+
+	_posPlayer = TeVector3f32(-1.0f, -1.0f, -1.0f);
+	if (_previousMousePos == TeVector2s32(-1, -1)) {
+		_previousMousePos = pt;
+	} else {
+		const TeVector3f32 winSize = app->getMainWindow().size();
+		const TeVector2s32 prevMousePos = _previousMousePos;
+		_previousMousePos = pt;
+		float xdist = (pt.x - prevMousePos._x) / winSize.x();
+		float ydist = (pt.y - prevMousePos._y) / winSize.y();
+		float sqrdist = xdist * xdist + ydist * ydist;
+		if (sqrdist < 0.0001 && (!_walkTimer.running() || _walkTimer.timeElapsed() > 300000.0
+						 || (_scene._character && _scene._character->walkModeStr() != "Walk"))) {
+			return false;
+			// Normal walk click
+		}
+	}
+
+	if (!app->frontLayout().isMouseIn(pt))
+		return false;
+
+	Common::String nearestMeshName = "None";
+	TeIntrusivePtr<TeCamera> curCamera = _scene.currentCamera();
+	Common::Array<TePickMesh2*> pickMeshes = _scene.clickMeshes();
+	TePickMesh2 *nearestMesh = TeFreeMoveZone::findNearestMesh(curCamera, pt, pickMeshes, nullptr, false);
+	if (nearestMesh) {
+		nearestMeshName = nearestMesh->name();
+		debug("Game::onMouseClick: Click near mesh %s", nearestMeshName.c_str());
+		_lastCharMoveMousePos = TeVector2s32();
+	}
+
+	Character *character = _scene._character;
+	if (app->isLockCursor() || _movePlayerCharacterDisabled || !character)
+		return false;
+
+	const Common::String &charAnim = character->curAnimName();
+
+	if (charAnim == character->characterSettings()._idleAnimFileName
+		|| charAnim == character->walkAnim(Character::WalkPart_Start)
+		|| charAnim == character->walkAnim(Character::WalkPart_Loop)
+		|| charAnim == character->walkAnim(Character::WalkPart_EndD)
+		|| charAnim == character->walkAnim(Character::WalkPart_EndG)) {
+		_luaScript.execute("On");
+		if (!_scene.isObjectBlocking(nearestMeshName) && character->freeMoveZone()) {
+			const TeVector3f32 charPos = character->_model->position();
+			TeIntrusivePtr<TeBezierCurve> curve = character->freeMoveZone()->curve(charPos, pt, 8.0, true);
+			if (!curve)
+				return false;
+
+			_scene.setCurve(curve);
+			character->setCurveStartLocation(TeVector3f32());
+			if (curve->controlPoints().size() == 1) {
+				character->endMove();
+			} else {
+				if (!_walkTimer.running() || _walkTimer.timeElapsed() > 300000 || !_runModeEnabled) {
+					_walkTimer.stop();
+					_walkTimer.start();
+					character->walkMode("Walk");
+				} else {
+					// Note: original checks the timer elapsed again here.. why?
+					_walkTimer.stop();
+					character->walkMode("Jog");
+				}
+				character->placeOnCurve(curve);
+				character->setCurveOffset(0.0);
+				if (charAnim != character->walkAnim(Character::WalkPart_Start)) {
+					character->setAnimation(character->walkAnim(Character::WalkPart_Start), false);
+				}
+				character->walkTo(1.0, false);
+				_sceneCharacterVisibleFromLoad = false;
+				_lastCharMoveMousePos = pt;
+			}
+		}
+		// FIXME: The original never checks for empty/null curve here..
+		// but it seems our curve can possibly become null.
+		if (_scene.curve() && _scene.curve()->length()) {
+			TeVector3f32 lastPoint = _scene.curve()->controlPoints().back();
+			character->setAnimation(character->walkAnim(Character::WalkPart_Loop), true);
+			character->walkTo(1.0, false);
+			_isCharacterWalking = true;
+			_posPlayer = lastPoint;
+		}
+	}
+
+	// Note: charAnim above may no longer be valid as anim may have changed.
+	if (_sceneCharacterVisibleFromLoad || (character->curAnimName() == character->characterSettings()._idleAnimFileName)) {
+		_lastCharMoveMousePos = TeVector2s32();
+		_movePlayerCharacterDisabled = false;
+		_isCharacterIdle = true;
+		_isCharacterWalking = false;
+		if (nearestMesh) {
+			character->stop();
+			_luaScript.execute("OnWarpObjectHit", nearestMeshName);
+		}
+	}
+
+	return false;
+}
+
+bool SyberiaGame::onVideoFinished() {
+	if (!_inGameGui.loaded()) {
+		_music.stop();
+		return false;
+	}
+
+	Application *app = g_engine->getApplication();
+
+	app->captureFade();
+
+	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
+	Common::String vidPath = video->_tiledSurfacePtr->loadedPath();
+	TeButtonLayout *btn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
+	btn->setVisible(false);
+	btn = _inGameGui.buttonLayoutChecked("skipVideoButton");
+	btn->setVisible(false);
+	video->setVisible(false);
+	_music.stop();
+	_running = true;
+	bool resumed = false;
+	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
+		YieldedCallback &cb = _yieldedCallbacks[i];
+		if (cb._luaFnName == "OnMovieFinished" && cb._luaParam == vidPath) {
+			TeLuaThread *lua = cb._luaThread;
+			_yieldedCallbacks.remove_at(i);
+			resumed = true;
+			if (lua)
+				lua->resume();
+			break;
+		}
+	}
+	if (!resumed)
+		_luaScript.execute("OnMovieFinished", vidPath);
+	app->fade();
+	return false;
+}
+
+
+#ifdef TETRAEDGE_ENABLE_CUSTOM_CURSOR_CHECKS
+// Note: None of these cursor files seem to be actually shipped with the game
+// but the logic is reproduced here just in case there's some different
+// version that uses them.
+static const char cursorsTable[][2][80] = {
+	{"H000", "pictures/F000.png"},
+	{"H045", "pictures/F045.png"},
+	{"H090", "pictures/F090.png"},
+	{"H135", "pictures/F135.png"},
+	{"H180", "pictures/F180.png"},
+	{"H225", "pictures/F225.png"},
+	{"H270", "pictures/F270.png"},
+	{"H315", "pictures/F315.png"},
+	{"Main", "pictures/Main.png"},
+	{"Action", "pictures/Action.png"},
+	{"Parler", "pictures/Cursor_Large/Anim_Cursor_Talking.anim"},
+	{"Type01", "pictures/Type01.png"},
+	{"Type02", "pictures/Type02.png"},
+	{"Type03", "pictures/Type03.png"},
+	{"Type04", "pictures/Type04.png"},
+	{"Type05", "pictures/Type05.png"}
+};
+#endif
+
+
+/* Unused
+void SyberiaGame::pauseMovie() {
+	_music.pause();
+	TeSpriteLayout *sprite = _inGameGui.spriteLayoutChecked("video");
+	sprite->pause();
+}
+*/
+
+
+void SyberiaGame::playRandomSound(const Common::String &name) {
+	if (!_randomSounds.contains(name)) {
+		warning("Game::playRandomSound: can't find sound list %s", name.c_str());
+		return;
+	}
+
+	if (!_randomSoundFinished) {
+		_randomSoundTimer.start();
+		int r = g_engine->getRandomNumber(RAND_MAX);
+		float f = (r + 1 + (r / 100) * -100);
+		uint64 time = 1000000;
+		if (f >= 25.0) {
+			time = f * 45000.0;
+		}
+		_randomSoundTimer.setAlarmIn(time);
+		_randomSoundTimer.alarmSignal().remove(_randomSound, &RandomSound::onSoundFinished);
+		_randomSoundTimer.alarmSignal().add(_randomSound, &RandomSound::onSoundFinished);
+		_randomSound->_name = name;
+	} else {
+		Common::Array<RandomSound *> &sndlist = _randomSounds[name];
+		float total = 0.0;
+		for (auto *snd : sndlist) {
+			total += snd->_f1;
+		}
+		int r = g_engine->getRandomNumber(RAND_MAX);
+		float total2 = 0.0;
+		uint i = 0;
+		while (i < sndlist.size() && total2 <= r * 4.656613e-10 * total) {
+			total2 += sndlist[i]->_f1;
+			i++;
+		}
+		assert(i > 0);
+		i--;
+		RandomSound *sound = sndlist[i];
+		sound->_music.volume(sound->_volume);
+		sound->_music.onStopSignal().remove(sound, &RandomSound::onSoundFinished);
+		sound->_music.onStopSignal().add(sound, &RandomSound::onSoundFinished);
+		sound->_music.load(sound->_path.toString());
+		sound->_music.repeat(false);
+		sound->_music.play();
+		// TODO: set a flag that it's playing?
+	}
+}
+
+void SyberiaGame::removeNoScale2Children() {
+	if (!_noScaleLayout2)
+		return;
+
+	TeLayout *vidbtn = _inGameGui.layout("videoButtonLayout");
+	if (vidbtn)
+		_noScaleLayout2->removeChild(vidbtn);
+
+	TeLayout *bg = _inventory.cellphone()->gui().layout("background");
+	if (bg)
+		_noScaleLayout2->removeChild(bg);
+
+	TeButtonLayout *bgbtn = _objectif.gui1().buttonLayout("background");
+	if (bgbtn)
+		_noScaleLayout2->removeChild(bgbtn);
+
+	TeLayout *notifier = _notifier.gui().layout("notifier");
+	if (notifier)
+		_noScaleLayout2->removeChild(notifier);
+}
+
+void SyberiaGame::removeNoScaleChildren() {
+	if (!_noScaleLayout)
+		return;
+	_noScaleLayout->removeChild(&_question2);
+	Application *app = g_engine->getApplication();
+	app->frontLayout().removeChild(&_dialog2);
+	_noScaleLayout->removeChild(&_inventory);
+	_noScaleLayout->removeChild(&_inventoryMenu);
+	_noScaleLayout->removeChild(&_documentsBrowser);
+	_noScaleLayout->removeChild(&_documentsBrowser.zoomedLayout());
+}
+
+void SyberiaGame::resetPreviousMousePos() {
+	_previousMousePos = TeVector2s32(-1, -1);
+}
+
+bool SyberiaGame::unloadCharacter(const Common::String &charname) {
+	Character *c = _scene.character(charname);
+	if (!c)
+		return false;
+
+	for (uint i = 0; i < _scene.models().size(); i++) {
+		if (_scene.models()[i] == c->_model) {
+			_scene.models().remove_at(i);
+			break;
+		}
+	}
+	c->_onCharacterAnimFinishedSignal.remove(this, &SyberiaGame::onCharacterAnimationFinished);
+	c->removeAnim();
+	// Syberia 2 uses a simplified callback here.
+	// We have made onDisplacementPlayerFinished more like Syberia 1's onDisplacementPlayerFinished.
+	if (g_engine->gameType() == TetraedgeEngine::kSyberia)
+		c->onFinished().remove(this, &SyberiaGame::onDisplacementPlayerFinished);
+	else
+		c->onFinished().remove(this, &SyberiaGame::onDisplacementFinished);
+	_scene.unloadCharacter(charname);
+	return true;
+}
+
+bool SyberiaGame::unloadCharacters() {
+	// Loop will update the array, take a copy first.
+	Common::Array<Character *> chars = _scene._characters;
+	for (Character *c : chars) {
+		unloadCharacter(c->_model->name());
+	}
+	return true;
+}
+
+bool SyberiaGame::unloadPlayerCharacter(const Common::String &charname) {
+	Character *c = _scene.character(charname);
+	if (c) {
+		c->_onCharacterAnimFinishedSignal.remove(this, &SyberiaGame::onCharacterAnimationPlayerFinished);
+		c->onFinished().remove(this, &SyberiaGame::onDisplacementPlayerFinished);
+		_scene.unloadCharacter(charname);
+	}
+	return c != nullptr;
+}
+
+void SyberiaGame::update() {
+	if (!_entered)
+		return;
+
+	TeITextLayout *debugTimeTextLayout = _inGameGui.textLayout("debugTimeText1");
+	if (debugTimeTextLayout) {
+		warning("TODO: SyberiaGame::update: Fill out debugTimeTextLayout");
+	}
+
+	if (!_warped) {
+		if (_gameLoadState == 2) {
+			initLoadedBackupData();
+			return;
+		} else if (_gameLoadState != 0) {
+			return;
+		}
+
+		Application *app = g_engine->getApplication();
+
+		if (_scene._character) {
+			if (!_scene._character->_model->visible())
+				app->lockCursor(false);
+		}
+
+		TeButtonLayout *invbtn = _inGameGui.buttonLayout("inventoryButton");
+		if (invbtn)
+			invbtn->setVisible(!app->isLockCursor() && !_dialog2.isDialogPlaying());
+
+		Character *player = _scene._character;
+		if (player) {
+			TeIntrusivePtr<TeModel> model = player->_model;
+			bool modelVisible = model->visible();
+			if (model->anim())
+				player->permanentUpdate();
+			if (modelVisible) {
+				if (player->needsSomeUpdate()) {
+					_sceneCharacterVisibleFromLoad = false;
+					TeVector3f32 charPos = player->_model->position();
+					const Common::String charName = player->_model->name();
+					TeFreeMoveZone *zone = _scene.pathZone(player->freeMoveZoneName());
+					if (zone) {
+						TeIntrusivePtr<TeCamera> cam = _scene.currentCamera();
+						zone->setCamera(cam, false);
+						player->setFreeMoveZone(zone);
+						_scene.setPositionCharacter(charName, player->freeMoveZoneName(), charPos);
+						TeIntrusivePtr<TeBezierCurve> curve = zone->curve(model->position(), player->positionCharacter());
+						_scene.setCurve(curve);
+						player->setCurveStartLocation(TeVector3f32(0, 0, 0));
+						player->placeOnCurve(curve);
+						player->setCurveOffset(0.0f);
+						player->setAnimation(player->walkAnim(Character::WalkPart_Start), false);
+						player->walkTo(1.0f, false);
+						_isCharacterWalking = true;
+					}
+					player->setNeedsSomeUpdate(false);
+				}
+
+				const Common::String &charAnim = _scene._character->curAnimName();
+				bool unlockCursor = (charAnim == _scene._character->walkAnim(Character::WalkPart_Start) ||
+						charAnim == _scene._character->walkAnim(Character::WalkPart_Loop) ||
+						charAnim == _scene._character->walkAnim(Character::WalkPart_EndD) ||
+						charAnim == _scene._character->walkAnim(Character::WalkPart_EndG) ||
+						charAnim == _scene._character->characterSettings()._idleAnimFileName);
+				app->lockCursor(!unlockCursor);
+			}
+		}
+
+		Common::Array<Character *> characters = _scene._characters;
+		for (Character *c : characters) {
+			if (c->_model->anim())
+				c->permanentUpdate();
+		}
+
+		Common::Point mousePos = g_engine->getInputMgr()->lastMousePos();
+		if (_lastUpdateMousePos != mousePos) {
+			onMouseMove();
+			_lastUpdateMousePos = mousePos;
+		}
+		if (_saveRequested) {
+			_saveRequested = false;
+			saveBackup("save.xml");
+		}
+
+		_luaScript.execute("Update");
+		_objectif.update();
+		_scene.update();
+	} else {
+		TeSoundManager *soundmgr = g_engine->getSoundManager();
+		// Take a copy in case the active music objects changes as we iterate.
+		Common::Array<TeMusic *> musics = soundmgr->musics();
+		for (TeMusic *music : musics) {
+			const Common::String &chanName = music->channelName();
+			if (chanName != "music" && chanName != "sfx" && chanName != "dialog")
+				music->stop();
+		}
+		changeWarp2(_warpZone, _warpScene, _warpFadeFlag);
+	}
+}
+
+
+bool SyberiaGame::HitObject::onChangeWarp() {
+	// Seems like this function is never used?
+	error("TODO: Implement SyberiaGame::HitObject::onChangeWarp");
+	return false;
+}
+
+bool SyberiaGame::HitObject::onDown() {
+	_game->luaScript().execute("OnButtonDown", _name);
+	_game->_isCharacterIdle = true;
+	return false;
+}
+
+bool SyberiaGame::HitObject::onUp() {
+	// debug("Game::HitObject mouseup: %s", _name.c_str());
+	_game->luaScript().execute("OnButtonUp", _name);
+	_game->_isCharacterIdle = true;
+	return false;
+}
+
+bool SyberiaGame::HitObject::onValidated() {
+	if (!g_engine->getApplication()->isLockCursor()) {
+		_game->luaScript().execute("OnWarpObjectHit", _name);
+		_game->_isCharacterIdle = true;
+	}
+	return false;
+}
+
+bool SyberiaGame::RandomSound::onSoundFinished() {
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
+	_music.onStopSignal().remove(this, &RandomSound::onSoundFinished);
+	if (game->_randomSoundFinished) {
+		game->_randomSoundFinished = false;
+	} else {
+		game->_randomSoundFinished = true;
+		game->_randomSound->_music.onStopSignal().remove(this, &RandomSound::onSoundFinished);
+		game->_randomSoundTimer.stop();
+	}
+	game->playRandomSound(_name);
+	return false;
+}
+
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/game/syberia_game.h b/engines/tetraedge/game/syberia_game.h
new file mode 100644
index 00000000000..8642b0e4dec
--- /dev/null
+++ b/engines/tetraedge/game/syberia_game.h
@@ -0,0 +1,217 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_GAME_SYBERIA_GAME_H
+#define TETRAEDGE_GAME_SYBERIA_GAME_H
+
+#include "common/types.h"
+#include "common/serializer.h"
+#include "common/str.h"
+#include "common/random.h"
+
+#include "tetraedge/game/documents_browser.h"
+#include "tetraedge/game/inventory.h"
+#include "tetraedge/game/inventory_menu.h"
+#include "tetraedge/game/in_game_scene.h"
+#include "tetraedge/game/game.h"
+#include "tetraedge/game/notifier.h"
+#include "tetraedge/game/cellphone.h"
+#include "tetraedge/game/game_sound.h"
+#include "tetraedge/game/objectif.h"
+#include "tetraedge/game/question2.h"
+#include "tetraedge/game/dialog2.h"
+#include "tetraedge/te/te_lua_gui.h"
+#include "tetraedge/te/te_music.h"
+#include "tetraedge/te/te_checkbox_layout.h"
+#include "tetraedge/te/te_vector2s32.h"
+
+namespace Tetraedge {
+
+class TeLuaThread;
+
+class SyberiaGame : public Tetraedge::Game {
+public:
+	SyberiaGame();
+	~SyberiaGame();
+
+	struct HitObject {
+		bool onChangeWarp();
+		bool onDown();
+		bool onUp();
+		bool onValidated();
+		//byte OnVisible(); empty never used?
+
+		Common::String _name;
+		SyberiaGame *_game;
+		TeButtonLayout *_button;
+	};
+
+	class RandomSound {
+	public:
+		Common::Path _path;
+		Common::String _name;
+		TeMusic _music;
+		float _f1;
+		float _volume;
+		bool onSoundFinished();
+	};
+
+	struct YieldedCallback {
+		TeLuaThread *_luaThread;
+		Common::String _luaParam;
+		Common::String _luaParam2;
+		Common::String _luaFnName;
+		// Note: original game long, and int fields.. unused?
+	};
+
+	void addArtworkUnlocked(const Common::String &name, bool notify);
+	void addRandomSound(const Common::String &s1, const Common::String &s2, float f1, float f2);
+	void addToBag(const Common::String &objname) override;
+	void addToHand(const Common::String &objname);
+	void addToScore(int score);
+
+	bool changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) override;
+
+	void draw() override;
+	void enter() override; // will load game if _loadName is set.
+
+	void finishFreemium();
+	void finishGame() override;
+	void initLoadedBackupData() override;
+	void leave(bool flag) override;
+	void loadBackup(const Common::String &path);
+	bool loadCharacter(const Common::String &name);
+	bool loadPlayerCharacter(const Common::String &name);
+	bool loadScene(const Common::String &name);
+
+	// Not in original. Load unlocked artwork from ScummVM config.
+	void loadUnlockedArtwork() override;
+
+	void playRandomSound(const Common::String &name);
+	void resetPreviousMousePos();
+	bool unloadCharacter(const Common::String &character);
+	bool unloadCharacters();
+	bool unloadPlayerCharacter(const Common::String &character);
+	void update() override;
+
+	bool _movePlayerCharacterDisabled;
+	bool _sceneCharacterVisibleFromLoad;
+	bool _isCharacterWalking;
+	bool _isCharacterIdle;
+
+	const Common::Path &sceneZonePath() const { return _sceneZonePath; }
+	Objectif &objectif() { return _objectif; }
+	Common::Array<YieldedCallback> &yieldedCallbacks() { return _yieldedCallbacks; }
+	void setSaveRequested() { _saveRequested = true; }
+	bool markersVisible() const { return _markersVisible; }
+	const TeVector3f32 &posPlayer() const { return _posPlayer; }
+	void setPosPlayer(const TeVector3f32 &pos) { _posPlayer = pos; }
+	TeTimer &walkTimer() { return _walkTimer; }
+	void setExitZone(const Common::String &zone) { _exitZone = zone; }
+	bool isArtworkUnlocked(const Common::String &name) const;
+	static Common::String artworkConfName(const Common::String &name);
+
+	void setRunModeEnabled(bool val) { _runModeEnabled = val; }
+	bool runModeEnabled() const { return _runModeEnabled; }
+
+private:
+	bool addAnimToSet(const Common::String &path);
+	void addNoScale2Children();
+	void addNoScaleChildren();
+
+	void attachButtonsLayoutGoto() {}; // does nothing?
+	void createButtonsLayoutGoto() {}; // does nothing?
+	void deleteButtonsLayoutGoto() {}; // does nothing?
+
+	bool changeWarp2(const Common::String &zone, const Common::String &scene, bool fadeFlag);
+
+	void deleteNoScale();
+
+	void initNoScale();
+	void initScene(bool param_1, const Common::String &scenePath);
+	bool initWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag);
+
+	bool onCallNumber(Common::String val);
+	bool onCharacterAnimationFinished(const Common::String &val);
+	bool onCharacterAnimationPlayerFinished(const Common::String &val);
+	bool onDialogFinished(const Common::String &val) override;
+	bool onDisplacementFinished();
+	bool onDisplacementPlayerFinished();
+	bool onFinishedCheckBackup(bool result);
+	bool onFinishedLoadingBackup(const Common::String &val) override;
+	bool onFinishedSavingBackup(int something);
+	bool onMarkersVisible(TeCheckboxLayout::State state);
+	bool onMouseClick(const Common::Point &pt);
+	bool onVideoFinished() override;
+
+	void removeNoScale2Children();
+	void removeNoScaleChildren();
+
+	bool _enteredFlag2;
+
+	int _score;
+
+	int _frameCounter;
+
+	TeVector2s32 _previousMousePos;
+	TeVector2s32 _lastCharMoveMousePos;
+
+	Common::String _warpZone;
+	Common::String _warpScene;
+	bool _warpFadeFlag;
+	bool _warped;
+
+	Common::String _exitZone;
+	Common::String _someSceneName;
+	Common::Path _sceneZonePath;
+
+	Common::Array<HitObject *> _gameHitObjects;
+	// These are static in original, but cleaner to keep here.
+	Common::Array<YieldedCallback> _yieldedCallbacks;
+
+	Common::HashMap<Common::String, Common::Array<RandomSound *>> _randomSounds;
+
+	Common::HashMap<Common::String, bool> _unlockedArtwork;
+
+	int _gameLoadState;
+
+	Objectif _objectif;
+
+	bool _markersVisible;
+	bool _saveRequested;
+	bool _randomSoundFinished;
+
+	RandomSound *_randomSound;
+	TeTimer _randomSoundTimer;
+
+	TeLayout *_noScaleLayout;
+
+	TeVector3f32 _posPlayer;
+
+	Common::Point _lastUpdateMousePos;
+
+	// Syberia 2 specific data
+	bool _runModeEnabled;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_GAME_SYBERIA_GAME_H
diff --git a/engines/tetraedge/game/youki_manager.cpp b/engines/tetraedge/game/youki_manager.cpp
index 12437d59ef2..54d64628be0 100644
--- a/engines/tetraedge/game/youki_manager.cpp
+++ b/engines/tetraedge/game/youki_manager.cpp
@@ -22,7 +22,7 @@
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/youki_manager.h"
 #include "tetraedge/game/character.h"
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 
 namespace Tetraedge {
 
@@ -52,7 +52,8 @@ void YoukiManager::update() {
 	if (g_engine->gameType() != TetraedgeEngine::kSyberia2 || !_followKate)
 		return;
 
-	Game *game = g_engine->getGame();
+	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
+	assert(game);
 	Character *youki = game->scene().character("Youki");
 	if (!youki || !youki->freeMoveZone())
 		return;
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 008a6c270cd..1e233229e0c 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -41,6 +41,7 @@ MODULE_OBJS := \
 	game/question2.o \
 	game/scene_lights_xml_parser.o \
 	game/splash_screens.o \
+	game/syberia_game.o \
 	game/upsell_screen.o \
 	game/youki_manager.o \
 	te/micropather.o \
diff --git a/engines/tetraedge/tetraedge.cpp b/engines/tetraedge/tetraedge.cpp
index bbcec02c1d0..9c9b4bc877f 100644
--- a/engines/tetraedge/tetraedge.cpp
+++ b/engines/tetraedge/tetraedge.cpp
@@ -31,7 +31,7 @@
 #include "engines/dialogs.h"
 #include "graphics/palette.h"
 
-#include "tetraedge/game/game.h"
+#include "tetraedge/game/syberia_game.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/game/character.h"
 #include "tetraedge/te/te_core.h"
@@ -99,7 +99,7 @@ TeCore *TetraedgeEngine::getCore() {
 
 Game *TetraedgeEngine::getGame() {
 	if (_game == nullptr)
-		_game = new Game();
+		_game = new SyberiaGame();
 	return _game;
 }
 


Commit: 9baaeee37f17a17a412be2fe3d88eae43070b74b
    https://github.com/scummvm/scummvm/commit/9baaeee37f17a17a412be2fe3d88eae43070b74b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Starting to add classes needed for Amerzone

Changed paths:
  A engines/tetraedge/game/amerzone_game.cpp
  A engines/tetraedge/game/amerzone_game.h
  A engines/tetraedge/te/te_marker.cpp
  A engines/tetraedge/te/te_marker.h
  A engines/tetraedge/te/te_warp.cpp
  A engines/tetraedge/te/te_warp.h
  A engines/tetraedge/te/te_warp_marker.cpp
  A engines/tetraedge/te/te_warp_marker.h
    engines/tetraedge/game/application.cpp
    engines/tetraedge/game/application.h
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/main_menu.cpp
    engines/tetraedge/game/syberia_game.h
    engines/tetraedge/module.mk
    engines/tetraedge/tetraedge.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
new file mode 100644
index 00000000000..cf7e76e9302
--- /dev/null
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -0,0 +1,207 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/tetraedge.h"
+#include "tetraedge/game/application.h"
+#include "tetraedge/game/amerzone_game.h"
+#include "tetraedge/te/te_input_mgr.h"
+
+namespace Tetraedge {
+
+AmerzoneGame::AmerzoneGame() : Tetraedge::Game(), _orientationX(0.0f), _orientationY(0.0f),
+_speedX(0.0f), _speedY(0.0f), _isInDrag(false), _edgeButtonRolloverCount(0),
+_warpX(nullptr), _warpY(nullptr) {
+
+}
+
+void AmerzoneGame::addToBag(const Common::String &objname) {
+	inventory().addObject(objname);
+	// TODO: set this once _puzzleDisjoncteur is created
+	//if (objname == "A_Fil_cuivre_jour")
+	//	_puzzleDisjoncteur.addState(2);
+
+	_notifier.push("<section style=\"center\" /><color r=\"0\" g=\"0\" b=\"0\"/><font file=\"Common/Fonts/Arial_r_16.tef\" />" + inventory().objectName(objname), "");
+}
+
+void AmerzoneGame::changeSpeedToMouseDirection() {
+	error("TODO: Implement AmerzoneGame::changeSpeedToMouseDirection");
+}
+
+bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
+	error("TODO: Implement AmerzoneGame::changeWarp");
+	return false;
+}
+
+void AmerzoneGame::draw() {
+	error("TODO: Implement AmerzoneGame::draw");
+}
+
+void AmerzoneGame::enter() {
+	// TODO:
+	//_puzzleDisjoncteur.setState(5);
+	_inGameGui.load("GUI/InGame.lua");
+
+	error("TODO: Implement AmerzoneGame::enter");
+}
+
+void AmerzoneGame::finishGame() {
+	// Skip the animations of the original.
+	// This is more like OnGameFinishedRotateAnimFinished.
+	leave(true);
+	Application *app = g_engine->getApplication();
+	app->mainMenu().enter();
+}
+
+void AmerzoneGame::initLoadedBackupData() {
+
+}
+
+void AmerzoneGame::leave(bool flag) {
+	error("TODO: Implement AmerzoneGame::leave");
+}
+
+void AmerzoneGame::setAngleX(float angle) {
+	float diff = angle - _orientationX;
+	float distFromMin = _xAngleMin - diff;
+	if (distFromMin < 0)
+		angle += distFromMin;
+	float distFromMax = diff + _xAngleMax;
+	if (distFromMax < 0)
+		angle -= distFromMax;
+
+	diff = angle - _orientationX;
+	_xAngleMin -= diff;
+	_xAngleMax += diff;
+
+	float roundedAngle = (int)(angle / 360.0f) * 360;
+	_orientationX = roundedAngle;
+	if (roundedAngle > 360.0f || roundedAngle < -360.0f)
+		_orientationX = 0;
+}
+
+void AmerzoneGame::setAngleY(float angle) {
+	float diff = angle - _orientationY;
+	float distFromMin = _yAngleMin - diff;
+	if (distFromMin < 0)
+		angle += distFromMin;
+	float distFromMax = diff + _yAngleMax;
+	if (distFromMax < 0)
+		angle -= distFromMax;
+
+	diff = angle - _orientationY;
+	_yAngleMin -= diff;
+	_yAngleMax += diff;
+
+	if (angle < -55.0f)
+		_orientationY = -55.0f;
+	else if (_orientationY > 45.0f)
+		_orientationY = 45.0f;
+}
+
+void AmerzoneGame::speedX(float speed) {
+	_speedX = CLIP(speed, -10000.0f, 10000.0f);
+}
+
+void AmerzoneGame::speedY(float speed) {
+	_speedY = CLIP(speed, -10000.0f, 10000.0f);
+}
+
+void AmerzoneGame::update() {
+	TeInputMgr *inputMgr = g_engine->getInputMgr();
+
+	// TODO:
+	// if (!inputMgr->isLeftDown())
+	//     isInDrag(false);
+
+	Application *app = g_engine->getApplication();
+	if (!app->compassLook()) {
+		if (_isInDrag) {
+			TeVector2s32 mousePos = TeVector2s32(inputMgr->lastMousePos());
+			TeVector3f32 offset = TeVector3f32(mousePos - _mouseDragLast);
+			TeMatrix4x4 orientLayoutMatrix = app->frontOrientationLayout().rotation().toTeMatrix();
+			TeVector3f32 rotOffset = orientLayoutMatrix * offset;
+			if (app->inverseLook()) {
+				setAngleX(_orientationX + rotOffset.x() / 2);
+				setAngleY(_orientationY - rotOffset.y() / 2);
+			} else {
+				setAngleX(_orientationX - rotOffset.x() / 2);
+				setAngleY(_orientationY + rotOffset.y() / 2);
+			}
+			_mouseDragLast = inputMgr->lastMousePos();
+		} else {
+			if (_edgeButtonRolloverCount > 0) {
+				changeSpeedToMouseDirection();
+			}
+			float dragtime = (float)(_dragTimer.timeElapsed() / 1000000.0);
+			setAngleX(_orientationX - _speedX * dragtime);
+			setAngleY(_orientationY + _speedY * dragtime);
+		}
+	} else {
+		// Compass stuff happens here in the game, but it's
+		// not fully implemented - the TeCompass class is just
+		// stubs.
+		error("TODO: Implement compass support in AmerzoneGame::update.");
+	}
+
+	if (_warpY) {
+		TeVector2s32 mousePos = TeVector2s32(inputMgr->lastMousePos());
+		TeVector3f32 offset = TeVector3f32(mousePos - _mouseDragStart);
+		if (offset.length() > 20.0f)
+			_warpY->setMouseLeftUpForMakers();
+	}
+
+	TeQuaternion xRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(0, 1, 0), (float)(_orientationX * M_PI) / 180);
+	TeQuaternion yRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(1, 0, 0), (float)(_orientationY * M_PI) / 180);
+
+	if (_warpX)
+		_warpX->rotateCamera(xRot * yRot);
+	if (_warpY)
+		_warpY->rotateCamera(xRot * yRot);
+	if (_warpX)
+		_warpX->update();
+	if (_warpY)
+		_warpY->update();
+
+}
+
+bool AmerzoneGame::onDialogFinished(const Common::String &val) {
+	_luaScript.execute("OnDialogFinished", val);
+	return false;
+}
+
+bool AmerzoneGame::onVideoFinished() {
+	_inGameGui.buttonLayoutChecked("videoBackgroundButton")->setVisible(false);
+	_inGameGui.buttonLayoutChecked("skipVideoButton")->setVisible(false);
+	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
+	Common::String vidPath = video->_tiledSurfacePtr->loadedPath();
+	video->setVisible(false);
+	_music.stop();
+	// TODO:
+	//Application *app = g_engine->getApplication();
+	//if (app->musicOn()) {
+	//	app->music().play();
+	//}
+	_running = true;
+	_luaScript.execute("OnMovieFinished", vidPath);
+	return false;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/game/amerzone_game.h b/engines/tetraedge/game/amerzone_game.h
new file mode 100644
index 00000000000..da2427593e8
--- /dev/null
+++ b/engines/tetraedge/game/amerzone_game.h
@@ -0,0 +1,80 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_GAME_AMERZONE_GAME_H
+#define TETRAEDGE_GAME_AMERZONE_GAME_H
+
+#include "tetraedge/game/game.h"
+#include "tetraedge/te/te_timer.h"
+#include "tetraedge/te/te_warp.h"
+
+namespace Tetraedge {
+
+/** The main Amerzone Game class.  This is known as GameWarp in the original
+ *  code, but was renamed to be more descriptive in the ScummVM context */
+class AmerzoneGame : public Tetraedge::Game {
+public:
+	AmerzoneGame();
+
+	~AmerzoneGame() {}
+
+	virtual void addToBag(const Common::String &objname) override;
+	virtual bool changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) override;
+	virtual void draw() override;
+	virtual void enter() override;
+	virtual void finishGame() override;
+	virtual void initLoadedBackupData() override;
+	virtual void leave(bool flag) override;
+	virtual void update() override;
+	virtual bool onDialogFinished(const Common::String &val) override;
+	virtual bool onVideoFinished() override;
+
+private:
+	void changeSpeedToMouseDirection();
+	void setAngleX(float angle);
+	void setAngleY(float angle);
+	void speedX(float speed);
+	void speedY(float speed);
+
+	TeTimer _dragTimer;
+	float _orientationX;
+	float _orientationY;
+	float _xAngleMin;
+	float _xAngleMax;
+	float _yAngleMin;
+	float _yAngleMax;
+	float _speedX;
+	float _speedY;
+	bool _isInDrag;
+	int _edgeButtonRolloverCount;
+	TeVector2s32 _mouseDragStart;
+	TeVector2s32 _mouseDragLast;
+	/*
+	TeCurveAnim<AmerzoneGame, float> _decelAnimX;
+	TeCurveAnim<AmerzoneGame, float> _decelAnimY;
+	*/
+	TeWarp *_warpX;
+	TeWarp *_warpY;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_GAME_AMERZONE_GAME_H
diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp
index 3da0e119a23..5f7736396de 100644
--- a/engines/tetraedge/game/application.cpp
+++ b/engines/tetraedge/game/application.cpp
@@ -48,7 +48,7 @@ bool Application::_dontUpdateWhenApplicationPaused = false;
 
 Application::Application() : _finishedGame(false), _finishedFremium(false),
 _captureFade(false), _difficulty(1), _created(false), _tutoActivated(false),
-_drawShadows(true) {
+_drawShadows(true), _compassLook(false), _inverseLook(false) {
 	//
 	// TODO: Game defaults _ratioStretched to false, but then
 	// the horizontally scrolling scenes don't scroll properly.
diff --git a/engines/tetraedge/game/application.h b/engines/tetraedge/game/application.h
index 7a1bb59ff6a..6b1215db1cb 100644
--- a/engines/tetraedge/game/application.h
+++ b/engines/tetraedge/game/application.h
@@ -112,6 +112,8 @@ public:
 	TeLayout &backLayout() { return _backLayout; }
 	LocFile &loc() { return _loc; }
 	bool ratioStretched() const { return _ratioStretched; }
+	bool compassLook() const { return _compassLook; }
+	bool inverseLook() const { return _inverseLook; }
 
 private:
 	void drawBack();
@@ -178,6 +180,8 @@ private:
 	bool _tutoActivated;
 	bool _drawShadows;
 	bool _ratioStretched;
+	bool _compassLook;
+	bool _inverseLook;
 
 	int _difficulty;
 
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 7f0ab07c49d..cb5ecd5243b 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -28,6 +28,7 @@
 
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
+#include "tetraedge/game/cellphone.h"
 #include "tetraedge/game/character.h"
 #include "tetraedge/game/in_game_scene.h"
 #include "tetraedge/game/game.h"
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index b8502db1659..d3ee0fd04b1 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -32,14 +32,11 @@
 #include "tetraedge/game/inventory_menu.h"
 #include "tetraedge/game/in_game_scene.h"
 #include "tetraedge/game/notifier.h"
-#include "tetraedge/game/cellphone.h"
 #include "tetraedge/game/game_sound.h"
-#include "tetraedge/game/objectif.h"
 #include "tetraedge/game/question2.h"
 #include "tetraedge/game/dialog2.h"
 #include "tetraedge/te/te_lua_gui.h"
 #include "tetraedge/te/te_music.h"
-#include "tetraedge/te/te_checkbox_layout.h"
 #include "tetraedge/te/te_vector2s32.h"
 
 namespace Tetraedge {
diff --git a/engines/tetraedge/game/main_menu.cpp b/engines/tetraedge/game/main_menu.cpp
index fa82bba68df..1ef121427b5 100644
--- a/engines/tetraedge/game/main_menu.cpp
+++ b/engines/tetraedge/game/main_menu.cpp
@@ -127,6 +127,11 @@ void MainMenu::enter() {
 	// TODO: confirmation (menus/confirm/confirmNotSound.lua)
 	// if TeSoundManager is not valid.
 
+	// Hide the Facebook button since we don't support it anyway..
+	TeButtonLayout *fbButton = buttonLayout("facebookButton");
+	if (fbButton)
+		fbButton->setVisible(false);
+
 	_confirmingTuto = false;
 	TeLayout *panel = layout("panel");
 
diff --git a/engines/tetraedge/game/syberia_game.h b/engines/tetraedge/game/syberia_game.h
index 8642b0e4dec..f9a7d3e149b 100644
--- a/engines/tetraedge/game/syberia_game.h
+++ b/engines/tetraedge/game/syberia_game.h
@@ -25,23 +25,15 @@
 #include "common/types.h"
 #include "common/serializer.h"
 #include "common/str.h"
-#include "common/random.h"
 
-#include "tetraedge/game/documents_browser.h"
-#include "tetraedge/game/inventory.h"
-#include "tetraedge/game/inventory_menu.h"
 #include "tetraedge/game/in_game_scene.h"
 #include "tetraedge/game/game.h"
-#include "tetraedge/game/notifier.h"
 #include "tetraedge/game/cellphone.h"
 #include "tetraedge/game/game_sound.h"
 #include "tetraedge/game/objectif.h"
-#include "tetraedge/game/question2.h"
-#include "tetraedge/game/dialog2.h"
-#include "tetraedge/te/te_lua_gui.h"
-#include "tetraedge/te/te_music.h"
 #include "tetraedge/te/te_checkbox_layout.h"
 #include "tetraedge/te/te_vector2s32.h"
+#include "tetraedge/te/te_vector3f32.h"
 
 namespace Tetraedge {
 
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 1e233229e0c..fdea988313a 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/tetraedge
 MODULE_OBJS := \
 	tetraedge.o \
 	to_lua.o \
+	game/amerzone_game.o \
 	game/application.o \
 	game/billboard.o \
 	game/bonus_menu.o \
@@ -78,6 +79,7 @@ MODULE_OBJS := \
 	te/te_lua_gui_lua_callbacks.o \
 	te/te_lua_script.o \
 	te/te_lua_thread.o \
+	te/te_marker.o \
 	te/te_material.o \
 	te/te_matricies_stack.o \
 	te/te_matrix4x4.o \
@@ -118,6 +120,8 @@ MODULE_OBJS := \
 	te/te_vector2s32.o \
 	te/te_vector3f32.o \
 	te/te_visual_fade.o \
+	te/te_warp.o \
+	te/te_warp_marker.o \
 	te/te_xml_parser.o \
 	te/te_xml_gui.o \
 	metaengine.o
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
new file mode 100644
index 00000000000..6eb98addb68
--- /dev/null
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/te/te_marker.h"
+
+namespace Tetraedge {
+
+TeMarker::TeMarker() : _visible(true), _isActive(false) {
+}
+
+void TeMarker::active(bool val) {
+	_isActive = val;
+	_button.setVisible(!_visible && val);
+}
+
+void TeMarker::update(TeCamera *camera) {
+	if (!_visible)
+		return;
+	error("TODO: Finish TeMarker::update");
+}
+
+void TeMarker::visible(bool vis) {
+	_visible = vis;
+	bool buttonVis = (vis && _isActive);
+	_button.setVisible(buttonVis);
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_marker.h b/engines/tetraedge/te/te_marker.h
new file mode 100644
index 00000000000..fbc5cd3e781
--- /dev/null
+++ b/engines/tetraedge/te/te_marker.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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_TE_TE_MARKER_H
+#define TETRAEDGE_TE_TE_MARKER_H
+
+#include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_button_layout.h"
+#include "tetraedge/te/te_vector3f32.h"
+
+namespace Tetraedge {
+
+// Note: Only used in Amerzone
+class TeMarker {
+public:
+	TeMarker();
+
+	void active(bool val);
+	void update(TeCamera *camera);
+	void visible(bool val);
+
+	TeButtonLayout &button() { return _button; }
+private:
+	bool _visible;
+	bool _isActive;
+	TeVector3f32 _loc;
+	// Note: this is a TeSpriteButton in the original, updated
+	// to use the newer ButtonLayout
+	TeButtonLayout _button;
+
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_MARKER_H
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
new file mode 100644
index 00000000000..f6b1ffc5e5c
--- /dev/null
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/te/te_warp.h"
+
+namespace Tetraedge {
+
+TeWarp::TeWarp() {
+}
+
+void TeWarp::update() {
+	error("TODO: Implement TeWarp::update");
+}
+
+void TeWarp::setMouseLeftUpForMakers() {
+	// TODO:
+	//for (auto &marker : _warpMarkers) {
+	//	marker->marker()->sprite()->setEnable(true)
+	//}
+	error("TODO: Implement TeWarp::setMouseLeftUpForMakers");
+}
+
+void TeWarp::rotateCamera(const TeQuaternion &rot) {
+	TeQuaternion normRot = rot;
+	normRot.normalize();
+	_camera.setRotation(normRot);
+}
+
+void TeWarp::setFov(float fov) {
+	_camera.setFov(fov);
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp.h b/engines/tetraedge/te/te_warp.h
new file mode 100644
index 00000000000..27291dc57a2
--- /dev/null
+++ b/engines/tetraedge/te/te_warp.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_TE_TE_WARP_H
+#define TETRAEDGE_TE_TE_WARP_H
+
+#include "tetraedge/te/te_3d_object2.h"
+#include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_quaternion.h"
+#include "tetraedge/te/te_warp_marker.h"
+
+namespace Tetraedge {
+
+// Note: Only used in Amerzone
+class TeWarp : Te3DObject2 {
+public:
+	class AnimData {
+	};
+
+	TeWarp();
+
+	void update();
+	void rotateCamera(const TeQuaternion &rot);
+	void setMarkersOpacity(float opacity);
+	void setMouseLeftUpForMakers();
+	void setFov(float fov);
+
+private:
+	Common::String _warpPath;
+	TeCamera _camera;
+	bool _markersActive;
+
+	Common::Array<TeWarpMarker *> _warpMarkers;
+
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_WARP_H
diff --git a/engines/tetraedge/te/te_warp_marker.cpp b/engines/tetraedge/te/te_warp_marker.cpp
new file mode 100644
index 00000000000..676663972ba
--- /dev/null
+++ b/engines/tetraedge/te/te_warp_marker.cpp
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/te/te_warp_marker.h"
+
+namespace Tetraedge {
+
+TeWarpMarker::TeWarpMarker() : _marker(nullptr) {
+}
+
+TeWarpMarker::~TeWarpMarker() {
+	if (_marker)
+		_marker->button().onMouseClickValidated().remove(this, &TeWarpMarker::onMarkerButtonValidated);
+}
+
+void TeWarpMarker::marker(TeMarker *marker) {
+	if (_marker)
+		_marker->button().onMouseClickValidated().remove(this, &TeWarpMarker::onMarkerButtonValidated);
+	_marker = marker;
+	if (_marker)
+		_marker->button().onMouseClickValidated().add(this, &TeWarpMarker::onMarkerButtonValidated);
+}
+
+bool TeWarpMarker::onMarkerButtonValidated() {
+	_markerButtonSignal.call(_name);
+	return false;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp_marker.h b/engines/tetraedge/te/te_warp_marker.h
new file mode 100644
index 00000000000..30a643783a3
--- /dev/null
+++ b/engines/tetraedge/te/te_warp_marker.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_TE_TE_WARP_MARKER_H
+#define TETRAEDGE_TE_TE_WARP_MARKER_H
+
+#include "common/str.h"
+#include "tetraedge/te/te_marker.h"
+#include "tetraedge/te/te_signal.h"
+
+namespace Tetraedge {
+
+// Note: Only used in Amerzone
+class TeWarpMarker {
+public:
+	TeWarpMarker();
+	~TeWarpMarker();
+
+	void marker(TeMarker *marker);
+	bool onMarkerButtonValidated();
+
+private:
+	TeMarker *_marker;
+	Common::String _name;
+	TeSignal1Param<const Common::String &> _markerButtonSignal;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_WARP_MARKER_H
diff --git a/engines/tetraedge/tetraedge.cpp b/engines/tetraedge/tetraedge.cpp
index 9c9b4bc877f..4ba0bce3a84 100644
--- a/engines/tetraedge/tetraedge.cpp
+++ b/engines/tetraedge/tetraedge.cpp
@@ -31,6 +31,7 @@
 #include "engines/dialogs.h"
 #include "graphics/palette.h"
 
+#include "tetraedge/game/amerzone_game.h"
 #include "tetraedge/game/syberia_game.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/game/character.h"
@@ -98,8 +99,12 @@ TeCore *TetraedgeEngine::getCore() {
 }
 
 Game *TetraedgeEngine::getGame() {
-	if (_game == nullptr)
-		_game = new SyberiaGame();
+	if (_game == nullptr) {
+		if (gameType() == kAmerzone)
+			_game = new AmerzoneGame();
+		else
+			_game = new SyberiaGame();
+	}
 	return _game;
 }
 


Commit: 0b90939b9ffa4795c9b589cf8d63a00d02fba6ae
    https://github.com/scummvm/scummvm/commit/0b90939b9ffa4795c9b589cf8d63a00d02fba6ae
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Fix crash in Syberia 1

Changed paths:
    engines/tetraedge/game/in_game_scene.cpp


diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 23134f6965f..9c5eb5e5f7e 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -138,10 +138,11 @@ bool InGameScene::addMarker(const Common::String &markerName, const Common::Stri
 		float yscale = 1.0f;
 
 		// Originally this is only done in Syberia 2, but
-		// should be fine to calculate in Syberia 1.
+		// should be fine to calculate in Syberia 1, as long
+		// as the root layout is loaded.
 		TeLayout *bglayout = _bgGui.layoutChecked("background");
 		TeSpriteLayout *rootlayout = Game::findSpriteLayoutByName(bglayout, "root");
-		if (rootlayout) {
+		if (rootlayout && rootlayout->_tiledSurfacePtr && rootlayout->_tiledSurfacePtr->tiledTexture()) {
 			TeVector2s32 bgSize = rootlayout->_tiledSurfacePtr->tiledTexture()->totalSize();
 			xscale = 800.0f / bgSize._x;
 			yscale = 600.0f / bgSize._y;


Commit: c0eaf1227d983af02bd8acac18101711b0ca7e7b
    https://github.com/scummvm/scummvm/commit/c0eaf1227d983af02bd8acac18101711b0ca7e7b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-07T21:54:18+09:00

Commit Message:
TETRAEDGE: Add more implementation for Amerzone support

Changed paths:
  A engines/tetraedge/te/te_frustum.cpp
  A engines/tetraedge/te/te_frustum.h
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/amerzone_game.h
    engines/tetraedge/game/application.cpp
    engines/tetraedge/game/application.h
    engines/tetraedge/game/dialog2.cpp
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/inventory_menu.cpp
    engines/tetraedge/game/notifier.cpp
    engines/tetraedge/game/syberia_game.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/te/te_lua_gui.cpp
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/te/te_warp.h
    engines/tetraedge/te/te_warp_marker.h


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index cf7e76e9302..30854c48cb2 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -22,7 +22,10 @@
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/game/amerzone_game.h"
+#include "tetraedge/game/lua_binds.h"
 #include "tetraedge/te/te_input_mgr.h"
+#include "tetraedge/te/te_sound_manager.h"
+#include "tetraedge/te/te_warp.h"
 
 namespace Tetraedge {
 
@@ -55,11 +58,59 @@ void AmerzoneGame::draw() {
 }
 
 void AmerzoneGame::enter() {
+	Application *app = g_engine->getApplication();
 	// TODO:
 	//_puzzleDisjoncteur.setState(5);
 	_inGameGui.load("GUI/InGame.lua");
 
-	error("TODO: Implement AmerzoneGame::enter");
+	TeLayout *inGame = _inGameGui.layoutChecked("inGame");
+	// Note:
+	app->frontOrientationLayout().addChild(inGame);
+	_inventoryMenu.load();
+	app->frontOrientationLayout().addChild(&_inventoryMenu);
+
+	TeButtonLayout *invbtn = _inGameGui.buttonLayoutChecked("inventoryButton");
+	invbtn->onMouseClickValidated().add(this, &AmerzoneGame::onInventoryButtonValidated);
+	TeButtonLayout *helpbtn = _inGameGui.buttonLayoutChecked("helpButton");
+	helpbtn->onMouseClickValidated().add(this, &AmerzoneGame::onHelpButtonValidated);
+	if (app->permanentHelp()) {
+		helpbtn->setVisible(false);
+	}
+	TeButtonLayout *skipvidbtn = _inGameGui.buttonLayoutChecked("skipVideoButton");
+	skipvidbtn->setVisible(false);
+	skipvidbtn->onMouseClickValidated().add(this, &AmerzoneGame::onSkipVideoButtonValidated);
+	TeSpriteLayout *vid = _inGameGui.spriteLayoutChecked("video");
+	vid->_tiledSurfacePtr->_frameAnim.onStop().add(this, &Game::onVideoFinished);
+	vid->setVisible(false);
+	_dialog2.load();
+	app->frontOrientationLayout().addChild(&_dialog2);
+	_question2.load();
+
+	TeInputMgr *inputMgr = g_engine->getInputMgr();
+	inputMgr->_mouseMoveSignal.add(this, &AmerzoneGame::onMouseMove);
+	inputMgr->_mouseLUpSignal.add(this, &AmerzoneGame::onMouseLeftUp);
+	inputMgr->_mouseLDownSignal.add(this, &AmerzoneGame::onMouseLeftDown);
+
+	_orientationX = 0;
+	_orientationY = 0;
+	_isInDrag = false;
+	_speedX = 0;
+	_speedY = 0;
+
+	_notifier.load();
+	_warpX = new TeWarp();
+	_warpX->setRotation(app->frontOrientationLayout().rotation());
+	_warpX->init();
+	_warpX->setVisible(true, false);
+	_luaContext.create();
+	_luaScript.attachToContext(&_luaContext);
+
+	warning("TODO: Finish AmerzoneGame::enter");
+
+	_playedTimer.start();
+	_edgeButtonRolloverCount = 0;
+
+	initLoadedBackupData();
 }
 
 void AmerzoneGame::finishGame() {
@@ -71,13 +122,38 @@ void AmerzoneGame::finishGame() {
 }
 
 void AmerzoneGame::initLoadedBackupData() {
-
+	_luaContext.destroy();
+	_luaContext.create();
+	_luaContext.addBindings(LuaBinds::LuaOpenBinds);
+	//if (!_loadName.empty()) {
+	//}
+	error("TODO: finish AmerzoneGame::initLoadedBackupData");
 }
 
 void AmerzoneGame::leave(bool flag) {
 	error("TODO: Implement AmerzoneGame::leave");
 }
 
+bool AmerzoneGame::onHelpButtonValidated() {
+	g_engine->getSoundManager()->playFreeSound("Sounds/SFX/Clic_prec-suiv.ogg", 1.0f, "sfx");
+
+	bool active = true;
+	TeWarp::debug = TeWarp::debug == false;
+	if (!TeWarp::debug && !g_engine->getApplication()->permanentHelp())
+		active = false;
+
+	_warpY->activeMarkers(active);
+	return false;
+}
+
+bool AmerzoneGame::onMouseLeftUp(const Common::Point &pt) {
+	error("TODO: Implement AmerzoneGame::onMouseLeftUp");
+}
+
+bool AmerzoneGame::onMouseLeftDown(const Common::Point &pt) {
+	error("TODO: Implement AmerzoneGame::onMouseLeftDown");
+}
+
 void AmerzoneGame::setAngleX(float angle) {
 	float diff = angle - _orientationX;
 	float distFromMin = _xAngleMin - diff;
diff --git a/engines/tetraedge/game/amerzone_game.h b/engines/tetraedge/game/amerzone_game.h
index da2427593e8..e739e6d8c73 100644
--- a/engines/tetraedge/game/amerzone_game.h
+++ b/engines/tetraedge/game/amerzone_game.h
@@ -54,6 +54,10 @@ private:
 	void speedX(float speed);
 	void speedY(float speed);
 
+	bool onHelpButtonValidated();
+	bool onMouseLeftUp(const Common::Point &pt);
+	bool onMouseLeftDown(const Common::Point &pt);
+
 	TeTimer _dragTimer;
 	float _orientationX;
 	float _orientationY;
diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp
index 5f7736396de..15245e6efde 100644
--- a/engines/tetraedge/game/application.cpp
+++ b/engines/tetraedge/game/application.cpp
@@ -48,7 +48,8 @@ bool Application::_dontUpdateWhenApplicationPaused = false;
 
 Application::Application() : _finishedGame(false), _finishedFremium(false),
 _captureFade(false), _difficulty(1), _created(false), _tutoActivated(false),
-_drawShadows(true), _compassLook(false), _inverseLook(false) {
+_drawShadows(true), _compassLook(false), _inverseLook(false),
+_permanentHelp(false) {
 	//
 	// TODO: Game defaults _ratioStretched to false, but then
 	// the horizontally scrolling scenes don't scroll properly.
diff --git a/engines/tetraedge/game/application.h b/engines/tetraedge/game/application.h
index 6b1215db1cb..f24ccd069d0 100644
--- a/engines/tetraedge/game/application.h
+++ b/engines/tetraedge/game/application.h
@@ -114,6 +114,7 @@ public:
 	bool ratioStretched() const { return _ratioStretched; }
 	bool compassLook() const { return _compassLook; }
 	bool inverseLook() const { return _inverseLook; }
+	bool permanentHelp() const { return _permanentHelp; }
 
 private:
 	void drawBack();
@@ -182,6 +183,7 @@ private:
 	bool _ratioStretched;
 	bool _compassLook;
 	bool _inverseLook;
+	bool _permanentHelp;
 
 	int _difficulty;
 
diff --git a/engines/tetraedge/game/dialog2.cpp b/engines/tetraedge/game/dialog2.cpp
index 04b32693c29..b355096fc7c 100644
--- a/engines/tetraedge/game/dialog2.cpp
+++ b/engines/tetraedge/game/dialog2.cpp
@@ -98,7 +98,8 @@ void Dialog2::load() {
 	setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
 	size(); // refresh size? seems to do nothing with result
 	_music.repeat(false);
-	_gui.load("menus/dialog.lua");
+	const char *luaPath = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/dialog.lua" : "menus/dialog.lua";
+	_gui.load(luaPath);
 	size(); // refresh size? seems to do nothing with result
 	TeButtonLayout *dialogLockBtn = _gui.buttonLayoutChecked("dialogLockButton");
 
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index cb5ecd5243b..576577bd23b 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -198,7 +198,7 @@ static const char cursorsTable[][2][80] = {
 };
 #endif
 
-bool Game::onMouseMove() {
+bool Game::onMouseMove(const Common::Point &pt) {
 	if (!_entered)
 		return false;
 
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index d3ee0fd04b1..6e187124b98 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -123,7 +123,7 @@ public:
 	virtual bool onFinishedLoadingBackup(const Common::String &val) { return false; }
 	bool onInventoryButtonValidated();
 	bool onLockVideoButtonValidated();
-	bool onMouseMove();
+	bool onMouseMove(const Common::Point &pt);
 	bool onSkipVideoButtonValidated();
 	virtual bool onVideoFinished() = 0;
 
diff --git a/engines/tetraedge/game/inventory_menu.cpp b/engines/tetraedge/game/inventory_menu.cpp
index 09d1b63a76c..ef7c2182373 100644
--- a/engines/tetraedge/game/inventory_menu.cpp
+++ b/engines/tetraedge/game/inventory_menu.cpp
@@ -56,8 +56,10 @@ void InventoryMenu::load() {
 	addChild(_gui.layoutChecked("inventoryMenu"));
 	_gui.buttonLayoutChecked("quitButton")->onMouseClickValidated()
 				.add(this, &InventoryMenu::onQuitButton);
-	_gui.buttonLayoutChecked("quitBackground")->onMouseClickValidated()
-				.add(this, &InventoryMenu::onQuitButton);
+	// Quit background is only in Syberia 1 and 2 (not amerzone)
+	TeButtonLayout *quitBackground = _gui.buttonLayout("quitBackground");
+	if (quitBackground)
+		quitBackground->onMouseClickValidated().add(this, &InventoryMenu::onQuitButton);
 	_gui.buttonLayoutChecked("mainMenuButton")->onMouseClickValidated()
 				.add(this, &InventoryMenu::onMainMenuButton);
 	_gui.buttonLayoutChecked("documentsButton")->onMouseClickValidated()
diff --git a/engines/tetraedge/game/notifier.cpp b/engines/tetraedge/game/notifier.cpp
index 32c1fb5da71..0a4f8066e31 100644
--- a/engines/tetraedge/game/notifier.cpp
+++ b/engines/tetraedge/game/notifier.cpp
@@ -76,8 +76,10 @@ void Notifier::launchNextnotifier() {
 }
 
 void Notifier::load() {
-	_gui.load("menus/Notifier.lua");
-	TeLayout *notifierLayout = _gui.layoutChecked("notifier");
+	const char *luaPath = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/Notify.lua" : "menus/Notifier.lua";
+	_gui.load(luaPath);
+	const char *layoutName = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "notify" : "notifier";
+	TeLayout *notifierLayout = _gui.layoutChecked(layoutName);
 	Game *game = g_engine->getGame();
 	game->addNoScale2Child(notifierLayout);
 	notifierLayout->setVisible(false);
diff --git a/engines/tetraedge/game/syberia_game.cpp b/engines/tetraedge/game/syberia_game.cpp
index f96c542cf18..14dda809a1b 100644
--- a/engines/tetraedge/game/syberia_game.cpp
+++ b/engines/tetraedge/game/syberia_game.cpp
@@ -1387,7 +1387,7 @@ void SyberiaGame::update() {
 
 		Common::Point mousePos = g_engine->getInputMgr()->lastMousePos();
 		if (_lastUpdateMousePos != mousePos) {
-			onMouseMove();
+			onMouseMove(mousePos);
 			_lastUpdateMousePos = mousePos;
 		}
 		if (_saveRequested) {
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index fdea988313a..031499ba56c 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -62,6 +62,7 @@ MODULE_OBJS := \
 	te/te_font3.o \
 	te/te_frame_anim.o \
 	te/te_free_move_zone.o \
+	te/te_frustum.o \
 	te/te_i_3d_object2.o \
 	te/te_i_layout.o \
 	te/te_i_loc.o \
diff --git a/engines/tetraedge/te/te_frustum.cpp b/engines/tetraedge/te/te_frustum.cpp
new file mode 100644
index 00000000000..b5c300caa57
--- /dev/null
+++ b/engines/tetraedge/te/te_frustum.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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/te/te_frustum.h"
+
+namespace Tetraedge {
+
+TeFrustum::TeFrustum() {
+}
+
+void TeFrustum::computeNormal(unsigned int val) {
+	error("TODO: implement TeFrustum::computeNormal");
+}
+
+void TeFrustum::extractPlanAdd(const TeMatrix4x4 &matrix, uint dest, uint col) {
+	_m[dest * 4 + 0] = matrix(0, 3) - matrix(0, col);
+	_m[dest * 4 + 1] = matrix(1, 3) - matrix(1, col);
+	_m[dest * 4 + 2] = matrix(2, 3) - matrix(2, col);
+	_m[dest * 4 + 3] = matrix(3, 3) - matrix(3, col);
+}
+
+void TeFrustum::extractPlanSub(const TeMatrix4x4 &matrix, uint dest, uint col) {
+	_m[dest * 4 + 0] = matrix(0, 3) + matrix(0, col);
+	_m[dest * 4 + 1] = matrix(1, 3) + matrix(1, col);
+	_m[dest * 4 + 2] = matrix(2, 3) + matrix(2, col);
+	_m[dest * 4 + 3] = matrix(3, 3) + matrix(3, col);
+}
+
+bool TeFrustum::pointIsIn(const TeVector3f32 &pt) {
+	error("TODO: Implement TeFrustum::pointIsIn");
+}
+
+float TeFrustum::planeLen(int num) const {
+	assert(num >= 0 && num < 6);
+	const float *p = _m + num * 4;
+	float result = (float)sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
+	if (result == 0)
+		result = 1e-08;
+	return result;
+}
+
+bool TeFrustum::sphereIsIn(const TeVector3f32 &vec, float f) {
+	error("TODO: Implement TeFrustum::sphereIsIn");
+}
+
+bool TeFrustum::triangleIsIn(const TeVector3f32 *verts) {
+	for (unsigned int p = 0; p < 6; p++) {
+		bool inside = true;
+		for (unsigned int v = 0; v < 3; v++) {
+			float *pm = _m + p * 4;
+			if(pm[0] * verts[v].x() + pm[1] * verts[v].y() +
+				pm[2] * verts[v].z() + pm[3] >= 0.0)
+					inside = false;
+		}
+		if (!inside)
+			return false;
+	}
+	
+	return true;
+}
+
+void TeFrustum::update(TeCamera *camera) {
+	const TeMatrix4x4 camMatrix = camera->worldTransformationMatrix();
+	for (unsigned int plane = 0; plane < 6; plane++) {
+		if (plane % 2)
+			extractPlanAdd(camMatrix, plane / 2, plane);
+		else
+			extractPlanSub(camMatrix, plane / 2, plane);
+		float len = planeLen(plane);
+		float *p = _m + plane * 4;
+		for (int i = 0; i < 4; i++)
+			p[i] /= len;
+	}
+}
+
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_frustum.h b/engines/tetraedge/te/te_frustum.h
new file mode 100644
index 00000000000..dbbc7a9a077
--- /dev/null
+++ b/engines/tetraedge/te/te_frustum.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_TE_TE_FRUSTUM_H
+#define TETRAEDGE_TE_TE_FRUSTUM_H
+
+#include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_vector3f32.h"
+#include "tetraedge/te/te_matrix4x4.h"
+
+namespace Tetraedge {
+
+class TeFrustum {
+public:
+	TeFrustum();
+
+	void computeNormal(unsigned int val);
+	void extractPlanAdd(const TeMatrix4x4 &matrix, uint param_2, uint param_3);
+	void extractPlanSub(const TeMatrix4x4 &matrix, uint param_2, uint param_3);
+	bool pointIsIn(const TeVector3f32 &pt);
+	bool sphereIsIn(const TeVector3f32 &vec, float f);
+	bool triangleIsIn(const TeVector3f32 *vertexes);
+	void update(TeCamera *camera);
+
+private:
+	float planeLen(int num) const;
+	float _m[24];
+
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_FRUSTUM_H
diff --git a/engines/tetraedge/te/te_lua_gui.cpp b/engines/tetraedge/te/te_lua_gui.cpp
index d975b165d5b..97d596efc41 100644
--- a/engines/tetraedge/te/te_lua_gui.cpp
+++ b/engines/tetraedge/te/te_lua_gui.cpp
@@ -208,6 +208,9 @@ bool TeLuaGUI::load(const Common::FSNode &node) {
 	_luaContext.registerCFunction("TeRotationLinearAnimation", rotationLinearAnimationBindings);
 	_luaContext.registerCFunction("TeScrollingLayout", scrollingLayoutBindings);
 	_luaContext.registerCFunction("TeExtendedTextLayout", extendedTextLayoutBindings);
+	// TODO: We replaced the video layout from Amerzone with a sprite layout.  Probably
+	// works ok?
+	_luaContext.registerCFunction("TeVideoLayout", spriteLayoutBindings);
 	_luaContext.setInRegistry("__TeLuaGUIThis", this);
 	_luaScript.attachToContext(&_luaContext);
 	_luaScript.load(node);
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index 6eb98addb68..b10c296520a 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -34,7 +34,12 @@ void TeMarker::active(bool val) {
 void TeMarker::update(TeCamera *camera) {
 	if (!_visible)
 		return;
-	error("TODO: Finish TeMarker::update");
+	TeVector3f32 transformLoc = camera->transformCoord(_loc);
+	if (transformLoc.z() < 0) {
+		error("TODO: Finish TeMarker::update");
+	} else {
+		error("TODO: Finish TeMarker::update");
+	}
 }
 
 void TeMarker::visible(bool vis) {
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index f6b1ffc5e5c..1fa3ed159fb 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -19,14 +19,39 @@
  *
  */
 
+#include "tetraedge/tetraedge.h"
+#include "tetraedge/game/application.h"
 #include "tetraedge/te/te_warp.h"
+#include "tetraedge/te/te_input_mgr.h"
 
 namespace Tetraedge {
 
-TeWarp::TeWarp() {
+/*static*/
+bool TeWarp::debug = false;
+
+TeWarp::TeWarp() : _visible1(false) {
+}
+
+void TeWarp::activeMarkers(bool active) {
+	_markersActive = active;
+	for (auto &warpMarker : _warpMarkers)
+		warpMarker->marker()->active(active);
+}
+
+void TeWarp::init() {
+	// This mostly sets up the camera.. maybe nothing to do?
+	warning("TODO: Implement TeWarp::init");
+}
+
+bool TeWarp::onMouseLeftDown(const Common::Point &pt) {
+	error("TODO: Implement TeWarp::onMouseLeftDown");
 }
 
 void TeWarp::update() {
+	if (!_visible1 || !_file.isOpen())
+		return;
+	Application *app = g_engine->getApplication();
+	_frustum.update(app->mainWindowCamera());
 	error("TODO: Implement TeWarp::update");
 }
 
@@ -38,6 +63,22 @@ void TeWarp::setMouseLeftUpForMakers() {
 	error("TODO: Implement TeWarp::setMouseLeftUpForMakers");
 }
 
+void TeWarp::setVisible(bool v1, bool v2) {
+	if (_visible1 == v1)
+		return;
+
+	_visible1 = v1;
+	TeInputMgr *inputMgr = g_engine->getInputMgr();
+	if (v1) {
+		inputMgr->_mouseLDownSignal.add(this, &TeWarp::onMouseLeftDown);
+	} else {
+		if (v2) {
+			error("TODO: Implement TeWarp::setVisible for v2==true");
+		}
+		inputMgr->_mouseLDownSignal.remove(this, &TeWarp::onMouseLeftDown);
+	}
+}
+
 void TeWarp::rotateCamera(const TeQuaternion &rot) {
 	TeQuaternion normRot = rot;
 	normRot.normalize();
diff --git a/engines/tetraedge/te/te_warp.h b/engines/tetraedge/te/te_warp.h
index 27291dc57a2..e783f3d67e5 100644
--- a/engines/tetraedge/te/te_warp.h
+++ b/engines/tetraedge/te/te_warp.h
@@ -22,31 +22,45 @@
 #ifndef TETRAEDGE_TE_TE_WARP_H
 #define TETRAEDGE_TE_TE_WARP_H
 
+#include "common/file.h"
+
 #include "tetraedge/te/te_3d_object2.h"
 #include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_frustum.h"
 #include "tetraedge/te/te_quaternion.h"
 #include "tetraedge/te/te_warp_marker.h"
 
 namespace Tetraedge {
 
 // Note: Only used in Amerzone
-class TeWarp : Te3DObject2 {
+class TeWarp : public Te3DObject2 {
 public:
 	class AnimData {
 	};
 
 	TeWarp();
 
+	void activeMarkers(bool active);
+	void init();
 	void update();
 	void rotateCamera(const TeQuaternion &rot);
 	void setMarkersOpacity(float opacity);
 	void setMouseLeftUpForMakers();
 	void setFov(float fov);
+	void setVisible(bool v1, bool v2);
+
+	static bool debug;
 
 private:
+	bool onMouseLeftDown(const Common::Point &pt);
+
+	Common::File _file;
 	Common::String _warpPath;
 	TeCamera _camera;
 	bool _markersActive;
+	bool _visible1;
+
+	TeFrustum _frustum;
 
 	Common::Array<TeWarpMarker *> _warpMarkers;
 
diff --git a/engines/tetraedge/te/te_warp_marker.h b/engines/tetraedge/te/te_warp_marker.h
index 30a643783a3..7bd06540c25 100644
--- a/engines/tetraedge/te/te_warp_marker.h
+++ b/engines/tetraedge/te/te_warp_marker.h
@@ -34,6 +34,7 @@ public:
 	TeWarpMarker();
 	~TeWarpMarker();
 
+	TeMarker *marker() { return _marker; }
 	void marker(TeMarker *marker);
 	bool onMarkerButtonValidated();
 




More information about the Scummvm-git-logs mailing list