/* 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 "fullpipe/fullpipe.h"
#include "fullpipe/messages.h"
#include "fullpipe/constants.h"
#include "fullpipe/motion.h"
#include "fullpipe/scenes.h"
#include "fullpipe/gameloader.h"
#include "fullpipe/statics.h"
#include "fullpipe/modal.h"

#include "fullpipe/constants.h"

#include "graphics/palette.h"
#include "video/avi_decoder.h"

#include "engines/savestate.h"

namespace Fullpipe {

ModalIntro::ModalIntro() {
	_field_8 = 0;
	_countDown = 0;
	_stillRunning = 0;

	if (g_vars->sceneIntro_skipIntro) {
		_introFlags = 4;
	} else {
		_introFlags = 33;
		_countDown = 150;

		PictureObject *pict = g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0);
		pict->setFlags(pict->_flags & 0xFFFB);
	}

	g_vars->sceneIntro_skipIntro = false;
	_sfxVolume = g_fp->_sfxVolume;
}

ModalIntro::~ModalIntro() {
	g_fp->stopAllSounds();
	g_fp->_sfxVolume = _sfxVolume;
}

bool ModalIntro::handleMessage(ExCommand *message) {
	if (message->_messageKind != 17)
		return false;

	if (message->_messageNum != 36)
		return false;

	if (message->_keyCode != 13 && message->_keyCode != 27 && message->_keyCode != 32)
		return false;

	if (_stillRunning) {
		if (!(_introFlags & 0x10)) {
			_countDown = 0;
			g_vars->sceneIntro_needBlackout = true;
			return true;
		}
		g_vars->sceneIntro_playing = false;
		g_vars->sceneIntro_needBlackout = true;
	}

	return true;
}

bool ModalIntro::init(int counterdiff) {
	if (!g_vars->sceneIntro_playing) {
		if (!_stillRunning) {
			finish();
			return false;
		}

		if (_introFlags & 0x10)
			g_fp->_gameLoader->updateSystems(42);

		_introFlags |= 2;

		return true;
	}

	if (_introFlags & 4) {
		ModalVideoPlayer *player = new ModalVideoPlayer();

		g_fp->_modalObject = player;
		player->_parentObj = this;
		player->play("intro.avi");

		_countDown--;

		if (_countDown > 0 )
			return true;

		if (_stillRunning <= 0) {
			_countDown = 0;
			_stillRunning = 0;
			_introFlags = (_introFlags & 0xfb) | 0x40;

			return true;
		}

		_introFlags |= 2;
		return true;
	}

	if (_introFlags & 0x40) {
		ModalVideoPlayer *player = new ModalVideoPlayer();

		g_fp->_modalObject = player;
		player->_parentObj = this;
		player->play("intro2.avi");

		_countDown--;
		if (_countDown > 0)
			return true;

		if (_stillRunning <= 0) {
			_countDown = 50;
			_stillRunning = 0;
			_introFlags = (_introFlags & 0xbf) | 9;

			return true;
		}

		_introFlags |= 2;
		return true;
	}

	if (_introFlags & 8) {
		_countDown--;

		if (_countDown > 0 )
			return true;

		if (_stillRunning > 0) {
			_introFlags |= 2;
			return true;
		}

		_countDown = 150;
		_introFlags = (_introFlags & 0xf7) | 0x21;
		g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0)->_flags &= 0xfffb;
	}

	if (!(_introFlags & 0x20)) {
		if (_introFlags & 0x10) {
			if (!_stillRunning) {
				_introFlags |= 1;

				g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0)->_flags &= 0xfffb;
				g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_GAMETITLE, 0)->_flags &= 0xfffb;

				chainQueue(QU_INTR_STARTINTRO, 1);
			}
			g_fp->_gameLoader->updateSystems(42);
		}
		return true;
	}

	_countDown--;

	if (_countDown <= 0) {
		if (_stillRunning > 0) {
			_introFlags |= 2;

			return true;
		}

		_introFlags = (_introFlags & 0xdf) | 0x10;

		g_fp->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_GAMETITLE, 0)->_flags &= 0xfffb;

		_stillRunning = 0;
	}

	return true;
}

void ModalIntro::update() {
	if (g_fp->_currentScene) {
		if (_introFlags & 1) {
			g_fp->sceneFade(g_fp->_currentScene, true);
			_stillRunning = 255;
			_introFlags &= 0xfe;

			if (_introFlags & 0x20)
				g_fp->playSound(SND_INTR_019, 0);
		} else if (_introFlags & 2) {
			if (g_vars->sceneIntro_needBlackout) {
				g_fp->drawAlphaRectangle(0, 0, 800, 600, 0);
				g_vars->sceneIntro_needBlackout = 0;
				_stillRunning = 0;
				_introFlags &= 0xfd;
			} else {
				g_fp->sceneFade(g_fp->_currentScene, false);
				_stillRunning = 0;
				_introFlags &= 0xfd;
			}
		} else if (_stillRunning) {
			g_fp->_currentScene->draw();
		}
	}
}

void ModalIntro::finish() {
	g_fp->_gameLoader->unloadScene(SC_INTRO2);
	g_fp->_currentScene = g_fp->accessScene(SC_INTRO1);
	g_fp->_gameLoader->preloadScene(SC_INTRO1, TrubaDown);

	if (g_fp->_currentScene)
		g_fp->_gameLoader->updateSystems(42);
}

void ModalVideoPlayer::play(const char *filename) {
	// TODO: Videos are encoded using Intel Indeo 5 (IV50), which isn't supported yet

	Video::AVIDecoder *aviDecoder = new Video::AVIDecoder();

	if (!aviDecoder->loadFile(filename))
		return;

	uint16 x = (g_system->getWidth() - aviDecoder->getWidth()) / 2;
	uint16 y = (g_system->getHeight() - aviDecoder->getHeight()) / 2;
	bool skipVideo = false;

	aviDecoder->start();

	while (!g_fp->shouldQuit() && !aviDecoder->endOfVideo() && !skipVideo) {
		if (aviDecoder->needsUpdate()) {
			const Graphics::Surface *frame = aviDecoder->decodeNextFrame();
			if (frame) {
				g_fp->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h);

				if (aviDecoder->hasDirtyPalette())
					g_fp->_system->getPaletteManager()->setPalette(aviDecoder->getPalette(), 0, 256);

				g_fp->_system->updateScreen();
			}
		}

		Common::Event event;
		while (g_fp->_system->getEventManager()->pollEvent(event)) {
			if ((event.type == Common::EVENT_KEYDOWN && (event.kbd.keycode == Common::KEYCODE_ESCAPE ||
														 event.kbd.keycode == Common::KEYCODE_RETURN ||
														 event.kbd.keycode == Common::KEYCODE_SPACE))
				 || event.type == Common::EVENT_LBUTTONUP)
				skipVideo = true;
		}

		g_fp->_system->delayMillis(aviDecoder->getTimeToNextFrame());
	}
}

ModalMap::ModalMap() {
	_mapScene = 0;
	_pic = 0;
	_isRunning = false;
	_rect1 = g_fp->_sceneRect;
	_x = g_fp->_currentScene->_x;
	_y = g_fp->_currentScene->_y;
	_flag = 0;
	_mouseX = 0;
	_mouseY = 0;
	_field_38 = 0;
	_field_3C = 0;
	_field_40 = 12;
	_rect2.top = 0;
	_rect2.left = 0;
	_rect2.bottom = 600;
	_rect2.right = 800;
}

ModalMap::~ModalMap() {
	g_fp->_gameLoader->unloadScene(SC_MAP);

	g_fp->_sceneRect = _rect1;

	g_fp->_currentScene->_x = _x;
	g_fp->_currentScene->_y = _y;
}

bool ModalMap::init(int counterdiff) {
	g_fp->setCursor(PIC_CSR_ITN);

	if (_flag) {
		_rect2.left = _mouseX + _field_38 - g_fp->_mouseScreenPos.x;
		_rect2.top = _mouseY + _field_3C - g_fp->_mouseScreenPos.y;
		_rect2.right = _rect2.left + 800;
		_rect2.bottom = _rect2.top + 600;

		g_fp->_sceneRect =_rect2;

		_mapScene->updateScrolling2();

		_rect2 = g_fp->_sceneRect;
	}

	_field_40--;

	if (_field_40 <= 0) {
		_field_40 = 12;

		if (_pic)
			_pic->_flags ^= 4;
	}

	return _isRunning;
}

void ModalMap::update() {
	g_fp->_sceneRect = _rect2;

	_mapScene->draw();

	g_fp->drawArcadeOverlay(1);
}

bool ModalMap::handleMessage(ExCommand *cmd) {
	if (cmd->_messageKind != 17)
		return false;

	switch (cmd->_messageNum) {
	case 29:
		_flag = 1;
		_mouseX = g_fp->_mouseScreenPos.x;
		_mouseY = g_fp->_mouseScreenPos.x;

		_field_3C = _rect2.top;
		_field_38 = _rect2.left;

		break;

	case 30:
		_flag = 0;
		break;

	case 36:
		if (cmd->_keyCode != 9 && cmd->_keyCode != 27 )
			return false;

		break;

	case 107:
		break;

	default:
		return false;
	}

	_isRunning = 0;

	return true;
}

void ModalMap::initMap() {
	_isRunning = 1;

	_mapScene = g_fp->accessScene(SC_MAP);

	if (!_mapScene)
		error("ModalMap::initMap(): error accessing scene SC_MAP");

	PictureObject *pic;

	for (int i = 0; i < 200; i++) {
		if (!(g_fp->_mapTable[i] >> 16))
			break;

		pic = _mapScene->getPictureObjectById(g_fp->_mapTable[i] >> 16, 0);

		if ((g_fp->_mapTable[i] & 0xffff) == 1)
			pic->_flags |= 4;
		else
			pic->_flags &= 0xfffb;
	}

	pic = getScenePicture();

	Common::Point point;
	Common::Point point2;

	if (pic) {
		pic->getDimensions(&point);

		_rect2.left = point.x / 2 + pic->_ox - 400;
		_rect2.top = point.y / 2 + pic->_oy - 300;
		_rect2.right = _rect2.left + 800;
		_rect2.bottom = _rect2.top + 600;

		_mapScene->updateScrolling2();

		_pic = _mapScene->getPictureObjectById(PIC_MAP_I02, 0);
		_pic->getDimensions(&point2);

		_pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 24);
		_pic->_flags |= 4;

		_pic = _mapScene->getPictureObjectById(PIC_MAP_I01, 0);
		_pic->getDimensions(&point2);

		_pic->setOXY(pic->_ox + point.x / 2 - point2.x / 2, point.y - point2.y / 2 + pic->_oy - 25);
		_pic->_flags |= 4;
	}

	g_fp->setArcadeOverlay(PIC_CSR_MAP);
}

PictureObject *ModalMap::getScenePicture() {
	int picId = 0;

	switch (g_fp->_currentScene->_sceneId) {
	case SC_1:
        picId = PIC_MAP_S01;
        break;
	case SC_2:
        picId = PIC_MAP_S02;
        break;
	case SC_3:
        picId = PIC_MAP_S03;
        break;
	case SC_4:
        picId = PIC_MAP_S04;
        break;
	case SC_5:
        picId = PIC_MAP_S05;
        break;
	case SC_6:
		picId = PIC_MAP_S06;
		break;
	case SC_7:
		picId = PIC_MAP_S07;
		break;
	case SC_8:
		picId = PIC_MAP_S08;
		break;
	case SC_9:
		picId = PIC_MAP_S09;
		break;
	case SC_10:
		picId = PIC_MAP_S10;
		break;
	case SC_11:
		picId = PIC_MAP_S11;
		break;
	case SC_12:
		picId = PIC_MAP_S12;
		break;
	case SC_13:
		picId = PIC_MAP_S13;
		break;
	case SC_14:
		picId = PIC_MAP_S14;
		break;
	case SC_15:
		picId = PIC_MAP_S15;
		break;
	case SC_16:
		picId = PIC_MAP_S16;
		break;
	case SC_17:
		picId = PIC_MAP_S17;
		break;
	case SC_18:
	case SC_19:
		picId = PIC_MAP_S1819;
		break;
	case SC_20:
		picId = PIC_MAP_S20;
		break;
	case SC_21:
        picId = PIC_MAP_S21;
		break;
	case SC_22:
		picId = PIC_MAP_S22;
		break;
	case SC_23:
		picId = PIC_MAP_S23_1;
		break;
	case SC_24:
		picId = PIC_MAP_S24;
		break;
	case SC_25:
		picId = PIC_MAP_S25;
		break;
	case SC_26:
		picId = PIC_MAP_S26;
		break;
	case SC_27:
		picId = PIC_MAP_S27;
		break;
	case SC_28:
		picId = PIC_MAP_S28;
		break;
	case SC_29:
		picId = PIC_MAP_S29;
		break;
	case SC_30:
		picId = PIC_MAP_S30;
		break;
	case SC_31:
		picId = PIC_MAP_S31_1;
		break;
	case SC_32:
		picId = PIC_MAP_S32_1;
		break;
	case SC_33:
		picId = PIC_MAP_S33;
		break;
	case SC_34:
		picId = PIC_MAP_S34;
		break;
	case SC_35:
		picId = PIC_MAP_S35;
		break;
	case SC_36:
		picId = PIC_MAP_S36;
		break;
	case SC_37:
		picId = PIC_MAP_S37;
		break;
	case SC_38:
		picId = PIC_MAP_S38;
		break;
	case SC_FINAL1:
		picId = PIC_MAP_S38;
		break;
	}

	if (picId)
		return _mapScene->getPictureObjectById(picId, 0);

	error("ModalMap::getScenePicture(): Unknown scene id: %d", g_fp->_currentScene->_sceneId);
}

void FullpipeEngine::openMap() {
	if (!_modalObject) {
		ModalMap *map = new ModalMap;

		_modalObject = map;

		map->initMap();
	}
}

ModalFinal::ModalFinal() {
	_flags = 0;
	_counter = 255;
	_sfxVolume = g_fp->_sfxVolume;
}

ModalFinal::~ModalFinal() {
	if (g_vars->sceneFinal_var01) {
		g_fp->_gameLoader->unloadScene(SC_FINAL2);
		g_fp->_gameLoader->unloadScene(SC_FINAL3);
		g_fp->_gameLoader->unloadScene(SC_FINAL4);

		g_fp->_currentScene = g_fp->accessScene(SC_FINAL1);

		g_fp->stopAllSounds();

		g_vars->sceneFinal_var01 = 0;
	}

	g_fp->_sfxVolume = _sfxVolume;
}

bool ModalFinal::init(int counterdiff) {
	if (g_vars->sceneFinal_var01) {
		g_fp->_gameLoader->updateSystems(42);

		return true;
	}

	if (_counter > 0) {
		_flags |= 2u;

		g_fp->_gameLoader->updateSystems(42);

		return true;
	}

	unloadScenes();

	g_fp->_modalObject = new ModalCredits();

	return true;
}

void ModalFinal::unloadScenes() {
	g_fp->_gameLoader->unloadScene(SC_FINAL2);
	g_fp->_gameLoader->unloadScene(SC_FINAL3);
	g_fp->_gameLoader->unloadScene(SC_FINAL4);

	g_fp->_currentScene = g_fp->accessScene(SC_FINAL1);

	g_fp->stopAllSounds();
}

bool ModalFinal::handleMessage(ExCommand *cmd) {
	if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) {
		g_fp->_modalObject = new ModalMainMenu();
		g_fp->_modalObject->_parentObj = this;

		return true;
	}

	return false;
}

void ModalFinal::update() {
	if (g_fp->_currentScene) {
		g_fp->_currentScene->draw();

		if (_flags & 1) {
			g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter);

			_counter += 10;

			if (_counter >= 255) {
				_counter = 255;
				_flags &= 0xfe;
			}
		} else {
			if (!(_flags & 2))
				return;

			g_fp->drawAlphaRectangle(0, 0, 800, 600, 0xff - _counter);
			_counter -= 10;

			if (_counter <= 0) {
				_counter = 0;
				_flags &= 0xFD;
			}
		}

		g_fp->_sfxVolume = _counter * (_sfxVolume + 3000) / 255 - 3000;

		g_fp->updateSoundVolume();
	}
}

ModalCredits::ModalCredits() {
	Common::Point point;

	_sceneTitles = g_fp->accessScene(SC_TITLES);

	_creditsPic = _sceneTitles->getPictureObjectById(PIC_TTL_CREDITS, 0);
	_creditsPic->_flags |= 4;

	_fadeIn = true;
	_fadeOut = false;

	_creditsPic->getDimensions(&point);

	_countdown = point.y / 2 + 470;
	_sfxVolume = g_fp->_sfxVolume;

	_currY = 630;
	_maxY = -1000 - point.y;

	_currX = 400 - point.x / 2;

	_creditsPic->setOXY(_currX, _currY);
}

ModalCredits::~ModalCredits() {
	g_fp->_gameLoader->unloadScene(SC_TITLES);

	g_fp->_sfxVolume = _sfxVolume;
}

bool ModalCredits::handleMessage(ExCommand *cmd) {
	if (cmd->_messageKind == 17 && cmd->_messageNum == 36 && cmd->_keyCode == 27) {
		_fadeIn = false;

		return true;
	}

	return false;
}

bool ModalCredits::init(int counterdiff) {
	if (_fadeIn || _fadeOut) {
		_countdown--;

		if (_countdown < 0)
			_fadeIn = false;

		_creditsPic->setOXY(_currX, _currY);

		if (_currY > _maxY)
			_currY -= 2;
	} else {
		if (_parentObj)
			return 0;

		ModalMainMenu *menu = new ModalMainMenu;

		g_fp->_modalObject = menu;

		menu->_mfield_34 = 1;
	}

	return true;
}

void ModalCredits::update() {
	if (_fadeOut) {
		if (_fadeIn) {
			_sceneTitles->draw();

			return;
		}
	} else if (_fadeIn) {
		g_fp->sceneFade(_sceneTitles, true);
		_fadeOut = 1;

		return;
	}

	if (_fadeOut) {
		g_fp->sceneFade(_sceneTitles, false);
		_fadeOut = 0;
		return;
	}

	_sceneTitles->draw();
}

ModalMainMenu::ModalMainMenu() {
	_areas.clear();

	_lastArea = 0;
	_hoverAreaId = 0;
	_mfield_34 = 0;
	_scene = g_fp->accessScene(SC_MAINMENU);
	_debugKeyCount = 0;
	_sliderOffset = 0;
	_screct.left = g_fp->_sceneRect.left;
	_screct.top = g_fp->_sceneRect.top;
	_screct.right = g_fp->_sceneRect.right;
	_screct.bottom = g_fp->_sceneRect.bottom;

	if (g_fp->_currentScene) {
		_bgX = g_fp->_currentScene->_x;
		_bgY = g_fp->_currentScene->_y;
	} else {
		_bgX = 0;
		_bgY = 0;
	}

	g_fp->_sceneRect.top = 0;
	g_fp->_sceneRect.left = 0;
	g_fp->_sceneRect.right = 800;
	g_fp->_sceneRect.bottom = 600;

	MenuArea *area;

	area = new MenuArea();
	area->picIdL = PIC_MNU_EXIT_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);

	area = new MenuArea();
	area->picIdL = PIC_MNU_CONTINUE_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);

	if (isSaveAllowed()) {
		area = new MenuArea();
		area->picIdL = PIC_MNU_SAVE_L;
		area->picObjD = 0;
		area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
		area->picObjL->_flags &= 0xFFFB;
		_areas.push_back(area);
	}

	area = new MenuArea();
	area->picIdL = PIC_MNU_LOAD_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);

	area = new MenuArea();
	area->picIdL = PIC_MNU_RESTART_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);

	area = new MenuArea();
	area->picIdL = PIC_MNU_AUTHORS_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);

	area = new MenuArea();
	area->picIdL = PIC_MNU_SLIDER_L;
	area->picObjD = _scene->getPictureObjectById(PIC_MNU_SLIDER_D, 0);
	area->picObjD->_flags |= 4;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);
	_menuSliderIdx = _areas.size() - 1;

	area = new MenuArea();
	area->picIdL = PIC_MNU_MUSICSLIDER_L;
	area->picObjD = _scene->getPictureObjectById(PIC_MNU_MUSICSLIDER_D, 0);
	area->picObjD->_flags |= 4;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);
	_musicSliderIdx = _areas.size() - 1;

	if (g_fp->_mainMenu_debugEnabled)
		enableDebugMenuButton();

	setSliderPos();
}

void ModalMainMenu::update() {
	_scene->draw();
}

bool ModalMainMenu::handleMessage(ExCommand *message) {
	if (message->_messageKind != 17)
		return false;

	Common::Point point;

	if (message->_messageNum == 29) {
		point.x = message->_x;
		point.y = message->_y;

		int numarea = checkHover(point);

		if (numarea >= 0) {
			if (numarea == _menuSliderIdx) {
				_lastArea = _areas[_menuSliderIdx];
				_sliderOffset = _lastArea->picObjL->_ox - point.x;

				return false;
			}

			if (numarea == _musicSliderIdx) {
				_lastArea = _areas[_musicSliderIdx];
				_sliderOffset = _lastArea->picObjL->_ox - point.x;

				return false;
			}

			_hoverAreaId = _areas[numarea]->picIdL;
		}

		return false;
	}

	if (message->_messageNum == 30) {
		if (_lastArea)
			_lastArea = 0;

		return false;
	}

	if (message->_messageNum != 36)
		return false;

	if (message->_keyCode == 27)
		_hoverAreaId = PIC_MNU_CONTINUE_L;
	else
		enableDebugMenu(message->_keyCode);

	return false;
}

bool ModalMainMenu::init(int counterdiff) {
	switch (_hoverAreaId) {
	case PIC_MNU_RESTART_L:
		g_fp->restartGame();

		if (this == g_fp->_modalObject)
			return false;

		delete this;
		break;

	case PIC_MNU_EXIT_L:
		{
			ModalQuery *mq = new ModalQuery();

			g_fp->_modalObject = mq;

			mq->_parentObj = this;
			mq->create(_scene, _scene, PIC_MEX_BGR);

			_hoverAreaId = 0;

			return true;
		}

	case PIC_MNU_DEBUG_L:
		g_fp->_gameLoader->unloadScene(SC_MAINMENU);
		g_fp->_sceneRect = _screct;

		if (!g_fp->_currentScene)
			error("ModalMainMenu::init: Bad state");

		g_fp->_currentScene->_x = _bgX;
		g_fp->_currentScene->_y = _bgY;

		g_fp->_gameLoader->preloadScene(g_fp->_currentScene->_sceneId, SC_DBGMENU);

		return false;

	case PIC_MNU_CONTINUE_L:
		if (!_mfield_34) {
			g_fp->_gameLoader->unloadScene(SC_MAINMENU);
			g_fp->_sceneRect = _screct;

			if (g_fp->_currentScene) {
				g_fp->_currentScene->_x = _bgX;
				g_fp->_currentScene->_y = _bgY;
			}

			return false;
		}

		g_fp->restartGame();

		if (this == g_fp->_modalObject)
			return false;

		delete this;
		break;

	case PIC_MNU_AUTHORS_L:
		g_fp->_modalObject = new ModalCredits();
		g_fp->_modalObject->_parentObj = this;

		_hoverAreaId = 0;

		return true;

	case PIC_MNU_SAVE_L:
	case PIC_MNU_LOAD_L:
		{
			ModalSaveGame *sg = new ModalSaveGame();

			g_fp->_modalObject = sg;
			g_fp->_modalObject->_parentObj = _parentObj;

			int mode = 0;
			if (_hoverAreaId == PIC_MNU_SAVE_L)
				mode = 1;

			sg->setup(g_fp->accessScene(SC_MAINMENU), mode);
			sg->setScene(g_fp->accessScene(SC_MAINMENU));

			sg->_rect = _screct;
			sg->_oldBgX = _bgX;
			sg->_oldBgY = _bgY;

			delete this;
		}

		break;

	default:
		if (_lastArea) {
			updateSliderPos();
		} else {
			g_fp->_cursorId = PIC_CSR_DEFAULT;

			int idx = checkHover(g_fp->_mouseScreenPos);

			if (idx < 0)
				goto LABEL_40;

			g_fp->_cursorId = PIC_CSR_DEFAULT;

			if (idx != this->_menuSliderIdx && idx != this->_musicSliderIdx )
				goto LABEL_40;
		}

		g_fp->_cursorId = PIC_CSR_LIFT;

	LABEL_40:
		g_fp->setCursor(g_fp->_cursorId);

		updateVolume();

		return true;
	}

	return true;
}

void ModalMainMenu::updateVolume() {
	if (g_fp->_soundEnabled ) {
		for (int s = 0; s < g_fp->_currSoundListCount; s++)
			for (int i = 0; i < g_fp->_currSoundList1[s]->getCount(); i++) {
				updateSoundVolume(g_fp->_currSoundList1[s]->getSoundByIndex(i));
			}
	}
}

void ModalMainMenu::updateSoundVolume(Sound *snd) {
	if (!snd->_objectId)
		return;

	StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(snd->_objectId, -1);
	if (!ani)
		return;

	int a, b;

	if (ani->_ox >= _screct.left) {
		int par, pan;

		if (ani->_ox <= _screct.right) {
			int dx;

			if (ani->_oy <= _screct.bottom) {
				if (ani->_oy >= _screct.top) {
					snd->setPanAndVolume(g_fp->_sfxVolume, 0);

					return;
				}
				dx = _screct.top - ani->_oy;
			} else {
				dx = ani->_oy - _screct.bottom;
			}

		    par = 0;

			if (dx > 800) {
				snd->setPanAndVolume(-3500, 0);
				return;
			}

			pan = -3500;
			a = g_fp->_sfxVolume - (-3500);
			b = 800 - dx;
		} else {
			int dx = ani->_ox - _screct.right;

			if (dx > 800) {
				snd->setPanAndVolume(-3500, 0);
				return;
			}

			pan = -3500;
			par = dx * (-3500) / -800;
			a = g_fp->_sfxVolume - (-3500);
			b = 800 - dx;
		}

		int32 pp = b * a;

		snd->setPanAndVolume(pan + pp / 800, par);

		return;
	}

	int dx = _screct.left - ani->_ox;
	if (dx <= 800) {
		int32 s = (800 - dx) * (g_fp->_sfxVolume - (-3500));
		int32 p = -3500 + s / 800;

		if (p > g_fp->_sfxVolume)
			p = g_fp->_sfxVolume;

		snd->setPanAndVolume(p, dx * (-3500) / 800);
	} else {
		snd->setPanAndVolume(-3500, 0);
	}
}

void ModalMainMenu::updateSliderPos() {
	if (_lastArea->picIdL == PIC_MNU_SLIDER_L) {
		int x = g_fp->_mouseScreenPos.x + _sliderOffset;

		if (x >= 65) {
			if (x > 238)
				x = 238;
		} else {
			x = 65;
		}

		_lastArea->picObjD->setOXY(x, _lastArea->picObjD->_oy);
		_lastArea->picObjL->setOXY(x, _lastArea->picObjD->_oy);

		int vol = 1000 * (3 * x - 195);
		g_fp->_sfxVolume = vol / 173 - 3000;

		if (!(vol / 173))
			g_fp->_sfxVolume = -10000;

		g_fp->updateSoundVolume();
	} else if (_lastArea->picIdL == PIC_MNU_MUSICSLIDER_L) {
		int x = g_fp->_mouseScreenPos.x + _sliderOffset;

		if (x >= 65) {
			if (x > 238)
				x = 238;
		} else {
			x = 65;
		}

		_lastArea->picObjD->setOXY(x, _lastArea->picObjD->_oy);
		_lastArea->picObjL->setOXY(x, _lastArea->picObjD->_oy);

		g_fp->setMusicVolume(255 * (x - 65) / 173);
	}
}

int ModalMainMenu::checkHover(Common::Point &point) {
	for (uint i = 0; i < _areas.size(); i++) {
		if (_areas[i]->picObjL->isPixelHitAtPos(point.x, point.y)) {
			_areas[i]->picObjL->_flags |= 4;

			return i;
		} else {
			_areas[i]->picObjL->_flags &= 0xFFFB;
		}
	}

	if (isOverArea(_areas[_menuSliderIdx]->picObjL, &point)) {
		_areas[_menuSliderIdx]->picObjL->_flags |= 4;

		return _menuSliderIdx;
	}

	if (isOverArea(_areas[_musicSliderIdx]->picObjL, &point)) {
		_areas[_musicSliderIdx]->picObjL->_flags |= 4;

		return _musicSliderIdx;
	}

	return -1;
}

bool ModalMainMenu::isOverArea(PictureObject *obj, Common::Point *point) {
	Common::Point p;

	obj->getDimensions(&p);

	int left = point->x - 8;
	int right = point->x + 12;
	int down = point->y - 11;
	int up = point->y + 9;

	if (left >= obj->_ox && right < obj->_ox + p.x && down >= obj->_oy && up < obj->_oy + p.y)
		return true;

	return false;
}

bool ModalMainMenu::isSaveAllowed() {
	if (!g_fp->_isSaveAllowed)
		return false;

	if (g_fp->_aniMan->_flags & 0x100)
		return false;

	for (Common::Array<MessageQueue *>::iterator s = g_fp->_globalMessageQueueList->begin(); s != g_fp->_globalMessageQueueList->end(); ++s) {
		if (!(*s)->_isFinished && ((*s)->getFlags() & 1))
			return false;
	}

	return true;
}

void ModalMainMenu::enableDebugMenu(char c) {
	const char deb[] = "DEBUGER";

	if (c == deb[_debugKeyCount]) {
		_debugKeyCount++;

		if (deb[_debugKeyCount] )
			return;

		enableDebugMenuButton();
	}

	_debugKeyCount = 0;
}

void ModalMainMenu::enableDebugMenuButton() {
	MenuArea *area;

	for (uint i = 0; i < _areas.size(); i++)
		if (_areas[i]->picIdL == PIC_MNU_DEBUG_L)
			return;

	area = new MenuArea();
	area->picIdL = PIC_MNU_DEBUG_L;
	area->picObjD = 0;
	area->picObjL = _scene->getPictureObjectById(area->picIdL, 0);
	area->picObjL->_flags &= 0xFFFB;
	_areas.push_back(area);
}

void ModalMainMenu::setSliderPos() {
	int x = 173 * (g_fp->_sfxVolume + 3000) / 3000 + 65;
	PictureObject *obj = _areas[_menuSliderIdx]->picObjD;

	if (x >= 65) {
		if (x > 238)
			x = 238;
	} else {
		x = 65;
	}

	obj->setOXY(x, obj->_oy);
	_areas[_menuSliderIdx]->picObjL->setOXY(x, obj->_oy);

	x = 173 * g_fp->_musicVolume / 255 + 65;
	obj = _areas[_musicSliderIdx]->picObjD;

	if (x >= 65) {
		if (x > 238)
			x = 238;
	} else {
		x = 65;
	}

	obj->setOXY(x, obj->_oy);
	_areas[_musicSliderIdx]->picObjL->setOXY(x, obj->_oy);
}

ModalHelp::ModalHelp() {
	_mainMenuScene = 0;
	_bg = 0;
	_isRunning = false;
	_rect = g_fp->_sceneRect;
	_hx = g_fp->_currentScene->_x;
	_hy = g_fp->_currentScene->_y;

	g_fp->_sceneRect.left = 0;
	g_fp->_sceneRect.bottom = 600;
	g_fp->_sceneRect.top = 0;
	g_fp->_sceneRect.right = 800;
}

ModalHelp::~ModalHelp() {
	g_fp->_gameLoader->unloadScene(SC_MAINMENU);

	g_fp->_sceneRect = _rect;

	g_fp->_currentScene->_x = _hx;
	g_fp->_currentScene->_y = _hy;
}

bool ModalHelp::handleMessage(ExCommand *cmd) {
	if (cmd->_messageKind == 17) {
		int msg = cmd->_messageNum;

		if (msg == 29 || msg == 36 || msg == 107) {
			_isRunning = 0;

			return true;
		}
	}

	return false;
}

bool ModalHelp::init(int counterdiff) {
	g_fp->setCursor(PIC_CSR_DEFAULT);

	return _isRunning;
}

void ModalHelp::update() {
	g_fp->_sceneRect.left = 0;
	g_fp->_sceneRect.top = 0;
	g_fp->_sceneRect.right = 800;
	g_fp->_sceneRect.bottom = 600;

	_bg->draw(0, 0, 0, 0);
}

void ModalHelp::launch() {
	_mainMenuScene = g_fp->accessScene(SC_MAINMENU);

	if (_mainMenuScene) {
		_bg = _mainMenuScene->getPictureObjectById(PIC_HLP_BGR, 0)->_picture;
		_isRunning = 1;
	}
}

ModalQuery::ModalQuery() {
	_bgScene = 0;
	_bg = 0;
	_okBtn = 0;
	_cancelBtn = 0;
	_queryResult = -1;
}

ModalQuery::~ModalQuery() {
	_bg->_flags &= 0xFFFB;
	_cancelBtn->_flags &= 0xFFFB;
	_okBtn->_flags &= 0xFFFB;
}

bool ModalQuery::create(Scene *sc, Scene *bgScene, int id) {
	if (id == PIC_MEX_BGR) {
		_bg = sc->getPictureObjectById(PIC_MEX_BGR, 0);

		if (!_bg)
			return false;

		_okBtn = sc->getPictureObjectById(PIC_MEX_OK, 0);

		if (!_okBtn)
			return false;

		_cancelBtn = sc->getPictureObjectById(PIC_MEX_CANCEL, 0);

		if (!_cancelBtn)
			return 0;
	} else {
		if (id != PIC_MOV_BGR)
			return false;

		_bg = sc->getPictureObjectById(PIC_MOV_BGR, 0);

		if (!_bg)
			return false;

		_okBtn = sc->getPictureObjectById(PIC_MOV_OK, 0);

		if (!_okBtn)
			return false;

		_cancelBtn = sc->getPictureObjectById(PIC_MOV_CANCEL, 0);

		if (!_cancelBtn)
			return false;
	}

	_queryResult = -1;
	_bgScene = bgScene;

	return true;
}

void ModalQuery::update() {
	if (_bgScene)
		_bgScene->draw();

	_bg->draw();

	if (_okBtn->_flags & 4)
		_okBtn->draw();

	if (_cancelBtn->_flags & 4)
		_cancelBtn->draw();
}

bool ModalQuery::handleMessage(ExCommand *cmd) {
	if (cmd->_messageKind == 17) {
		if (cmd->_messageNum == 29) {
			if (_okBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y)) {
				_queryResult = 1;

				return false;
			}

			if (_cancelBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y))
				_queryResult = 0;
		} else if (cmd->_messageNum == 36 && cmd->_keyCode == 27) {
			_queryResult = 0;

			return false;
		}
	}

	return false;
}

bool ModalQuery::init(int counterdiff) {
	if (_okBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y))
		_okBtn->_flags |= 4;
	else
		_okBtn->_flags &= 0xFFFB;

	if (_cancelBtn->isPointInside(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y))
		_cancelBtn->_flags |= 4;
	else
		_cancelBtn->_flags &= 0xFFFB;

	if (_queryResult == -1) {
		return true;
	} else {
		if (_bg->_id == PIC_MEX_BGR) {
			_cancelBtn->_flags &= 0xFFFB;
			_okBtn->_flags &= 0xFFFB;

			if (_queryResult == 1) {
				if (_bgScene)
					g_fp->sceneFade(_bgScene, false);

				warning("STUB: ModalQuery::init()");

				// Quit game
				//if (inputArFlag) {
				//	g_needRestart = 1;
				//	return 0;
				//}
				//SendMessageA(hwndCallback, WM_DESTROY, 0, 0);
			}
		}
	}

	return false;
}

ModalSaveGame::ModalSaveGame() {
	_oldBgX = 0;
	_oldBgY = 0;

	_bgr = 0;
	_okD = 0;
	_okL = 0;
	_cancelD = 0;
	_cancelL = 0;
	_emptyD = 0;
	_emptyL = 0;
	_fullD = 0;
	_fullL = 0;
	_menuScene = 0;
	_queryRes = -1;
	_rect = g_fp->_sceneRect;
	_queryDlg = 0;
	_mode = 1;

	_objtype = kObjTypeModalSaveGame;
}

ModalSaveGame::~ModalSaveGame() {
	g_fp->_sceneRect = _rect;

	_arrayD.clear();
	_arrayL.clear();

	for (uint i = 0; i < _files.size(); i++)
		free(_files[i]);

	_files.clear();
}

void ModalSaveGame::setScene(Scene *sc) {
	_queryRes = -1;
	_menuScene = sc;
}

void ModalSaveGame::processKey(int key) {
	if (key == 27)
		_queryRes = 0;
}

bool ModalSaveGame::init(int counterdiff) {
	if (_queryDlg) {
		if (!_queryDlg->init(counterdiff)) {
			if (!_queryDlg->getQueryResult())
				_queryRes = -1;

			delete _queryDlg;
			_queryDlg = 0;
		}

		return true;
	}

	if (_queryRes == -1)
		return true;

	g_fp->_sceneRect = _rect;

	if (g_fp->_currentScene) {
		g_fp->_currentScene->_x = _oldBgX;
		g_fp->_currentScene->_y = _oldBgY;
	}

	if (!_queryRes) {
		ModalMainMenu *m = new ModalMainMenu;

		g_fp->_modalObject = m;

		m->_parentObj = _parentObj;
		m->_screct = _rect;
		m->_bgX = _oldBgX;
		m->_bgY = _oldBgY;

		delete this;

		return true;
	}

	return false;
}

void ModalSaveGame::setup(Scene *sc, int mode) {
	_files.clear();
	_arrayL.clear();
	_arrayD.clear();
	_mode = mode;

	if (mode) {
		_bgr = sc->getPictureObjectById(PIC_MSV_BGR, 0);
		_cancelD = sc->getPictureObjectById(PIC_MSV_CANCEL_D, 0);
		_cancelL = sc->getPictureObjectById(PIC_MSV_CANCEL_L, 0);
		_okD = sc->getPictureObjectById(PIC_MSV_OK_D, 0);
		_okL = sc->getPictureObjectById(PIC_MSV_OK_L, 0);
		_emptyD = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0);
		_emptyL = sc->getPictureObjectById(PIC_MSV_EMPTY_L, 0);
	} else {
		_bgr = sc->getPictureObjectById(PIC_MLD_BGR, 0);
		_cancelD = sc->getPictureObjectById(PIC_MLD_CANCEL_D, 0);
		_cancelL = sc->getPictureObjectById(PIC_MLD_CANCEL_L, 0);
		_okD = sc->getPictureObjectById(PIC_MLD_OK_D, 0);
		_okL = sc->getPictureObjectById(PIC_MLD_OK_L, 0);
		_emptyD = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0);
		_emptyL = sc->getPictureObjectById(PIC_MSV_EMPTY_D, 0);
	}

	_fullD = sc->getPictureObjectById(PIC_MSV_FULL_D, 0);
	_fullL = sc->getPictureObjectById(PIC_MSV_FULL_L, 0);
	_queryRes = -1;

	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_0_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_0_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_1_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_1_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_2_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_2_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_3_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_3_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_4_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_4_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_5_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_5_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_6_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_6_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_7_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_7_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_8_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_8_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_9_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_9_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_DOTS_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_DOTS_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_DOT_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_DOT_L, 0));
	_arrayL.push_back(sc->getPictureObjectById(PIC_MSV_SPACE_D, 0));
	_arrayD.push_back(sc->getPictureObjectById(PIC_MSV_SPACE_L, 0));

	Common::Point point;

	int x = _bgr->_ox + _bgr->getDimensions(&point)->x / 2;
	int y = _bgr->_oy + 90;
	int w;
	FileInfo *fileinfo;

	for (int i = 0; i < 7; i++) {
		fileinfo = new FileInfo;
		memset(fileinfo, 0, sizeof(FileInfo));

		Common::strlcpy(fileinfo->filename, getSavegameFile(i), 160);

		if (!getFileInfo(i, fileinfo)) {
			fileinfo->empty = true;
			w = _emptyD->getDimensions(&point)->x;
		} else {
			w = 0;

			for (int j = 0; j < 16; j++) {
				_arrayL[j]->getDimensions(&point);
				w += point.x + 2;
			}
		}

		fileinfo->fx1 = x - w / 2;
		fileinfo->fx2 = x + w / 2;
		fileinfo->fy1 = y;
		fileinfo->fy2 = y + _emptyD->getDimensions(&point)->y;

		_files.push_back(fileinfo);

		y = fileinfo->fy2 + 3;
	}
}

char *ModalSaveGame::getSaveName() {
	if (_queryRes < 0)
		return 0;

	return _files[_queryRes]->filename;
}

bool ModalSaveGame::getFileInfo(int slot, FileInfo *fileinfo) {
	Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(
		Fullpipe::getSavegameFile(slot));

	if (!f)
		return false;

	Fullpipe::FullpipeSavegameHeader header;
	Fullpipe::readSavegameHeader(f, header);
	delete f;

	// Create the return descriptor
	SaveStateDescriptor desc(slot, header.saveName);
	char res[17];

	snprintf(res, 17, "%s  %s", desc.getSaveDate().c_str(), desc.getSaveTime().c_str());

	for (int i = 0; i < 16; i++) {
		switch(res[i]) {
		case '.':
			fileinfo->date[i] = 11;
			break;
		case ' ':
			fileinfo->date[i] = 12;
			break;
		case ':':
			fileinfo->date[i] = 10;
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			fileinfo->date[i] = res[i] - '0';
			break;
		default:
			error("Incorrect date format: %s", res);
		}
	}

	return true;
}

void ModalSaveGame::update() {
	if (_menuScene)
		_menuScene->draw();

	_bgr->draw();

	if (_queryDlg) {
		_queryDlg->update();

		return;
	}

	g_fp->_cursorId = PIC_CSR_DEFAULT;

	g_fp->setCursor(g_fp->_cursorId);

	Common::Point point;

	for (uint i = 0; i < _files.size(); i++) {
		if (g_fp->_mouseScreenPos.x < _files[i]->fx1 || g_fp->_mouseScreenPos.x > _files[i]->fx2 ||
			g_fp->_mouseScreenPos.y < _files[i]->fy1 || g_fp->_mouseScreenPos.y > _files[i]->fy2 ) {
			if (_files[i]->empty) {
				_emptyD->setOXY(_files[i]->fx1, _files[i]->fy1);
				_emptyD->draw();
			} else {
				int x = _files[i]->fx1;

				for (int j = 0; j < 16; j++) {
					_arrayL[_files[i]->date[j]]->setOXY(x + 1, _files[i]->fy1);
					_arrayL[_files[i]->date[j]]->draw();

					x += _arrayL[_files[i]->date[j]]->getDimensions(&point)->x + 2;
				}
			}
		} else {
			if (_files[i]->empty) {
				_emptyL->setOXY(_files[i]->fx1, _files[i]->fy1);
				_emptyL->draw();
			} else {
				int x = _files[i]->fx1;

				for (int j = 0; j < 16; j++) {
					_arrayD[_files[i]->date[j]]->setOXY(x + 1, _files[i]->fy1);
					_arrayD[_files[i]->date[j]]->draw();

					x += _arrayD[_files[i]->date[j]]->getDimensions(&point)->x + 2;
				}
			}
		}
	}
	if (_cancelL->isPixelHitAtPos(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y))
		_cancelL->draw();
	else if (_okL->isPixelHitAtPos(g_fp->_mouseScreenPos.x, g_fp->_mouseScreenPos.y))
		_okL->draw();
}

bool ModalSaveGame::handleMessage(ExCommand *cmd) {
	if (_queryDlg)
		return _queryDlg->handleMessage(cmd);

	if (cmd->_messageNum == 29)
		processMouse(cmd->_x, cmd->_y);
	else if (cmd->_messageNum == 36)
		processKey(cmd->_keyCode);

	return false;
}

void ModalSaveGame::processMouse(int x, int y) {
	for (uint i = 0; i < _files.size(); i++) {
		if (x >= _files[i]->fx1 && x <= _files[i]->fx2 && y >= _files[i]->fy1 && y <= _files[i]->fy2) {
			_queryRes = i + 1;

			if (_mode) {
				if (!_files[i]->empty) {
					_queryDlg = new ModalQuery;

					_queryDlg->create(_menuScene, 0, PIC_MOV_BGR);
				}
			}

			return;
		}
	}

	if (_cancelL->isPixelHitAtPos(x, y))
		_queryRes = 0;
}

void ModalSaveGame::saveload() {
	if (_objtype != kObjTypeModalSaveGame)
		return;

	if (_mode) {
		if (getSaveName()) {
			bool allowed = true;

			for (Common::Array<MessageQueue *>::iterator s = g_fp->_globalMessageQueueList->begin(); s != g_fp->_globalMessageQueueList->end(); ++s) {
				if (!(*s)->_isFinished && ((*s)->getFlags() & 1))
					allowed = false;
			}

			if (g_fp->_isSaveAllowed && allowed)
				g_fp->_gameLoader->writeSavegame(g_fp->_currentScene, getSaveName());
		}
	} else {
		if (getSaveName()) {
			if (_parentObj) {
				delete _parentObj;

				_parentObj = 0;
			}

			g_fp->stopAllSoundStreams();
			g_fp->stopSoundStream2();

			g_fp->_gameLoader->readSavegame(getSaveName());
		}
	}
}

void FullpipeEngine::openHelp() {
	if (!_modalObject) {
		ModalHelp *help = new ModalHelp;

		_modalObject = help;

		help->launch();
	}
}

void FullpipeEngine::openMainMenu() {
	ModalMainMenu *menu = new ModalMainMenu;

	menu->_parentObj = g_fp->_modalObject;

	g_fp->_modalObject = menu;
}

} // End of namespace Fullpipe
