aboutsummaryrefslogtreecommitdiff
path: root/engines/avalanche/avalot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/avalanche/avalot.cpp')
-rw-r--r--engines/avalanche/avalot.cpp1744
1 files changed, 1744 insertions, 0 deletions
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
new file mode 100644
index 0000000000..8ef41a2c93
--- /dev/null
+++ b/engines/avalanche/avalot.cpp
@@ -0,0 +1,1744 @@
+/* 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;
+ _oldHour = _oldHourAngle = _oldMinute = 17717;
+}
+
+void Clock::update() { // TODO: Move variables from Gyro to here (or at least somewhere nearby), rename them.
+ 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() {
+ if ((_oldHour == 17717) || (!_vm->_soundFx)) // Too high - must be first time around
+ 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 {
+ _isLoaded = false; // Set to true in _vm->loadGame().
+ 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;
+
+ _roomTime = 0;
+
+
+ if ((_lastRoom == kRoomMap) && (_lastRoomNotMap != _room))
+ enterNewTown();
+
+ 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!
+ _isLoaded = false;
+}
+
+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;
+ _favouriteDrink = "";
+ _favouriteSong = "";
+ _worstPlaceOnEarth = "";
+ _spareEvening = "";
+ _totalTime = 0;
+ _jumpStatus = 0;
+ _mushroomGrowing = false;
+ _spludwickAtHome = false;
+ _lastRoom = 0;
+ _lastRoomNotMap = 0;
+ _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;
+
+ _parser->resetVariables();
+ _animation->resetVariables();
+ _sequence->resetVariables();
+ _background->resetVariables();
+ _menu->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";
+ _favouriteDrink = "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;
+
+ 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 < kPeopleArkata)
+ return Common::String(lads[whose - kPeopleAvalot]);
+ else
+ return Common::String(lasses[whose - kPeopleArkata]);
+}
+
+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;
+
+ 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