diff options
Diffstat (limited to 'engines/avalanche/avalot.cpp')
| -rw-r--r-- | engines/avalanche/avalot.cpp | 1755 | 
1 files changed, 1755 insertions, 0 deletions
| diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp new file mode 100644 index 0000000000..ec3f81e55d --- /dev/null +++ b/engines/avalanche/avalot.cpp @@ -0,0 +1,1755 @@ +/* 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 the original source code of Lord Avalot d'Argent version 1.3. + * Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman. + */ + +/* AVALOT		The kernel of the program. */ + +#include "avalanche/avalanche.h" + +#include "common/random.h" +#include "common/system.h" +#include "common/config-manager.h" +#include "graphics/palette.h" + +namespace Avalanche { + +// vv Stairs trap. + +/* Explanation: $NSEW. +		Nibble N: North. +		0     = no connection, +		2     = (left,) middle(, right) door with left-hand handle, +		5     = (left,) middle(, right) door with right-hand handle, +		7     = arch, +		8     = arch and 1 north of it, +		9     = arch and 2 north of it, +		D     = no connection + WINDOW, +		E     = no connection + TORCH, +		F     = recessed door (to Geida's room.) + +		Nibble S: South. +		0     = no connection, +		1,2,3 = left, middle, right door. + +		Nibble E: East. +		0     = no connection (wall), +		1     = no connection (wall + window), +		2     = wall with door, +		3     = wall with door and window, +		6     = wall with candles, +		7     = wall with door and candles, +		F     = straight-through corridor. + +		Nibble W: West. +		0     = no connection (wall), +		1     = no connection (wall + shield), +		2     = wall with door, +		3     = wall with door and shield, +		4     = no connection (window), +		5     = wall with door and window, +		6     = wall with candles, +		7     = wall with door and candles, +		F     = straight-through corridor. */ + +const char AvalancheEngine::kSpludwicksOrder[3] = {kObjectOnion, kObjectInk, kObjectMushroom}; +const uint16 AvalancheEngine::kNotes[12] = {196, 220, 247, 262, 294, 330, 350, 392, 440, 494, 523, 587}; +const TuneType AvalancheEngine::kTune = { +	kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher, +	kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher, +	kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher +}; + +Room AvalancheEngine::_whereIs[29] = { +	// The Lads +	kRoomYours, // Avvy +	kRoomSpludwicks, // Spludwick +	kRoomOutsideYours, // Crapulus +	kRoomDucks, // Duck - r__DucksRoom's not defined yet. +	kRoomArgentPub, // Malagauche +	kRoomRobins, // Friar Tuck. +	kRoomDummy, // Robin Hood - can't meet him at the start. +	kRoomBrummieRoad, // Cwytalot +	kRoomLustiesRoom, // Baron du Lustie. +	kRoomOutsideCardiffCastle, // The Duke of Cardiff. +	kRoomArgentPub, // Dogfood +	kRoomOutsideDucks, // Trader +	kRoomArgentPub, // Ibythneth +	kRoomAylesOffice, // Ayles +	kRoomNottsPub, // Port +	kRoomNottsPub, // Spurge +	kRoomMusicRoom, // Jacques +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	kRoomNowhere, +	// The Lasses +	kRoomYours, // Arkata +	kRoomGeidas, // Geida +	kRoomDummy, // nobody allocated here! +	kRoomWiseWomans  // The Wise Woman. +}; + +Clock::Clock(AvalancheEngine *vm) { +	_vm = vm; +	// Magic value to determine if we just created the instance +	_oldHour = _oldHourAngle = _oldMinute = 17717; +	_hour = _minute = _second = 0; +	_hourAngle = 0; +} + +void Clock::update() { +	TimeDate t; +	_vm->_system->getTimeAndDate(t); +	_hour = t.tm_hour; +	_minute = t.tm_min; +	_second = t.tm_sec; + +	_hourAngle = (_hour % 12) * 30 + _minute / 2; + +	if (_oldHour != _hour)  { +		plotHands(); +		chime(); +	} + +	if (_oldMinute != _minute) +		plotHands(); + +	if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) { +		Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \ +			"midnight. Are you having an all-night Avvy session? Glad you like the game that much!", +			kControlNewLine, kControlNewLine); +		_vm->_dialogs->displayText(tmpStr); +	} +	_oldHour = _hour; +	_oldHourAngle = _hourAngle; +	_oldMinute = _minute; +} + +Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) { +	if (angle > 900) { +		return(Common::Point(177, 177)); +	} + +	return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color)); +} + +void Clock::drawHand(const Common::Point &endPoint, Color color) { +	if (endPoint.x == 177) +		return; + +	_vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color); +} + +void Clock::plotHands() { +	_clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow); +	_clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow); +	drawHand(_clockHandHour, kColorBrown); +	drawHand(_clockHandMinute, kColorBrown); + +	_clockHandHour = calcHand(_hourAngle, 14, kColorBrown); +	_clockHandMinute = calcHand(_minute * 6, 17, kColorBrown); +	drawHand(_clockHandHour, kColorYellow); +	drawHand(_clockHandMinute, kColorYellow); +} + +void Clock::chime() { +	// Too high - must be first time around +	// Mute - skip the sound generation +	if ((_oldHour == 17717) || (!_vm->_soundFx)) +		return; + +	byte hour = _hour % 12; +	if (hour == 0) +		hour = 12; + +	_vm->_graphics->loadMouse(kCurWait); + +	for (int i = 1; i <= hour; i++) { +		for (int j = 1; j <= 3; j++) +			_vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12); +		if (i != hour) +			_vm->_system->delayMillis(100); +	} +} + +void AvalancheEngine::handleKeyDown(Common::Event &event) { +	_sound->click(); + +	if ((Common::KEYCODE_F1 <= event.kbd.keycode) && (event.kbd.keycode <= Common::KEYCODE_F15)) +		_parser->handleFunctionKey(event); +	else if ((32 <= event.kbd.ascii) && (event.kbd.ascii <= 128) && (event.kbd.ascii != 47)) +		_parser->handleInputText(event); +	else +		switch (event.kbd.keycode) { // We can control Avvy with the numpad as well. +		case Common::KEYCODE_KP8: +			event.kbd.keycode = Common::KEYCODE_UP; +			break; +		case Common::KEYCODE_KP2: +			event.kbd.keycode = Common::KEYCODE_DOWN; +			break; +		case Common::KEYCODE_KP6: +			event.kbd.keycode = Common::KEYCODE_RIGHT; +			break; +		case Common::KEYCODE_KP4: +			event.kbd.keycode = Common::KEYCODE_LEFT; +			break; +		case Common::KEYCODE_KP9: +			event.kbd.keycode = Common::KEYCODE_PAGEUP; +			break; +		case Common::KEYCODE_KP3: +			event.kbd.keycode = Common::KEYCODE_PAGEDOWN; +			break; +		case Common::KEYCODE_KP7: +			event.kbd.keycode = Common::KEYCODE_HOME; +			break; +		case Common::KEYCODE_KP1: +			event.kbd.keycode = Common::KEYCODE_END; +			break; +		default: +			break; +	} + +	switch (event.kbd.keycode) { +	case Common::KEYCODE_UP: +	case Common::KEYCODE_DOWN: +	case Common::KEYCODE_RIGHT: +	case Common::KEYCODE_LEFT: +	case Common::KEYCODE_PAGEUP: +	case Common::KEYCODE_PAGEDOWN: +	case Common::KEYCODE_HOME: +	case Common::KEYCODE_END: +	case Common::KEYCODE_KP5: +		if (_alive && _avvyIsAwake) { +			_animation->handleMoveKey(event); // Fallthroughs are intended. +			drawDirection(); +			return; +		} +	case Common::KEYCODE_BACKSPACE: +		_parser->handleBackspace(); +		break; +	case Common::KEYCODE_RETURN: +		_parser->handleReturn(); +		break; +	default: +		break; +	} + +	drawDirection(); +} + +void AvalancheEngine::setup() { +	init(); + +	_dialogs->reset(); +	fadeOut(); +	_graphics->loadDigits(); + +	_parser->_inputTextPos = 0; +	_parser->_quote = true; + +	_animation->resetAnims(); + +	drawToolbar(); +	_dialogs->setReadyLight(2); + +	fadeIn(); +	_parser->_cursorState = false; +	_parser->cursorOn(); +	_animation->_sprites[0]->_speedX = kWalk; +	_animation->updateSpeed(); + +	_menu->init(); + +	int16 loadSlot = ConfMan.instance().getInt("save_slot"); +	if (loadSlot >= 0) { +		_thinks = 2; // You always have money. +		thinkAbout(kObjectMoney, kThing); + +		loadGame(loadSlot); +	} else { +		newGame(); + +		_soundFx = !_soundFx; +		fxToggle(); +		thinkAbout(kObjectMoney, kThing); + +		_dialogs->displayScrollChain('Q', 83); // Info on the game, etc. +	} +} + +void AvalancheEngine::runAvalot() { +	setup(); + +	do { +		uint32 beginLoop = _system->getMillis(); + +		updateEvents(); // The event handler. + +		_clock->update(); +		_menu->update(); +		_background->update(); +		_animation->animLink(); +		checkClick(); +		_timer->updateTimer(); + +		_graphics->drawDebugLines(); +		_graphics->refreshScreen(); + +		uint32 delay = _system->getMillis() - beginLoop; +		if (delay <= 55) +			_system->delayMillis(55 - delay); // Replaces slowdown(); 55 comes from 18.2 Hz (B Flight). +	} while (!_letMeOut && !shouldQuit()); + +	warning("STUB: run()"); + +	_closing->exitGame(); +} + +void AvalancheEngine::init() { +	for (int i = 0; i < 31; i++) { +		for (int j = 0; j < 2; j++) +			_also[i][j] = nullptr; +	} + +#if 0 +	if (_vm->_enhanced->atbios) +		atkey = "f1"; +	else +		atkey = "alt-"; +#endif + +	_letMeOut = false; +	_currentMouse = 177; +	_dropsOk = true; +	_mouseText = ""; +	_cheat = false; +	_cp = 0; +	_ledStatus = 177; +	for (int i = 0; i < 3; i++) +		_scoreToDisplay[i] = -1; // Impossible digits. +	_holdTheDawn = false; + +	_graphics->loadMouse(kCurWait); +	CursorMan.showMouse(true); +} + +/** + * Call a given Verb + * @remarks	Originally called 'callverb' + */ +void AvalancheEngine::callVerb(VerbCode id) { +	if (id == _parser->kPardon) { +		Common::String tmpStr = Common::String::format("The f5 key lets you do a particular action in certain " \ +			"situations. However, at the moment there is nothing assigned to it. You may press alt-A to see " \ +			"what the current setting of this key is."); +		_dialogs->displayText(tmpStr); +	} else +		_parser->doVerb(id); +} + +/** + * Check is it's possible to give something to Spludwick + * @remarks	Originally called 'nextstring' + */ +Common::String AvalancheEngine::readAlsoStringFromFile(Common::File &file) { +	Common::String str; +	byte length = file.readByte(); +	for (int i = 0; i < length; i++) +		str += file.readByte(); +	return str; +} + +void AvalancheEngine::scram(Common::String &str) { +	for (uint i = 0; i < str.size(); i++) +		str.setChar(str[i] ^ 177, i); +} + +void AvalancheEngine::unScramble() { +	for (int i = 0; i < 31; i++) { +		for (int j = 0; j < 2; j++) { +			if (_also[i][j] != nullptr) +				scram(*_also[i][j]); +		} +	} +	scram(_listen); +	scram(_flags); +} + +void AvalancheEngine::loadAlso(byte num) { +	for (int i = 0; i < 31; i++) { +		for (int j = 0; j < 2; j++) { +			if (_also[i][j] != nullptr)  { +				delete _also[i][j]; +				_also[i][j] = nullptr; +			} +		} +	} +	Common::String filename; +	filename = Common::String::format("also%d.avd", num); +	Common::File file; +	if (!file.open(filename)) +		error("AVALANCHE: File not found: %s", filename.c_str()); + +	file.seek(128); + +	byte alsoNum = file.readByte(); +	Common::String tmpStr; +	for (int i = 0; i <= alsoNum; i++) { +		for (int j = 0; j < 2; j++) { +			_also[i][j] = new Common::String; +			*_also[i][j] = readAlsoStringFromFile(file); +		} +		tmpStr = Common::String::format("\x9D%s\x9D", _also[i][0]->c_str()); +		*_also[i][0] = tmpStr; +	} + +	memset(_lines, 0xFF, sizeof(_lines)); + +	_lineNum = file.readByte(); +	for (int i = 0; i < _lineNum; i++) { +		LineType *curLine = &_lines[i]; +		curLine->_x1 = file.readSint16LE(); +		curLine->_y1 = file.readSint16LE(); +		curLine->_x2 = file.readSint16LE(); +		curLine->_y2 = file.readSint16LE(); +		curLine->_color = (Color)file.readByte(); +	} + +	memset(_peds, 177, sizeof(_peds)); +	byte pedNum = file.readByte(); +	for (int i = 0; i < pedNum; i++) { +		PedType *curPed = &_peds[i]; +		curPed->_x = file.readSint16LE(); +		curPed->_y = file.readSint16LE(); +		curPed->_direction = (Direction)file.readByte(); +	} + +	_fieldNum = file.readByte(); +	for (int i = 0; i < _fieldNum; i++) { +		FieldType *curField = &_fields[i]; +		curField->_x1 = file.readSint16LE(); +		curField->_y1 = file.readSint16LE(); +		curField->_x2 = file.readSint16LE(); +		curField->_y2 = file.readSint16LE(); +	} + +	for (int i = 0; i < 15; i++) { +		MagicType *magic = &_magics[i]; +		magic->_operation = file.readByte(); +		magic->_data = file.readUint16LE(); +	} + +	for (int i = 0; i < 7; i++) { +		MagicType *portal = &_portals[i]; +		portal->_operation = file.readByte(); +		portal->_data = file.readUint16LE(); +	} + +	_flags.clear(); +	for (int i = 0;  i < 26; i++) +		_flags += file.readByte(); + +	int16 size = file.readByte(); +	_listen.clear(); +	for (int i = 0; i < size; i++) +		_listen += file.readByte(); + +	_graphics->clearAlso(); + +	CursorMan.showMouse(false); +	for (int i = 0; i < _lineNum; i++) { +		// We had to check if the lines are within the borders of the screen. +		if ((_lines[i]._x1 >= 0) && (_lines[i]._x1 < kScreenWidth) && (_lines[i]._y1 >= 0) && (_lines[i]._y1 < kScreenHeight) +			&& (_lines[i]._x2 >= 0) && (_lines[i]._x2 < kScreenWidth) && (_lines[i]._y2 >= 0) && (_lines[i]._y2 < kScreenHeight)) +			_graphics->setAlsoLine(_lines[i]._x1, _lines[i]._y1, _lines[i]._x2, _lines[i]._y2, _lines[i]._color); +	} +	CursorMan.showMouse(true); + +	file.close(); + +	unScramble(); +	for (int i = 0; i <= alsoNum; i++) { +		tmpStr = Common::String::format(",%s,", _also[i][0]->c_str()); +		*_also[i][0] = tmpStr; +	} +} + +void AvalancheEngine::loadRoom(byte num) { +	CursorMan.showMouse(false); + +	Common::String filename = Common::String::format("place%d.avd", num); +	Common::File file; +	if (!file.open(filename)) +		error("AVALANCHE: File not found: %s", filename.c_str()); + +	file.seek(146); +	if (!_roomnName.empty()) +		_roomnName.clear(); +	for (int i = 0; i < 30; i++) { +		char actChar = file.readByte(); +		if ((32 <= actChar) && (actChar <= 126)) +			_roomnName += actChar; +	} +	// Compression method byte follows this... + +	file.seek(177); + +	_graphics->loadBackground(file); +	_graphics->refreshBackground(); + +	file.close(); + +	loadAlso(num); +	_background->load(num); +	CursorMan.showMouse(true); +} + +void AvalancheEngine::findPeople(byte room) { +	for (int i = 1; i < 29; i++) { +		if (_whereIs[i] == room) { +			if (i < 25) +				_him = (People)(150 + i); +			else +				_her = (People)(150 + i); +		} +	} +} + +void AvalancheEngine::exitRoom(byte x) { +	_sound->stopSound(); +	_background->release(); +	_seeScroll = true;  // This stops the trippancy system working over the length of this procedure. + +	switch (x) { +	case kRoomSpludwicks: +		_timer->loseTimer(Timer::kReasonAvariciusTalks); +		 _avariciusTalk = 0; +		// He doesn't HAVE to be talking for this to work. It just deletes it IF it exists. +		break; +	case kRoomBridge: +		if (_drawbridgeOpen > 0) { +			_drawbridgeOpen = 4; // Fully open. +			_timer->loseTimer(Timer::kReasonDrawbridgeFalls); +		} +		break; +	case kRoomOutsideCardiffCastle: +		_timer->loseTimer(Timer::kReasonCardiffsurvey); +		break; +	case kRoomRobins: +		_timer->loseTimer(Timer::kReasonGettingTiedUp); +		break; +	} + +	_interrogation = 0; // Leaving the room cancels all the questions automatically. +	_seeScroll = false; // Now it can work again! + +	_lastRoom = _room; +	if (_room != kRoomMap) +		_lastRoomNotMap = _room; +} + +/** + * Only when entering a NEW town! Not returning to the last one, + * but choosing another from the map. + * @remarks	Originally called 'new_town' + */ +void AvalancheEngine::enterNewTown() { +	_menu->setup(); + +	switch (_room) { +	case kRoomOutsideNottsPub: // Entry into Nottingham. +		if ((_roomCount[kRoomRobins] > 0) && (_beenTiedUp) && (!_takenMushroom)) +			_mushroomGrowing = true; +		break; +	case kRoomWiseWomans: // Entry into Argent. +		if (_talkedToCrapulus && (!_lustieIsAsleep)) { +			_spludwickAtHome = !((_roomCount[kRoomWiseWomans] % 3) == 1); +			_crapulusWillTell = !_spludwickAtHome; +		} else { +			_spludwickAtHome = true; +			_crapulusWillTell = false; +		} +		if (_boxContent == kObjectWine) +			_wineState = 3; // Vinegar +		break; +	default: +		break; +	} + +	if ((_room != kRoomOutsideDucks) && (_objects[kObjectOnion - 1]) && !(_onionInVinegar)) +		_rottenOnion = true; // You're holding the onion +} + +void AvalancheEngine::putGeidaAt(byte whichPed, byte ped) { +	if (ped == 0) +		return; +	AnimationType *spr1 = _animation->_sprites[1]; + +	spr1->init(5, false); // load Geida +	_animation->appearPed(1, whichPed); +	spr1->_callEachStepFl = true; +	spr1->_eachStepProc = Animation::kProcGeida; +} + +void AvalancheEngine::enterRoom(Room roomId, byte ped) { +	_seeScroll = true;  // This stops the trippancy system working over the length of this procedure. + +	findPeople(roomId); +	_room = roomId; +	if (ped != 0) +		_roomCount[roomId]++; + +	loadRoom(roomId); + +	if ((_roomCount[roomId] == 0) && (!getFlag('S'))) +		incScore(1); + +	_whereIs[kPeopleAvalot - 150] = _room; + +	if (_geidaFollows) +		_whereIs[kPeopleGeida - 150] = roomId; + +	_roomCycles = 0; + +	if ((_lastRoom == kRoomMap) && (_lastRoomNotMap != _room)) +		enterNewTown(); + +	_animation->updateSpeed(); + +	switch (roomId) { +	case kRoomYours: +		if (_avvyInBed) { +			_background->draw(-1, -1, 2); +			_graphics->refreshBackground(); +			_timer->addTimer(100, Timer::kProcArkataShouts, Timer::kReasonArkataShouts); +		} +		break; + +	case kRoomOutsideYours: +		if (ped > 0) { +			AnimationType *spr1 = _animation->_sprites[1]; +			if (!_talkedToCrapulus) { +				_whereIs[kPeopleCrapulus - 150] = kRoomOutsideYours; +				spr1->init(8, false); // load Crapulus + +				if (_roomCount[kRoomOutsideYours] == 1) { +					_animation->appearPed(1, 3); // Start on the right-hand side of the screen. +					spr1->walkTo(4); // Walks up to greet you. +				} else { +					_animation->appearPed(1, 4); // Starts where he was before. +					spr1->_facingDir = kDirLeft; +				} + +				spr1->_callEachStepFl = true; +				spr1->_eachStepProc = Animation::kProcFaceAvvy; // He always faces Avvy. + +			} else +				_whereIs[kPeopleCrapulus - 150] = kRoomNowhere; + +			if (_crapulusWillTell) { +				spr1->init(8, false); +				_animation->appearPed(1, 1); +				spr1->walkTo(3); +				_timer->addTimer(20, Timer::kProcCrapulusSpludOut, Timer::kReasonCrapulusSaysSpludwickOut); +				_crapulusWillTell = false; +			} +		} +		break; + +	case kRoomOutsideSpludwicks: +		if ((_roomCount[kRoomOutsideSpludwicks] == 1) && (ped == 1)) { +			_timer->addTimer(20, Timer::kProcBang, Timer::kReasonExplosion); +			_spludwickAtHome = true; +		} +		break; + +	case kRoomSpludwicks: +		if (_spludwickAtHome) { +			AnimationType *spr1 = _animation->_sprites[1]; +			if (ped > 0) { +				spr1->init(2, false); // load Spludwick +				_animation->appearPed(1, 1); +				_whereIs[kPeopleSpludwick - 150] = kRoomSpludwicks; +			} + +			spr1->_callEachStepFl = true; +			spr1->_eachStepProc = Animation::kProcGeida; +		} else +			_whereIs[kPeopleSpludwick - 150] = kRoomNowhere; +		break; + +	case kRoomBrummieRoad: +		if (_geidaFollows) +			putGeidaAt(4, ped); +		if (_cwytalotGone) { +			_magics[kColorLightred - 1]._operation = kMagicNothing; +			_whereIs[kPeopleCwytalot - 150] = kRoomNowhere; +		} else if (ped > 0) { +			AnimationType *spr1 = _animation->_sprites[1]; +			spr1->init(4, false); // 4 = Cwytalot +			spr1->_callEachStepFl = true; +			spr1->_eachStepProc = Animation::kProcFollowAvvyY; +			_whereIs[kPeopleCwytalot - 150] = kRoomBrummieRoad; + +			if (_roomCount[kRoomBrummieRoad] == 1) { // First time here... +				_animation->appearPed(1, 1); // He appears on the right of the screen... +				spr1->walkTo(3); // ...and he walks up... +			} else { +				// You've been here before. +				_animation->appearPed(1, 3); // He's standing in your way straight away... +				spr1->_facingDir = kDirLeft; +			} +		} +		break; + +	case kRoomArgentRoad: +		if ((_cwytalotGone) && (!_passedCwytalotInHerts) && (ped == 2) && (_roomCount[kRoomArgentRoad] > 3)) { +			AnimationType *spr1 = _animation->_sprites[1]; +			spr1->init(4, false); // 4 = Cwytalot again +			_animation->appearPed(1, 0); +			spr1->walkTo(1); +			spr1->_vanishIfStill = true; +			_passedCwytalotInHerts = true; +			// whereis[#157] = r__Nowhere; // can we fit this in? +			_timer->addTimer(20, Timer::kProcCwytalotInHerts, Timer::kReasonCwytalotInHerts); +		} +		break; + +	case kRoomBridge: +		if (_drawbridgeOpen == 4) { // open +			_background->draw(-1, -1, 2); // Position of drawbridge +			_graphics->refreshBackground(); +			_magics[kColorGreen - 1]._operation = kMagicNothing; // You may enter the drawbridge. +		} +		if (_geidaFollows) +			putGeidaAt(ped + 2, ped); // load Geida +		break; + +	case kRoomRobins: +		if ((ped > 0) && (!_beenTiedUp)) { +			// A welcome party... or maybe not... +			AnimationType *spr1 = _animation->_sprites[1]; +			spr1->init(6, false); +			_animation->appearPed(1, 1); +			spr1->walkTo(2); +			_timer->addTimer(36, Timer::kProcGetTiedUp, Timer::kReasonGettingTiedUp); +		} + +		if (_beenTiedUp) { +			_whereIs[kPeopleRobinHood - 150] = kRoomNowhere; +			_whereIs[kPeopleFriarTuck - 150] = kRoomNowhere; +		} + +		if (_tiedUp) +			_background->draw(-1, -1, 1); + +		if (!_mushroomGrowing) +			_background->draw(-1, -1, 2); +		_graphics->refreshBackground(); +		break; + +	case kRoomOutsideCardiffCastle: +		if (ped > 0) { +			AnimationType *spr1 = _animation->_sprites[1]; +			switch (_cardiffQuestionNum) { +			case 0 : // You've answered NONE of his questions. +				spr1->init(9, false); +				_animation->appearPed(1, 1); +				spr1->walkTo(2); +				_timer->addTimer(47, Timer::kProcCardiffSurvey, Timer::kReasonCardiffsurvey); +				break; +			case 5 : +				_magics[1]._operation = kMagicNothing; +				break; // You've answered ALL his questions. => nothing happens. +			default: // You've answered SOME of his questions. +				spr1->init(9, false); +				_animation->appearPed(1, 2); +				spr1->_facingDir = kDirRight; +				_timer->addTimer(3, Timer::kProcCardiffReturn, Timer::kReasonCardiffsurvey); +			} +		} + +		if (_cardiffQuestionNum < 5) +			_interrogation = _cardiffQuestionNum; +		else +			_interrogation = 0; +		break; + +	case kRoomMap: +		// You're entering the map. +		fadeIn(); +		if (ped > 0) +			_graphics->zoomOut(_peds[ped - 1]._x, _peds[ped - 1]._y); + +		if ((_objects[kObjectWine - 1]) && (_wineState != 3)) { +			_dialogs->displayScrollChain('Q', 9); // Don't want to waste the wine! +			_objects[kObjectWine - 1] = false; +			refreshObjectList(); +		} + +		_dialogs->displayScrollChain('Q', 69); +		break; + +	case kRoomCatacombs: +		if ((ped == 0) || (ped == 3) || (ped == 5) || (ped == 6)) { + +			switch (ped) { +			case 3: // Enter from oubliette +				_catacombX = 8; +				_catacombY = 4; +				break; +			case 5: // Enter from du Lustie's +				_catacombX = 8; +				_catacombY = 7; +				break; +			case 6: // Enter from Geida's +				_catacombX = 4; +				_catacombY = 1; +				break; +			} + +			_enterCatacombsFromLustiesRoom = true; +			_animation->catacombMove(ped); +			_enterCatacombsFromLustiesRoom = false; +		} +		break; + +	case kRoomArgentPub: +		if (_wonNim) +			_background->draw(-1, -1, 0);   // No lute by the settle. +		_malagauche = 0; // Ready to boot Malagauche +		if (_givenBadgeToIby) { +			_background->draw(-1, -1, 7); +			_background->draw(-1, -1, 8); +		} +		_graphics->refreshBackground(); +		break; + +	case kRoomLustiesRoom: +		_npcFacing = 1; // du Lustie. +		if (_animation->getAvvyClothes() == 0) // Avvy in his normal clothes +			_timer->addTimer(3, Timer::kProcCallsGuards, Timer::kReasonDuLustieTalks); +		else if (!_enteredLustiesRoomAsMonk) // already +			// Presumably, Avvy dressed as a monk. +			_timer->addTimer(3, Timer::kProcGreetsMonk, Timer::kReasonDuLustieTalks); + +		if (_geidaFollows) { +			putGeidaAt(4, ped); +			if (_lustieIsAsleep) { +				_background->draw(-1, -1, 4); +				_graphics->refreshBackground(); +			} +		} +		break; + +	case kRoomMusicRoom: +		if (_jacquesState > 0) { +			_jacquesState = 5; +			_background->draw(-1, -1, 1); +			_graphics->refreshBackground(); +			_background->draw(-1, -1, 3); +			_magics[kColorBrown - 1]._operation = kMagicNothing; +			_whereIs[kPeopleJacques - 150] = kRoomNowhere; +		} +		if (ped != 0) { +			_background->draw(-1, -1, 5); +			_graphics->refreshBackground(); +			_sequence->startMusicRoomSeq(); +		} +		break; + +	case kRoomOutsideNottsPub: +		if (ped == 2) { +			_background->draw(-1, -1, 2); +			_graphics->refreshBackground(); +			_sequence->startDuckSeq(); +		} +		break; + +	case kRoomOutsideArgentPub: +		if (ped == 2)  { +			_background->draw(-1, -1, 5); +			_graphics->refreshBackground(); +			_sequence->startMusicRoomSeq(); +		} +		break; + +	case kRoomWiseWomans: { +		AnimationType *spr1 = _animation->_sprites[1]; +		spr1->init(11, false); +		if ((_roomCount[kRoomWiseWomans] == 1) && (ped > 0)) { +			_animation->appearPed(1, 1); // Start on the right-hand side of the screen. +			spr1->walkTo(3); // Walks up to greet you. +		} else { +			_animation->appearPed(1, 3); // Starts where she was before. +			spr1->_facingDir = kDirLeft; +		} + +		spr1->_callEachStepFl = true; +		spr1->_eachStepProc = Animation::kProcFaceAvvy; // She always faces Avvy. +		} +		break; + +	case kRoomInsideCardiffCastle: +		if (ped > 0) { +			_animation->_sprites[1]->init(10, false); // Define the dart. +			_background->draw(-1, -1, 0); +			_graphics->refreshBackground(); +			_sequence->startCardiffSeq2(); +		} else { +			_background->draw(-1, -1, 0); +			if (_arrowInTheDoor) +				_background->draw(-1, -1, 2); +			else +				_background->draw(-1, -1, 1); +			_graphics->refreshBackground(); +		} +		break; + +	case kRoomAvvysGarden: +		if (ped == 1)  { +			_background->draw(-1, -1, 1); +			_graphics->refreshBackground(); +			_sequence->startGardenSeq(); +		} +		break; + +	case kRoomEntranceHall: +	case kRoomInsideAbbey: +	case kRoomYourHall: +		if (ped == 2)  { +#if 0 +			// It was the original: +			_celer->show_one(-1, -1, 2); +			_sequence->first_show(1); +			_sequence->then_show(3); +			_sequence->start_to_close(); +#endif + +			_background->draw(-1, -1, 1); +			_graphics->refreshBackground(); +			_sequence->startGardenSeq(); +		} +		break; + +	case kRoomAylesOffice: +		if (_aylesIsAwake) +			_background->draw(-1, -1, 1); +		_graphics->refreshBackground(); +		break; // Ayles awake. + +	case kRoomGeidas: +		putGeidaAt(1, ped); +		break; // load Geida + +	case kRoomEastHall: +	case kRoomWestHall: +		if (_geidaFollows) +			putGeidaAt(ped + 1, ped); +		break; + +	case kRoomLusties: +		if (_geidaFollows) +			putGeidaAt(ped + 5, ped); +		break; + +	case kRoomNottsPub: +		if (_sittingInPub) +			_background->draw(-1, -1, 2); +		_npcFacing = 1; // Port. +		break; + +	case kRoomOutsideDucks: +		if (ped == 2) { +			// Shut the door +			_background->draw(-1, -1, 2); +			_graphics->refreshBackground(); +			_sequence->startDuckSeq(); +		} +		break; + +	case kRoomDucks: +		_npcFacing = 1; // Duck. +		break; + +	default: +		break; +	} + +	_seeScroll = false; // Now it can work again! +} + +void AvalancheEngine::thinkAbout(byte object, bool type) { +	_thinks = object; +	object--; + +	Common::String filename; +	if (type == kThing) { +		filename = "thinks.avd"; +	} else { // kPerson +		filename = "folk.avd"; + +		object -= 149; +		if (object >= 25) +			object -= 8; +		if (object == 20) +			object--; // Last time... +	} + +	_graphics->loadMouse(kCurWait); +	CursorMan.showMouse(false); +	_graphics->drawThinkPic(filename, object); +	CursorMan.showMouse(true); + +	_thinkThing = type; +} + +void AvalancheEngine::drawToolbar() { +	_graphics->drawToolbar(); +	_animation->setOldDirection(kDirNone); +	drawDirection(); +} + +void AvalancheEngine::drawScore() { +	uint16 score = _dnascore; +	int8 numbers[3] = {0, 0, 0}; +	for (int i = 0; i < 2; i++) { +		byte divisor = 1; +		for (int j = 0; j < (2 - i); j++) +			divisor *= 10; +		numbers[i] = score / divisor; +		score -= numbers[i] * divisor; +	} +	numbers[2] = score; + +	CursorMan.showMouse(false); + +	for (int i = 0; i < 3; i++) { +		if (_scoreToDisplay[i] != numbers[i]) +			_graphics->drawDigit(numbers[i], 250 + (i + 1) * 15, 177); +	} + +	CursorMan.showMouse(true); + +	for (int i = 0; i < 3; i++) +		_scoreToDisplay[i] = numbers[i]; +} + +void AvalancheEngine::incScore(byte num) { +	for (int i = 1; i <= num; i++) { +		_dnascore++; + +		if (_soundFx) { +			for (int j = 1; j <= 97; j++) +				// Length os 2 is a guess, the original doesn't have a delay specified +				_sound->playNote(177 + _dnascore * 3, 2); +		} +	} +	warning("STUB: points()"); + +	drawScore(); +} + +void AvalancheEngine::useCompass(const Common::Point &cursorPos) { +	byte color = _graphics->getScreenColor(cursorPos); + +	switch (color) { +	case kColorGreen: +		_animation->setDirection(kDirUp); +		_animation->setMoveSpeed(0, kDirUp); +		drawDirection(); +		break; +	case kColorBrown: +		_animation->setDirection(kDirDown); +		_animation->setMoveSpeed(0, kDirDown); +		drawDirection(); +		break; +	case kColorCyan: +		_animation->setDirection(kDirLeft); +		_animation->setMoveSpeed(0, kDirLeft); +		drawDirection(); +		break; +	case kColorLightmagenta: +		_animation->setDirection(kDirRight); +		_animation->setMoveSpeed(0, kDirRight); +		drawDirection(); +		break; +	case kColorRed: +	case kColorWhite: +	case kColorLightcyan: +	case kColorYellow: // Fall-throughs are intended. +		_animation->stopWalking(); +		drawDirection(); +		break; +	} +} + +void AvalancheEngine::fxToggle() { +	warning("STUB: fxtoggle()"); +} + +void AvalancheEngine::refreshObjectList() { +	_carryNum = 0; +	if (_thinkThing && !_objects[_thinks - 1]) +		thinkAbout(kObjectMoney, kThing); // you always have money + +	for (int i = 0; i < kObjectNum; i++) { +		if (_objects[i]) { +			_objectList[_carryNum] = i + 1; +			_carryNum++; +		} +	} +} + +/** + * @remarks	Originally called 'verte' + */ +void AvalancheEngine::guideAvvy(Common::Point cursorPos) { +	if (!_userMovesAvvy) +		return; + +	cursorPos.y /= 2; +	byte what; + +	// _animation->tr[0] is Avalot.) +	AnimationType *avvy = _animation->_sprites[0]; +	if (cursorPos.x < avvy->_x) +		what = 1; +	else if (cursorPos.x > (avvy->_x + avvy->_xLength)) +		what = 2; +	else +		what = 0; // On top + +	if (cursorPos.y < avvy->_y) +		what += 3; +	else if (cursorPos.y > (avvy->_y + avvy->_yLength)) +		what += 6; + +	switch (what) { +	case 0: +		_animation->stopWalking(); +		break; // Clicked on Avvy: no movement. +	case 1: +		_animation->setMoveSpeed(0, kDirLeft); +		break; +	case 2: +		_animation->setMoveSpeed(0, kDirRight); +		break; +	case 3: +		_animation->setMoveSpeed(0, kDirUp); +		break; +	case 4: +		_animation->setMoveSpeed(0, kDirUpLeft); +		break; +	case 5: +		_animation->setMoveSpeed(0, kDirUpRight); +		break; +	case 6: +		_animation->setMoveSpeed(0, kDirDown); +		break; +	case 7: +		_animation->setMoveSpeed(0, kDirDownLeft); +		break; +	case 8: +		_animation->setMoveSpeed(0, kDirDownRight); +		break; +	}    // No other values are possible. + +	drawDirection(); +} + +void AvalancheEngine::checkClick() { +	Common::Point cursorPos = getMousePos(); + +	/*if (mrelease > 0) +		after_the_scroll = false;*/ + +	if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) +		_graphics->loadMouse(kCurUpArrow); // up arrow +	else if ((317 <= cursorPos.y) && (cursorPos.y <= 339)) +		_graphics->loadMouse(kCurIBeam); //I-beam +	else if ((340 <= cursorPos.y) && (cursorPos.y <= 399)) +		_graphics->loadMouse(kCurScrewDriver); // screwdriver +	else if (!_menu->isActive()) { // Dropdown can handle its own pointers. +		if (_holdLeftMouse) { +			_graphics->loadMouse(kCurCrosshair); // Mark's crosshairs +			guideAvvy(cursorPos); // Normally, if you click on the picture, you're guiding Avvy around. +		} else +			_graphics->loadMouse(kCurFletch); // fletch +	} + +	if (_holdLeftMouse) { +		if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) { // Click on the dropdown menu. +			if (_dropsOk) +				_menu->update(); +		} else if ((317 <= cursorPos.y) && (cursorPos.y <= 339)) { // Click on the command line. +			_parser->_inputTextPos = (cursorPos.x - 23) / 8; +			if (_parser->_inputTextPos > _parser->_inputText.size() + 1) +				_parser->_inputTextPos = _parser->_inputText.size() + 1; +			if (_parser->_inputTextPos < 1) +				_parser->_inputTextPos = 1; +			_parser->_inputTextPos--; +			_parser->plotText(); +		} else if ((340 <= cursorPos.y) && (cursorPos.y <= 399)) { // Check the toolbar. +			if ((137 <= cursorPos.x) && (cursorPos.x <= 207)) { // Control Avvy with the compass. +				if (_alive && _avvyIsAwake) +					useCompass(cursorPos); +			} else if ((208 <= cursorPos.x) && (cursorPos.x <= 260)) { // Examine the _thing. +				do { +					updateEvents(); +				} while (_holdLeftMouse); + +				if (_thinkThing) { +					_parser->_thing = _thinks; +					_parser->_thing += 49; +					_parser->_person = kPeoplePardon; +				} else { +					_parser->_person = (People)_thinks; +					_parser->_thing = _parser->kPardon; +				} +				callVerb(kVerbCodeExam); +			} else if ((261 <= cursorPos.x) && (cursorPos.x <= 319)) { // Display the score. +				do { +					updateEvents(); +				} while (_holdLeftMouse); + +				callVerb(kVerbCodeScore); +			} else if ((320 <= cursorPos.x) && (cursorPos.x <= 357)) { // Change speed. +				_animation->_sprites[0]->_speedX = kWalk; +				_animation->updateSpeed(); +			} else if ((358 <= cursorPos.x) && (cursorPos.x <= 395)) { // Change speed. +				_animation->_sprites[0]->_speedX = kRun; +				_animation->updateSpeed(); +			} else if ((396 <= cursorPos.x) && (cursorPos.x <= 483)) +				fxToggle(); +			else if ((535 <= cursorPos.x) && (cursorPos.x <= 640)) +				_mouseText.insertChar(kControlNewLine, 0); +		} else if (!_dropsOk) +			_mouseText = Common::String(13) + _mouseText; +	} +} + +void AvalancheEngine::errorLed() { +	warning("STUB: errorled()"); +} + +/** + * Displays a fade out, full screen. + * This version is different to the one in the original, which was fading in 3 steps. + * @remarks	Originally called 'dusk' + */ +void AvalancheEngine::fadeOut() { +	byte pal[3], tmpPal[3]; + +	_graphics->setBackgroundColor(kColorBlack); +	if (_fxHidden) +		return; +	_fxHidden = true; + +	for (int i = 0; i < 16; i++) { +		for (int j = 0; j < 16; j++) { +			g_system->getPaletteManager()->grabPalette((byte *)tmpPal, j, 1); +			_fxPal[i][j][0] = tmpPal[0]; +			_fxPal[i][j][1] = tmpPal[1]; +			_fxPal[i][j][2] = tmpPal[2]; +			if (tmpPal[0] >= 16) +				pal[0] = tmpPal[0] - 16; +			else +				pal[0] = 0; + +			if (tmpPal[1] >= 16) +				pal[1] = tmpPal[1] - 16; +			else +				pal[1] = 0; + +			if (tmpPal[2] >= 16) +				pal[2] = tmpPal[2] - 16; +			else +				pal[2] = 0; + +			g_system->getPaletteManager()->setPalette(pal, j, 1); +		} +		_system->delayMillis(10); +		_graphics->refreshScreen(); +	} +} + +/** + * Displays a fade in, full screen. + * This version is different to the one in the original, which was fading in 3 steps. + * @remarks	Originally called 'dawn' + */ +void AvalancheEngine::fadeIn() { +	if (_holdTheDawn || !_fxHidden) +		return; + +	_fxHidden = false; + +	byte pal[3]; +	for (int i = 15; i >= 0; i--) { +		for (int j = 0; j < 16; j++) { +			pal[0] = _fxPal[i][j][0]; +			pal[1] = _fxPal[i][j][1]; +			pal[2] = _fxPal[i][j][2]; +			g_system->getPaletteManager()->setPalette(pal, j, 1); +		} +		_system->delayMillis(10); +		_graphics->refreshScreen(); +	} + +	if ((_room == kRoomYours) && _avvyInBed && _teetotal) +		_graphics->setBackgroundColor(kColorYellow); +} + +void AvalancheEngine::drawDirection() { // It's data is loaded in load_digits(). +	if (_animation->getOldDirection() == _animation->getDirection()) +		return; + +	_animation->setOldDirection(_animation->getDirection()); + +	CursorMan.showMouse(false); +	_graphics->drawDirection(_animation->getDirection(), 0, 161); +	CursorMan.showMouse(true); +} + +void AvalancheEngine::gameOver() { +	_userMovesAvvy = false; + +	AnimationType *avvy = _animation->_sprites[0]; +	int16 sx = avvy->_x; +	int16 sy = avvy->_y; + +	avvy->remove(); +	avvy->init(12, true); // 12 = Avalot falls +	avvy->_stepNum = 0; +	avvy->appear(sx, sy, kDirUp); + +	_timer->addTimer(3, Timer::kProcAvalotFalls, Timer::kReasonFallingOver); +	_alive = false; +} + +void AvalancheEngine::minorRedraw() { +	fadeOut(); + +	enterRoom(_room, 0); // Ped unknown or non-existant. + +	for (int i = 0; i < 3; i++) +		_scoreToDisplay[i] = -1; // impossible digits +	drawScore(); + +	fadeIn(); +} + +void AvalancheEngine::majorRedraw() { +	warning("STUB: major_redraw()"); +} + +uint16 AvalancheEngine::bearing(byte whichPed) { +	AnimationType *avvy = _animation->_sprites[0]; +	PedType *curPed = &_peds[whichPed]; + +	if (avvy->_x == curPed->_x) +		return 0; + +	int16 deltaX = avvy->_x - curPed->_x; +	int16 deltaY = avvy->_y - curPed->_y; +	uint16 result = (uint16)(atan((float)(deltaY / deltaX)) * 180 / M_PI); +	if (avvy->_x < curPed->_x) { +		return result + 90; +	} else { +		return result + 270; +	} +} + +/** + * @remarks	Originally called 'sprite_run' + */ +void AvalancheEngine::spriteRun() { +	_doingSpriteRun = true; +	_animation->animLink(); +	_doingSpriteRun = false; +} + +// CHECKME: Unused function +void AvalancheEngine::fixFlashers() { +	_ledStatus = 177; +	_animation->setOldDirection(kDirNone); +	_dialogs->setReadyLight(2); +	drawDirection(); +} + +Common::String AvalancheEngine::intToStr(int32 num) { +	return Common::String::format("%d", num); +} + +void AvalancheEngine::resetVariables() { +	_animation->setDirection(kDirUp); +	_carryNum = 0; +	for (int i = 0; i < kObjectNum; i++) +		_objects[i] = false; + +	_dnascore = 0; +	_money = 0; +	_room = kRoomNowhere; +	_saveNum = 0; +	for (int i = 0; i < 100; i++) +		_roomCount[i] = 0; + +	_wonNim = false; +	_wineState = 0; +	_cwytalotGone = false; +	_passwordNum = 0; +	_aylesIsAwake = false; +	_drawbridgeOpen = 0; +	_avariciusTalk = 0; +	_rottenOnion = false; +	_onionInVinegar = false; +	_givenToSpludwick = 0; +	_brummieStairs = 0; +	_cardiffQuestionNum = 0; +	_passedCwytalotInHerts = false; +	_avvyIsAwake = false; +	_avvyInBed = false; +	_userMovesAvvy = false; +	_npcFacing = 0; +	_givenBadgeToIby = false; +	_friarWillTieYouUp = false; +	_tiedUp = false; +	_boxContent = 0; +	_talkedToCrapulus = false; +	_jacquesState = 0; +	_bellsAreRinging = false; +	_standingOnDais = false; +	_takenPen = false; +	_arrowInTheDoor = false; +	_favoriteDrink = ""; +	_favoriteSong = ""; +	_worstPlaceOnEarth = ""; +	_spareEvening = ""; +	_totalTime = 0; +	_jumpStatus = 0; +	_mushroomGrowing = false; +	_spludwickAtHome = false; +	_lastRoom = kRoomDummy; +	_lastRoomNotMap = kRoomDummy; +	_crapulusWillTell = false; +	_enterCatacombsFromLustiesRoom = false; +	_teetotal = false; +	_malagauche = 0; +	_drinking = 0; +	_enteredLustiesRoomAsMonk = false; +	_catacombX = 0; +	_catacombY = 0; +	_avvysInTheCupboard = false; +	_geidaFollows = false; +	_givenPotionToGeida = false; +	_lustieIsAsleep = false; +	_beenTiedUp = false; +	_sittingInPub = false; +	_spurgeTalkCount = 0; +	_metAvaroid = false; +	_takenMushroom = false; +	_givenPenToAyles = false; +	_askedDogfoodAboutNim = false; +	_startTime = getTimeInSeconds(); + +	_parser->resetVariables(); +	_nim->resetVariables(); +	_animation->resetVariables(); +	_sequence->resetVariables(); +	_background->resetVariables(); +	_menu->resetVariables(); +	_timer->resetVariables(); +} + +void AvalancheEngine::newGame() { +	for (int i = 0; i < kMaxSprites; i++) { +		AnimationType *spr = _animation->_sprites[i]; +		if (spr->_quick) +			spr->remove(); +	} +	// Deallocate sprite. Sorry, beta testers! + +	AnimationType *avvy = _animation->_sprites[0]; +	avvy->init(0, true); + +	_alive = true; +	resetVariables(); + +	_dialogs->setBubbleStateNatural(); + +	_spareEvening = "answer a questionnaire"; +	_favoriteDrink = "beer"; +	_money = 30; // 2/6 +	_animation->setDirection(kDirStopped); +	_parser->_wearing = kObjectClothes; +	_objects[kObjectMoney - 1] = true; +	_objects[kObjectBodkin - 1] = true; +	_objects[kObjectBell - 1] = true; +	_objects[kObjectClothes - 1] = true; + +	_thinkThing = true; +	_thinks = 2; +	refreshObjectList(); +	_seeScroll = false; + +	avvy->appear(300, 117, kDirRight); // Needed to initialize Avalot. +	//for (gd = 0; gd <= 30; gd++) for (gm = 0; gm <= 1; gm++) also[gd][gm] = nil; +	// fillchar(previous^,sizeof(previous^),#0); { blank out array } +	_him = kPeoplePardon; +	_her = kPeoplePardon; +	_it = Parser::kPardon; +	_passwordNum = _rnd->getRandomNumber(29) + 1; //Random(30) + 1; +	_userMovesAvvy = false; +	_doingSpriteRun = false; +	_avvyInBed = true; + +	_isLoaded = false; + +	enterRoom(kRoomYours, 1); +	avvy->_visible = false; +	drawScore(); +	_menu->setup(); +	_clock->update(); +	spriteRun(); +} + +bool AvalancheEngine::getFlag(char x) { +	for (uint16 i = 0; i < _flags.size(); i++) { +		if (_flags[i] == x) +			return true; +	} + +	return false; +} + +bool AvalancheEngine::decreaseMoney(uint16 amount) { +	_money -= amount; +	if (_money < 0) { +		_dialogs->displayScrollChain('Q', 2); // "You are now denariusless!" +		gameOver(); +		return false; +	} else +		return true; +} + +Common::String AvalancheEngine::getName(People whose) { +	static const char lads[17][20] = { +		"Avalot",     "Spludwick",  "Crapulus",  "Dr. Duck",  "Malagauche", +		"Friar Tuck", "Robin Hood", "Cwytalot",  "du Lustie", "the Duke of Cardiff", +		"Dogfood",    "A trader",   "Ibythneth", "Ayles",     "Port", +		"Spurge",     "Jacques" +	}; + +	static const char lasses[4][15] = {"Arkata", "Geida", "\0xB1", "the Wise Woman"}; + +	if (whose <= kPeopleJacques) +		return Common::String(lads[whose - kPeopleAvalot]); +	else if ((whose >= kPeopleArkata) && (whose <= kPeopleWisewoman)) +		return Common::String(lasses[whose - kPeopleArkata]); +	else +		error("getName() - Unexpected character id %d", (byte) whose); +} + +Common::String AvalancheEngine::getItem(byte which) { +	static const char items[kObjectNum][18] = { +		"some wine",       "your money-bag", "your bodkin", "a potion",          "a chastity belt", +		"a crossbow bolt", "a crossbow",     "a lute",      "a pilgrim's badge", "a mushroom", +		"a key",           "a bell",         "a scroll",    "a pen",             "some ink", +		"your clothes",    "a habit",        "an onion" +	}; + +	Common::String result; +	if (which > 150) +		which -= 149; + +	switch (which) { +	case kObjectWine: +		switch (_wineState) { +		case 0: +		case 1: +		case 4: +			result = Common::String(items[which - 1]); +			break; +		case 3: +			result = "some vinegar"; +			break; +		} +		break; +	case kObjectOnion: +		if (_rottenOnion) +			result = "a rotten onion"; +		else if (_onionInVinegar) +			result = "a pickled onion (in the vinegar)"; +		else +			result = Common::String(items[which - 1]); +		break; +	default: +		if ((which < kObjectNum) && (which > 0)) +			result = Common::String(items[which - 1]); +		else +			result = ""; +	} +	return result; +} + +Common::String AvalancheEngine::f5Does() { +	switch (_room) { +	case kRoomYours: +		if (!_avvyIsAwake) +			return Common::String::format("%cWWake up", kVerbCodeWake); +		else if (_avvyInBed) +			return Common::String::format("%cGGet up", kVerbCodeStand); +		break; +	case kRoomInsideCardiffCastle: +		if (_standingOnDais) +			return Common::String::format("%cCClimb down", kVerbCodeClimb); +		else +			return Common::String::format("%cCClimb up", kVerbCodeClimb); +		break; +	case kRoomNottsPub: +		if (_sittingInPub) +			return Common::String::format("%cSStand up", kVerbCodeStand); +		else +			return Common::String::format("%cSSit down", kVerbCodeSit); +		break; +	case kRoomMusicRoom: +		if (_animation->inField(5)) +			return Common::String::format("%cPPlay the harp", kVerbCodePlay); +		break; +	default: +		break; +	} + +	return Common::String::format("%c", kVerbCodePardon); // If all else fails... +} + +void AvalancheEngine::flipRoom(Room room, byte ped) { +	assert((ped > 0) && (ped < 15)); +	if (!_alive) { +		// You can't leave the room if you're dead. +		_animation->_sprites[0]->_moveX = 0; +		_animation->_sprites[0]->_moveY = 0; // Stop him from moving. +		return; +	} + +	if ((room == kRoomDummy) && (_room == kRoomLusties)) { +		_animation->hideInCupboard(); +		return; +	} + +	if ((_jumpStatus > 0) && (_room == kRoomInsideCardiffCastle)) { +		// You can't *jump* out of Cardiff Castle! +		_animation->_sprites[0]->_moveX = 0; +		return; +	} + +	exitRoom(_room); +	fadeOut(); + +	for (int16 i = 1; i < _animation->kSpriteNumbMax; i++) { +		if (_animation->_sprites[i]->_quick) +			_animation->_sprites[i]->remove(); +	} // Deallocate sprite + +	if (_room == kRoomLustiesRoom) +		_enterCatacombsFromLustiesRoom = true; + +	if (room > kRoomMap) +		return; + +	enterRoom(room, ped); +	_animation->appearPed(0, ped - 1); +	_enterCatacombsFromLustiesRoom = false; +	_animation->setOldDirection(_animation->getDirection()); +	_animation->setDirection(_animation->_sprites[0]->_facingDir); +	drawDirection(); + +	fadeIn(); +} + +/** + * Open the Door. + * This slides the door open. The data really ought to be saved in + * the Also file, and will be next time. However, for now, they're + * here. + * @remarks	Originally called 'open_the_door' + */ +void AvalancheEngine::openDoor(Room whither, byte ped, byte magicnum) { +	switch (_room) { +	case kRoomOutsideYours: +	case kRoomOutsideNottsPub: +	case kRoomOutsideDucks: +		_sequence->startOutsideSeq(whither, ped); +		break; +	case kRoomInsideCardiffCastle: +		_sequence->startCardiffSeq(whither, ped); +		break; +	case kRoomAvvysGarden: +	case kRoomEntranceHall: +	case kRoomInsideAbbey: +	case kRoomYourHall: +		_sequence->startHallSeq(whither, ped); +		break; +	case kRoomMusicRoom: +	case kRoomOutsideArgentPub: +		_sequence->startMusicRoomSeq2(whither, ped); +		break; +	case kRoomLusties: +		switch (magicnum) { +		case 14: +			if (_avvysInTheCupboard) { +				_animation->hideInCupboard(); +				_sequence->startCupboardSeq(); +				return; +			} else { +				_animation->appearPed(0, 5); +				_animation->_sprites[0]->_facingDir = kDirRight; +				_sequence->startLustiesSeq2(whither, ped); +			} +			break; +		case 12: +			_sequence->startLustiesSeq3(whither, ped); +			break; +		} +		break; +	default: +		_sequence->startDummySeq(whither, ped); +	} +} + +void AvalancheEngine::setRoom(People persId, Room roomId) { +	_whereIs[persId - kPeopleAvalot] = roomId; +} + +Room AvalancheEngine::getRoom(People persId) { +	return _whereIs[persId - kPeopleAvalot]; +} +} // End of namespace Avalanche | 
