diff options
Diffstat (limited to 'engines/mortevielle/utils.cpp')
| -rw-r--r-- | engines/mortevielle/utils.cpp | 3405 | 
1 files changed, 3405 insertions, 0 deletions
| diff --git a/engines/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp new file mode 100644 index 0000000000..c4f2d5714b --- /dev/null +++ b/engines/mortevielle/utils.cpp @@ -0,0 +1,3405 @@ +/* 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. + * + */ + +/* + * This code is based on original Mortville Manor DOS source code + * Copyright (c) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" + +#include "mortevielle/dialogs.h" +#include "mortevielle/menu.h" +#include "mortevielle/mouse.h" +#include "mortevielle/outtext.h" + +#include "common/scummsys.h" +#include "graphics/cursorman.h" + +namespace Mortevielle { + +/** + * Check is a key was pressed + * It also delays the engine and check if the screen has to be updated + * @remarks	Originally called 'keypressed' + */ +bool MortevielleEngine::keyPressed() { +	// Check for any pending key presses +	handleEvents(); + +	// Check if it's time to draw the next frame +	if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) { +		_lastGameFrame = g_system->getMillis(); + +		_screenSurface.updateScreen(); + +		_debugger.onFrame(); +	} + +	// Delay briefly to keep CPU usage down +	g_system->delayMillis(5); + +	// Return if there are any pending key presses +	return !_keypresses.empty(); +} + +/** + * Wait for a keypress + * @remarks	Originally called 'get_ch' + */ +int MortevielleEngine::getChar() { +	bool end = false; +	// If there isn't any pending keypress, wait until there is +	while (!shouldQuit() && !end) { +		end = keyPressed(); +	} + +	// Return the top keypress +	return shouldQuit() ? 0 : _keypresses.pop(); +} + +/** + * Handle pending events + * @remarks		Since the ScummVM screen surface is double height to handle 640x200 using 640x400, + * the mouse Y position is divided by 2 to keep the game thinking the Y goes from 0 - 199 + */ +bool MortevielleEngine::handleEvents() { +	Common::Event event; +	if (!g_system->getEventManager()->pollEvent(event)) +		return false; + +	switch (event.type) { +	case Common::EVENT_LBUTTONDOWN: +	case Common::EVENT_LBUTTONUP: +	case Common::EVENT_MOUSEMOVE: +		_mousePos = Common::Point(event.mouse.x, event.mouse.y / 2); +		_mouse._pos.x = event.mouse.x; +		_mouse._pos.y = event.mouse.y / 2; + +		if (event.type == Common::EVENT_LBUTTONDOWN) +			_mouseClick = true; +		else if (event.type == Common::EVENT_LBUTTONUP) +			_mouseClick = false; + +		break; +	case Common::EVENT_KEYDOWN: +		addKeypress(event); +		break; +	default: +		break; +	} + +	return true; +} + +/** + * Add the specified key to the pending keypress stack + */ +void MortevielleEngine::addKeypress(Common::Event &evt) { +	// Character to add +	char ch = evt.kbd.ascii; + +	// Check for debugger +	if ((evt.kbd.keycode == Common::KEYCODE_d) && (evt.kbd.flags & Common::KBD_CTRL)) { +		// Attach to the debugger +		_debugger.attach(); +		_debugger.onFrame(); +	} else if ((evt.kbd.keycode >= Common::KEYCODE_a) && (evt.kbd.keycode <= Common::KEYCODE_z)) { +		// Handle alphabetic keys +		if (evt.kbd.hasFlags(Common::KBD_CTRL)) +			ch = evt.kbd.keycode - Common::KEYCODE_a + 1; +		else +			ch = evt.kbd.keycode - Common::KEYCODE_a + 'A'; +	} else if ((evt.kbd.keycode >= Common::KEYCODE_F1) && (evt.kbd.keycode <= Common::KEYCODE_F12)) { +		// Handle function keys +		ch = 59 + evt.kbd.keycode - Common::KEYCODE_F1; +	} else { +		// Series of special cases +		switch (evt.kbd.keycode) { +		case Common::KEYCODE_KP4: +		case Common::KEYCODE_LEFT: +			ch = '4'; +			break; +		case Common::KEYCODE_KP2: +		case Common::KEYCODE_DOWN: +			ch = '2'; +			break; +		case Common::KEYCODE_KP6: +		case Common::KEYCODE_RIGHT: +			ch = '6'; +			break; +		case Common::KEYCODE_KP8: +		case Common::KEYCODE_UP: +			ch = '8'; +			break; +		case Common::KEYCODE_KP7: +			ch = '7'; +			break; +		case Common::KEYCODE_KP1: +			ch = '1'; +			break; +		case Common::KEYCODE_KP9: +			ch = '9'; +			break; +		case Common::KEYCODE_KP3: +			ch = '3'; +			break; +		case Common::KEYCODE_KP5: +			ch = '5'; +			break; +		case Common::KEYCODE_RETURN: +			ch = '\13'; +			break; +		case Common::KEYCODE_ESCAPE: +			ch = '\33'; +			break; +		default: +			break; +		} +	} + +	if (ch != 0) +		_keypresses.push(ch); +} + + +static const byte CURSOR_ARROW_DATA[16 * 16] = { +	0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0x0f, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/** + * Initialize the mouse + */ +void MortevielleEngine::initMouse() { +	CursorMan.replaceCursor(CURSOR_ARROW_DATA, 16, 16, 0, 0, 0xff); +	CursorMan.showMouse(true); + +	_mouse.initMouse(); +} + +/** + * Sets the mouse position + * @remarks		Since the ScummVM screen surface is double height to handle 640x200 using 640x400, + * the mouse Y position is doubled to convert from 0-199 to 0-399 + */ +void MortevielleEngine::setMousePos(const Common::Point &pt) { +	// Adjust the passed position from simulated 640x200 to 640x400 co-ordinates +	Common::Point newPoint(pt.x, (pt.y == 199) ? 399 : pt.y * 2); + +	if (newPoint != _mousePos) +		// Warp the mouse to the new position +		g_system->warpMouse(newPoint.x, newPoint.y); + +	// Save the new position +	_mousePos = newPoint; +} + +/** + * Delay by a given amount + */ +void MortevielleEngine::delay(int amount) { +	uint32 endTime = g_system->getMillis() + amount; + +	while (g_system->getMillis() < endTime) { +		if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) { +			_lastGameFrame = g_system->getMillis(); +			_screenSurface.updateScreen(); + +			_debugger.onFrame(); +		} + +		g_system->delayMillis(10); +	} +} + +/** + * Waits for the user to select an action, and then handles it + * @remarks	Originally called tecran + */ +void MortevielleEngine::handleAction() { +	const int lim = 20000; +	int temps = 0; +	char inkey = '\0'; +	bool funct = false; + +	clearVerbBar(); + +	bool handledOpcodeFl = false; +	_controlMenu = 0; +	if (!_keyPressedEsc) { +		_menu.drawMenu(); +		_menu._menuDisplayed = true; +		temps = 0; +		_key = 0; +		funct = false; +		inkey = '.'; + +		_inMainGameLoop = true; +		do { +			_menu.updateMenu(); +			prepareRoom(); +			_mouse.moveMouse(funct, inkey); +			if (shouldQuit()) +				return; +			++temps; +			if (keyPressed() || _mouseClick) { +				_soundManager._mixer->stopHandle(_soundManager._soundHandle); +			} +		} while (!((_menu._menuSelected) || (temps > lim) || (funct) || (_anyone))); +		_inMainGameLoop = false; + +		_menu.eraseMenu(); +		_menu._menuDisplayed = false; +		if (_menu._menuSelected && (_currMenu == MENU_SAVE)) { +			Common::String saveName = Common::String::format("Savegame #%d", _currAction & 15); +			_savegameManager.saveGame(_currAction & 15, saveName); +		} +		if (_menu._menuSelected && (_currMenu == MENU_LOAD)) +			_savegameManager.loadGame((_currAction & 15) - 1); +		if (inkey == '\103') {       /* F9 */ +			temps = _dialogManager.show(_hintPctMessage); +			return; +		} else if (inkey == '\77') { +			if ((_menuOpcode != OPCODE_NONE) && ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF))) { +				_currAction = _menuOpcode; +				displayTextInVerbBar(getEngineString(S_IDEM)); +			} else +				return; +		} else if (inkey == '\104') { +			if ((_x != 0) && (_y != 0)) +				_num = 9999; +			return; +		} +	} +	if (inkey == '\73') { +		_quitGame = true; +		hourToChar(); +	} else { +		if ((funct) && (inkey != '\77')) +			return; +		if (temps > lim) { +			handleDescriptionText(2, 141); +			if (_num == 9999) +				_num = 0; +		} else { +			_menuOpcode = _currMenu; +			if ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF)) +				_menuOpcode = _currAction; +			if (!_anyone) { +				if ((_heroSearching) || (_obpart)) { +					if (_mouse._pos.y < 12) +						return; + +					if ((_currAction == _menu._opcodeSound) || (_currAction == _menu._opcodeLift)) { +						handledOpcodeFl = true; +						if ((_currAction == _menu._opcodeLift) || (_obpart)) { +							endSearch(); +							_caff = _coreVar._currPlace; +							_crep = 998; +						} else +							prepareNextObject(); +						menuUp(); +					} +				} +			} +			do { +				if (!handledOpcodeFl) +					handleOpcode(); + +				if ((_controlMenu == 0) && (! _loseGame) && (! _endGame)) { +					_text.taffich(); +					if (_destinationOk) { +						_destinationOk = false; +						drawPicture(); +					} +					if ((!_syn) || (_col)) +						handleDescriptionText(2, _crep); +				} +			} while (_syn); +			if (_controlMenu != 0) +				displayControlMenu(); +		} +	} +} + +/** + * Engine function - Init Places + * @remarks	Originally called 'init_lieu' + */ +void MortevielleEngine::loadPlaces() { +	Common::File f; + +	if (!f.open("MXX.mor")) +		if (!f.open("MFXX.mor")) +			error("Missing file - MXX.mor"); + +	for (int i = 0; i < 7; ++i) { +		for (int j = 0; j < 25; ++j) +			_destinationArray[i][j] = f.readByte(); +	} + +	f.close(); +} + +/** + * Set Text Color + * @remarks	Originally called 'text_color' + */ +void MortevielleEngine::setTextColor(int col) { +	_textColor = col; +} + +/** + * Prepare screen - Type 1! + * @remarks	Originally called 'ecrf1' + */ +void MortevielleEngine::prepareScreenType1() { +	// Large drawing +	_screenSurface.drawBox(0, 11, 512, 164, 15); +} + +/** + * Prepare room - Type 2! + * @remarks	Originally called 'ecrf2' + */ +void MortevielleEngine::prepareScreenType2() { +	setTextColor(5); +} + +/** + * Prepare room - Type 3! + * @remarks	Originally called 'ecrf7' + */ +void MortevielleEngine::prepareScreenType3() { +	setTextColor(4); +} + +/** + * Engine function - Update hour + * @remarks	Originally called 'calch' + */ +void MortevielleEngine::updateHour(int &day, int &hour, int &minute) { +	int newTime = readclock(); +	int th = _currentHourCount + ((newTime - _currentTime) / _inGameHourDuration); +	minute = ((th % 2) + _currHalfHour) * 30; +	hour = ((uint)th >> 1) + _currHour; +	if (minute == 60) { +		minute = 0; +		++hour; +	} +	day = (hour / 24) + _currDay; +	hour = hour - ((day - _currDay) * 24); +} + +/** + * Engine function - Convert character index to bit index + * @remarks	Originally called 'conv' + */ +int MortevielleEngine::convertCharacterIndexToBitIndex(int characterIndex) { +	return 128 >> (characterIndex - 1); +} + +/** + * Engine function - Convert bit index to character index + * @remarks	Originally called 'tip' + */ +int MortevielleEngine::convertBitIndexToCharacterIndex(int bitIndex) { +	int retVal = 0; + +	if (bitIndex == 128) +		retVal = 1; +	else if (bitIndex == 64) +		retVal = 2; +	else if (bitIndex == 32) +		retVal = 3; +	else if (bitIndex == 16) +		retVal = 4; +	else if (bitIndex == 8) +		retVal = 5; +	else if (bitIndex == 4) +		retVal = 6; +	else if (bitIndex == 2) +		retVal = 7; +	else if (bitIndex == 1) +		retVal = 8; + +	return retVal; +} + +/** + * Engine function - Reset presence in other rooms + * @remarks	Originally called 't5' + */ +void MortevielleEngine::resetPresenceInRooms(int roomId) { +	if (roomId == DINING_ROOM) +		_blo = false; + +	if (roomId != GREEN_ROOM) { +		_roomPresenceLuc = false; +		_roomPresenceIda = false; +	} + +	if (roomId != PURPLE_ROOM) +		_purpleRoomPresenceLeo = false; + +	if (roomId != DARKBLUE_ROOM) { +		_roomPresenceGuy = false; +		_roomPresenceEva = false; +	} + +	if (roomId != BLUE_ROOM) +		_roomPresenceMax = false; +	if (roomId != RED_ROOM) +		_roomPresenceBob = false; +	if (roomId != GREEN_ROOM2) +		_roomPresencePat = false; +	if (roomId != TOILETS) +		_toiletsPresenceBobMax = false; +	if (roomId != BATHROOM) +		_bathRoomPresenceBobMax = false; +	if (roomId != JULIA_ROOM) +		_juliaRoomPresenceLeo = false; +} + +/** + * Engine function - Show the people present in the given room + * @remarks	Originally called 'affper' + */ +void MortevielleEngine::showPeoplePresent(int bitIndex) { +	int xp = 580 - (_screenSurface.getStringWidth("LEO") / 2); + +	for (int i = 1; i <= 8; ++i) +		_menu.disableMenuItem(_menu._discussMenu[i]); + +	clearUpperRightPart(); +	if ((bitIndex & 128) == 128) { +		_screenSurface.putxy(xp, 24); +		_screenSurface.drawString("LEO", 4); +		_menu.enableMenuItem(_menu._discussMenu[1]); +	} +	if ((bitIndex & 64) == 64) { +		_screenSurface.putxy(xp, 32); +		_screenSurface.drawString("PAT", 4); +		_menu.enableMenuItem(_menu._discussMenu[2]); +	} +	if ((bitIndex & 32) == 32) { +		_screenSurface.putxy(xp, 40); +		_screenSurface.drawString("GUY", 4); +		_menu.enableMenuItem(_menu._discussMenu[3]); +	} +	if ((bitIndex & 16) == 16) { +		_screenSurface.putxy(xp, 48); +		_screenSurface.drawString("EVA", 4); +		_menu.enableMenuItem(_menu._discussMenu[4]); +	} +	if ((bitIndex & 8) == 8) { +		_screenSurface.putxy(xp, 56); +		_screenSurface.drawString("BOB", 4); +		_menu.enableMenuItem(_menu._discussMenu[5]); +	} +	if ((bitIndex & 4) == 4) { +		_screenSurface.putxy(xp, 64); +		_screenSurface.drawString("LUC", 4); +		_menu.enableMenuItem(_menu._discussMenu[6]); +	} +	if ((bitIndex & 2) == 2) { +		_screenSurface.putxy(xp, 72); +		_screenSurface.drawString("IDA", 4); +		_menu.enableMenuItem(_menu._discussMenu[7]); +	} +	if ((bitIndex & 1) == 1) { +		_screenSurface.putxy(xp, 80); +		_screenSurface.drawString("MAX", 4); +		_menu.enableMenuItem(_menu._discussMenu[8]); +	} +	_currBitIndex = bitIndex; +} + +/** + * Engine function - Select random characters + * @remarks	Originally called 'choix' + */ +int MortevielleEngine::selectCharacters(int min, int max) { +	bool invertSelection = false; +	int rand = getRandomNumber(min, max); + +	if (rand > 4) { +		rand = 8 - rand; +		invertSelection = true; +	} + +	int i = 0; +	int retVal = 0; +	while (i < rand) { +		int charIndex = getRandomNumber(1, 8); +		int charBitIndex = convertCharacterIndexToBitIndex(charIndex); +		if ((retVal & charBitIndex) != charBitIndex) { +			++i; +			retVal |= charBitIndex; +		} +	} +	if (invertSelection) +		retVal = 255 - retVal; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Green Room + * @remarks	Originally called 'cpl1' + */ +int MortevielleEngine::getPresenceStatsGreenRoom() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	// The original uses an || instead of an &&, resulting +	// in an always true condition. Based on the other tests, +	// and on other scenes, we use an && instead. +	if ((hour > 7) && (hour < 11)) +		retVal = 25; +	else if ((hour > 10) && (hour < 14)) +		retVal = 35; +	else if ((hour > 13) && (hour < 16)) +		retVal = 50; +	else if ((hour > 15) && (hour < 18)) +		retVal = 5; +	else if ((hour > 17) && (hour < 22)) +		retVal = 35; +	else if ((hour > 21) && (hour < 24)) +		retVal = 50; +	else if ((hour >= 0) && (hour < 8)) +		retVal = 70; + +	_menu.updateMenu(); + +	return retVal; +} +/** + * Engine function - Get Presence Statistics - Purple Room + * @remarks	Originally called 'cpl2' + */ +int MortevielleEngine::getPresenceStatsPurpleRoom() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if ((hour > 7) && (hour < 11)) +		retVal = -2; +	else if (hour == 11) +		retVal = 100; +	else if ((hour > 11) && (hour < 23)) +		retVal = 10; +	else if (hour == 23) +		retVal = 20; +	else if ((hour >= 0) && (hour < 8)) +		retVal = 50; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Toilets + * @remarks	Originally called 'cpl3' + */ +int MortevielleEngine::getPresenceStatsToilets() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if (((hour > 8) && (hour < 10)) || ((hour > 19) && (hour < 24))) +		retVal = 34; +	else if (((hour > 9) && (hour < 20)) || ((hour >= 0) && (hour < 9))) +		retVal = 0; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Blue Room + * @remarks	Originally called 'cpl5' + */ +int MortevielleEngine::getPresenceStatsBlueRoom() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if ((hour > 6) && (hour < 10)) +		retVal = 0; +	else if (hour == 10) +		retVal = 100; +	else if ((hour > 10) && (hour < 24)) +		retVal = 15; +	else if ((hour >= 0) && (hour < 7)) +		retVal = 50; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Red Room + * @remarks	Originally called 'cpl6' + */ +int MortevielleEngine::getPresenceStatsRedRoom() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if (((hour > 7) && (hour < 13)) || ((hour > 17) && (hour < 20))) +		retVal = -2; +	else if (((hour > 12) && (hour < 17)) || ((hour > 19) && (hour < 24))) +		retVal = 35; +	else if (hour == 17) +		retVal = 100; +	else if ((hour >= 0) && (hour < 8)) +		retVal = 60; + +	return retVal; +} + +/** + * Shows the "you are alone" message in the status area + * on the right hand side of the screen + * @remarks	Originally called 'person' + */ +void MortevielleEngine::displayAloneText() { +	for (int i = 1; i <= 8; ++i) +		_menu.disableMenuItem(_menu._discussMenu[i]); + +	Common::String sYou = getEngineString(S_YOU); +	Common::String sAre = getEngineString(S_ARE); +	Common::String sAlone = getEngineString(S_ALONE); + +	clearUpperRightPart(); +	_screenSurface.putxy(580 - (_screenSurface.getStringWidth(sYou) / 2), 30); +	_screenSurface.drawString(sYou, 4); +	_screenSurface.putxy(580 - (_screenSurface.getStringWidth(sAre) / 2), 50); +	_screenSurface.drawString(sAre, 4); +	_screenSurface.putxy(580 - (_screenSurface.getStringWidth(sAlone) / 2), 70); +	_screenSurface.drawString(sAlone, 4); + +	_currBitIndex = 0; +} + +/** + * Engine function - Get Presence Statistics - Room Bureau + * @remarks	Originally called 'cpl10' + */ +int MortevielleEngine::getPresenceStatsDiningRoom(int &hour) { +	int day, minute; + +	int retVal = 0; +	updateHour(day, hour, minute); +	if (((hour > 7) && (hour < 11)) || ((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) +		retVal = 100; +	else if ((hour == 11) || ((hour > 20) && (hour < 24))) +		retVal = 45; +	else if (((hour > 13) && (hour < 17)) || (hour == 18)) +		retVal = 35; +	else if (hour == 17) +		retVal = 60; +	else if ((hour >= 0) && (hour < 8)) +		retVal = 5; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Bureau + * @remarks	Originally called 'cpl11' + */ +int MortevielleEngine::getPresenceStatsBureau(int &hour) { +	int day, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if (((hour > 8) && (hour < 12)) || ((hour > 20) && (hour < 24))) +		retVal = 25; +	else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) +		retVal = 5; +	else if ((hour > 13) && (hour < 17)) +		retVal = 55; +	else if ((hour > 16) && (hour < 19)) +		retVal = 45; +	else if ((hour >= 0) && (hour < 9)) +		retVal = 0; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Kitchen + * @remarks	Originally called 'cpl12' + */ +int MortevielleEngine::getPresenceStatsKitchen() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if (((hour > 8) && (hour < 15)) || ((hour > 16) && (hour < 22))) +		retVal = 55; +	else if (((hour > 14) && (hour < 17)) || ((hour > 21) && (hour < 24))) +		retVal = 25; +	else if ((hour >= 0) && (hour < 5)) +		retVal = 0; +	else if ((hour > 4) && (hour < 9)) +		retVal = 15; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Attic + * @remarks	Originally called 'cpl13' + */ +int MortevielleEngine::getPresenceStatsAttic() { +	return 0; +} + +/** + * Engine function - Get Presence Statistics - Room Landing + * @remarks	Originally called 'cpl15' + */ +int MortevielleEngine::getPresenceStatsLanding() { +	int day, hour, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if ((hour > 7) && (hour < 12)) +		retVal = 25; +	else if ((hour > 11) && (hour < 14)) +		retVal = 0; +	else if ((hour > 13) && (hour < 18)) +		retVal = 10; +	else if ((hour > 17) && (hour < 20)) +		retVal = 55; +	else if ((hour > 19) && (hour < 22)) +		retVal = 5; +	else if ((hour > 21) && (hour < 24)) +		retVal = 15; +	else if ((hour >= 0) && (hour < 8)) +		retVal = -15; + +	return retVal; +} + +/** + * Engine function - Get Presence Statistics - Room Chapel + * @remarks	Originally called 'cpl20' + */ +int MortevielleEngine::getPresenceStatsChapel(int &hour) { +	int day, minute; +	int retVal = 0; + +	updateHour(day, hour, minute); +	if (hour == 10) +		retVal = 65; +	else if ((hour > 10) && (hour < 21)) +		retVal = 5; +	else if ((hour > 20) && (hour < 24)) +		retVal = -15; +	else if ((hour >= 0) && (hour < 5)) +		retVal = -300; +	else if ((hour > 4) && (hour < 10)) +		retVal = -5; + +	return retVal; +} + +/** + * Engine function - Check who is in the Green Room + * @remarks	Originally called 'quelq1' + */ +void MortevielleEngine::setPresenceGreenRoom(int roomId) { +	int rand = getRandomNumber(1, 2); +	if (roomId == GREEN_ROOM) { +		if (rand == 1) +			_roomPresenceLuc = true; +		else +			_roomPresenceIda = true; +	} else if (roomId == DARKBLUE_ROOM) { +		if (rand == 1) +			_roomPresenceGuy = true; +		else +			_roomPresenceEva = true; +	} + +	_currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Purple Room + * @remarks	Originally called 'quelq2' + */ +void MortevielleEngine::setPresencePurpleRoom() { +	if (_place == PURPLE_ROOM) +		_purpleRoomPresenceLeo = true; +	else +		_juliaRoomPresenceLeo = true; + +	_currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Blue Room + * @remarks	Originally called 'quelq5' + */ +void MortevielleEngine::setPresenceBlueRoom() { +	_roomPresenceMax = true; +	_currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Red Room + * @remarks	Originally called 'quelq6' + */ +void MortevielleEngine::setPresenceRedRoom(int roomId) { +	if (roomId == RED_ROOM) +		_roomPresenceBob = true; +	else if (roomId == GREEN_ROOM2) +		_roomPresencePat = true; + +	_currBitIndex = 10; +} + +/** + * Engine function - Check who is in the Dining Room + * @remarks	Originally called 'quelq10' + */ +int MortevielleEngine::setPresenceDiningRoom(int hour) { +	int retVal = 0; + +	if ((hour >= 0) && (hour < 8)) +		retVal = checkLeoMaxRandomPresence(); +	else { +		int min = 0, max = 0; +		if ((hour > 7) && (hour < 10)) { +			min = 5; +			max = 7; +		} else if ((hour > 9) && (hour < 12)) { +			min = 1; +			max = 4; +		} else if (((hour > 11) && (hour < 15)) || ((hour > 18) && (hour < 21))) { +			min = 6; +			max = 8; +		} else if (((hour > 14) && (hour < 19)) || ((hour > 20) && (hour < 24))) { +			min = 1; +			max = 5; +		} +		retVal = selectCharacters(min, max); +	} +	showPeoplePresent(retVal); + +	return retVal; +} + +/** + * Engine function - Check who is in the Bureau + * @remarks	Originally called 'quelq11' + */ +int MortevielleEngine::setPresenceBureau(int hour) { +	int retVal = 0; + +	if ((hour >= 0) && (hour < 8)) +		retVal = checkLeoMaxRandomPresence(); +	else { +		int min = 0, max = 0; +		if (((hour > 7) && (hour < 10)) || ((hour > 20) && (hour < 24))) { +			min = 1; +			max = 3; +		} else if (((hour > 9) && (hour < 12)) || ((hour > 13) && (hour < 19))) { +			min = 1; +			max = 4; +		} else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) { +			min = 1; +			max = 2; +		} +		retVal = selectCharacters(min, max); +	} +	showPeoplePresent(retVal); + +	return retVal; +} + +/** + * Engine function - Check who is in the Kitchen + * @remarks	Originally called 'quelq12' + */ +int MortevielleEngine::setPresenceKitchen() { +	int retVal = checkLeoMaxRandomPresence(); +	showPeoplePresent(retVal); + +	return retVal; +} + +/** + * Engine function - Check who is in the Landing + * @remarks	Originally called 'quelq15' + */ +int MortevielleEngine::setPresenceLanding() { +	bool test = false; +	int rand = 0; +	do { +		rand = getRandomNumber(1, 8); +		test = (((rand == 1) && (_purpleRoomPresenceLeo || _juliaRoomPresenceLeo)) || +		        ((rand == 2) && _roomPresencePat) || +		        ((rand == 3) && _roomPresenceGuy) || +		        ((rand == 4) && _roomPresenceEva) || +		        ((rand == 5) && _roomPresenceBob) || +		        ((rand == 6) && _roomPresenceLuc) || +		        ((rand == 7) && _roomPresenceIda) || +		        ((rand == 8) && _roomPresenceMax)); +	} while (test); + +	int retVal = convertCharacterIndexToBitIndex(rand); +	showPeoplePresent(retVal); + +	return retVal; +} + +/** + * Engine function - Check who is in the chapel + * @remarks	Originally called 'quelq20' + */ +int MortevielleEngine::setPresenceChapel(int hour) { +	int retVal = 0; + +	if (((hour >= 0) && (hour < 10)) || ((hour > 18) && (hour < 24))) +		retVal = checkLeoMaxRandomPresence(); +	else { +		int min = 0, max = 0; +		if ((hour > 9) && (hour < 12)) { +			min = 3; +			max = 7; +		} else if ((hour > 11) && (hour < 18)) { +			min = 1; +			max = 2; +		} else if (hour == 18) { +			min = 2; +			max = 4; +		} +		retVal = selectCharacters(min, max); +	} +	showPeoplePresent(retVal); + +	return retVal; +} + +/** + * Engine function - Get the answer after you known a door + * @remarks	Originally called 'frap' + */ +void MortevielleEngine::getKnockAnswer() { +	int day, hour, minute; + +	updateHour(day, hour, minute); +	if ((hour >= 0) && (hour < 8)) +		_crep = 190; +	else { +		if (getRandomNumber(1, 100) > 70) +			_crep = 190; +		else +			_crep = 147; +	} +} + +/** + * Engine function - Get Room Presence Bit Index + * @remarks	Originally called 'nouvp' + */ +int MortevielleEngine::getPresenceBitIndex(int roomId) { +	int bitIndex = 0; +	if (roomId == GREEN_ROOM) { +		if (_roomPresenceLuc) +			bitIndex = 4;  // LUC +		if (_roomPresenceIda) +			bitIndex = 2;  // IDA +	} else if ( ((roomId == PURPLE_ROOM) && (_purpleRoomPresenceLeo)) +			 || ((roomId == JULIA_ROOM) && (_juliaRoomPresenceLeo))) +		bitIndex = 128;    // LEO +	else if (roomId == DARKBLUE_ROOM) { +		if (_roomPresenceGuy) +			bitIndex = 32; // GUY +		if (_roomPresenceEva) +			bitIndex = 16; // EVA +	} else if ((roomId == BLUE_ROOM) && (_roomPresenceMax)) +		bitIndex = 1;      // MAX +	else if ((roomId == RED_ROOM) && (_roomPresenceBob)) +		bitIndex = 8;      // BOB +	else if ((roomId == GREEN_ROOM2) && (_roomPresencePat)) +		bitIndex = 64;     // PAT +	else if ( ((roomId == TOILETS) && (_toiletsPresenceBobMax)) +		   || ((roomId == BATHROOM) && (_bathRoomPresenceBobMax)) ) +		bitIndex = 9;      // BOB + MAX + +	if (bitIndex != 9) +		showPeoplePresent(bitIndex); + +	return bitIndex; +} + +/** + * Engine function - initGame + * @remarks	Originally called 'dprog' + */ +void MortevielleEngine::initGame() { +	_place = MANOR_FRONT; +	_currentHourCount = 0; +	if (!_coreVar._alreadyEnteredManor) +		_blo = true; +	_inGameHourDuration = kTime1; +	_currentTime = readclock(); +} + +/** + * Engine function - Set Random Presence - Green Room + * @remarks	Originally called 'pl1' + */ +void MortevielleEngine::setRandomPresenceGreenRoom(int faithScore) { +	if ( ((_place == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda)) +	  || ((_place == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) ) { +		int p = getPresenceStatsGreenRoom(); +		p += faithScore; +		if (getRandomNumber(1, 100) > p) +			displayAloneText(); +		else +			setPresenceGreenRoom(_place); +	} +} + +/** + * Engine function - Set Random Presence - Purple Room + * @remarks	Originally called 'pl2' + */ +void MortevielleEngine::setRandomPresencePurpleRoom(int faithScore) { +	if (!_purpleRoomPresenceLeo) { +		int p = getPresenceStatsPurpleRoom(); +		p += faithScore; +		if (getRandomNumber(1, 100) > p) +			displayAloneText(); +		else +			setPresencePurpleRoom(); +	} +} + +/** + * Engine function - Set Random Presence - Blue Room + * @remarks	Originally called 'pl5' + */ +void MortevielleEngine::setRandomPresenceBlueRoom(int faithScore) { +	if (!_roomPresenceMax) { +		int p = getPresenceStatsBlueRoom(); +		p += faithScore; +		if (getRandomNumber(1, 100) > p) +			displayAloneText(); +		else +			setPresenceBlueRoom(); +	} +} + +/** + * Engine function - Set Random Presence - Red Room + * @remarks	Originally called 'pl6' + */ +void MortevielleEngine::setRandomPresenceRedRoom(int faithScore) { +	if ( ((_place == RED_ROOM) && (!_roomPresenceBob)) +	  || ((_place == GREEN_ROOM2) && (!_roomPresencePat)) ) { +		int p = getPresenceStatsRedRoom(); +		p += faithScore; +		if (getRandomNumber(1, 100) > p) +			displayAloneText(); +		else +			setPresenceRedRoom(_place); +	} +} + +/** + * Engine function - Set Random Presence - Room 9 + * @remarks	Originally called 'pl9' + */ +void MortevielleEngine::setRandomPresenceJuliaRoom(int faithScore) { +	if (!_juliaRoomPresenceLeo) { +		faithScore = -10; +		if (getRandomNumber(1, 100) > faithScore) // always true? +			displayAloneText(); +		else +			setPresencePurpleRoom(); +	} +} + +/** + * Engine function - Set Random Presence - Dining Room + * @remarks	Originally called 'pl10' + */ +void MortevielleEngine::setRandomPresenceDiningRoom(int faithScore) { +	int h; +	int p = getPresenceStatsDiningRoom(h); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceDiningRoom(h); +} + +/** + * Engine function - Set Random Presence - Bureau + * @remarks	Originally called 'pl11' + */ +void MortevielleEngine::setRandomPresenceBureau(int faithScore) { +	int h; + +	int p = getPresenceStatsBureau(h); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceBureau(h); +} + +/** + * Engine function - Set Random Presence - Kitchen + * @remarks	Originally called 'pl12' + */ +void MortevielleEngine::setRandomPresenceKitchen(int faithScore) { + +	int p = getPresenceStatsKitchen(); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceKitchen(); +} + +/** + * Engine function - Set Random Presence - Attic / Cellar + * @remarks	Originally called 'pl13' + */ +void MortevielleEngine::setRandomPresenceAttic(int faithScore) { +	int p = getPresenceStatsAttic(); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceKitchen(); +} + +/** + * Engine function - Set Random Presence - Landing + * @remarks	Originally called 'pl15' + */ +void MortevielleEngine::setRandomPresenceLanding(int faithScore) { +	int p = getPresenceStatsLanding(); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceLanding(); +} + +/** + * Engine function - Set Random Presence - Chapel + * @remarks	Originally called 'pl20' + */ +void MortevielleEngine::setRandomPresenceChapel(int faithScore) { +	int h; + +	int p = getPresenceStatsChapel(h); +	p += faithScore; +	if (getRandomNumber(1, 100) > p) +		displayAloneText(); +	else +		setPresenceChapel(h); +} + +/** + * Start music or speech + * @remarks	Originally called 'musique' + */ +void MortevielleEngine::startMusicOrSpeech(int so) { +	if (so == 0) { +		/* musik(0) */ +		; +	} else if ((!_introSpeechPlayed) && (!_coreVar._alreadyEnteredManor)) { +		// Type 1: Speech +		_soundManager.startSpeech(10, 1, 1); +		_introSpeechPlayed = true; +	} else { +		if (((_coreVar._currPlace == MOUNTAIN) || (_coreVar._currPlace == MANOR_FRONT) || (_coreVar._currPlace == MANOR_BACK)) && (getRandomNumber(1, 3) == 2)) +			// Type 1: Speech +			_soundManager.startSpeech(9, getRandomNumber(2, 4), 1); +		else if ((_coreVar._currPlace == CHAPEL) && (getRandomNumber(1, 2) == 1)) +			// Type 1: Speech +			_soundManager.startSpeech(8, 1, 1); +		else if ((_coreVar._currPlace == WELL) && (getRandomNumber(1, 2) == 2)) +			// Type 1: Speech +			_soundManager.startSpeech(12, 1, 1); +		else if (_coreVar._currPlace == INSIDE_WELL) +			// Type 1: Speech +			_soundManager.startSpeech(13, 1, 1); +		else +			// Type 2 : music +			_soundManager.startSpeech(getRandomNumber(1, 17), 1, 2); +	} +} + +/** + * Engine function - You lose! + * @remarks	Originally called 'tperd' + */ +void MortevielleEngine::loseGame() { +	resetOpenObjects(); +	_roomDoorId = OWN_ROOM; +	_curSearchObjId = 0; +	_menu.unsetSearchMenu(); +	if (!_blo) +		getPresence(MANOR_FRONT); + +	_loseGame = true; +	clearUpperLeftPart(); +	_screenSurface.drawBox(60, 35, 400, 50, 15); +	handleDescriptionText(9, _crep); +	clearDescriptionBar(); +	clearVerbBar(); +	_col = false; +	_syn = false; +	_destinationOk = false; +} + +/** + * Engine function - Check inventory for a given object + * @remarks	Originally called 'cherjer' + */ +bool MortevielleEngine::checkInventory(int objectId) { +	bool retVal = false; +	for (int i = 1; i <= 6; ++i) +		retVal = (retVal || (_coreVar._inventory[i] == objectId)); + +	if (_coreVar._selectedObjectId == objectId) +		retVal = true; + +	return retVal; +} + +/** + * Engine function - Display Dining Room + * @remarks	Originally called 'st1sama' + */ +void MortevielleEngine::displayDiningRoom() { +	_coreVar._currPlace = DINING_ROOM; +	prepareDisplayText(); +} + +/** + * Engine function - Start non interactive Dialog + * @remarks	Originally called 'sparl' + */ +void MortevielleEngine::startDialog(int16 rep) { +	const int haut[9] = { 0, 0, 1, -3, 6, -2, 2, 7, -1 }; +	int key; + +	assert(rep >= 0); + +	_mouse.hideMouse(); +	Common::String dialogStr = getString(rep + kDialogStringIndex); +	_text.displayStr(dialogStr, 230, 4, 65, 26, 5); +	_dialogManager.drawF3F8(); + +	key = 0; +	do { +		_soundManager.startSpeech(rep, haut[_caff - 69], 0); +		key = _dialogManager.waitForF3F8(); +		if (shouldQuit()) +			return; +	} while (key != 66); +	clearScreen(); +	_mouse.showMouse(); +} + +/** + * Engine function - End of Search: reset globals + * @remarks	Originally called 'finfouill' + */ +void MortevielleEngine::endSearch() { +	_heroSearching = false; +	_obpart = false; +	_searchCount = 0; +	_menu.unsetSearchMenu(); +} + +/** + * Engine function - Go to Dining room + * @remarks	Originally called 't1sama' + */ +void MortevielleEngine::gotoDiningRoom() { +	int day, hour, minute; + +	updateHour(day, hour, minute); +	if ((hour < 5) && (_coreVar._currPlace > ROOM18)) { +		if (!checkInventory(137)) {        //You don't have the keys, and it's late +			_crep = 1511; +			loseGame(); +		} else +			displayDiningRoom(); +	} else if (!_coreVar._alreadyEnteredManor) {     //Is it your first time? +		_currBitIndex = 255; // Everybody is present +		showPeoplePresent(_currBitIndex); +		_caff = 77; +		drawPictureWithText(); +		_screenSurface.drawBox(223, 47, 155, 92, 15); +		handleDescriptionText(2, 33); +		testKey(false); +		menuUp(); +		_mouse.hideMouse(); +		clearScreen(); +		drawDiscussionBox(); +		startDialog(140); +		drawRightFrame(); +		drawClock(); +		_mouse.showMouse(); +		_coreVar._currPlace = OWN_ROOM; +		prepareDisplayText(); +		resetPresenceInRooms(DINING_ROOM); +		if (!_blo) +			getPresence(OWN_ROOM); +		_currBitIndex = 0; +		_savedBitIndex = 0; +		_coreVar._alreadyEnteredManor = true; +	} else +		displayDiningRoom(); +} + +/** + * Engine function - Check Manor distance (in the mountains) + * @remarks	Originally called 't1neig' + */ +void MortevielleEngine::checkManorDistance() { +	++_manorDistance; +	if (_manorDistance > 2) { +		_crep = 1506; +		loseGame(); +	} else { +		_destinationOk = true; +		_coreVar._currPlace = MOUNTAIN; +		prepareDisplayText(); +	} +} + +/** + * Engine function - Go to Manor front + * @remarks	Originally called 't1deva' + */ +void MortevielleEngine::gotoManorFront() { +	_manorDistance = 0; +	_coreVar._currPlace = MANOR_FRONT; +	prepareDisplayText(); +} + +/** + * Engine function - Go to Manor back + * @remarks	Originally called 't1derr' + */ +void MortevielleEngine::gotoManorBack() { +	_coreVar._currPlace = MANOR_BACK; +	prepareDisplayText(); +} + +/** + * Engine function - Dead : Flooded in Well + * @remarks	Originally called 't1deau' + */ +void MortevielleEngine::floodedInWell() { +	_crep = 1503; +	loseGame(); +} + +/** + * Called when a savegame has been loaded. + * @remarks	Originally called 'antegame' + */ +void MortevielleEngine::gameLoaded() { +	_mouse.hideMouse(); +	_menu._menuDisplayed = false; +	_loseGame = true; +	_anyone = false; +	_destinationOk = true; +	_col = false; +	_hiddenHero = false; +	_uptodatePresence = false; +	_maff = 68; +	_menuOpcode = OPCODE_NONE; +	_introSpeechPlayed = false; +	_x = 0; +	_y = 0; +	_num = 0; +	_startTime = 0; +	_endTime = 0; +	_searchCount = 0; +	_roomDoorId = OWN_ROOM; +	_syn = true; +	_heroSearching = true; +	_curSearchObjId = 0; +	_manorDistance = 0; +	resetOpenObjects(); +	_takeObjCount = 0; +	prepareDisplayText(); +	_hintPctMessage = getString(580); + +	_destinationOk = false; +	_endGame = true; +	_loseGame = false; +	_heroSearching = false; + +	displayAloneText(); +	prepareRoom(); +	drawClock(); +	drawPictureWithText(); +	handleDescriptionText(2, _crep); +	clearVerbBar(); +	_endGame = false; +	_menu.setDestinationText(_coreVar._currPlace); +	_menu.setInventoryText(); +	if (_coreVar._selectedObjectId != 0) +		displayItemInHand(_coreVar._selectedObjectId + 400); +	_mouse.showMouse(); +} + +/** + * Engine function - Handle OpCodes + * @remarks	Originally called 'tsitu' + */ +void MortevielleEngine::handleOpcode() { +	if (!_col) +		clearDescriptionBar(); +	_syn = false; +	_keyPressedEsc = false; +	if (!_anyone) { +		if (_uptodatePresence) { +			if ((_currMenu == MENU_MOVE) || (_currAction == _menu._opcodeLeave) || (_currAction == _menu._opcodeSleep) || (_currAction == _menu._opcodeEat)) { +				_controlMenu = 4; +				menuUp(); +				return; +			} +		} + +		if (_currMenu == MENU_MOVE) +			fctMove(); +		else if (_currMenu == MENU_DISCUSS) +			fctDiscuss(); +		else if (_currMenu == MENU_INVENTORY) +			fctInventoryTake(); +		else if (_currAction == _menu._opcodeAttach) +			fctAttach(); +		else if (_currAction == _menu._opcodeWait) +			fctWait(); +		else if (_currAction == _menu._opcodeForce) +			fctForce(); +		else if (_currAction == _menu._opcodeSleep) +			fctSleep(); +		else if (_currAction == _menu._opcodeListen) +			fctListen(); +		else if (_currAction == _menu._opcodeEnter) +			fctEnter(); +		else if (_currAction == _menu._opcodeClose) +			fctClose(); +		else if (_currAction == _menu._opcodeSearch) +			fctSearch(); +		else if (_currAction == _menu._opcodeKnock) +			fctKnock(); +		else if (_currAction == _menu._opcodeScratch) +			fctScratch(); +		else if (_currAction == _menu._opcodeRead) +			fctRead(); +		else if (_currAction == _menu._opcodeEat) +			fctEat(); +		else if (_currAction == _menu._opcodePlace) +			fctPlace(); +		else if (_currAction == _menu._opcodeOpen) +			fctOpen(); +		else if (_currAction == _menu._opcodeTake) +			fctTake(); +		else if (_currAction == _menu._opcodeLook) +			fctLook(); +		else if (_currAction == _menu._opcodeSmell) +			fctSmell(); +		else if (_currAction == _menu._opcodeSound) +			fctSound(); +		else if (_currAction == _menu._opcodeLeave) +			fctLeave(); +		else if (_currAction == _menu._opcodeLift) +			fctLift(); +		else if (_currAction == _menu._opcodeTurn) +			fctTurn(); +		else if (_currAction == _menu._opcodeSSearch) +			fctSelfSearch(); +		else if (_currAction == _menu._opcodeSRead) +			fctSelfRead(); +		else if (_currAction == _menu._opcodeSPut) +			fctSelfPut(); +		else if (_currAction == _menu._opcodeSLook) +			fctSelftLook(); + +		_hiddenHero = false; + +		if (_currAction == _menu._opcodeSHide) +			fctSelfHide(); +	} else if (_anyone) { +		interactNPC(); +		_anyone = false; +		menuUp(); +		return; +	} +	int hour, day, minute; +	updateHour(day, hour, minute); +	if ((((hour == 12) || (hour == 13) || (hour == 19)) && (_coreVar._currPlace != DINING_ROOM)) || +	        ((hour > 0) && (hour < 6) && (_coreVar._currPlace != OWN_ROOM))) +		++_coreVar._faithScore; +	if (((_coreVar._currPlace < CRYPT) || (_coreVar._currPlace > MOUNTAIN)) && (_coreVar._currPlace != INSIDE_WELL) +	        && (_coreVar._currPlace != OWN_ROOM) && (_coreVar._selectedObjectId != 152) && (!_loseGame)) { +		if ((_coreVar._faithScore > 99) && (hour > 8) && (hour < 16)) { +			_crep = 1501; +			loseGame(); +		} else if ((_coreVar._faithScore > 99) && (hour > 0) && (hour < 9)) { +			_crep = 1508; +			loseGame(); +		} else if ((day > 1) && (hour > 8) && (!_loseGame)) { +			_crep = 1502; +			loseGame(); +		} +	} +	menuUp(); +} + +/** + * Engine function - Transform time into a char + * @remarks	Originally called 'tmaj3' + */ +void MortevielleEngine::hourToChar() { +	int day, hour, minute; + +	updateHour(day, hour, minute); +	if (minute == 30) +		minute = 1; +	hour += day * 24; +	minute += hour * 2; +	_coreVar._fullHour = (unsigned char)minute; +} + +/** + * Engine function - extract time from a char + * @remarks	Originally called 'theure' + */ +void MortevielleEngine::charToHour() { +	int fullHour = _coreVar._fullHour; +	int tmpHour = fullHour % 48; +	_currDay = fullHour / 48; +	_currHalfHour = tmpHour % 2; +	_currHour = tmpHour / 2; +	_hour = _currHour; +	if (_currHalfHour == 1) +		_minute = 30; +	else +		_minute = 0; +} + +/** + * Engine function - Clear upper left part of Screen - Type 1 + * @remarks	Originally called 'clsf1' + */ +void MortevielleEngine::clearUpperLeftPart() { +	_mouse.hideMouse(); +	_screenSurface.fillRect(0, Common::Rect(0, 11, 514, 175)); +	_mouse.showMouse(); +} + +/** + * Engine function - Clear low bar used by description + * @remarks	Originally called 'clsf2' + */ +void MortevielleEngine::clearDescriptionBar() { +	_mouse.hideMouse(); +	if (_largestClearScreen) { +		_screenSurface.fillRect(0, Common::Rect(1, 176, 633, 199)); +		_screenSurface.drawBox(0, 176, 634, 23, 15); +		_largestClearScreen = false; +	} else { +		_screenSurface.fillRect(0, Common::Rect(1, 176, 633, 190)); +		_screenSurface.drawBox(0, 176, 634, 14, 15); +	} +	_mouse.showMouse(); +} + +/** + * Engine function - Clear lowest bar used by verbs + * @remarks	Originally called 'clsf3' + */ +void MortevielleEngine::clearVerbBar() { +	_mouse.hideMouse(); +	_screenSurface.fillRect(0, Common::Rect(1, 192, 633, 199)); +	_screenSurface.drawBox(0, 191, 634, 8, 15); +	_mouse.showMouse(); +} + +/** + * Engine function - Clear upper right part of the screen + * @remarks	Originally called 'clsf10' + */ +void MortevielleEngine::clearUpperRightPart() { +	Common::String st; + +	_mouse.hideMouse(); + +	// Clear ambiance description +	_screenSurface.fillRect(15, Common::Rect(544, 93, 600, 98)); +	if (_coreVar._faithScore < 33) +		st = getEngineString(S_COOL); +	else if (_coreVar._faithScore < 66) +		st = getEngineString(S_LOURDE); +	else if (_coreVar._faithScore > 65) +		st = getEngineString(S_MALSAINE); + +	int x1 = 580 - (_screenSurface.getStringWidth(st) / 2); +	_screenSurface.putxy(x1, 92); +	_screenSurface.drawString(st, 4); + +	// Clear person list +	_screenSurface.fillRect(15, Common::Rect(560, 24, 610, 86)); +	_mouse.showMouse(); +} + +/** + * Engine function - Get a random number between two values + * @remarks	Originally called 'get_random_number' and 'hazard' + */ +int MortevielleEngine::getRandomNumber(int minval, int maxval) { +	return _randomSource.getRandomNumber(maxval - minval) + minval; +} + +/** + * Engine function - Show alert "use move menu" + * @remarks	Originally called 'aldepl' + */ +void MortevielleEngine::showMoveMenuAlert() { +	_dialogManager.show(getEngineString(S_USE_DEP_MENU)); +} + +/** + * The original engine used this method to display a starting text screen letting the player + * select the graphics mode to use + * @remarks	Originally called 'dialpre' + */ +void MortevielleEngine::showConfigScreen() { +	_crep = 998; +} + +/** + * Decodes a number of 64 byte blocks + * @param pStart	Start of data + * @param count		Number of 64 byte blocks + * @remarks	Originally called 'zzuul' + */ +void MortevielleEngine::decodeNumber(byte *pStart, int count) { +	while (count-- > 0) { +		for (int idx = 0; idx < 64; ++pStart, ++idx) { +			uint16 v = ((*pStart - 0x80) << 1) + 0x80; + +			if (v & 0x8000) +				*pStart = 0; +			else if (v & 0xff00) +				*pStart = 0xff; +			else +				*pStart = (byte)v; +		} +	} +} + +const byte cryptoArrDefaultFr[32] = { +	32, 101, 115,  97, 114, 105, 110, +	117, 116, 111, 108,  13, 100,  99, +	112, 109,  46, 118, 130,  39, 102, +	98,  44, 113, 104, 103,  33,  76, +	85, 106,  30,  31 +}; + +const byte cryptoArr30Fr[32] = { +	69,  67,  74, 138, 133, 120,  77, 122, +	121,  68,  65,  63,  73,  80,  83,  82, +	156,  45,  58,  79,  49,  86,  78,  84, +	71,  81,  64,  66, 135,  34, 136,  91 +}; + +const byte cryptoArr31Fr[32]= { +	93,  47,  48,  53,  50,  70, 124,  75, +	72, 147, 140, 150, 151,  57,  56,  51, +	107, 139,  55,  89, 131,  37,  54,  88, +	119,   0,   0,   0,   0,   0,   0,   0 +}; + +const byte cryptoArrDefaultDe[32] = { +	0x20, 0x65, 0x6E, 0x69, 0x73, 0x72, 0x74, +	0x68, 0x61, 0x75, 0x0D, 0x63, 0x6C, 0x64, +	0x6D, 0x6F, 0x67, 0x2E, 0x62, 0x66, 0x53, +	0x2C, 0x77, 0x45, 0x7A, 0x6B, 0x44, 0x76, +	0x9C, 0x47, 0x1E, 0x1F +}; + +const byte cryptoArr30De[32] = { +	0x49, 0x4D, 0x21, 0x42, 0x4C, 0x70, 0x41, 0x52, +	0x57, 0x4E, 0x48, 0x3F, 0x46, 0x50, 0x55, 0x4B, +	0x5A, 0x4A, 0x54, 0x31, 0x4F, 0x56, 0x79, 0x3A, +	0x6A, 0x5B, 0x5D, 0x40, 0x22, 0x2F, 0x30, 0x35 +}; + +const byte cryptoArr31De[32]= { +	0x78, 0x2D, 0x32, 0x82, 0x43, 0x39, 0x33, 0x38, +	0x7C, 0x27, 0x37, 0x3B, 0x25, 0x28, 0x29, 0x36, +	0x51, 0x59, 0x71, 0x81, 0x87, 0x88, 0x93, 0, +	0,    0,    0,    0,    0,    0,    0,    0 +}; + +const byte *cryptoArrDefault, *cryptoArr30, *cryptoArr31; +uint16 ctrlChar; + +/** + * Decrypt the next character + * @param c		OUT, next decrypted char + * @param idx	IN/OUT, current buffer index + * @param pt	IN/OUT, current encryption point + * @return a boolean specifying if a stop character has been encountered + * @remarks	Originally called 'cinq_huit' + */ +bool MortevielleEngine::decryptNextChar(char &c, int &idx, byte &pt) { +	uint16 oct, ocd; + +	/* 5-8 */ +	oct = _dialogIndexArray[idx]; +	oct = ((uint16)(oct << (16 - pt))) >> (16 - pt); +	if (pt < 6) { +		++idx; +		oct = oct << (5 - pt); +		pt += 11; +		oct = oct | ((uint)_dialogIndexArray[idx] >> pt); +	} else { +		pt -= 5; +		oct = (uint)oct >> pt; +	} + +	if (oct == ctrlChar) { +		c = '$'; +		return true; +	} else if (oct == 30 || oct == 31) { +		ocd = _dialogIndexArray[idx]; +		ocd = (uint16)(ocd << (16 - pt)) >> (16 - pt); +		if (pt < 6) { +			++idx; +			ocd = ocd << (5 - pt); +			pt += 11; +			ocd = ocd | ((uint)_dialogIndexArray[idx] >> pt); +		} else { +			pt -= 5; +			ocd = (uint)ocd >> pt; +		} + +		if (oct == 30) +			c = (unsigned char)cryptoArr30[ocd]; +		else +			c = (unsigned char)cryptoArr31[ocd]; + +		if (c == '\0') { +			c = '#'; +			return true; +		} +	} else { +		c = (unsigned char)cryptoArrDefault[oct]; +	} +	return false; +} + +/** + * Decode and extract the line with the given Id + * @remarks	Originally called 'deline' + */ +Common::String MortevielleEngine::getString(int num) { +	Common::String wrkStr = ""; + +	if (num < 0) { +		warning("getString(%d): num < 0! Skipping", num); +	} else if (!_txxFileFl) { +		wrkStr = getGameString(num); +	} else { +		int hint = _dialogHintArray[num]._hintId; +		byte point = _dialogHintArray[num]._point; +		int length = 0; +		bool endFl = false; +		char let; +		do { +			endFl = decryptNextChar(let, hint, point); +			wrkStr += let; +			++length; +		} while (!endFl); +	} + +	while (wrkStr.lastChar() == '$') +		// Remove trailing '$'s +		wrkStr.deleteLastChar(); + +	return wrkStr; +} + +/** + * Reset object place + * @remarks	Originally called 'copcha' + */ +void MortevielleEngine::resetObjectPlace() { +	for (int i = kAcha; i < kAcha + 390; i++) +		_tabdon[i] = _tabdon[i + 390]; +} + +/** + * Engine function - When restarting the game, reset the main variables used by the engine + * @remarks	Originally called 'inzon' + */ +void MortevielleEngine::resetVariables() { +	resetObjectPlace(); + +	_coreVar._alreadyEnteredManor = false; +	_coreVar._selectedObjectId = 0; +	_coreVar._cellarObjectId = 0; +	_coreVar._atticBallHoleObjectId = 0; +	_coreVar._atticRodHoleObjectId = 0; +	_coreVar._wellObjectId = 0; +	_coreVar._secretPassageObjectId = 0; +	_coreVar._purpleRoomObjectId = 136; +	_coreVar._cryptObjectId = 141; +	_coreVar._faithScore = getRandomNumber(4, 10); +	_coreVar._currPlace = MANOR_FRONT; + +	for (int i = 2; i <= 6; ++i) +		_coreVar._inventory[i] = 0; + +	// Only object in inventory: a gun +	_coreVar._inventory[1] = 113; + +	_coreVar._fullHour = (unsigned char)20; + +	for (int i = 1; i <= 10; ++i) +		_coreVar._pctHintFound[i] = ' '; + +	for (int i = 1; i <= 6; ++i) +		_coreVar._availableQuestion[i] = '*'; + +	for (int i = 7; i <= 9; ++i) +		_coreVar._availableQuestion[i] = ' '; + +	for (int i = 10; i <= 28; ++i) +		_coreVar._availableQuestion[i] = '*'; + +	for (int i = 29; i <= 42; ++i) +		_coreVar._availableQuestion[i] = ' '; + +	_coreVar._availableQuestion[33] = '*'; + +	for (int i = 1; i <= 8; ++i) +		_charAnswerCount[i] = 0; + +	initMaxAnswer(); +} + +/** + * Engine function - Set the palette + * @remarks	Originally called 'writepal' + */ +void MortevielleEngine::setPal(int n) { +	for (int i = 1; i <= 16; ++i) { +		_curPict[(2 * i)] = _stdPal[n][i].x; +		_curPict[(2 * i) + 1] = _stdPal[n][i].y; +	} +} + +/** + * Engine function - Load Palette from File + * @remarks	Originally called 'charpal' + */ +void MortevielleEngine::loadPalette() { +	Common::File f; + +	if (!f.open("fxx.mor")) { +		if (f.open("mfxx.mor")) +			f.seek(7 * 25); +		else +			error("Missing file - fxx.mor"); +	} + +	for (int i = 0; i < 108; ++i) +		_drawingSizeArr[i] = f.readSint16LE(); +	f.close(); + +	if (!f.open("plxx.mor")) +		error("Missing file - plxx.mor"); +	for (int i = 0; i <= 90; ++i) { +		for (int j = 1; j <= 16; ++j) { +			_stdPal[i][j].x = f.readByte(); +			_stdPal[i][j].y = f.readByte(); +		} +	} +	f.close(); + +	if (!f.open("cxx.mor")) +		error("Missing file - cxx.mor"); + +	// Skip CGA Palette and Patterns + +	f.close(); +} + +/** + * Engine function - Load Texts from File + * @remarks	Originally called 'chartex' + */ +void MortevielleEngine::loadTexts() { +	Common::File inpFile; +	Common::File ntpFile; + +	_txxFileFl = false; +	if (!useOriginalData()) { +		warning("Using improved translation from DAT file"); +		return; +	} + +	if (!inpFile.open("TXX.INP")) { +		if (!inpFile.open("TXX.MOR")) { +			warning("Missing file - TXX.INP or .MOR - Switching to DAT file"); +			return; +		} +	} +	if (ntpFile.open("TXX.NTP")) { +		cryptoArr30 = cryptoArr30Fr; +		cryptoArr31 = cryptoArr31Fr; +		cryptoArrDefault = cryptoArrDefaultFr; +		ctrlChar = 11; +	} else if (ntpFile.open("TXX.IND")) { +		cryptoArr30 = cryptoArr30De; +		cryptoArr31 = cryptoArr31De; +		cryptoArrDefault = cryptoArrDefaultDe; +		ctrlChar = 10; +	} else { +		warning("Missing file - TXX.NTP or .IND - Switching to DAT file"); +		return; +	} + +	if ((inpFile.size() > (kMaxDialogIndex * 2)) || (ntpFile.size() > (kMaxDialogHint * 3))) { +		warning("TXX file - Unexpected format - Switching to DAT file"); +		return; +	} + +	for (int i = 0; i < inpFile.size() / 2; ++i) +		_dialogIndexArray[i] = inpFile.readUint16LE(); + +	inpFile.close(); +	_txxFileFl = true; + +	for (int i = 0; i < (ntpFile.size() / 3); ++i) { +		_dialogHintArray[i]._hintId = ntpFile.readSint16LE(); +		_dialogHintArray[i]._point = ntpFile.readByte(); +	} + +	ntpFile.close(); + +} + +void MortevielleEngine::loadCFIEC() { +	Common::File f; + +	if (!f.open("cfiec.mor")) { +		if (!f.open("alcfiec.mor")) +			error("Missing file - *cfiec.mor"); +	} + +	_cfiecBufferSize = ((f.size() / 128) + 1) * 128; +	int32 fileSize = f.size(); + +	if (!_reloadCFIEC) +		_cfiecBuffer = (byte *)malloc(sizeof(byte) * _cfiecBufferSize); + +	for (int32 i = 0; i < fileSize; ++i) +		_cfiecBuffer[i] = f.readByte(); + +	for (int i = fileSize; i < _cfiecBufferSize; i++) +		_cfiecBuffer[i] = 0; + +	f.close(); + +	_reloadCFIEC = false; +} + + +void MortevielleEngine::loadCFIPH() { +	Common::File f; + +	if (!f.open("cfiph.mor")) { +		if (!f.open("alcfiph.mor")) +			error("Missing file - *cfiph.mor"); +	} + +	_soundManager._cfiphBuffer = (uint16 *)malloc(sizeof(uint16) * (f.size() / 2)); + +	for (int i = 0; i < (f.size() / 2); ++i) +		_soundManager._cfiphBuffer[i] = f.readUint16BE(); + +	f.close(); +} + +/** + * Engine function - Play Music + * @remarks	Originally called 'music' + */ +void MortevielleEngine::music() { +	if (_soundOff) +		return; + +	_reloadCFIEC = true; + +	Common::File f; +	if (!f.open("mort.img")) +		error("Missing file - mort.img"); + +	int size = f.size(); +	byte *compMusicBuf = (byte *)malloc(sizeof(byte) * size); +	byte *musicBuf = (byte *)malloc(sizeof(byte) * size * 2); +	f.read(compMusicBuf, size); +	f.close(); + +	int musicSize = _soundManager.decodeMusic(compMusicBuf, musicBuf, size); +	free(compMusicBuf); + +	_soundManager.playSong(musicBuf, musicSize, 5); +	while (keyPressed()) +		getChar(); + +	free(musicBuf); +} + +/** + * Engine function - Show title screen + * @remarks	Originally called 'suite' + */ +void MortevielleEngine::showTitleScreen() { +	clearScreen(); +	handleDescriptionText(7, 2035); +	_caff = 51; +	_text.taffich(); +	testKeyboard(); +	clearScreen(); +	draw(0, 0); + +	Common::String cpr = "COPYRIGHT 1989 : LANKHOR"; +	_screenSurface.putxy(104 + 72 * kResolutionScaler, 185); +	_screenSurface.drawString(cpr, 0); +} + +/** + * Draw picture + * @remarks	Originally called 'dessine' + */ +void MortevielleEngine::draw(int x, int y) { +	_mouse.hideMouse(); +	setPal(_numpal); +	displayPicture(_curPict, x, y); +	_mouse.showMouse(); +} + +/** + * Draw right frame + * @remarks	Originally called 'dessine_rouleau' + */ +void MortevielleEngine::drawRightFrame() { +	setPal(89); +	_mouse.hideMouse(); +	displayPicture(_rightFramePict, 0, 0); +	_mouse.showMouse(); +} + +/** + * Read the current system time + */ +int MortevielleEngine::readclock() { +	return (int)(g_system->getMillis() / 1000); +} + +/** + * Engine function - Prepare room and hint string + * @remarks	Originally called 'tinke' + */ +void MortevielleEngine::prepareRoom() { +	int day, hour, minute; + +	_anyone = false; +	updateHour(day, hour, minute); +	if (day != _day) { +		_day = day; +		for (int i = 0; i < 9; i++) { +			if (_charAnswerMax[i] > 0) +				--_charAnswerMax[i]; +			_charAnswerCount[i] = 0; +		} +	} +	if ((hour > _hour) || ((hour == 0) && (_hour == 23))) { +		_hour = hour; +		_minute = 0; +		drawClock(); +		int hintCount = 0; +		for (int i = 1; i <= 10; ++i) { +			if (_coreVar._pctHintFound[i] == '*') +				++hintCount; +		} + +		Common::String pctStr; +		if (hintCount == 10) +			pctStr = "10"; +		else +			pctStr = (unsigned char)(hintCount + 48); + +		_hintPctMessage = "[1]["; +		_hintPctMessage += getEngineString(S_SHOULD_HAVE_NOTICED); +		_hintPctMessage += pctStr; +		_hintPctMessage += '0'; +		_hintPctMessage += getEngineString(S_NUMBER_OF_HINTS); +		_hintPctMessage += "]["; +		_hintPctMessage += getEngineString(S_OKAY); +		_hintPctMessage += ']'; +	} +	if (minute > _minute) { +		_minute = 30; +		drawClock(); +	} +	if (_mouse._pos.y < 12) +		return; + +	if (!_blo) { +		if ((hour == 12) || ((hour > 18) && (hour < 21)) || ((hour >= 0) && (hour < 7))) +			_inGameHourDuration = kTime2; +		else +			_inGameHourDuration = kTime1; +		if ((_coreVar._faithScore > 33) && (_coreVar._faithScore < 66)) +			_inGameHourDuration -= (_inGameHourDuration / 3); + +		if (_coreVar._faithScore > 65) +			_inGameHourDuration -= ((_inGameHourDuration / 3) * 2); + +		int newTime = readclock(); +		if ((newTime - _currentTime) > _inGameHourDuration) { +			bool activeMenu = _menu._menuActive; +			_menu.eraseMenu(); +			_currentHourCount += ((newTime - _currentTime) / _inGameHourDuration); +			_currentTime = newTime; +			switch (_place) { +			case GREEN_ROOM: +			case DARKBLUE_ROOM: +				setRandomPresenceGreenRoom(_coreVar._faithScore); +				break; +			case PURPLE_ROOM: +				setRandomPresencePurpleRoom(_coreVar._faithScore); +				break; +			case BLUE_ROOM: +				setRandomPresenceBlueRoom(_coreVar._faithScore); +				break; +			case RED_ROOM: +			case GREEN_ROOM2: +				setRandomPresenceRedRoom(_coreVar._faithScore); +				break; +			case JULIA_ROOM: +				setRandomPresenceJuliaRoom(_coreVar._faithScore); +				break; +			case DINING_ROOM: +				setRandomPresenceDiningRoom(_coreVar._faithScore); +				break; +			case BUREAU: +				setRandomPresenceBureau(_coreVar._faithScore); +				break; +			case KITCHEN: +				setRandomPresenceKitchen(_coreVar._faithScore); +				break; +			case ATTIC: +			case CELLAR: +				setRandomPresenceAttic(_coreVar._faithScore); +				break; +			case LANDING: +			case ROOM26: +				setRandomPresenceLanding(_coreVar._faithScore); +				break; +			case CHAPEL: +				setRandomPresenceChapel(_coreVar._faithScore); +				break; +			} +			if ((_savedBitIndex != 0) && (_currBitIndex != 10)) +				_savedBitIndex = _currBitIndex; + +			if ((_savedBitIndex == 0) && (_currBitIndex > 0)) { +				if ((_coreVar._currPlace == ATTIC) || (_coreVar._currPlace == CELLAR)) { +					initCaveOrCellar(); +				} else if (_currBitIndex == 10) { +					_currBitIndex = 0; +					if (!_uptodatePresence) { +						_uptodatePresence = true; +						_startTime = readclock(); +						if (getRandomNumber(1, 5) < 5) { +							clearVerbBar(); +							prepareScreenType2(); +							displayTextInVerbBar(getEngineString(S_HEAR_NOISE)); +							int rand = (getRandomNumber(0, 4)) - 2; +							_soundManager.startSpeech(1, rand, 1); +							_soundManager.waitSpeech(); +							clearVerbBar(); +						} +					} +				} +			} + +			if (activeMenu) +				_menu.drawMenu(); +		} +	} +	_endTime = readclock(); +	if ((_uptodatePresence) && ((_endTime - _startTime) > 17)) { +		getPresenceBitIndex(_place); +		_uptodatePresence = false; +		_startTime = 0; +		if ((_coreVar._currPlace > OWN_ROOM) && (_coreVar._currPlace < DINING_ROOM)) +			_anyone = true; +	} +} + +/** + * Engine function - Draw Clock + * @remarks	Originally called 'pendule' + */ +void MortevielleEngine::drawClock() { +	const int cv[2][12] = { +		{  5,  8, 10,  8,  5,  0, -5, -8, -10, -8, -5,  0 }, +		{ -5, -3,  0,  3,  5,  6,  5,  3,   0, -3, -5, -6 } +	}; +	const int x = 580; +	const int y = 123; +	const int rg = 9; + +	_mouse.hideMouse(); + +	_screenSurface.drawRectangle(570, 118, 20, 10); +	_screenSurface.drawRectangle(578, 114, 6, 18); + +	if (_minute == 0) +		_screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y - rg), 1); +	else +		_screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y + rg), 1); + +	int hour12 = _hour; +	if (hour12 > 12) +		hour12 -= 12; +	if (hour12 == 0) +		hour12 = 12; + +	_screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)(x + cv[0][hour12 - 1]) >> 1) * kResolutionScaler, y + cv[1][hour12 - 1], 1); +	_mouse.showMouse(); +	_screenSurface.putxy(568, 154); + +	if (_hour > 11) +		_screenSurface.drawString("PM ", 1); +	else +		_screenSurface.drawString("AM ", 1); + +	_screenSurface.putxy(550, 160); +	if ((_day >= 0) && (_day <= 8)) { +		Common::String tmp = getEngineString(S_DAY); +		tmp.insertChar((char)(_day + 49), 0); +		_screenSurface.drawString(tmp, 1); +	} +} + +void MortevielleEngine::palette(int v1) { +	warning("TODO: palette"); +} + +/** + * Returns a substring of the given string + * @param s		Source string + * @param idx	Starting index (1 based) + * @param size	Number of characters to return + */ + +Common::String MortevielleEngine::copy(const Common::String &s, int idx, size_t size) { +	assert(idx + size < s.size()); + +	// Copy the substring into a temporary buffer +	char *tmp = new char[size + 1]; +	Common::strlcpy(tmp, s.c_str() + idx - 1, size + 1); + +	Common::String result(tmp); +	delete[] tmp; +	return result; +} + +/** + * Clear Screen + * @remarks	Originally called 'hirs' + */ +void MortevielleEngine::clearScreen() { +	_screenSurface.clearScreen(); +} + +/** + * Init room : Cave or Cellar + * @remarks	Originally called 'cavegre' + */ +void MortevielleEngine::initCaveOrCellar() { +	_coreVar._faithScore += 2; +	if (_coreVar._faithScore > 69) +		_coreVar._faithScore += (_coreVar._faithScore / 10); +	clearVerbBar(); +	prepareScreenType2(); +	displayTextInVerbBar(getEngineString(S_SOMEONE_ENTERS)); +	int rand = (getRandomNumber(0, 4)) - 2; +	_soundManager.startSpeech(2, rand, 1); +	_soundManager.waitSpeech(); +	// The original was doing here a useless loop. +	// It has been removed + +	clearVerbBar(); +	displayAloneText(); +} + +/** + * Display control menu string + * @remarks	Originally called 'tctrm' + */ +void MortevielleEngine::displayControlMenu() { +	handleDescriptionText(2, (3000 + _controlMenu)); +	_controlMenu = 0; +} + +/** + * Display picture at a given coordinate + * @remarks	Originally called 'pictout' + */ +void MortevielleEngine::displayPicture(const byte *pic, int x, int y) { +	GfxSurface surface; +	surface.decode(pic); +	_screenSurface.drawPicture(surface, x, y); +} + +void MortevielleEngine::adzon() { +	Common::File f; + +	if (!f.open("don.mor")) +		error("Missing file - don.mor"); + +	f.read(_tabdon, 7 * 256); +	f.close(); + +	if (!f.open("bmor.mor")) +		error("Missing file - bmor.mor"); + +	f.read(&_tabdon[kFleche], 1916); +	f.close(); + +	// Read Right Frame Drawing +	if (!f.open("dec.mor")) +		error("Missing file - dec.mor"); + +	free(_rightFramePict); +	_rightFramePict = (byte *)malloc(sizeof(byte) * f.size()); +	f.read(_rightFramePict, f.size()); +	f.close(); +} + +/** + * Returns the offset within the compressed image data resource of the desired image + * @remarks	Originally called 'animof' + */ +int MortevielleEngine::getAnimOffset(int frameNum, int animNum) { +	int animCount = _curAnim[1]; +	int aux = animNum; +	if (frameNum != 1) +		aux += animCount; + +	return (animCount << 2) + 2 + READ_BE_UINT16(&_curAnim[aux << 1]); +} + +/** + * Display text in description bar + * @remarks	Originally called 'text1' + */ +void MortevielleEngine::displayTextInDescriptionBar(int x, int y, int nb, int mesgId) { +	Common::String tmpStr = getString(mesgId); +	if ((y == 182) && ((int) tmpStr.size() > nb)) +		y = 176; +	_text.displayStr(tmpStr, x, y, nb, 20, _textColor); +} + +/** + * Display description text + * @remarks	Originally called 'repon' + */ +void MortevielleEngine::handleDescriptionText(int f, int mesgId) { +	if ((mesgId > 499) && (mesgId < 563)) { +		Common::String tmpStr = getString(mesgId - 501 + kInventoryStringIndex); + +		if ((int) tmpStr.size() > ((58 + (kResolutionScaler - 1) * 37) << 1)) +			_largestClearScreen = true; +		else +			_largestClearScreen = false; + +		clearDescriptionBar(); +		_text.displayStr(tmpStr, 8, 176, 85, 3, 5); +	} else { +		mapMessageId(mesgId); +		switch (f) { +		case 2: +		case 8: +			clearDescriptionBar(); +			prepareScreenType2(); +			displayTextInDescriptionBar(8, 182, 103, mesgId); +			if ((mesgId == 68) || (mesgId == 69)) +				_coreVar._availableQuestion[40] = '*'; +			else if ((mesgId == 104) && (_caff == CELLAR)) { +				_coreVar._availableQuestion[36] = '*'; +				if (_coreVar._availableQuestion[39] == '*') { +					_coreVar._pctHintFound[3] = '*'; +					_coreVar._availableQuestion[38] = '*'; +				} +			} +			break; +		case 1: +		case 6: +		case 9: { +			int i; +			if ((f == 1) || (f == 6)) +				i = 4; +			else +				i = 5; + +			Common::String tmpStr = getString(mesgId); +			_text.displayStr(tmpStr, 80, 40, 60, 25, i); + +			if (mesgId == 180) +				_coreVar._pctHintFound[6] = '*'; +			else if (mesgId == 179) +				_coreVar._pctHintFound[10] = '*'; +			} +			break; +		default: +			break; +		} +	} +} + +/** + * Recompute message Id + * @remarks	Originally called 'modif' + */ +void MortevielleEngine::mapMessageId(int &mesgId) { +	if (mesgId == 26) +		mesgId = 25; +	else if ((mesgId > 29) && (mesgId < 36)) +		mesgId -= 4; +	else if ((mesgId > 69) && (mesgId < 78)) +		mesgId -= 37; +	else if ((mesgId > 99) && (mesgId < 194)) +		mesgId -= 59; +	else if ((mesgId > 996) && (mesgId < 1000)) +		mesgId -= 862; +	else if ((mesgId > 1500) && (mesgId < 1507)) +		mesgId -= 1363; +	else if ((mesgId > 1507) && (mesgId < 1513)) +		mesgId -= 1364; +	else if ((mesgId > 1999) && (mesgId < 2002)) +		mesgId -= 1851; +	else if (mesgId == 2010) +		mesgId = 151; +	else if ((mesgId > 2011) && (mesgId < 2025)) +		mesgId -= 1860; +	else if (mesgId == 2026) +		mesgId = 165; +	else if ((mesgId > 2029) && (mesgId < 2037)) +		mesgId -= 1864; +	else if ((mesgId > 3000) && (mesgId < 3005)) +		mesgId -= 2828; +	else if (mesgId == 4100) +		mesgId = 177; +	else if (mesgId == 4150) +		mesgId = 178; +	else if ((mesgId > 4151) && (mesgId < 4156)) +		mesgId -= 3973; +	else if (mesgId == 4157) +		mesgId = 183; +	else if ((mesgId == 4160) || (mesgId == 4161)) +		mesgId -= 3976; +} + +/** + * Initialize open objects array + * @remarks	Originally called 'initouv' + */ +void MortevielleEngine::resetOpenObjects() { +	for (int i = 1; i <= 6; ++i) +		_openObjects[i] = 0; +	_openObjCount = 0; +} + +/** + * Display Text Block + * @remarks	Originally called 'ecr2' + */ +void MortevielleEngine::displayTextBlock(Common::String text) { +	// Some dead code was present in the original: removed +	_screenSurface.putxy(8, 177); +	int tlig = 59 + (kResolutionScaler - 1) * 36; + +	if ((int)text.size() < tlig) +		_screenSurface.drawString(text, 5); +	else if ((int)text.size() < (tlig << 1)) { +		_screenSurface.putxy(8, 176); +		_screenSurface.drawString(copy(text, 1, (tlig - 1)), 5); +		_screenSurface.putxy(8, 182); +		_screenSurface.drawString(copy(text, tlig, tlig << 1), 5); +	} else { +		_largestClearScreen = true; +		clearDescriptionBar(); +		_screenSurface.putxy(8, 176); +		_screenSurface.drawString(copy(text, 1, (tlig - 1)), 5); +		_screenSurface.putxy(8, 182); +		_screenSurface.drawString(copy(text, tlig, ((tlig << 1) - 1)), 5); +		_screenSurface.putxy(8, 190); +		_screenSurface.drawString(copy(text, tlig << 1, tlig * 3), 5); +	} +} + +void MortevielleEngine::displayTextInVerbBar(Common::String text) { +	clearVerbBar(); +	_screenSurface.putxy(8, 192); +	_screenSurface.drawString(text, 5); +} + +/** + * Display item in hand + * @remarks	Originally called 'modobj' + */ +void MortevielleEngine::displayItemInHand(int objId) { +	Common::String strp = Common::String(' '); + +	if (objId != 500) +		strp = getString(objId - 501 + kInventoryStringIndex); + +	_menu.setText(_menu._inventoryMenu[8], strp); +	_menu.disableMenuItem(_menu._inventoryMenu[8]); +} + +/** + * Display empty hand + * @remarks	Originally called 'maivid' + */ +void MortevielleEngine::displayEmptyHand() { +	_coreVar._selectedObjectId = 0; +	displayItemInHand(500); +} + +/** + * Set a random presence: Leo or Max + * @remarks	Originally called 'chlm' + */ +int MortevielleEngine::checkLeoMaxRandomPresence() { +	int retval = getRandomNumber(1, 2); +	if (retval == 2) +		retval = 128; + +	return retval; +} + +/** + * Reset room variables + * @remarks	Originally called 'debloc' + */ +void MortevielleEngine::resetRoomVariables(int roomId) { +	_num = 0; +	_x = 0; +	_y = 0; +	if ((roomId != ROOM26) && (roomId != LANDING)) +		resetPresenceInRooms(roomId); +	_savedBitIndex = _currBitIndex; +} + +/** + * Compute presence stats + * @remarks	Originally called 'ecfren' + */ +int MortevielleEngine::getPresenceStats(int &rand, int faithScore, int roomId) { +	if (roomId == OWN_ROOM) +		displayAloneText(); +	int retVal = -500; +	rand = 0; +	if ( ((roomId == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda)) +	  || ((roomId == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) ) +		retVal = getPresenceStatsGreenRoom(); +	if ((roomId == PURPLE_ROOM) && (!_purpleRoomPresenceLeo) && (!_juliaRoomPresenceLeo)) +		retVal = getPresenceStatsPurpleRoom(); +	if ( ((roomId == TOILETS) && (!_toiletsPresenceBobMax)) +	  || ((roomId == BATHROOM) && (!_bathRoomPresenceBobMax)) ) +		retVal = getPresenceStatsToilets(); +	if ((roomId == BLUE_ROOM) && (!_roomPresenceMax)) +		retVal = getPresenceStatsBlueRoom(); +	if ( ((roomId == RED_ROOM) && (!_roomPresenceBob)) +	  || ((roomId == GREEN_ROOM2) && (!_roomPresencePat))) +		retVal = getPresenceStatsRedRoom(); +	if ((roomId == JULIA_ROOM) && (!_juliaRoomPresenceLeo) && (!_purpleRoomPresenceLeo)) +		retVal = 10; +	if ( ((roomId == PURPLE_ROOM) && (_juliaRoomPresenceLeo)) +	  || ((roomId == JULIA_ROOM) && (_purpleRoomPresenceLeo))) +		retVal = -400; +	if (retVal != -500) { +		retVal += faithScore; +		rand = getRandomNumber(1, 100); +	} + +	return retVal; +} + +/** + * Set presence flags + * @remarks	Originally called 'becfren' + */ +void MortevielleEngine::setPresenceFlags(int roomId) { +	if ((roomId == GREEN_ROOM) || (roomId == DARKBLUE_ROOM)) { +		int rand = getRandomNumber(1, 2); +		if (roomId == GREEN_ROOM) { +			if (rand == 1) +				_roomPresenceLuc = true; +			else +				_roomPresenceIda = true; +		} else { // roomId == DARKBLUE_ROOM +			if (rand == 1) +				_roomPresenceGuy = true; +			else +				_roomPresenceEva = true; +		} +	} else if (roomId == PURPLE_ROOM) +		_purpleRoomPresenceLeo = true; +	else if (roomId == TOILETS) +		_toiletsPresenceBobMax = true; +	else if (roomId == BLUE_ROOM) +		_roomPresenceMax = true; +	else if (roomId == RED_ROOM) +		_roomPresenceBob = true; +	else if (roomId == BATHROOM) +		_bathRoomPresenceBobMax = true; +	else if (roomId == GREEN_ROOM2) +		_roomPresencePat = true; +	else if (roomId == JULIA_ROOM) +		_juliaRoomPresenceLeo = true; +} + +/** + * Initialize max answers per character + * @remarks	Originally called 'init_nbrepm' + */ +void MortevielleEngine::initMaxAnswer() { +	static const byte maxAnswer[9] = { 0, 4, 5, 6, 7, 5, 6, 5, 8 }; + +	for (int idx = 0; idx < 9; ++idx) { +		_charAnswerMax[idx] = maxAnswer[idx]; +		_charAnswerCount[idx] = 0; +	} +} + +/** + * Get Presence + * @remarks	Originally called 't11' + */ +int MortevielleEngine::getPresence(int roomId) { +	int retVal = 0; +	int rand; + +	int pres = getPresenceStats(rand, _coreVar._faithScore, roomId); +	_place = roomId; +	if ((roomId > OWN_ROOM) && (roomId < DINING_ROOM)) { +		if (pres != -500) { +			if (rand > pres) { +				displayAloneText(); +				retVal = 0; +			} else { +				setPresenceFlags(_place); +				retVal = getPresenceBitIndex(_place); +			} +		} else +			retVal = getPresenceBitIndex(_place); +	} + +	if (roomId > JULIA_ROOM) { +		if ((roomId > LANDING) && (roomId != CHAPEL) && (roomId != ROOM26)) +			displayAloneText(); +		else { +			int h = 0; +			switch (roomId) { +			case DINING_ROOM: +				pres = getPresenceStatsDiningRoom(h); +				break; +			case BUREAU: +				pres = getPresenceStatsBureau(h); +				break; +			case KITCHEN: +				pres = getPresenceStatsKitchen(); +				break; +			case ATTIC: +			case CELLAR: +				pres = getPresenceStatsAttic(); +				break; +			case LANDING: +			case ROOM26: +				pres = getPresenceStatsLanding(); +				break; +			case CHAPEL: +				pres = getPresenceStatsChapel(h); +				break; +			} +			pres += _coreVar._faithScore; +			rand = getRandomNumber(1, 100); +			if (rand > pres) { +				displayAloneText(); +				retVal = 0; +			} else { +				switch (roomId) { +				case DINING_ROOM: +					pres = setPresenceDiningRoom(h); +					break; +				case BUREAU: +					pres = setPresenceBureau(h); +					break; +				case KITCHEN: +				case ATTIC: +				case CELLAR: +					pres = setPresenceKitchen(); +					break; +				case LANDING: +				case ROOM26: +					pres = setPresenceLanding(); +					break; +				case CHAPEL: +					pres = setPresenceChapel(h); +					break; +				} +				retVal = pres; +			} +		} +	} + +	return retVal; +} + +/** + * Display Question String + * @remarks	Originally called 'writetp' + */ +void MortevielleEngine::displayQuestionText(Common::String s, int cmd) { +	_screenSurface.drawString(s, cmd); +} + +/** + * Display animation frame + * @remarks	Originally called 'aniof' + */ +void MortevielleEngine::displayAnimFrame(int frameNum, int animId) { +	if ((_caff == BATHROOM) && ((animId == 4) || (animId == 5))) +		return; + +	if ((_caff == DINING_ROOM) && (animId == 7)) +		animId = 6; +	else if (_caff == KITCHEN) { +		if (animId == 3) +			animId = 4; +		else if (animId == 4) +			animId = 3; +	} + +	int offset = getAnimOffset(frameNum, animId); + +	GfxSurface surface; +	surface.decode(&_curAnim[offset]); +	_screenSurface.drawPicture(surface, 0, 12); + +	prepareScreenType1(); +} + +/** + * Draw Picture + * @remarks	Originally called 'dessin' + */ +void MortevielleEngine::drawPicture() { +	clearUpperLeftPart(); +	if (_caff > 99) { +		draw(60, 33); +		_screenSurface.drawBox(118, 32, 291, 122, 15);         // Medium box +	} else if (_caff > 69) { +		draw(112, 48);           // Heads +		_screenSurface.drawBox(222, 47, 155, 92, 15); +	} else { +		draw(0, 12); +		prepareScreenType1(); +		if ((_caff < 30) || (_caff > 32)) { +			for (int i = 1; i <= 6; ++i) { +				if (_openObjects[i] != 0) +					displayAnimFrame(1, _openObjects[i]); +			} + +			switch (_caff) { +			case ATTIC: +				if (_coreVar._atticBallHoleObjectId == 141) +					displayAnimFrame(1, 7); + +				if (_coreVar._atticRodHoleObjectId == 159) +					displayAnimFrame(1, 6); +				break; +			case CELLAR: +				if (_coreVar._cellarObjectId == 151) +					displayAnimFrame(1, 2); +				break; +			case SECRET_PASSAGE: +				if (_coreVar._secretPassageObjectId == 143) +					displayAnimFrame(1, 1); +				break; +			case WELL: +				if (_coreVar._wellObjectId != 0) +					displayAnimFrame(1, 1); +				break; +			} +		} + +		if (_caff < ROOM26) +			startMusicOrSpeech(1); +	} +} + +void MortevielleEngine::drawPictureWithText() { +	_text.taffich(); +	drawPicture(); +	_destinationOk = false; +} + +/** + * Engine function - Place + * @remarks	Originally called 'tkey1' + */ +void MortevielleEngine::testKey(bool d) { +	bool quest = false; +	int x, y; +	bool click; + +	_mouse.hideMouse(); +	displayStatusInDescriptionBar('K'); + +	// Wait for release from any key or mouse button +	while (keyPressed()) +		_key = gettKeyPressed(); + +	do { +		_mouse.getMousePosition(x, y, click); +		quest = keyPressed(); +		if (quest && shouldQuit()) +			return; +	} while (click); + +	// Event loop +	do { +		if (d) +			prepareRoom(); +		quest = keyPressed(); +		_mouse.getMousePosition(x, y, click); +		if (shouldQuit()) +			return; +	} while (!(quest || (click) || (d && _anyone))); +	if (quest) +		gettKeyPressed(); +	setMouseClick(false); +	_mouse.showMouse(); +} + +/** + * Display Narrative Picture + * @remarks	Originally called 'tlu' + */ +void MortevielleEngine::displayNarrativePicture(int af, int ob) { +	_caff = 32; +	drawPictureWithText(); +	handleDescriptionText(6, ob + 4000); +	handleDescriptionText(2, 999); +	testKey(true); +	_caff = af; +	_currMenu = OPCODE_NONE; +	_crep = 998; +} + +/** + * Prepare Display Text + * @remarks	Originally called 'affrep' + */ +void MortevielleEngine::prepareDisplayText() { +	_caff = _coreVar._currPlace; +	_crep = _coreVar._currPlace; +} + +/** + * Exit room + * @remarks	Originally called 'tsort' + */ +void MortevielleEngine::exitRoom() { +	if ((_openObjCount > 0) && (_coreVar._currPlace != OWN_ROOM)) { +		if (_coreVar._faithScore < 50) +			_coreVar._faithScore += 2; +		else +			_coreVar._faithScore += (_coreVar._faithScore / 10); +	} + +	resetOpenObjects(); + +	_roomDoorId = OWN_ROOM; +	_curSearchObjId = 0; +	resetRoomVariables(_coreVar._currPlace); +} + +/** + * get 'read' description + * @remarks	Originally called 'st4' + */ +void MortevielleEngine::getReadDescription(int objId) { +	_crep = 997; + +	switch (objId) { +	case 114 : +		_crep = 109; +		break; +	case 110 : +		_crep = 107; +		break; +	case 158 : +		_crep = 113; +		break; +	case 152: +	case 153: +	case 154: +	case 155: +	case 156: +	case 150: +	case 100: +	case 157: +	case 160: +	case 161 : +		displayNarrativePicture(_caff, objId); +		break; +	default: +		break; +	} +} + +/** + * get 'search' description + * @remarks	Originally called 'st7' + */ +void MortevielleEngine::getSearchDescription(int objId) { +	switch (objId) { +	case 116: +	case 144: +		_crep = 104; +		break; +	case 126: +	case 111: +		_crep = 108; +		break; +	case 132: +		_crep = 111; +		break; +	case 142: +		_crep = 112; +		break; +	default: +		_crep = 183; +		getReadDescription(objId); +	} +} + +/** + * Menu up + * @remarks	Originally called 'mennor' + */ +void MortevielleEngine::menuUp() { +	_menu.menuUp(_currMenu); +} + +/** + * Draw discussion box + * @remarks	Originally called 'premtet' + */ +void MortevielleEngine::drawDiscussionBox() { +	draw(10, 80); +	_screenSurface.drawBox(18, 79, 155, 92, 15); +} + +/** + * Try to put an object somewhere + * @remarks	Originally called 'ajchai' + */ +void MortevielleEngine::putObject() { +	int putId = kAcha + ((_curSearchObjId - 1) * 10) - 1; +	int i; +	for (i = 1; (i <= 9) && (_tabdon[putId + i] != 0); i++) +		; + +	if (_tabdon[putId + i] == 0) +		_tabdon[putId + i] = _coreVar._selectedObjectId; +	else +		_crep = 192; +} + +/** + * Check if inventory is full and, if not, add object in it. + * @remarks	Originally called 'ajjer' + */ +void MortevielleEngine::addObjectToInventory(int objectId) { +	int i; +	 +	for (i = 1; (i <= 5) && (_coreVar._inventory[i] != 0); i++) +		; + +	if (_coreVar._inventory[i] == 0) { +		_coreVar._inventory[i] = objectId; +		_menu.setInventoryText(); +	} else +		// Inventory is full +		_crep = 139; +} + +/** + * Interact with NPC + * @remarks	Originally called 'quelquun' + */ +void MortevielleEngine::interactNPC() { +	if (_menu._menuDisplayed) +		_menu.eraseMenu(); + +	endSearch(); +	_crep = 997; +L1: +	if (!_hiddenHero) { +		if (_crep == 997) +			_crep = 138; +		handleDescriptionText(2, _crep); +		if (_crep == 138) +			_soundManager.startSpeech(5, 2, 1); +		else +			_soundManager.startSpeech(4, 4, 1); + +		if (_openObjCount == 0) +			_coreVar._faithScore += 2; +		else if (_coreVar._faithScore < 50) +			_coreVar._faithScore += 4; +		else +			_coreVar._faithScore += 3 * (_coreVar._faithScore / 10); +		exitRoom(); +		_menu.setDestinationText(LANDING); +		int charIdx = convertBitIndexToCharacterIndex(_currBitIndex); +		_caff = 69 + charIdx; +		_crep = _caff; +		_currMenu = MENU_DISCUSS; +		_currAction = (_menu._discussMenu[charIdx]._menuId << 8) | _menu._discussMenu[charIdx]._actionId; +		_syn = true; +		_col = true; +	} else { +		if (getRandomNumber(1, 3) == 2) { +			_hiddenHero = false; +			_crep = 137; +			goto L1; +		} else { +			handleDescriptionText(2, 136); +			int rand = (getRandomNumber(0, 4)) - 2; +			_soundManager.startSpeech(3, rand, 1); +			clearDescriptionBar(); +			displayAloneText(); +			resetRoomVariables(MANOR_FRONT); +			prepareDisplayText(); +		} +	} +	if (_menu._menuDisplayed) +		_menu.drawMenu(); +} + +/** + * Search - Prepare next object + * @remarks	Originally called 'tsuiv' + */ +void MortevielleEngine::prepareNextObject() { +	int objId; +	int tabIdx = kAcha + ((_curSearchObjId - 1) * 10) - 1; +	int localSeearchCount = 0; +	do { +		++localSeearchCount; +		++_searchCount; +		objId = _tabdon[tabIdx + _searchCount]; +	} while ((objId == 0) && (_searchCount <= 9)); + +	if ((objId != 0) && (_searchCount < 11)) { +		_caff = objId; +		_crep = _caff + 400; +		if (_currBitIndex != 0) +			// Someone is present in the room +			_coreVar._faithScore += 2; +	} else { +		prepareDisplayText(); +		endSearch(); +		if (localSeearchCount > 9) +			_crep = 131; +	} +} + +/** + * Display Arrow status + * @remarks	Originally called 'tfleche' + */ +void MortevielleEngine::displayStatusArrow() { +	bool qust; +	char touch; + +	if (_num == 9999) +		return; + +	displayStatusInDescriptionBar((unsigned char)152); +	bool inRect = false; +	do { +		touch = '\0'; + +		do { +			_mouse.moveMouse(qust, touch); +			if (shouldQuit()) +				return; + +			if (getMouseClick()) +				inRect = (_mouse._pos.x < 256 * kResolutionScaler) && (_mouse._pos.y < 176) && (_mouse._pos.y > 12); +			prepareRoom(); +		} while (!(qust || inRect || _anyone)); + +		if (qust && (touch == '\103')) +			_dialogManager.show(_hintPctMessage); +	} while (!((touch == '\73') || ((touch == '\104') && (_x != 0) && (_y != 0)) || (_anyone) || (inRect))); + +	if (touch == '\73') +		_keyPressedEsc = true; + +	if (inRect) { +		_x = _mouse._pos.x; +		_y = _mouse._pos.y; +	} +} + +/** + * Set coordinates + * @remarks	Originally called 'tcoord' + */ +void MortevielleEngine::setCoordinates(int sx) { +	int sy, ix, iy; +	int ib; + + +	_num = 0; +	_crep = 999; +	int a = 0; +	int atdon = kAmzon + 3; +	int cy = 0; +	while (cy < _caff) { +		a += _tabdon[atdon]; +		atdon += 4; +		++cy; +	} + +	if (_tabdon[atdon] == 0) { +		_crep = 997; +		return; +	} + +	a += kFleche; +	int cb = 0; +	for (cy = 0; cy <= (sx - 2); ++cy) { +		ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)]; +		cb += (ib * 4) + 2; +	} +	ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)]; +	if (ib == 0) { +		_crep = 997; +		return; +	} + +	cy = 1; +	do { +		cb += 2; +		sx = _tabdon[a + cb] * kResolutionScaler; +		sy = _tabdon[(a + cb + 1)]; +		cb += 2; +		ix = _tabdon[a + cb] * kResolutionScaler; +		iy = _tabdon[(a + cb + 1)]; +		++cy; +	} while (!(((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) || (cy > ib))); + +	if ((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) { +		_num = cy - 1; +		return; +	} + +	_crep = 997; +} + +/** + * Display LOOK Screen + * @remarks	Originally called 'treg' + */ +void MortevielleEngine::displayLookScreen(int objId) { +	int mdes = _caff; +	_caff = objId; + +	if (((_caff > 29) && (_caff < 33)) || (_caff == 144) || (_caff == 147) || (_caff == 149) || (_currAction == _menu._opcodeSLook)) { +		drawPictureWithText(); +		if ((_caff > 29) && (_caff < 33)) +			handleDescriptionText(2, _caff); +		else +			handleDescriptionText(2, _caff + 400); +		testKey(true); +		_caff = mdes; +		_currMenu = MENU_NONE; +		_crep = 998; +	} else { +		_obpart = true; +		_crep = _caff + 400; +		_menu.setSearchMenu(); +	} +} + +/** + * Engine function - Put in hand + * @remarks	Originally called 'avpoing' + */ +void MortevielleEngine::putInHand(int &objId) { +	_crep = 999; +	if (_coreVar._selectedObjectId != 0) +		addObjectToInventory(_coreVar._selectedObjectId); + +	// If inventory wasn't full +	if (_crep != 139) { +		displayItemInHand(objId + 400); +		_coreVar._selectedObjectId = objId; +		objId = 0; +	} +} + +/** + * Search - Get the first object + * @remarks	Originally called 'rechai' + */ +int MortevielleEngine::getFirstObject() { +	int tmpPlace = _coreVar._currPlace; + +	if (_coreVar._currPlace == CRYPT) +		tmpPlace = CELLAR; + +	return _tabdon[kAsearch + (tmpPlace * 7) + _num - 1]; +} + +/** + * Check before leaving the secret passage + * @remarks	Originally called 't23coul' + */ +int MortevielleEngine::checkLeaveSecretPassage() { +	if (!checkInventory(143)) { +		_crep = 1512; +		loseGame(); +	} + +	return CELLAR; +} + +/** + * Display status character in description bar + * @remarks	Originally called 'fenat' + */ +void MortevielleEngine::displayStatusInDescriptionBar(char stat) { +	_mouse.hideMouse(); +	_screenSurface.writeCharacter(Common::Point(306, 193), stat, 12); +	_screenSurface.drawBox(300, 191, 16, 8, 15); +	_mouse.showMouse(); +} + +/** + * Test Keyboard + * @remarks	Originally called 'teskbd' + */ +void MortevielleEngine::testKeyboard() { +	if (keyPressed()) +		gettKeyPressed(); +} + +/** + * Test Key Pressed + * @remarks	Originally called 'testou' + */ +int MortevielleEngine::gettKeyPressed() { +	char ch = getChar(); + +	switch (ch)  { +	case '\23' : +		_soundOff = !_soundOff; +		break; +	case '\26' : +		if ((_x26KeyCount == 1) || (_x26KeyCount == 2)) { +			decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64); +			++_x26KeyCount; + +			return 61; +		} +		break; +	case '\33' : +		if (keyPressed()) +			ch = getChar(); +		break; +	default: +		break; +	} + +	return (int)ch; +} + +} // End of namespace Mortevielle | 
