/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "common/scummsys.h"
#include "common/config-manager.h"
#include "mads/mads.h"
#include "mads/game.h"
#include "mads/screen.h"
#include "mads/msurface.h"
#include "mads/phantom/game_phantom.h"
//#include "mads/nebular/dialogs_nebular.h"
#include "mads/phantom/globals_phantom.h"
#include "mads/phantom/phantom_scenes.h"

namespace MADS {

namespace Phantom {

	Catacombs _easyCatacombs[32] = {
		{ 401, { -1,  1,  2,  6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 404, { 10, 11,  3,  0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
		{ 404, {  0,  3,  4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
		{ 401, {  1, 14,  5,  2 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT },
		{ 453, {  2,  4, -1,  4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
		{ 403, {  3,  6, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
		{ 406, { -1,  0, -1,  5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 453, { -1,  8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1,  9, -1,  7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 401, {  1, -1, 10,  8 }, { 2, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
		{ 408, {  9, -1,  1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 453, { 12, -1, -1,  1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
		{ 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 401, { 13, 20, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
		{ 453, { 16, 15, -1,  3 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
		{ 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
		{ 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
		{ 403, { 21, 22, -1, 13 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_SKULL },
		{ 404, { -1, -1, 20, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 406, { -1, 23, -1, 20 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { 24, 23, 23, 22 }, { 2, 2, 1, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
		{ 401, { -1,  1, 23, 25 }, { 2, 1, 0, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT | MAZE_EVENT_BRICK },
		{ 407, { 29, 24, 28, 26 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
		{ 401, { 27, 25, 23, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
		{ 404, { -1, 28, 26, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
		{ 456, { -1, 25, -1, 27 }, { 2, 2, 0, 1 }, MAZE_EVENT_NONE },
		{ 406, { -1, 30, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
		{ 453, { -3, 30, -1, 29 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
		{ 408, { -5, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_BRICK }
	};

	Catacombs _hardCatacombs[62] = {
		{ 401, { -1,  1,  2,  6 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 404, { 10, 11,  3,  0 }, { 2, 3, 0, 1 }, MAZE_EVENT_PUDDLE },
		{ 404, {  0,  3,  4, -2 }, { 2, 3, 0, 1 }, MAZE_EVENT_BLOCK },
		{ 401, {  1, 20,  5,  2 }, { 2, 0, 0, 1 }, MAZE_EVENT_POT },
		{ 453, {  2,  4, -1,  4 }, { 2, 3, 0, 1 }, MAZE_EVENT_DRAIN },
		{ 403, {  3,  6, -1,  4 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_PLANK },
		{ 406, { -1,  0, -1,  5 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 453, { -1,  8, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1,  9, -1,  7 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 401, {  1, -1, 10,  8 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_SKULL },
		{ 408, {  9, -1,  1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 453, { 12, -1, -1,  1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_STONE },
		{ 408, { 13, -1, 11, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 401, { 13, 21, 12, 13 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK },
		{ 453, { 16, 15, -1, 20 }, { 2, 3, 0, 2 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
		{ 456, { -1, -1, -1, 14 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { -1, 17, 14, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_POT },
		{ 401, { 18, -1, 19, 16 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 408, { -1, -1, 17, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 403, { 17, -1, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
		{ 408, {  3, -1, 14, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_NONE },
		{ 404, {  9, 30, 22, 13 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST },
		{ 403, { 21, 23, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_HOLE | MAZE_EVENT_WEB },
		{ 401, { -1, -1, 24, 22 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1, 26, -1, 23 }, { 2, 0, 0, 2 }, MAZE_EVENT_NONE },
		{ 407, { 36, 33, 35, 34 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
		{ 453, { 24, 27, -1, -1 }, { 1, 0, 0, 1 }, MAZE_EVENT_BRICK },
		{ 403, { 26, -1, -1, 28 }, { 1, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
		{ 404, { 27, 28, 28, 29 }, { 3, 2, 1, 2 }, MAZE_EVENT_NONE },
		{ 408, { -1, -1, 28, -1 }, { 2, 3, 3, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1, 31, -1, 21 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
		{ 401, { 30, 33,  1, -1 }, { 1, 2, 1, 1 }, MAZE_EVENT_PUDDLE | MAZE_EVENT_POT },
		{ 456, { -1, 31, -1, 33 }, { 2, 1, 0, 0 }, MAZE_EVENT_NONE },
		{ 404, { 32, -1, 31, 25 }, { 3, 3, 1, 1 }, MAZE_EVENT_NONE },
		{ 401, { 46, 25, 31, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
		{ 401, { -1, 25, 41, -1 }, { 2, 2, 1, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_POT },
		{ 406, { -1, 37, -1, 25 }, { 2, 3, 0, 0 }, MAZE_EVENT_NONE },
		{ 453, { -3, 37, -1, 36 }, { 2, 3, 0, 1 }, MAZE_EVENT_STONE | MAZE_EVENT_RAT_NEST | MAZE_EVENT_WEB },
		{ 408, { 57, -1, 54, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 408, { 40, -1, -4, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
		{ 404, { 40, 40, 39, 53 }, { 1, 0, 0, 1 }, MAZE_EVENT_BLOCK | MAZE_EVENT_FALLEN_BLOCK },
		{ 456, { -1, 35, -1, 42 }, { 2, 2, 0, 2 }, MAZE_EVENT_NONE },
		{ 408, { 43, -1, 41, -1 }, { 1, 3, 3, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1, 42, -1, 61 }, { 2, 0, 0, 1 }, MAZE_EVENT_NONE },
		{ 403, { 58, 45, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_RAT_NEST },
		{ 401, { 34, -1, 46, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_RAT_NEST | MAZE_EVENT_BRICK },
		{ 404, { 45, -1, 34, 47 }, { 2, 3, 0, 1 }, MAZE_EVENT_WEB | MAZE_EVENT_FALLEN_BLOCK },
		{ 406, { -1, 46, -1, 48 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 403, { 49, 47, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL | MAZE_EVENT_WEB },
		{ 408, { 50, -1, 48, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 408, { 51, -1, 49, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 408, { 52, -1, 50, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 408, { -1, -1, 51, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK },
		{ 406, { -1, 40, -1, 54 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 403, { 38, 53, -1, 55 }, { 2, 3, 0, 1 }, MAZE_EVENT_SKULL },
		{ 453, { 56, 54, -1, -1 }, { 2, 3, 0, 1 }, MAZE_EVENT_BRICK | MAZE_EVENT_WEB },
		{ 401, { 56, -5, 55, 56 }, { 3, 3, 0, 0 }, MAZE_EVENT_BRICK | MAZE_EVENT_SKULL },
		{ 404, { -1, 57, 38, 57 }, { 2, 3, 0, 1 }, MAZE_EVENT_POT | MAZE_EVENT_BLOCK },
		{ 404, { 59, 59, 44, 60 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { 59, 60, 59, 58 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { 61, 58, 59, 59 }, { 2, 3, 0, 1 }, MAZE_EVENT_NONE },
		{ 404, { 34, 43, 60, 44 }, { 0, 3, 0, 1 }, MAZE_EVENT_NONE }
	};

GamePhantom::GamePhantom(MADSEngine *vm) : Game(vm) {
	_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
	_difficulty = DIFFICULTY_HARD;
	_catacombs = nullptr;
	_catacombSize = -1;
}

void GamePhantom::startGame() {
	_scene._priorSceneId = 0;
	_scene._currentSceneId = -1;
	_scene._nextSceneId = 101;

	initializeGlobals();
}

void GamePhantom::initializeGlobals() {
	_globals.reset();
	setupCatacombs();

	_player._facing = FACING_NORTH;
	_player._turnToFacing = FACING_NORTH;

	_globals[kTempVar]                 = false;
	_globals[kRoom103104Transition]    = 1;		// new room
	_globals[kCurrentYear]             = 1993;
	_globals[kTrapDoorStatus]          = 0;		// open
	_globals[kChristineDoorStatus]     = 0;		// Christine is in her room
	_globals[kSandbagStatus]           = 0;		// sandbag is secure
	_globals[kJacquesStatus]           = 0;		// alive
	_globals[kChrisFStatus]            = 1;		// Christine F. is alive in 1993
	_globals[kBrieTalkStatus]          = 0;		// before Brie motions
	_globals[kPanelIn206]              = 0;		// not discovered
	_globals[kFightStatus]             = 0;
	_globals[kJuliesDoor]              = 1;		// cracked open
	_globals[kPrompterStandStatus]     = 0;
	_globals[kChrisDStatus]            = 0;		// before love
	_globals[kJulieNameIsKnown]        = 0;
	_globals[kDoorsIn205]              = 0;		// both locked
	_globals[kMadameGiryLocation]      = 1;		// middle
	_globals[kTicketPeoplePresent]     = 0;
	_globals[kCoffinStatus]            = 0;		// closed and locked
	_globals[kDoneBrieConv203]         = 0;
	_globals[kFlorentNameIsKnown]      = 0;
	_globals[kDegasNameIsKnown]        = 0;
	_globals[kMadameGiryShowsUp]       = false;
	_globals[kJacquesNameIsKnown]      = 0;
	_globals[kCharlesNameIsKnown]      = false;
	_globals[kTopFloorLocked]          = true;
	_globals[kMadameNameIsKnown]       = 0;
	_globals[kChrisKickedRaoulOut]     = false;
	_globals[kLookedAtCase]            = false;
	_globals[kRingIsOnFinger]          = false;
	_globals[kHeListened]              = false;
	_globals[kKnockedOverHead]         = false;
	_globals[kObservedPhan104]         = false;
	_globals[kReadBook]                = false;
	_globals[kCanFindBookInLibrary]    = false;
	_globals[kLookedAtSkullFace]       = false;
	_globals[kScannedBookcase]         = false;
	_globals[kRanConvIn205]            = false;
	_globals[kDoneRichConv203]         = false;
	_globals[kHintThatDaaeIsHome1]     = false;
	_globals[kHintThatDaaeIsHome2]     = false;
	_globals[kMakeBrieLeave203]        = false;
	_globals[kMakeRichLeave203]        = false;
	_globals[kCameFromFade]            = false;
	_globals[kChristineToldEnvelope]   = false;
	_globals[kLeaveAngelMusicOn]       = false;
	_globals[kDoorIn409IsOpen]         = false;
	_globals[kPriestPistonPuke]        = false;
	_globals[kCobwebIsCut]             = false;
	_globals[kChristineIsInBoat]       = false;
	_globals[kRightDoorIsOpen504]      = false;
	_globals[kChrisLeft505]            = false;
	_globals[kChrisWillTakeSeat]       = true;
	_globals[kFlickedLever1]           = 0;
	_globals[kFlickedLever2]           = 0;
	_globals[kFlickedLever3]           = 0;
	_globals[kFlickedLever4]           = 0;
	_globals[kPlayerScore]             = 0;
	_globals[kPlayerScoreFlags]        = 0;

	_globals[kMusicSelected] = _vm->getRandomNumber(1, 4);

	_player._spritesPrefix = "RAL";	// Fixed prefix
	Player::preloadSequences("RAL", 1);
}

void GamePhantom::setSectionHandler() {
	delete _sectionHandler;

	switch (_sectionNumber) {
	case 1:
		_sectionHandler = new Section1Handler(_vm);
		break;
	case 2:
		_sectionHandler = new Section2Handler(_vm);
		break;
	case 3:
		_sectionHandler = new Section3Handler(_vm);
		break;
	case 4:
		_sectionHandler = new Section4Handler(_vm);
		break;
	case 5:
		_sectionHandler = new Section5Handler(_vm);
		break;
	default:
		break;
	}
}

void GamePhantom::checkShowDialog() {
	// TODO: Copied from Nebular
	if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[5]) {
		_player.releasePlayerSprites();

		// HACK: Skip the main menu (since it'll then try to show Rex's main menu)
		if (_vm->_dialogs->_pendingDialog == DIALOG_MAIN_MENU)
			_vm->_dialogs->_pendingDialog = DIALOG_NONE;

		_vm->_dialogs->showDialog();
		_vm->_dialogs->_pendingDialog = DIALOG_NONE;
	}
}

void GamePhantom::genericObjectExamine() {
	MADSAction &action = _scene._action;
	int	id = _objects.getIdFromDesc(action._activeAction._objectNameId);

	if (action.isAction(VERB_LOOK, NOUN_RED_FRAME))
		_vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 802 : 842, 0);
	else if (action.isAction(VERB_LOOK, NOUN_YELLOW_FRAME))
		_vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 804 : 843, 0);
	else if (action.isAction(VERB_LOOK, NOUN_BLUE_FRAME))
		_vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 817 : 844, 0);
	else if (action.isAction(VERB_LOOK, NOUN_GREEN_FRAME))
		_vm->_dialogs->showItem(id, (_globals[kCurrentYear] == 1993) ? 819 : 845, 0);
	else if (action.isAction(VERB_LOOK, NOUN_LANTERN))
		_vm->_dialogs->showItem(id, (_globals[kLanternStatus] == 1) ? 831 : 801, 0);
	else if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE))
		_vm->_dialogs->showItem(OBJ_SMALL_NOTE, 846, 2);
	else if (action.isAction(VERB_LOOK, NOUN_PARCHMENT))
		_vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
	else if (action.isAction(VERB_LOOK, NOUN_LETTER))
		_vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
	else if (action.isAction(VERB_LOOK, NOUN_NOTICE))
		_vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
	else if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE))
		_vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
	else if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE))
		_vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
	else
	_vm->_dialogs->showItem(id, 800 + id, 0);
}

void GamePhantom::doObjectAction() {
	MADSAction &action = _scene._action;

	if ((_scene._currentSceneId >= 401) && (_scene._currentSceneId <= 456)
	 && (action.isObject(NOUN_RED_FRAME) || action.isObject(NOUN_YELLOW_FRAME) || action.isObject(NOUN_GREEN_FRAME) || action.isObject(NOUN_BLUE_FRAME))
	 && action.isAction(VERB_PUT)) {
		if (action.isTarget(NOUN_UNLUCKY_ADVENTURER)) {
			_vm->_dialogs->show(35);
			action._inProgress = false;
			return;
		} else if (action.isTarget(NOUN_HOLE)) {
			_vm->_dialogs->show(36);
			action._inProgress = false;
			return;
		} else if (action.isTarget(NOUN_GRATE)) {
			_vm->_dialogs->show(37);
			action._inProgress = false;
			return;
		} else if (action.isTarget(NOUN_WALL)) {
			_vm->_dialogs->show(38);
			action._inProgress = false;
			return;
		}
	}

	if (action._lookFlag) {
		_vm->_dialogs->show(810);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_PUT, NOUN_RED_FRAME) || action.isAction(VERB_PUT, NOUN_BLUE_FRAME) || action.isAction(VERB_PUT, NOUN_YELLOW_FRAME) || action.isAction(VERB_PUT, NOUN_GREEN_FRAME)) {
		_vm->_dialogs->show((action.isTarget(NOUN_PUDDLE)) ? 40124 : 40125);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_WEAR, NOUN_WEDDING_RING)) {
		if (_globals[kRingIsOnFinger])
			_vm->_dialogs->show(849);
		else {
			_vm->_dialogs->show(835);
			_globals[kRingIsOnFinger] = true;
		}
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_REMOVE, NOUN_WEDDING_RING)) {
		if (!_globals[kRingIsOnFinger])
			_vm->_dialogs->show(848);
		else {
			_vm->_dialogs->show(836);
			_globals[kRingIsOnFinger] = false;
		}
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_WEST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_EAST) || action.isAction(VERB_LOOK, NOUN_ARCHWAY_TO_NORTH)) {
		_vm->_dialogs->show(34);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_ATTACK, NOUN_CHRISTINE)) {
		_vm->_dialogs->show(33);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_KEY)) {
		_vm->_dialogs->showItem(OBJ_KEY, 800, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_SANDBAG)) {
		_vm->_dialogs->showItem(OBJ_SANDBAG, 803, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_SMALL_NOTE) || action.isAction(VERB_READ, NOUN_SMALL_NOTE)) {
		_vm->_dialogs->showItem(OBJ_SMALL_NOTE, 806, 2);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_ROPE)) {
		_vm->_dialogs->showItem(OBJ_ROPE, 807, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_SWORD)) {
		_vm->_dialogs->showItem(OBJ_SWORD, 808, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_ENVELOPE) || action.isAction(VERB_READ, NOUN_ENVELOPE)) {
		_vm->_dialogs->showItem(OBJ_ENVELOPE, 809, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_TICKET) || action.isAction(VERB_READ, NOUN_TICKET)) {
		_vm->_dialogs->showItem(OBJ_TICKET, 810, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_PIECE_OF_PAPER) || action.isAction(VERB_READ, NOUN_PIECE_OF_PAPER)) {
		_vm->_dialogs->showItem(OBJ_PIECE_OF_PAPER, 811, 1);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_PARCHMENT) || action.isAction(VERB_READ, NOUN_PARCHMENT)) {
		_vm->_dialogs->showItem(OBJ_PARCHMENT, 812, 3);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_LETTER) || action.isAction(VERB_READ, NOUN_LETTER)) {
		_vm->_dialogs->showItem(OBJ_LETTER, 813, 4);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_NOTICE) || action.isAction(VERB_READ, NOUN_NOTICE)) {
		_vm->_dialogs->showItem(OBJ_NOTICE, 814, 5);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_BOOK) || action.isAction(VERB_READ, NOUN_BOOK)) {
		_vm->_dialogs->showItem(OBJ_BOOK, 815, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_CRUMPLED_NOTE) || action.isAction(VERB_READ, NOUN_CRUMPLED_NOTE)) {
		_vm->_dialogs->showItem(OBJ_CRUMPLED_NOTE, 816, 6);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_LARGE_NOTE) || action.isAction(VERB_READ, NOUN_LARGE_NOTE)) {
		_vm->_dialogs->showItem(OBJ_LARGE_NOTE, 818, 7);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_MUSIC_SCORE) || action.isAction(VERB_READ, NOUN_MUSIC_SCORE)) {
		_vm->_dialogs->showItem(OBJ_MUSIC_SCORE, 820, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_WEDDING_RING)) {
		_vm->_dialogs->showItem(OBJ_WEDDING_RING, 821, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_CABLE_HOOK)) {
		_vm->_dialogs->showItem(OBJ_CABLE_HOOK, 822, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_ROPE_WITH_HOOK)) {
		_vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK, NOUN_OAR)) {
		_vm->_dialogs->showItem(OBJ_OAR, 824, 0);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_LOOK) && _objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId))) {
		genericObjectExamine();
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_TURN_ON, NOUN_LANTERN)) {
		if ((_globals[kLanternStatus] == 1) && !_trigger)
			_vm->_dialogs->show(828);
		else {
			switch (_trigger) {
			case 0:
				_scene._sequences.addTimer(4, 1);
				_globals[kLanternStatus] = 1;
				_vm->_dialogs->spinObject(OBJ_LANTERN);
				break;

			case 1:
				_vm->_dialogs->show(825);
				break;

			default:
				break;
			}
		}
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_TURN_OFF, NOUN_LANTERN)) {
		if ((_globals[kLanternStatus] == 0) && !_trigger)
			_vm->_dialogs->show(829);
		else if ((_scene._currentSceneId / 100) == 4)
			_vm->_dialogs->show(826);
		else {
			switch (_trigger) {
			case 0:
				_scene._sequences.addTimer(4, 1);
				_globals[kLanternStatus] = 0;
				_vm->_dialogs->spinObject(OBJ_LANTERN);
				break;

			case 1:
				_vm->_dialogs->show(827);
				break;

			default:
				break;
			}
		}
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_OPEN, NOUN_ENVELOPE)) {
		_objects.setRoom(OBJ_ENVELOPE, NOWHERE);
		_objects.addToInventory(OBJ_TICKET);
		_objects.addToInventory(OBJ_PIECE_OF_PAPER);
		_vm->_dialogs->show(833);
		action._inProgress = false;
		return;
	}

	if (action.isAction(VERB_ATTACH, NOUN_CABLE_HOOK, NOUN_ROPE)) {
		if (!_objects.isInInventory(OBJ_ROPE))
			_vm->_dialogs->show(11438);
		else {
			_objects.setRoom(OBJ_CABLE_HOOK, NOWHERE);
			_objects.setRoom(OBJ_ROPE, NOWHERE);
			_objects.addToInventory(OBJ_ROPE_WITH_HOOK);
			_vm->_dialogs->showItem(OBJ_ROPE_WITH_HOOK, 823, 0);
		}
		action._inProgress = false;
	}
}

void GamePhantom::unhandledAction() {
	int messageId = 0;
	int rndNum = _vm->getRandomNumber(1, 1000);
	MADSAction &action = _scene._action;

	if (action.isAction(VERB_PUT, NOUN_CHANDELIER, NOUN_SEATS))
		_vm->_dialogs->show(10123);
	else if (action.isAction(VERB_TAKE)) {
		if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
			messageId = 25;
		else {
			if (rndNum <= 333)
				messageId = 1;
			else if (rndNum <= 666)
				messageId = 2;
			else
				messageId = 3;
		}
	} else if (action.isAction(VERB_PUSH)) {
		if (rndNum < 750)
			messageId = 4;
		else
			messageId = 5;
	} else if (action.isAction(VERB_PULL)) {
		if (rndNum < 750)
			messageId = 6;
		else
			messageId = 7;
	} else if (action.isAction(VERB_OPEN)) {
		if (rndNum <= 500)
			messageId = 8;
		else if (rndNum <= 750)
			messageId = 9;
		else
			messageId = 10;
	} else if (action.isAction(VERB_CLOSE)) {
		if (rndNum <= 500)
			messageId = 11;
		else if (rndNum <= 750)
			messageId = 12;
		else
			messageId = 13;
	} else if (action.isAction(VERB_PUT)) {
		if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
			messageId = 26;
		else if (rndNum < 500)
			messageId = 14;
		else
			messageId = 15;
	} else if (action.isAction(VERB_TALK_TO)) {
		if (rndNum <= 500)
			messageId = 16;
		else
			messageId = 17;
	} else if (action.isAction(VERB_GIVE)) {
		if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
			messageId = 27;
		else
			messageId = 18;
	} else if (action.isAction(VERB_THROW)) {
		if (_objects.isInInventory(_objects.getIdFromDesc(action._activeAction._objectNameId)))
			messageId = 19;
		else
			messageId = 28;
	} else if (action.isAction(VERB_LOOK)) {
		if (rndNum <= 333)
			messageId = 20;
		else if (rndNum <= 666)
			messageId = 21;
		else
			messageId = 22;
	} else if ((action.isAction(VERB_UNLOCK) || action.isAction(VERB_LOCK))
			&& (action.isObject(NOUN_DOOR) || action.isObject(NOUN_LEFT_DOOR) || action.isObject(NOUN_MIDDLE_DOOR) || action.isObject(NOUN_RIGHT_DOOR) || action.isObject(NOUN_TRAP_DOOR)))
		messageId = 32;
	else if (!action.isAction(VERB_WALK_TO) && !action.isAction(VERB_WALK_ACROSS) && !action.isAction(VERB_WALK_DOWN) && !action.isAction(VERB_WALK_UP)) {
		if (rndNum < 500)
			messageId = 23;
		else
			messageId = 24;
	}

	if (messageId)
		_vm->_dialogs->show(messageId);
}

void GamePhantom::stopWalker() {
	int state   = _globals[kWalkerConverseState];
	int command = _globals[kWalkerConverse];

	_globals[kWalkerConverseNow] = state;

	if ((_player._facing != FACING_NORTHEAST) && (_player._facing != FACING_NORTHWEST)) {
		state   = 0;
		command = 0;
	}

	switch (state) {
	case 1:
		switch (command) {
		case 1:
			_player.addWalker(3, 0);
			break;

		case 2:
		case 3:
			_player.addWalker(6, 0);
			_player.addWalker(5, 0);
			_player.addWalker(4, 0);
			state = 2;
			break;

		case 4:
			_player.addWalker(8, 0);
			_player.addWalker(4, 0);
			state = 4;
			break;

		default:
			_player.addWalker(-2, 0);
			state = 0;
			break;
		}
		break;

	case 2:
	case 3:
		switch (command) {
		case 2:
		case 3:
			if (state == 2) {
				if (_vm->getRandomNumber(1, 30000) < 2000) {
					_player.addWalker(10, 0);
					_player.addWalker(7, 0);
					state = 3;
				} else
					_player.addWalker(6, 0);
			} else {
				if (_vm->getRandomNumber(1, 30000) < 1000) {
					_player.addWalker(6, 0);
					_player.addWalker(7, 0);
					state = 2;
				} else
					_player.addWalker(10, 0);
			}
			break;

		default:
			_player.addWalker(-4, 0);
			_player.addWalker(-5, 0);
			if (state == 3) {
				_player.addWalker(6, 0);
				_player.addWalker(7, 0);
			}
			state = 1;
			break;
		}
		break;

	case 4:
		if (command == 4)
			_player.addWalker(9, 0);
		else {
			_player.addWalker(-4, 0);
			_player.addWalker(-8, 0);
			state = 1;
		}
		break;

	case 0:
	default:
		switch (command) {
		case 1:
		case 2:
		case 3:
		case 4:
			_player.addWalker(2, 0);
			state = 1;
			break;

		default:
			stopWalkerBasic();
			break;
		}
		break;
	}

	_globals[kWalkerConverse]       = command;
	_globals[kWalkerConverseState] = state;
}

void GamePhantom::step() {
	if (_player._visible  && !_globals[kStopWalkerDisabled]
	 && (_player._stepEnabled || (_vm->_gameConv->activeConvId() >= 0))
	 && !_player._moving && (_player._facing == _player._turnToFacing)
	 && (_scene._frameStartTime >= (uint32)_globals[kWalkerTiming])) {
		if (_player._stopWalkers.empty())
			stopWalker();

		_globals[kWalkerTiming] += 6;
	}
}

void GamePhantom::stopWalkerBasic() {
	int rndVal  = _vm->getRandomNumber(1, 30000);

	switch (_player._facing) {
	case FACING_SOUTH:
		if (rndVal < 500) {
			int maxSteps = _vm->getRandomNumber(4, 10);
			for (int i = 0; i < maxSteps; i++)
				_player.addWalker((rndVal < 250) ? 1 : 2, 0);
		} else if (rndVal < 750) {
			for (int i = 0; i < 4; i++)
				_player.addWalker(1, 0);

			_player.addWalker(0, 0);

			for (int i = 0; i < 4; i++)
				_player.addWalker(2, 0);

			_player.addWalker(0, 0);
		}
		break;

	case FACING_SOUTHEAST:
	case FACING_SOUTHWEST:
	case FACING_NORTHEAST:
	case FACING_NORTHWEST:
		if (rndVal < 150) {
			_player.addWalker(-1, 0);
			_player.addWalker(1, 0);
			for (int i = 0; i < 6; i++)
				_player.addWalker(0, 0);
		}
		break;

	case FACING_EAST:
	case FACING_WEST:
		if (rndVal < 250) {
			_player.addWalker(-1, 0);
			int maxSteps = _vm->getRandomNumber(2, 6);
			for (int i = 0; i < maxSteps; i++)
				_player.addWalker(2, 0);
			_player.addWalker(1, 0);
			_player.addWalker(0, 0);
			_player.addWalker(0, 0);
		} else if (rndVal < 500)
			_globals[kWalkerTiming] = (int)_scene._frameStartTime;
		break;

	case FACING_NORTH:
		if (rndVal < 250) {
			_player.addWalker(-1, 0);
			int maxSteps = _vm->getRandomNumber(3, 7);
			for (int i = 0; i < maxSteps; i++)
				_player.addWalker(2, 0);
			_player.addWalker(1, 0);
			_player.addWalker(0, 0);
		}
		break;

	default:
		break;
	}
}

void GamePhantom::synchronize(Common::Serializer &s, bool phase1) {
	Game::synchronize(s, phase1);

	// TODO: Copied from Nebular
	if (!phase1) {
		_globals.synchronize(s);
	}
}

void GamePhantom::enterCatacombs(bool val) {
	setupCatacombs();

	int var4, var2;
	if (_scene._currentSceneId == 409) {
		if (val) {
			var4 = _globals[kCatacombs409b];
			var2 = _globals[kCatacombs409bFrom];
		} else {
			var4 = _globals[kCatacombs409a];
			var2 = _globals[kCatacombs409aFrom];
		}
	} else if (_scene._currentSceneId == 501) {
		var4 = _globals[kCatacombs501];
		var2 = _globals[kCatacombs501From];
	} else {
		var4 = _globals[kCatacombs309];
		var2 = _globals[kCatacombs309From];
	}

	newCatacombRoom(var4, var2);
}

void GamePhantom::initCatacombs() {
	_globals[kCatacombsRoom] = _globals[kCatacombsNextRoom];
}

void GamePhantom::setupCatacombs() {
	switch (_difficulty) {
	case DIFFICULTY_EASY:
		_catacombs = _easyCatacombs;
		_catacombSize = 32;

		_globals[kCatacombs309]      = 2;
		_globals[kCatacombs309From]  = 3;
		_globals[kCatacombs409a]     = 30;
		_globals[kCatacombs409aFrom] = 0;
		_globals[kCatacombs409b]     = 31;
		_globals[kCatacombs409bFrom] = 2;
		_globals[kCatacombs501]      = 31;
		_globals[kCatacombs501From]  = 0;
		break;

	case DIFFICULTY_MEDIUM:
		// TODO: FIXME. Do we need to set something here?
		break;

	case DIFFICULTY_HARD:
		_catacombs = _hardCatacombs;
		_catacombSize = 62;

		_globals[kCatacombs309]      = 2;
		_globals[kCatacombs309From]  = 3;
		_globals[kCatacombs409a]     = 37;
		_globals[kCatacombs409aFrom] = 0;
		_globals[kCatacombs409b]     = 39;
		_globals[kCatacombs409bFrom] = 2;
		_globals[kCatacombs501]      = 56;
		_globals[kCatacombs501From]  = 1;
		break;
	}
}

int GamePhantom::exitCatacombs(int dir) {
	assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
	assert(dir == CLIP(dir, 0, 3));

	return (_catacombs[_globals[kCatacombsRoom]]._exit[dir]);
}

void GamePhantom::moveCatacombs(int dir) {
	assert(_globals[kCatacombsRoom] == CLIP(_globals[kCatacombsRoom], 0, _catacombSize - 1));
	assert(dir == CLIP(dir, 0, 3));

	newCatacombRoom(_catacombs[_globals[kCatacombsRoom]]._fromDirection[dir], _catacombs[_globals[kCatacombsRoom]]._exit[dir]);
}

void GamePhantom::newCatacombRoom(int toRoom, int fromExit) {
	_globals[kCatacombsNextRoom] = toRoom;
	_globals[kCatacombsFrom] = fromExit & 0x03;
	_globals[kCatacombsFlag] = fromExit & 0xFC;

	int newSceneNum = -1;

	if (toRoom < 0) {
		switch (toRoom) {
		case -5:
			newSceneNum = 501;
			break;

		case -4:
		case -3:
			newSceneNum = 409;
			break;

		case -2:
			newSceneNum = 309;
			break;

		default:
			error("Unexpected room in newCatacombRoom");
		}
	} else {
		newSceneNum = _catacombs[toRoom]._sceneNum;
		_globals[81] = _catacombs[toRoom]._flags;
	}

	if (_triggerSetupMode == SEQUENCE_TRIGGER_PREPARE) {
		_player._walkOffScreenSceneId = newSceneNum;
	} else {
		_scene._reloadSceneFlag = true;
		_scene._nextSceneId = newSceneNum;
	}
}

} // End of namespace Phantom

} // End of namespace MADS