/* 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/>.
 *
 * Copyright 2020 Google
 *
 */
#include "hadesch/hadesch.h"
#include "hadesch/video.h"
#include "hadesch/ambient.h"

namespace Hadesch {

static const char *kTalusImage = "r1100bb0";
static const char *kTalusImageWithShip = "r1100bc0";
static const char *kTalusMovie = "r1100ba0";
static const char *kTalusHotzone = "Talus";
static const char *kTavernImage = "r2190ba0";
static const char *kTavernHotzone = "Tavern";
static const char *kPoseidonHighlight = "r1230ba0";
static const char *kZeusHighlight = "r1240ba0";
static const char *kHermesHighlight = "r2320ba0";
static const char *kHornless1 = "g0170ob0";
static const char *kHornless2 = "g0170oe0";
static const char *kHornless3 = "g0170oh0";
static const char *kHornless4 = "g0170ok0";
static const char *kHorned = "g1800ob0";
static const char *kHornedHotzone = "HornedStatue";
static const char *kHornless1Hotzone = "HornlessStatue1";
static const char *kHornless2Hotzone = "HornlessStatue2";
static const char *kHornless3Hotzone = "HornlessStatue3";
static const char *kHornless4Hotzone = "HornlessStatue4";
static const char *kMerchantAnim = "r2130ba0";
static const char *kOneManBandAnim = "r2040ba1";
static const char *kOneManBandHotZone = "OneManBand";
static const char *kAtlantisOpening = "r1210bb0";
static const char *kAtlantisLargeDisk = "r1210be0";
static const char *kAtlantisMediumDisk = "r1210bf0";
static const char *kAtlantisSmallDisk = "r1210bg0";
static const char *kAtlantisDiskBackground = "r1210os0";

static const int vaseSol[] = {2, 3, 2, 3};
static const char *vaseSound[] = {
	"r1220ec0",
	"r1220ed0",
	"r1220ee0",
	"r1220ef0"
};

static const char *vaseSegment[] = {
	"r1220bc0",
	"r1220bd0",
	"r1220be0",
	"r1220bf0"
};

enum {
	kBackgroundZ = 10000,
	kTalusZ = 6000,
	kTavernImageZ = 5000,
	kOneManBandZ = 1600,
	kMerchantStandZ = 1205,
	kMerchantZ = 1200,
	kAtlantisDiskBackgroundZ = 1100,
	kAtlantisLargeDiskZ = 1000,
	kAtlantisMediumDiskZ = 900,
	kAtlantisSmallDiskZ = 800,
	kAtlantisOpeningZ = 700
};

enum {
	kIntroMerchantVideoFinished = 12107,
	kTakenHorned = 12115,
	kTakenHornless = 12118,
	kMerchantIdleTimer = 12121,
	kMerchantIdleAnimCleanup = 12122,
	kTalueMovieCompleted = 12129,
	// 12137 is the end of statue animation that we handle as functor instead
	kAtlantisDoorOpens = 12307,
	kTavernMovieCompleted = 1012001,
	kIntroMerchantPanFinished = 1012002,
	kAtlantisBoatIntro2Finished = 1012003,
	kTakenWood = 1012005,
	kSoundVaseSegment1Finished = 1012006,
	kSoundVaseSegment2Finished = 1012007,
	kSoundVaseSegment3Finished = 1012008,
	kSoundVaseSegment4Finished = 1012009,
	kCoinGiven = 1012010,
	kSandalsPlaced = 1012011
};

static const PrePoint strongBoxSideDotOffsets[] = {
	{1060, 278},
	{1090, 310},
	{1060, 339},
	{1032, 305}
};

static const PrePoint strongBoxTileOffsets[] = {
	{1005, 274},
	{1035, 276},
	{1064, 278},
	{1093, 280},
	{1005, 304},
	{1035, 306},
	{1064, 308},
	{1093, 310},
	{1035, 246},
	{1064, 248},
	{1035, 337},
	{1064, 339}
};

static const int baseFrame[4][8] = {
	{  1,  3,  4,  6,  1,  3,  4,  6 },
	{  7,  9, 10, 12, 13, 15, 16, 18 },
	{ 19, 21, 22, 24, 25, 27, 28, 30 },
	{ 31, 33, 34, 36, 31, 33, 34, 36 }
};

static const int kTileMovementTime = 500;

class StrongBoxTile {
public:
	enum Letter {
		kLetterZ = 1,
		kLetterE,
		kLetterU,
		kLetterS
	};
	enum Orientation {
		kOrientation0 = 0,
		kOrientation90 = 90,
		kOrientation180 = 180,
		kOrientation270 = 270
	};

	void rotate() {
		_orientation = (Orientation) ((_orientation + 90) % 360);
	}

	void show() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		int orientation = _orientation / 45;
		if (_nextPosition != -1 && g_vm->getCurrentTime() > kTileMovementTime + _movementStartTime) {
			_position = _nextPosition;
			_nextPosition = -1;
		}
		Common::Point pos = strongBoxTileOffsets[_position].get();
		if (_nextPosition != -1) {
			double frac = (g_vm->getCurrentTime() - _movementStartTime + 0.0) / kTileMovementTime;
			pos = strongBoxTileOffsets[_position].get() * (1-frac) + strongBoxTileOffsets[_nextPosition].get() * frac;
		}
		int zVal = 500;
		switch (_rotationPhase) {
		case 0:
		case 2:
			pos += Common::Point(-5, 4);
			zVal = 300;
			break;
		case 1:
			orientation++;
			switch (_position) {
			case 1:
				pos = Common::Point(1046, 277);
				break;
			case 2:
				pos = Common::Point(1065, 298);
				break;
			case 5:
				pos = Common::Point(1025, 297);
				break;
			case 6:
				pos = Common::Point(1045, 318);
				break;
			}
			zVal = 300;
			break;
		}
		int frame = baseFrame[_letter - kLetterZ][orientation] - 1;
		if (_position < 4 && _nextPosition == -1 && _rotationPhase < 0)
			frame++;
		room->selectFrame(LayerId("r2010om0", _position, "pos"),
				  zVal, frame, pos);
	}

	void setRotationPhase(int phase) {
		_rotationPhase = phase;
	}

	bool isMoving() {
		return _nextPosition != -1 || _rotationPhase != -1;
	}

	int getPosition() {
		return _position;
	}

	Letter getLetter() {
		return _letter;
	}

	Orientation getOrientation() {
		return _orientation;
	}

	void setPosition(int position) {
		_position = position;
	}

	void moveTo(int pos) {
		_nextPosition = pos;
		_movementStartTime = g_vm->getCurrentTime();
	}

	StrongBoxTile() {
		_letter = kLetterZ;
		_position = 0;
		_orientation = kOrientation0;
		_nextPosition = -1;
		_rotationPhase = -1;
	}

	StrongBoxTile(Letter letter, Orientation orientation, int position) {
		_letter = letter;
		_position = position;
		_orientation = orientation;
		_nextPosition = -1;
		_rotationPhase = -1;
	}
private:
	Letter _letter;
	int _position;
	int _nextPosition;
	int _movementStartTime;
	int _rotationPhase;
	Orientation _orientation;
};

static const struct {
	StrongBoxTile::Letter letter;
	StrongBoxTile::Orientation orientation;
} initialLetters[12] = {
	{StrongBoxTile::kLetterZ, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterE, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterU, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterS, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterE, StrongBoxTile::kOrientation0},
	{StrongBoxTile::kLetterZ, StrongBoxTile::kOrientation0},
	{StrongBoxTile::kLetterU, StrongBoxTile::kOrientation270},
	{StrongBoxTile::kLetterS, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterU, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterE, StrongBoxTile::kOrientation90},
	{StrongBoxTile::kLetterZ, StrongBoxTile::kOrientation0},
	{StrongBoxTile::kLetterS, StrongBoxTile::kOrientation0}
};

class CreteHandler : public Handler {
public:
	CreteHandler() {
		_tavernCounter = 0;
		_oneManBandCounter = 0;
		_merchantIsBusy = false;
		memset(_vaseBusy, 0, sizeof(_vaseBusy));
		for (int i =0; i < 12; i++)
			_strongBoxTiles[i] = StrongBoxTile(initialLetters[i].letter, initialLetters[i].orientation, i);
		_strongBoxPopup = false;
		_fadingHades = false;
		_fadingHadesStartTime = 0;
	}

	void handleClick(const Common::String &name) override {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		if (name == kTalusHotzone) {
			room->playVideo(kTalusMovie, kTalusZ, kTalueMovieCompleted,
					Common::Point(54, 29));
			room->setLayerEnabled(kTalusImageWithShip, false);
			return;
		}

		if (name == "MinosPalace") {
			room->disableMouse();
			g_vm->moveToRoom(kMinosPalaceRoom);
			return;
		}

		if (name == "Poseidon") {
			Common::Array<Common::String> videos;
			videos.push_back("r1230na0");
			videos.push_back("r1230nb0");
			videos.push_back("r1230nc0");

			room->playStatueSMK(kPoseidonStatue,
					    kPoseidonHighlight,
					    5000,
					    videos, 16, 39);
			return;
		}

		if (name == "Zeus") {
			Common::Array<Common::String> videos;
			videos.push_back("r1240wa0");
			videos.push_back("r1240wb0");

			room->playStatueSMK(kZeusStatue, kZeusHighlight, 5000,
					    videos, 23, 35);
			return;
		}

		if (name == "Hermes") {
			Common::Array<Common::String> videos;
			videos.push_back("r2320na0");
			videos.push_back("r2320nb0");

			room->playStatueSMK(kHermesStatue,
					    kHermesHighlight,
					    4000,
					    videos, 22, 39, kOffsetRightRoom);
			return;
		}

		if (name == kTavernHotzone) {
			room->playAnimLoop(kTavernImage, 5000, kOffsetRightRoom);
			room->playVideo(_tavernTalks[_tavernCounter], 5000,
					   kTavernMovieCompleted,
					   kOffsetRightRoom);
			_tavernCounter = (_tavernCounter + 1) % _tavernTalks.size();
			return;
		}

		if (name == "Argo") {
			g_vm->moveToRoom(kArgoRoom);
			return;
		}

		if (name == kHornedHotzone) {
			g_vm->getHeroBelt()->placeToInventory(kHornedStatue, kTakenHornless);
			room->setLayerEnabled(kHorned, false);
			persistent->_creteShowHorned = false;
			_merchantIsBusy = true;
			room->disableHotzone(kHornedHotzone);
			room->disableMouse();
			return;
		}

		if (name == kHornless1Hotzone) {
			g_vm->getHeroBelt()->placeToInventory(kHornlessStatue1, kTakenHorned);
			room->setLayerEnabled(kHornless1, false);
			persistent->_creteShowHornless1 = false;
			room->disableHotzone(kHornless1Hotzone);
			_merchantIsBusy = true;
			room->disableMouse();
			return;
		}

		if (name == kHornless2Hotzone) {
			g_vm->getHeroBelt()->placeToInventory(kHornlessStatue2, kTakenHorned);
			room->setLayerEnabled(kHornless2, false);
			persistent->_creteShowHornless2 = false;
			room->disableHotzone(kHornless2Hotzone);
			_merchantIsBusy = true;
			room->disableMouse();
			return;
		}

		if (name == kHornless3Hotzone) {
			g_vm->getHeroBelt()->placeToInventory(kHornlessStatue3, kTakenHorned);
			room->setLayerEnabled(kHornless3, false);
			persistent->_creteShowHornless3 = false;
			room->disableHotzone(kHornless3Hotzone);
			_merchantIsBusy = true;
			room->disableMouse();
			return;
		}

		if (name == kHornless4Hotzone) {
			g_vm->getHeroBelt()->placeToInventory(kHornlessStatue4, kTakenHorned);
			room->setLayerEnabled(kHornless4, false);
			persistent->_creteShowHornless4 = false;
			room->disableHotzone(kHornless4Hotzone);
			_merchantIsBusy = true;
			room->disableMouse();
			return;
		}

		if (name == kOneManBandHotZone) {
			room->playVideo(
				Common::String::format(
					"r2040b%c0", 'a' + (_oneManBandCounter % 3)),
				1600,
				12135, Common::Point(730, 183));
			room->stopAnim(kOneManBandAnim);
			_oneManBandCounter++;
			return;
		}

		if (name == "AtlantisBoat") {
			room->pushHotZones("Door.HOT");
			room->disableHotzone("wood");
			room->selectFrame("r1010ob0", 1200, 0);
			room->selectFrame(kAtlantisDiskBackground, kAtlantisDiskBackgroundZ, 0);
			for (unsigned i = 0; i < 3; i++)
				_atlantisBoatPosition[i] = g_vm->getRnd().getRandomNumberRng(1, 7);
			renderAtlantisDisks();
			if (persistent->_creteIntroAtlantisWood) {
				room->disableMouse();
				room->playVideo("R1210BA0", 600, kAtlantisBoatIntro2Finished);
				persistent->_creteIntroAtlantisWood = false;
			}
			return;

		}

		if (name == "SmallDisk") {
			advanceAtlantisDisk(2);
			return;
		}

		if (name == "MediumDisk") {
			advanceAtlantisDisk(1);
			return;
		}

		if (name == "LargeDisk") {
			advanceAtlantisDisk(0);
			return;
		}

		if (name == "wood") {
			room->selectFrame(kAtlantisOpening, kAtlantisOpeningZ, 9);
			g_vm->getHeroBelt()->placeToInventory(kWood, kTakenWood);
			room->popHotZones();
			room->disableHotzone("AtlantisBoat");
			persistent->_creteShowAtlantisBoat = false;
			return;
		}

		if (name == "Background") {
			room->popHotZones();
			room->stopAnim("r1010ob0");
			hideStrongBox();
			hideAtlantisPopupOverlays();
			showMiniStrongBox();
			return;
		}

		for (int i = 0; i < 4; i++) {
			if (name == Common::String::format("VaseSegment%d", i + 1) && !_vaseBusy[i]) {
				_vasePos[i]++;
				if (i == 1 || i == 3)
					_vasePos[i] %= 6;
				else
					_vasePos[i] %= 4;
				_vaseBusy[i] = true;
				renderVase();
				room->playSFX(vaseSound[i], kSoundVaseSegment1Finished + i);
				return;
			}
		}

		if (name == "sandals") {
			g_vm->getHeroBelt()->placeToInventory(kSandals, kSandalsPlaced);
			room->selectFrame("r1220ba0", 500, 0);
			room->disableMouse();
			persistent->_creteSandalsState = Persistent::SANDALS_TAKEN;
			return;
		}

		if (name == "AlchemistStand") {
			_alchemistAmbient.play(false);
			return;
		}

		if (name == "StrongBoxClosed"
			|| name == "StrongBoxOpen"
			|| name == "StrongBoxOpenPotion"
			|| name == "StrongBoxOpenNoPotion") {
			showStrongBox();
			return;
		}

		if (name == "Latch") {
			room->disableMouse();
			persistent->_creteStrongBoxState = Persistent::BOX_OPEN;
			room->playAnimWithSFX("r2230bb0", "g0082ea0", 1000,
					      PlayAnimParams::keepLastFrame().partial(1, 3),
					      12402, kOffsetRightRoom);
			return;
		}

		if (name == "ButtonN" && !strongBoxIsBusy()) {
			strongBoxMoveTiles(1, 8, 9, 2);
			return;
		}

		if (name == "ButtonE" && !strongBoxIsBusy()) {
			strongBoxMoveTiles(2, 3, 7, 6);
			return;
		}

		if (name == "ButtonW" && !strongBoxIsBusy()) {
			strongBoxMoveTiles(1, 5, 4, 0);
			return;
		}

		if (name == "ButtonS" && !strongBoxIsBusy()) {
			strongBoxMoveTiles(5, 6, 11, 10);
			return;
		}

		if (name == "ButtonC" && !strongBoxIsBusy()) {
			g_vm->addTimer(12409, 250);
			room->playSFX("r2230ed0", 12412);
			for (int i = 0; i < 12; i++) {
				int pos = _strongBoxTiles[i].getPosition();
				if (pos == 1 || pos == 2 || pos == 5 || pos == 6) {
					_strongBoxTiles[i].setRotationPhase(0);
				}
			}
			return;
		}

		if (name == "Potion") {
			room->disableHotzone("Potion");
			g_vm->getHeroBelt()->placeToInventory(kCoin, kCoinGiven);
			persistent->_creteStrongBoxState = Persistent::BOX_OPEN_NO_POTION;
			room->selectFrame("r2230bf0", 300, -1, kOffsetRightRoom);
			return;
		}
		/*
TODO:
 MNSH: Merchant
*/
	}

	void handleEvent(int eventId) override {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		switch (eventId) {
		case kTakenWood:
			room->stopAnim(kAtlantisOpening);
			room->stopAnim("r1010ob0");
			room->stopAnim(kAtlantisDiskBackground);
			room->enableMouse();
			break;
		case kTalueMovieCompleted:
			room->setLayerEnabled(kTalusImageWithShip, true);
			break;
		case kTavernMovieCompleted:
			room->selectFrame(kTavernImage, kTavernImageZ, 0, kOffsetRightRoom);
			break;
		case kMerchantIdleTimer:
			if (!persistent->_creteShowMerchant
			    || !persistent->_creteShowHornless4 || _merchantIsBusy)
				break;
			room->setLayerEnabled(kHornless4, false);
			room->disableHotzone(kHornless4Hotzone);
			room->playAnim(kMerchantAnim, kMerchantZ,
				       PlayAnimParams::disappear().partial(1, -2),
				       kMerchantIdleAnimCleanup);
			break;
		case kMerchantIdleAnimCleanup:
			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
			room->setLayerEnabled(kHornless4, persistent->_creteShowHornless4);
			room->setHotzoneEnabled(kHornless4Hotzone, persistent->_creteShowHornless4 && persistent->_creteTriedHornless[2]);
			break;
		case kIntroMerchantPanFinished:
			room->setLayerEnabled(kMerchantAnim, false);
			room->playVideo("R2200BA0", kMerchantZ,
					kIntroMerchantVideoFinished,
					Common::Point(308, 99));
			break;
		// TODO: replay of R2200BB0 and R2200BC0
		case kIntroMerchantVideoFinished:
			room->disableMouse();
			room->playVideo("R2200BB0", kMerchantZ,
					12108,
					Common::Point(304, 113));
			_merchantIsBusy = true;
			break;
		case 12108:
			room->disableMouse();
			room->playVideo("R2200BC0", kMerchantZ,
					12109,
					Common::Point(304, 110));
			_merchantIsBusy = true;
			break;
		case 12109:
			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
			room->enableMouse();
			_merchantIsBusy = false;
			break;
		case kTakenHorned:
			room->setLayerEnabled(kMerchantAnim, false);
			room->playVideo("r2210ba0", kMerchantZ, 12117,
					Common::Point(344, 111));
			room->disableMouse();
			break;
		case 12117:
			room->playVideo("r2210bb0", kMerchantZ, 12119,
				Common::Point(308, 112));
			break;
		case kTakenHornless:
			room->setLayerEnabled(kMerchantAnim, false);
			room->playVideo("r2240ba0", kMerchantZ, 12119,
				Common::Point(314, 91));
			_merchantIsBusy = true;
			break;
		case 12119:
			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
			if (!persistent->_cretePlayedEyeGhostTown) {
				room->playVideo("r2210bc0", 1000, 12120,
						   Common::Point(0, 216));
				persistent->_cretePlayedEyeGhostTown = true;
			} else {
				room->enableMouse();
				_merchantIsBusy = false;
			}
			break;
		case 12120:
			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
			room->enableMouse();
			_merchantIsBusy = false;
			break;
		case 12128:
		case 12134:
		case 12143:
		case 12146:
			room->enableMouse();
			break;
		case 12135:
			room->playAnimLoop(kOneManBandAnim, kOneManBandZ, kOffsetRightRoom);
			break;
		case 12142:
			if (persistent->_quest == kMedusaQuest && !persistent->_cretePlayedPhilAlchemist) {
				persistent->_cretePlayedPhilAlchemist = true;
				room->playVideo("r2220bc0", 1000, 12143, Common::Point(640, 216));
				room->disableMouse();
			}
			if (persistent->_quest == kRescuePhilQuest && !persistent->_cretePlayedZeusCheckOutThatBox && persistent->_hintsAreEnabled) {
				g_vm->addTimer(12144, 5000, -1);
			}
			break;
		case 12144:
			if (!room->isMouseEnabled() || persistent->_cretePlayedZeusCheckOutThatBox)
				break;
			persistent->_cretePlayedZeusCheckOutThatBox = true;
			room->disableMouse();
			room->playAnimWithSpeech("r2230ba0",
						TranscribedSound::make("r2230wa0",
								 "Hey, why don't you check out that box? Maybe it has something that can help"),
						4000,
						PlayAnimParams::keepLastFrame(),
						12145,
						kOffsetRightRoom);
			break;
		case kAtlantisBoatIntro2Finished:
			room->enableMouse();
			break;
		case kAtlantisDoorOpens:
			room->disableHotzone("LargeDisk");
			room->disableHotzone("MediumDisk");
			room->disableHotzone("SmallDisk");
			room->disableHotzone("Background");
			room->enableHotzone("wood");
			room->playVideo("r1210bd0", 600, 12308);
			break;
		case 12308:
			room->enableMouse();
			break;
		case kSoundVaseSegment1Finished:
		case kSoundVaseSegment2Finished:
		case kSoundVaseSegment3Finished:
		case kSoundVaseSegment4Finished: {
			int vase = eventId - kSoundVaseSegment1Finished;
			bool won = true;
			_vaseBusy[vase] = false;
			for (int i = 0; i < 4; i++) {
				if (_vaseBusy[i])
					won = false;
			}

			for (int i = 0; i < 4; i++) {
				if (_vasePos[i] != vaseSol[i])
					won = false;
			}

			if (!won)
				break;

			for (int i = 0; i < 4; i++)
				room->stopAnim(vaseSegment[i]);

			for (int i = 0; i < 4; i++)
				room->disableHotzone(Common::String::format("VaseSegment%d", i + 1));

			room->playAnim("r1220ba0", 500,
				       PlayAnimParams::disappear().partial(0, 17), 12206);
			room->playVideo("r1220mb0", 0);
			room->playSFX("r1220ea0");
			room->disableMouse();
			break;
		}
		case 12206:
			showSandals();
			persistent->_creteSandalsState = Persistent::SANDALS_SOLVED;
			room->enableMouse();
			break;
		case 12303:
		case 12304:
		case 12305:
			if (_atlantisBoatPosition[0] == 0
			    && _atlantisBoatPosition[1] == 0
			    && _atlantisBoatPosition[2] == 0) {
				handleEvent(12306);
			}
			break;
		case 12306:
			room->disableMouse();
			hideAtlantisPopupOverlays();
			room->playAnimWithSFX(kAtlantisOpening, "r1210eb0", kAtlantisOpeningZ,
						PlayAnimParams::keepLastFrame().partial(0, 8),
						kAtlantisDoorOpens);
			break;
		case 12402:
			room->enableMouse();
			redrawStrongBox();
			// Fallthrough
		case 12403:
			room->disableMouse();
			room->playAnimWithSpeech("r2230ba0",
						 TranscribedSound::make("r2230wb0", "I think those buttons control the symbols"),
						 4000,
						 PlayAnimParams::keepLastFrame(), 12404,
						 kOffsetRightRoom);
			break;
		case 12404:
		case 12405:
			if (persistent->_hintsAreEnabled)
				g_vm->addTimer(12406, 5000);
			// Fallthrough
		case 12407:
		case 12408:
		case 12145:
			room->playAnim("r2230ba0", 4000, PlayAnimParams::disappear().backwards(), -1,
				       kOffsetRightRoom);
			room->enableMouse();
			break;
		case 12406:
			if (!room->isMouseEnabled())
				break;
			room->disableMouse();
			room->playAnimWithSpeech("r2230ba0",
						 TranscribedSound::make("r2230wc0", "Try to spell my name"),
						 4000,
						 PlayAnimParams::keepLastFrame(), 12407,
						 kOffsetRightRoom);
			break;
		case 12409:
			for (int i = 0; i < 12; i++) {
				int pos = _strongBoxTiles[i].getPosition();
				if (pos == 1 || pos == 2 || pos == 5 || pos == 6) {
					_strongBoxTiles[i].setRotationPhase(1);
				}
			}
			g_vm->addTimer(12410, 250);
			break;
		case 12410:
			for (int i = 0; i < 12; i++) {
				int pos = _strongBoxTiles[i].getPosition();
				if (pos == 1 || pos == 2 || pos == 5 || pos == 6) {
					_strongBoxTiles[i].setRotationPhase(2);
					_strongBoxTiles[i].rotate();
					switch (pos) {
					case 1:
						_strongBoxTiles[i].setPosition(2);
						break;
					case 2:
						_strongBoxTiles[i].setPosition(6);
						break;
					case 5:
						_strongBoxTiles[i].setPosition(1);
						break;
					case 6:
						_strongBoxTiles[i].setPosition(5);
						break;
					}
				}
			}
			g_vm->addTimer(12411, 250);
			break;
		case 12411:
			for (int i = 0; i < 12; i++) {
				_strongBoxTiles[i].setRotationPhase(-1);
			}
			redrawStrongBox();
			break;
		case 12414:
			room->playVideo("v4190ma0", 0, 12415);
			break;
		case 12204:
		case 12415:
			room->enableMouse();
			break;
		case kCoinGiven:
			g_vm->getHeroBelt()->placeToInventory(kPotion);
			break;
		case 12124:
			_fadingHades = true;
			_fadingHadesStartTime = g_vm->getCurrentTime();
			break;
		case 12125:
			room->stopAnim("r2035ba0");
			room->playVideo("R2035BE0", 1200, 12127);
			break;
		case 12127:
			g_vm->moveToRoom(kDaedalusRoom);
			break;
		case kSandalsPlaced:
			room->playVideo("r1220bb0", 0, 12204);
			break;
		}
	}

	void prepareRoom() override {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		Quest quest = persistent->_quest;

		if (persistent->_creteHadesPusnishesPainAndPanic) {
			room->disableHeroBelt();
			room->disableMouse();
			room->addStaticLayer("r2035pa0", kBackgroundZ); // background
			room->selectFrame("r2035ba0", 1200, 0);

			// Originally event 12123
			room->playSpeech(TranscribedSound::make(
						      "r2035wa0",
						      "Seems the only thing I can count on you two for is target practice"), 12124);
			persistent->_creteHadesPusnishesPainAndPanic = false;
			return;
		}

		room->loadHotZones("Crete.HOT", false);
		room->addStaticLayer("r1010pa0", kBackgroundZ); // background
		g_vm->getHeroBelt()->setColour(HeroBelt::kWarm);

		if (quest != kMedusaQuest && quest != kRescuePhilQuest) {
			room->playAnimLoop("r2010oe0", 7000, kOffsetRightRoom);
			room->playAnimLoop("r2010tb0", 6500, kOffsetRightRoom);
		}
		room->playAnimLoop("r2010ta0", 7600, kOffsetRightRoom);
		room->playAnimLoop("r1120ba0", 5500);
		room->playAnimLoop("r1160ba0", 5000);
		room->playAnimLoop("r1170ba0", 5000);

		room->selectFrame(kTavernImage, kTavernImageZ, 0, kOffsetRightRoom);
		room->enableMouse();
		room->setPannable(true);
		room->enableHotzone(kTavernHotzone);
		room->enableHotzone("Argo");
		room->enableHotzone("Hermes");
		room->enableHotzone("Zeus");
		room->enableHotzone("Poseidon");
		room->enableHotzone("MinosPalace");
		if (quest != kMedusaQuest && quest != kRescuePhilQuest) {
			room->enableHotzone("AlchemistStand");
		}

		room->setUserPanCallback(-1, -1, 12140, 12142);

		if (quest == kMedusaQuest && !persistent->_creteAlchemistExploded) {
			persistent->_creteAlchemistExploded = true;
			room->disableMouse();
			room->playAnimWithSFX("r1190ba0", "r1190ea0", 1005, PlayAnimParams::disappear(), 12128);
		}

		if (quest == kRescuePhilQuest || quest == kMedusaQuest) {
			room->selectFrame("r2010op0", 7500, 0, kOffsetRightRoom);
		}

		if (quest == kMedusaQuest) {
			room->playAnimWithSFX("r2220bb0", "r2220eb0", 4500, PlayAnimParams::loop(), -1, kOffsetRightRoom);
		}

		showMiniStrongBox();

		switch (quest) {
		case kCreteQuest:
			_tavernTalks.push_back("r2250xa0");
			_tavernTalks.push_back("r2250xb0");
			_tavernTalks.push_back("r2250xc0");
			_tavernTalks.push_back("r2250xd0");
			_tavernTalks.push_back("r2250xe0");
			_tavernTalks.push_back("r2250xf0");
			_tavernTalks.push_back("r2220xa0");
			_tavernTalks.push_back("r2220xb0");
			_tavernTalks.push_back("r2220xc0");
			_tavernTalks.push_back("r2220xd0");
			_tavernTalks.push_back("r2220xe0");
			_tavernTalks.push_back("r2220xf0");
			break;
		case kTroyQuest:
			_tavernTalks.push_back("r2260xa0");
			_tavernTalks.push_back("r2260xb0");
			_tavernTalks.push_back("r2195xa0");
			_tavernTalks.push_back("r2195xb0");
			_tavernTalks.push_back("r2290xf0");
			_tavernTalks.push_back("r2220xa0");
			_tavernTalks.push_back("r2220xb0");
			_tavernTalks.push_back("r2220xc0");
			_tavernTalks.push_back("r2220xd0");
			_tavernTalks.push_back("r2220xe0");
			_tavernTalks.push_back("r2220xf0");
			break;
		case kMedusaQuest:
			_tavernTalks.push_back("r2270xa0");
			_tavernTalks.push_back("r2270xb0");
			_tavernTalks.push_back("r2290xg0");
			_tavernTalks.push_back("r2290xh0");
			_tavernTalks.push_back("r2290xi0");
			_tavernTalks.push_back("r2290xj0");
			_tavernTalks.push_back("r2290xk0");
			_tavernTalks.push_back("r2290xl0");
			break;
		case kRescuePhilQuest:
			_tavernTalks.push_back("r2280xa0");
			_tavernTalks.push_back("r2280xc0");
			_tavernTalks.push_back("r2280xd0");
			_tavernTalks.push_back("r2290xg0");
			_tavernTalks.push_back("r2290xh0");
			_tavernTalks.push_back("r2290xi0");
			_tavernTalks.push_back("r2290xj0");
			_tavernTalks.push_back("r2290xk0");
			_tavernTalks.push_back("r2290xl0");
			break;

		// To silence warning
		case kNoQuest:
		case kEndGame:
		case kNumQuests:
			break;
		}
		_tavernTalks.push_back("r2290xa0");
		_tavernTalks.push_back("r2290xb0");
		_tavernTalks.push_back("r2290xc0");
		_tavernTalks.push_back("r2290xd0");
		_tavernTalks.push_back("r2290xe0");

		int bg1_variant = -1;
		int bg2_variant = -1;

		bool showOiBoat = false;

		if (!persistent->_creteShowMerchant && (quest != kMedusaQuest || !persistent->_medisleShowFates)) {
			bg1_variant = g_vm->getRnd().getRandomNumberRng(0, 2);
			bg2_variant = g_vm->getRnd().getRandomNumberRng(0, 2);
			debug("BG variants %d and %d", bg1_variant, bg2_variant);
		}

		if (randomBool()) {
			showOiBoat = true;
			room->addStaticLayer("r1010oi0", 4000);
		}
		if (randomBool())
			room->addStaticLayer("r1010oj0", 4000);
		if (randomBool())
			room->addStaticLayer("r1010ok0", 4000);
		if (randomBool())
			room->addStaticLayer("r1010ol0", 4000);
		if (randomBool())
			room->addStaticLayer("r1010on0", 4001);
		if (randomBool())
			room->addStaticLayer("r1010oo0", 4000);
		if (randomBool())
			room->addStaticLayer("r1010op0", 4100);
		if (randomBool())
			room->addStaticLayer("r1010or0", 6500);

		if (quest != kCreteQuest)
			persistent->_creteShowAtlantisBoat = false;

		if (persistent->_creteShowAtlantisBoat) {
			room->addStaticLayer("r1010od0", 3900);
			room->addStaticLayer("r1010ta0", 3800);
			room->enableHotzone("AtlantisBoat");
		}

		room->playAnimLoop("r1010om0", 3000);

		int minotaurPosition = -1;
		int toughGuyPosition = -1;
		int womanSmellPosition = -1;
		if (quest == kCreteQuest && !persistent->_creteShowMerchant && !persistent->_creteShowAtlantisBoat)
			minotaurPosition = g_vm->getRnd().getRandomNumberRng(0, 3);

		bool showCat = false;
		bool showStatueMan = false;
		bool showOldMan = false;
		bool showBlondBoy = false;
		bool showMotherAndKidSmall = false;
		bool showMotherAndKid = false;
		bool showManSelling = false;
		bool showDrawinWithoutWoman = false;
		bool showWomanDrawing = false;
		bool showWomanGraffiti = false;
		bool showGirlAndNut = false;
		bool showOneManBand = false;
		int ambientComposite = g_vm->getRnd().getRandomNumberRng(1, 8);
		debug("Ambients from Composite %d selected. \n", ambientComposite);
		switch (ambientComposite) {
		case 1:
			showGirlAndNut = true;
			if (quest != kCreteQuest && quest != kTroyQuest) {
				toughGuyPosition = 1;
				break;
			}
			if (minotaurPosition == 1) {
				if (randomBool())
					toughGuyPosition = 0;
				break;

			}
			if (persistent->_creteShowMerchant) {
				showOneManBand = true;
				showWomanGraffiti = true;
				break;
			}
			if (randomBool()) {
				toughGuyPosition = 0;
				showOneManBand = true;
				showWomanGraffiti = true;
			}
			else
				toughGuyPosition = 1;
			break;
		case 2:
			womanSmellPosition = g_vm->getRnd().getRandomNumberRng(0, 2);
			showWomanDrawing = true;
			showManSelling = true;
			if (quest != kMedusaQuest && quest != kRescuePhilQuest)
				showMotherAndKid = true;
			showBlondBoy = true;
			break;
		case 3:
			if (quest != kRescuePhilQuest && bg1_variant != 0 && bg1_variant != 1)
				showCat = true;
			showOldMan = true;
			if (!persistent->_creteShowMerchant) {
				showManSelling = true;
				toughGuyPosition = 2;
			}
			showWomanGraffiti = true;
			showWomanDrawing = true;
			break;
		case 4:
			if (quest != kRescuePhilQuest && bg1_variant != 0 && bg1_variant != 1)
				showCat = true;
			showWomanDrawing = true;
			toughGuyPosition = 2;
			showOneManBand = true;
			break;
		case 5:
			if (quest != kCreteQuest && quest != kTroyQuest)
				toughGuyPosition = 1;
			else
				toughGuyPosition = g_vm->getRnd().getRandomBit();
			womanSmellPosition = g_vm->getRnd().getRandomBit();
			break;
		case 6:
			showWomanGraffiti = true;
			showWomanDrawing = true;
			if (quest != kCreteQuest && quest != kTroyQuest)
				toughGuyPosition = 1;
			else
				toughGuyPosition = g_vm->getRnd().getRandomBit();
			break;
		case 7:
			womanSmellPosition = g_vm->getRnd().getRandomNumberRng(0, 2);
			if (womanSmellPosition == 2 && (quest != kCreteQuest && quest != kTroyQuest))
				womanSmellPosition = -1;
			if (quest == kMedusaQuest)
				showStatueMan = true;
			showMotherAndKidSmall = true;
			showWomanGraffiti = true;
			break;
		case 8:
			if (quest != kCreteQuest && quest != kTroyQuest) {
				toughGuyPosition = 1;
				showDrawinWithoutWoman = true;
				break;
			}

			if (!persistent->_creteShowMerchant && randomBool()) {
				toughGuyPosition = 2;
				showBlondBoy = true;
			}
			else
				toughGuyPosition = 1;
			showOldMan = true;
			showDrawinWithoutWoman = true;
			break;
		}

		int birdsState = g_vm->getRnd().getRandomNumberRng(0, 2);
		int dolphinPosition = -1;
		if (!persistent->_creteShowAtlantisBoat)
			dolphinPosition = g_vm->getRnd().getRandomNumberRng(0, showOiBoat ? 1 : 2);
		if (quest != kMedusaQuest && quest != kRescuePhilQuest)
			_alchemistAmbient = ambient("r2220ba0", "r2220ec0", 5500, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom, true);

		// Disable conflicting images
		if (minotaurPosition == 1
		    && (toughGuyPosition == 1 || toughGuyPosition == 2))
			toughGuyPosition = -1;
		if (minotaurPosition == 1) {
			showWomanGraffiti = false;
			showManSelling = false;
			showOneManBand = false;
		}
		if (persistent->_creteShowMerchant &&
		    (toughGuyPosition == 0 || toughGuyPosition == 1))
			toughGuyPosition = -1;
		if (womanSmellPosition == 2)
			showMotherAndKid = false;
		if (persistent->_creteShowMerchant)
			showCat = false;
		if (quest != kCreteQuest && quest != kTroyQuest)
			showOldMan = false;

		debug("toughGuyPosition = %d, minotaurPosition = %d, dolphinPosition = %d",
		      toughGuyPosition, minotaurPosition, dolphinPosition);
		if (showWomanGraffiti)
			ambient("r2370ba0", "r2370ea0", 1700, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		switch (toughGuyPosition) {
		case 0:
			ambient("r2340ba0", "r2340ea0", 1400, 15, 25, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
			break;
		case 1:
			ambient("r2340bb0", "r2340eb0", 1400, 15, 25, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
			break;
		case 2:
			ambient("r2340be0", "r2340ee0", 1600, 15, 25, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
			break;
		}
		if (showOneManBand) {
			room->playAnimLoop(kOneManBandAnim, kOneManBandZ, kOffsetRightRoom);
			room->enableHotzone(kOneManBandHotZone);
		}
		if (showGirlAndNut)
			ambient("r2140ba0", "r2140ea0", 1500, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showWomanDrawing)
			ambient("r2110ba0", "r2110ea0", 1600, 10, 30, AmbientAnim::PAN_LEFT);
		if (showDrawinWithoutWoman)
			room->addStaticLayer("r2110bb0", 1600);
		if (showManSelling)
			ambient("r2150ba0", "r2150ea0", 1600, 10, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showMotherAndKid)
			ambient("r2160ba0", "r2160ea0", 1500, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showMotherAndKidSmall)
			ambient("r2160bb0", "", 1500, 15, 30, AmbientAnim::PAN_LEFT);
		if (showBlondBoy)
			ambient("r2350ba0", "r2350ea0", 1500, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showOldMan)
			ambient("r2100bb0", "r2100eb0", 1500, 10, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showStatueMan)
			ambient("r2050ba0", "r2050ea0", 1500, 10, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
		if (showCat) {
			room->addStaticLayer("r2010on0", kMerchantStandZ);
			ambient("r2080bb0", "r2080eb0", kMerchantZ, 10, 30, AmbientAnim::PAN_LEFT);
		}

		if (persistent->_creteShowMerchant) {
			room->addStaticLayer("r2010on0", kMerchantStandZ);
			room->selectFrame(kMerchantAnim, kMerchantZ, 0);
			room->playSFX("G0261mA0");
			if (persistent->_creteShowHorned) {
				room->addStaticLayer(kHorned, 1220);
				room->enableHotzone(kHornedHotzone);
			}
			if (persistent->_creteShowHornless2) {
				room->addStaticLayer(kHornless2, 1190);
				room->setHotzoneEnabled(kHornless2Hotzone,
					persistent->_creteTriedHornless[0]);
			}
			if (persistent->_creteShowHornless1) {
				room->addStaticLayer(kHornless1, 1180);
				room->enableHotzone(kHornless1Hotzone);
			}
			if (persistent->_creteShowHornless3) {
				room->addStaticLayer(kHornless3, 1180);
				room->setHotzoneEnabled(kHornless3Hotzone,
					persistent->_creteTriedHornless[1]);
			}
			if (persistent->_creteShowHornless4) {
				room->addStaticLayer(kHornless4, 1180);
				room->setHotzoneEnabled(kHornless4Hotzone,
					persistent->_creteTriedHornless[2]);
				g_vm->addTimer(kMerchantIdleTimer, 10000, -1);
			}
		}

		if (birdsState == 0) {
			room->addStaticLayer(kTalusImageWithShip, kTalusZ);
			room->enableHotzone(kTalusHotzone);
		} else
			room->addStaticLayer(kTalusImage, kTalusZ);

		// TODO: fix this
		switch (minotaurPosition) {
		case 0:
			ambient("r2060bf0", "r2060ee0", 1800, 3, 4, AmbientAnim::PAN_RIGHT, kOffsetRightRoom); // shouldn't be an ambient
			break;
		case 1:
			ambient("r2060bt0", "r2060ei0", 1650, 3, 4, AmbientAnim::PAN_RIGHT, kOffsetRightRoom); // shouldn't be an ambient
			break;
		case 2:
//			ambient("r1110ea0", "", 15, 30); // wrong
			break;
		case 3:
			ambient("r1110ba0", "r1110eb0", 850, 20, 40, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
			break;
		}

		switch (womanSmellPosition) {
		case 0:
			ambient("r2380ba0", "r2380ea0", 1550, 15, 30, AmbientAnim::PAN_ANY);
			break;
		case 1:
			ambient("r2380bc0", "r2380ec0", 1550, 15, 30, AmbientAnim::PAN_ANY);
			break;
		case 2:
			ambient("r2380bd0", "r2380ed0", 1550, 15, 30, AmbientAnim::PAN_RIGHT, kOffsetRightRoom);
			break;
		}

		switch (birdsState) {
		case 0:
			ambient("r1060ba0", "r1060ea0", 4500, 10, 40, AmbientAnim::PAN_ANY);
			break;
		case 1:
			ambient("r1060bb0","r1060eb0", 4500, 5, 40, AmbientAnim::PAN_ANY);
			break;
		case 2:
			ambient("r1060bc0", "r1060ec0", 4500, 5, 40, AmbientAnim::PAN_ANY);
			break;
		}

		if (dolphinPosition >= 0) {
			Common::String dolphinAnim = Common::String::format(
				"r1150b%c0", 'a' + dolphinPosition);
			Common::String dolphinSound = Common::String::format(
				"r1150e%c0", 'a' + dolphinPosition);

			ambient(dolphinAnim, dolphinSound, 5500, 5, 20, AmbientAnim::PAN_LEFT);
		}

		if (bg1_variant >= 0 && bg2_variant >= 0) {
			Common::String bg2 = Common::String::format(
				"r1010o%c1", 'e' + bg2_variant);
			room->addStaticLayer(bg2, 3500);

			Common::String bg1 = Common::String::format(
				"r1010o%c0", 'e' + bg1_variant);
			room->addStaticLayer(bg1, 1000);
		}

		room->playMusicLoop("R1010eA0");

		if (g_vm->getPreviousRoomId() == kMinosPalaceRoom) {
			room->panRightInstant();
			if (persistent->_creteIntroMerchant) {
				room->disableMouse();
				room->panLeftAnim(kIntroMerchantPanFinished);
				_merchantIsBusy = true;
				persistent->_creteIntroMerchant = false;
			}

			if (persistent->_creteIntroAtlantisBoat) {
				persistent->_creteIntroAtlantisBoat = false;
				room->disableMouse();
				room->playVideo("r1180ba0", 0, 12134, Common::Point(640, 216));
			}

		}

		if (quest == kMedusaQuest && persistent->_medisleShowFates) {
			switch (persistent->_creteSandalsState) {
			case Persistent::SANDALS_NOT_SOLVED:
				for (int i = 0; i < 4; i++)
					room->enableHotzone(Common::String::format("VaseSegment%d", i + 1));
				_vasePos[0] = (g_vm->getRnd().getRandomNumberRng(1, 3) + 2) % 4;
				_vasePos[1] = (g_vm->getRnd().getRandomNumberRng(1, 5) + 3) % 6;
				_vasePos[2] = (g_vm->getRnd().getRandomNumberRng(1, 5) + 2) % 6;
				_vasePos[3] = (g_vm->getRnd().getRandomNumberRng(1, 3) + 3) % 4;
				renderVase();
				break;
			case Persistent::SANDALS_SOLVED:
				showSandals();
				break;
			case Persistent::SANDALS_TAKEN:
				room->selectFrame("r1220ba0", 500, 0);
				break;
			}
		}

		switch (persistent->_quest) {
		case kCreteQuest:
			if (!persistent->_roomVisited[kMinosPalaceRoom]) {
				room->playVideo("r1260ma0", 0);
				break;
			}

			if (persistent->_creteShowMerchant) {
				room->playVideo("g0261ma0", 0);
				break;
			}
			break;
		case kMedusaQuest:
			if (persistent->_medisleShowFates && persistent->_creteSandalsState == Persistent::SANDALS_NOT_SOLVED)
				room->playVideo("r1220ma0", 0);
			break;
		case kRescuePhilQuest:
			if (persistent->_creteStrongBoxState == Persistent::BOX_CLOSED || persistent->_creteStrongBoxState == Persistent::BOX_OPEN)
				room->playVideo("r2230ma0", 0);
			break;
		// To silence warning
		case kTroyQuest:
		case kNoQuest:
		case kEndGame:
		case kNumQuests:
			break;
		}

		if (!persistent->_creteSaidHelenPermanentResident && persistent->_quest == kTroyQuest) {
			persistent->_creteSaidHelenPermanentResident = true;
			room->disableMouse();
			room->playVideo("r1250ba0", 0, 12134, Common::Point(0, 216));
		}
	}

	void frameCallback() override {
		if (_strongBoxPopup && strongBoxIsBusy())
			redrawStrongBox();
		if (_fadingHades) {
			Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
			int val = (256 * (g_vm->getCurrentTime() - _fadingHadesStartTime)) / 2000;
			if (val >= 256) {
				_fadingHades = false;
				val = 256;
				handleEvent(12125);
			}
			room->setColorScale("r2035pa0", 256 - val);
		}
	}

private:
	void showMiniStrongBox() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		if (persistent->_quest != kRescuePhilQuest)
			return;

		switch(persistent->_creteStrongBoxState) {
		case Persistent::BOX_CLOSED:
			room->enableHotzone("StrongBoxClosed");
			room->selectFrame("r2010ba0", 5000, 0, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN:
			room->enableHotzone("StrongBoxOpen");
			room->selectFrame("r2010ba0", 5000, 1, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN_POTION:
			room->enableHotzone("StrongBoxOpenPotion");
			room->selectFrame("r2010ba0", 5000, 2, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN_NO_POTION:
			room->enableHotzone("StrongBoxOpenNoPotion");
			room->selectFrame("r2010ba0", 5000, 3, kOffsetRightRoom);
			break;
		}
	}

	AmbientAnim ambient(const Common::String &anim, const Common::String &sound,
			    int zValue, int minint, int maxint,
			    AmbientAnim::PanType pan,
			    Common::Point offset = Common::Point(0,0),
			    bool loop = true) {
		AmbientAnim ret = AmbientAnim(anim, sound, zValue, minint * 1000, maxint * 1000,
					      loop ? AmbientAnim::KEEP_LOOP : AmbientAnim::DISAPPEAR,
					      offset, pan);
		ret.start();
		return ret;
	}

	bool randomBool() const {
		return g_vm->getRnd().getRandomBit();
	}

	void renderAtlantisDisks() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		room->selectFrame(kAtlantisLargeDisk, kAtlantisLargeDiskZ, _atlantisBoatPosition[0]);
		room->selectFrame(kAtlantisMediumDisk, kAtlantisMediumDiskZ, _atlantisBoatPosition[1]);
		room->selectFrame(kAtlantisSmallDisk, kAtlantisSmallDiskZ, _atlantisBoatPosition[2]);
	}

	void advanceAtlantisDisk(int diskNum) {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		_atlantisBoatPosition[diskNum] = (_atlantisBoatPosition[diskNum] + 1) % 8;
		renderAtlantisDisks();
		room->playSFX(Common::String::format("r1210e%c0", 'e' + diskNum), 12303 + diskNum);
	}

	void hideAtlantisPopupOverlays() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		room->stopAnim(kAtlantisLargeDisk);
		room->stopAnim(kAtlantisMediumDisk);
		room->stopAnim(kAtlantisSmallDisk);
		room->stopAnim(kAtlantisDiskBackground);
	}

	void renderVase() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		for(int i = 0; i < 4; i++)
			room->selectFrame(vaseSegment[i], 1000, _vasePos[i]);

	}

	void showSandals() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		room->playAnim("r1220ba0", 500, PlayAnimParams::loop().partial(9, 17));
		room->enableHotzone("sandals");
	}

	void showStrongBox() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		// User already clicked, no need to play that anim
		persistent->_cretePlayedZeusCheckOutThatBox = true;
		room->pushHotZones("Box.Hot");
		room->playSFX("g0082ea0");
		redrawStrongBox();
		_strongBoxPopup = true;
		switch(persistent->_creteStrongBoxState) {
		case Persistent::BOX_CLOSED:
			room->selectFrame("r2230bb0", 1000, 1, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN:
			room->selectFrame("r2230bb0", 1000, 3, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN_POTION:
			room->selectFrame("r2230bb0", 1000, 3, kOffsetRightRoom);
			room->selectFrame("r2230bf0", 300, -2, kOffsetRightRoom);
			break;
		case Persistent::BOX_OPEN_NO_POTION:
			room->selectFrame("r2230bb0", 1000, 3, kOffsetRightRoom);
			room->selectFrame("r2230bf0", 300, -1, kOffsetRightRoom);
			break;
		}
	}

	void hideStrongBox() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		room->stopAnim("r2230bb0");
		room->stopAnim("r2230bf0");
		for (int i = 0; i < 12; i++)
			room->stopAnim(LayerId("r2010om0", i, "pos"));
		room->stopAnim(LayerId("r2010om1", 0, "center"));
		for (int i = 0; i < 4; i++) {
			room->stopAnim(LayerId("r2010om1", i, "side"));
		}
		_strongBoxPopup = false;
	}

	void redrawStrongBox() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();

		room->setHotzoneEnabled("Potion", persistent->_creteStrongBoxState == Persistent::BOX_OPEN_POTION);
		room->setHotzoneEnabled("Latch", persistent->_creteStrongBoxState == Persistent::BOX_CLOSED);
		room->setHotzoneEnabled("ButtonN", persistent->_creteStrongBoxState == Persistent::BOX_OPEN);
		room->setHotzoneEnabled("ButtonS", persistent->_creteStrongBoxState == Persistent::BOX_OPEN);
		room->setHotzoneEnabled("ButtonE", persistent->_creteStrongBoxState == Persistent::BOX_OPEN);
		room->setHotzoneEnabled("ButtonW", persistent->_creteStrongBoxState == Persistent::BOX_OPEN);
		room->setHotzoneEnabled("ButtonC", persistent->_creteStrongBoxState == Persistent::BOX_OPEN);

		switch(persistent->_creteStrongBoxState) {
		case Persistent::BOX_CLOSED:
			break;
		case Persistent::BOX_OPEN:
			room->selectFrame(LayerId("r2010om1", 0, "center"), 400, 0, Common::Point(1060, 308));
			for (int i = 0; i < 4; i++) {
				room->selectFrame(LayerId("r2010om1", i, "side"), 400, 1,
						  strongBoxSideDotOffsets[i].get());
			}
			{
				bool wasMoving = strongBoxIsBusy();
				for (int i = 0; i < 12; i++) {
					_strongBoxTiles[i].show();
				}
				if (wasMoving && !strongBoxIsBusy()) {
					strongBoxCheckSolution();
				}
			}
			break;
		case Persistent::BOX_OPEN_POTION:
		case Persistent::BOX_OPEN_NO_POTION:
			room->selectFrame(LayerId("r2010om1", 0, "center"), 400, 0, Common::Point(1060, 308));
			for (int i = 0; i < 4; i++) {
				room->selectFrame(LayerId("r2010om1", i, "side"), 400, 1,
						  strongBoxSideDotOffsets[i].get());
			}
			for (int i = 0; i < 12; i++) {
				_strongBoxTiles[i].show();
			}
			break;
		}
	}

	bool strongBoxIsBusy() {
		for (int i = 0; i < 12; i++) {
			if (_strongBoxTiles[i].isMoving()) {
				return true;
			}
		}
		return false;
	}

	void strongBoxCheckSolution() {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		Persistent *persistent = g_vm->getPersistent();
		bool zOk = false, eOk = false, uOk = false, sOk = false;
		for (int i = 0; i < 12; i++) {
			if (_strongBoxTiles[i].getPosition() == 0
			    && _strongBoxTiles[i].getLetter() == StrongBoxTile::kLetterZ
			    && (_strongBoxTiles[i].getOrientation() == 0
				|| _strongBoxTiles[i].getOrientation() == 180))
				zOk = true;
			if (_strongBoxTiles[i].getPosition() == 1
			    && _strongBoxTiles[i].getLetter() == StrongBoxTile::kLetterE
			    && _strongBoxTiles[i].getOrientation() == 0)
				eOk = true;
			if (_strongBoxTiles[i].getPosition() == 2
			    && _strongBoxTiles[i].getLetter() == StrongBoxTile::kLetterU
			    && _strongBoxTiles[i].getOrientation() == 0)
				uOk = true;
			if (_strongBoxTiles[i].getPosition() == 3
			    && _strongBoxTiles[i].getLetter() == StrongBoxTile::kLetterS
			    && (_strongBoxTiles[i].getOrientation() == 0
				|| _strongBoxTiles[i].getOrientation() == 180))
				sOk = true;
		}

		if (zOk && eOk && uOk && sOk) {
			persistent->_creteStrongBoxState = Persistent::BOX_OPEN_POTION;
			room->disableMouse();
			room->enableHotzone("Potion");
			room->disableHotzone("ButtonS");
			room->disableHotzone("ButtonN");
			room->disableHotzone("ButtonE");
			room->disableHotzone("ButtonW");
			room->disableHotzone("ButtonC");
			room->playAnimWithSFX("r2230bf0", "r2230ea0", 300,
					      PlayAnimParams::keepLastFrame().partial(0, -2),
					      12414, kOffsetRightRoom);
		}
	}

	void strongBoxMoveTiles(int p1, int p2, int p3, int p4) {
		Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
		room->playSFX("r2230ee0");
		for (int i = 0; i < 12; i++) {
			int pos = _strongBoxTiles[i].getPosition();
			if (pos == p1)
				_strongBoxTiles[i].moveTo(p2);
			if (pos == p2)
				_strongBoxTiles[i].moveTo(p3);
			if (pos == p3)
				_strongBoxTiles[i].moveTo(p4);
			if (pos == p4)
				_strongBoxTiles[i].moveTo(p1);
		}
	}

	bool _fadingHades;
	int _fadingHadesStartTime;
	int _tavernCounter;
	int _oneManBandCounter;
	int _atlantisBoatPosition[3];
	bool _merchantIsBusy;
	int _vasePos[4];
	bool _vaseBusy[4];
	bool _strongBoxPopup;
	StrongBoxTile _strongBoxTiles[12];
	Common::Array<Common::String> _tavernTalks;
	AmbientAnim _alchemistAmbient;
};

Common::SharedPtr<Hadesch::Handler> makeCreteHandler() {
	return Common::SharedPtr<Hadesch::Handler>(new CreteHandler());
}

}
