aboutsummaryrefslogtreecommitdiff
path: root/engines/queen
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/queen
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/queen')
-rw-r--r--engines/queen/bankman.cpp145
-rw-r--r--engines/queen/bankman.h87
-rw-r--r--engines/queen/command.cpp1255
-rw-r--r--engines/queen/command.h234
-rw-r--r--engines/queen/credits.cpp145
-rw-r--r--engines/queen/credits.h88
-rw-r--r--engines/queen/cutaway.cpp1324
-rw-r--r--engines/queen/cutaway.h265
-rw-r--r--engines/queen/debug.cpp219
-rw-r--r--engines/queen/debug.h69
-rw-r--r--engines/queen/defs.h322
-rw-r--r--engines/queen/display.cpp1307
-rw-r--r--engines/queen/display.h246
-rw-r--r--engines/queen/graphics.cpp1537
-rw-r--r--engines/queen/graphics.h293
-rw-r--r--engines/queen/grid.cpp255
-rw-r--r--engines/queen/grid.h136
-rw-r--r--engines/queen/input.cpp213
-rw-r--r--engines/queen/input.h178
-rw-r--r--engines/queen/journal.cpp587
-rw-r--r--engines/queen/journal.h208
-rw-r--r--engines/queen/logic.cpp2221
-rw-r--r--engines/queen/logic.h410
-rw-r--r--engines/queen/module.mk34
-rw-r--r--engines/queen/music.cpp344
-rw-r--r--engines/queen/music.h125
-rw-r--r--engines/queen/musicdata.cpp1944
-rw-r--r--engines/queen/queen.cpp454
-rw-r--r--engines/queen/queen.h164
-rw-r--r--engines/queen/resource.cpp287
-rw-r--r--engines/queen/resource.h169
-rw-r--r--engines/queen/restables.cpp1108
-rw-r--r--engines/queen/sound.cpp239
-rw-r--r--engines/queen/sound.h158
-rw-r--r--engines/queen/state.cpp130
-rw-r--r--engines/queen/state.h113
-rw-r--r--engines/queen/structs.h580
-rw-r--r--engines/queen/talk.cpp1812
-rw-r--r--engines/queen/talk.h244
-rw-r--r--engines/queen/walk.cpp564
-rw-r--r--engines/queen/walk.h144
-rw-r--r--engines/queen/xref.txt496
42 files changed, 20853 insertions, 0 deletions
diff --git a/engines/queen/bankman.cpp b/engines/queen/bankman.cpp
new file mode 100644
index 0000000000..18ad276d0f
--- /dev/null
+++ b/engines/queen/bankman.cpp
@@ -0,0 +1,145 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/bankman.h"
+
+#include "queen/resource.h"
+
+namespace Queen {
+
+BankManager::BankManager(Resource *res)
+ : _res(res) {
+ memset(_frames, 0, sizeof(_frames));
+ memset(_banks, 0, sizeof(_banks));
+ memset(_loadedBanks, 0, sizeof(_loadedBanks));
+}
+
+BankManager::~BankManager() {
+ for (uint32 i = 0; i < MAX_BANKS_NUMBER; ++i) {
+ close(i);
+ }
+ eraseFrames(true);
+}
+
+void BankManager::load(const char *bankname, uint32 bankslot) {
+ debug(9, "BankManager::load(%s, %d)", bankname, bankslot);
+ assert(bankslot < MAX_BANKS_NUMBER);
+
+ if (!scumm_stricmp(bankname, _loadedBanks[bankslot])) {
+ debug(9, "BankManager::load() bank '%s' already loaded", bankname);
+ return;
+ }
+
+ close(bankslot);
+ _banks[bankslot].data = _res->loadFile(bankname);
+
+ uint16 entries = READ_LE_UINT16(_banks[bankslot].data);
+ assert(entries < MAX_BANK_SIZE);
+ debug(9, "BankManager::load() entries = %d", entries);
+
+ uint32 offset = 2;
+ const uint8 *p = _banks[bankslot].data;
+ for (uint16 i = 1; i <= entries; ++i) {
+ _banks[bankslot].indexes[i] = offset;
+ uint16 w = READ_LE_UINT16(p + offset + 0);
+ uint16 h = READ_LE_UINT16(p + offset + 2);
+ // jump to next entry, skipping data & header
+ offset += w * h + 8;
+ }
+
+ // mark this bank as loaded
+ strcpy(_loadedBanks[bankslot], bankname);
+}
+
+void BankManager::unpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
+ debug(9, "BankManager::unpack(%d, %d, %d)", srcframe, dstframe, bankslot);
+ assert(bankslot < MAX_BANKS_NUMBER);
+ assert(_banks[bankslot].data != NULL);
+
+ BobFrame *pbf = &_frames[dstframe];
+ const uint8 *p = _banks[bankslot].data + _banks[bankslot].indexes[srcframe];
+ pbf->width = READ_LE_UINT16(p + 0);
+ pbf->height = READ_LE_UINT16(p + 2);
+ pbf->xhotspot = READ_LE_UINT16(p + 4);
+ pbf->yhotspot = READ_LE_UINT16(p + 6);
+
+ uint32 size = pbf->width * pbf->height;
+ delete[] pbf->data;
+ pbf->data = new uint8[ size ];
+ memcpy(pbf->data, p + 8, size);
+}
+
+void BankManager::overpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
+ debug(9, "BankManager::overpack(%d, %d, %d)", srcframe, dstframe, bankslot);
+ assert(bankslot < MAX_BANKS_NUMBER);
+ assert(_banks[bankslot].data != NULL);
+
+ const uint8 *p = _banks[bankslot].data + _banks[bankslot].indexes[srcframe];
+ uint16 src_w = READ_LE_UINT16(p + 0);
+ uint16 src_h = READ_LE_UINT16(p + 2);
+
+ // unpack if destination frame is smaller than source one
+ if (_frames[dstframe].width < src_w || _frames[dstframe].height < src_h) {
+ unpack(srcframe, dstframe, bankslot);
+ } else {
+ // copy data 'over' destination frame (without changing frame header)
+ memcpy(_frames[dstframe].data, p + 8, src_w * src_h);
+ }
+}
+
+void BankManager::close(uint32 bankslot) {
+ debug(9, "BankManager::close(%d)", bankslot);
+ assert(bankslot < MAX_BANKS_NUMBER);
+ delete[] _banks[bankslot].data;
+ memset(&_banks[bankslot], 0, sizeof(PackedBank));
+ _loadedBanks[bankslot][0] = '\0';
+}
+
+BobFrame *BankManager::fetchFrame(uint32 index) {
+ debug(9, "BankManager::fetchFrame(%d)", index);
+ assert(index < MAX_FRAMES_NUMBER);
+ BobFrame *pbf = &_frames[index];
+ assert(pbf->data != 0);
+ return pbf;
+}
+
+void BankManager::eraseFrame(uint32 index) {
+ debug(9, "BankManager::eraseFrame(%d)", index);
+ assert(index < MAX_FRAMES_NUMBER);
+ BobFrame *pbf = &_frames[index];
+ delete[] pbf->data;
+ memset(pbf, 0, sizeof(BobFrame));
+}
+
+void BankManager::eraseFrames(bool joe) {
+ uint32 i = 0;
+ if (!joe) {
+ i = FRAMES_JOE;
+ }
+ while (i < MAX_FRAMES_NUMBER) {
+ eraseFrame(i);
+ ++i;
+ }
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/bankman.h b/engines/queen/bankman.h
new file mode 100644
index 0000000000..63eb9224ff
--- /dev/null
+++ b/engines/queen/bankman.h
@@ -0,0 +1,87 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENBANKMAN_H
+#define QUEENBANKMAN_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+class Resource;
+
+class BankManager {
+public:
+
+ BankManager(Resource *res);
+ ~BankManager();
+
+ //! load a bank into the specified slot
+ void load(const char *bankname, uint32 bankslot);
+
+ //! unpack a frame from a loaded bank
+ void unpack(uint32 srcframe, uint32 dstframe, uint32 bankslot);
+
+ //! unpack a frame over an existing one from a loaded bank
+ void overpack(uint32 srcframe, uint32 dstframe, uint32 bankslot);
+
+ //! close a bank
+ void close(uint32 bankslot);
+
+ //! get a reference to unpacked frame
+ BobFrame *fetchFrame(uint32 index);
+
+ //! erase a frame
+ void eraseFrame(uint32 index);
+
+ //! erase all unpacked frames
+ void eraseFrames(bool joe);
+
+ enum {
+ MAX_BANK_SIZE = 110,
+ MAX_FRAMES_NUMBER = 256,
+ MAX_BANKS_NUMBER = 18
+ };
+
+private:
+
+ struct PackedBank {
+ uint32 indexes[MAX_BANK_SIZE];
+ uint8 *data;
+ };
+
+ //! unpacked bob frames
+ BobFrame _frames[MAX_FRAMES_NUMBER];
+
+ //! banked bob frames
+ PackedBank _banks[MAX_BANKS_NUMBER];
+
+ //! loaded banks names
+ char _loadedBanks[MAX_BANKS_NUMBER][20];
+
+ Resource *_res;
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/command.cpp b/engines/queen/command.cpp
new file mode 100644
index 0000000000..a84d859fe6
--- /dev/null
+++ b/engines/queen/command.cpp
@@ -0,0 +1,1255 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/command.h"
+
+#include "queen/display.h"
+#include "queen/input.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+#include "queen/state.h"
+#include "queen/walk.h"
+
+namespace Queen {
+
+CmdText::CmdText(bool reversed, uint8 y, QueenEngine *vm)
+ : _isReversed(reversed), _y(y), _vm(vm) {
+ clear();
+}
+
+void CmdText::clear() {
+ memset(_command, 0, sizeof(_command));
+}
+
+void CmdText::display(uint8 color) {
+ _vm->display()->textCurrentColor(color);
+ _vm->display()->setTextCentered(_y, _command, false);
+}
+
+void CmdText::displayTemp(uint8 color, Verb v, const char *name, bool outlined) {
+ char temp[MAX_COMMAND_LEN] = "";
+ if (_isReversed) {
+ if (name != NULL)
+ sprintf(temp, "%s ", name);
+ strcat(temp, _vm->logic()->verbName(v));
+ } else {
+ strcpy(temp, _vm->logic()->verbName(v));
+ if (name != NULL) {
+ strcat(temp, " ");
+ strcat(temp, name);
+ }
+ }
+ _vm->display()->textCurrentColor(color);
+ _vm->display()->setTextCentered(_y, temp, outlined);
+}
+
+void CmdText::displayTemp(uint8 color, const char *name, bool outlined) {
+ char temp[MAX_COMMAND_LEN];
+ if (_isReversed)
+ sprintf(temp, "%s %s", name, _command);
+ else
+ sprintf(temp, "%s %s", _command, name);
+ _vm->display()->textCurrentColor(color);
+ _vm->display()->setTextCentered(_y, temp, outlined);
+}
+
+void CmdText::setVerb(Verb v) {
+ strcpy(_command, _vm->logic()->verbName(v));
+}
+
+void CmdText::addLinkWord(Verb v) {
+ if (_isReversed) {
+ char temp[MAX_COMMAND_LEN];
+
+ strcpy(temp, _command);
+ strcpy(_command, _vm->logic()->verbName(v));
+ strcat(_command, " ");
+ strcat(_command, temp);
+ } else {
+ strcat(_command, " ");
+ strcat(_command, _vm->logic()->verbName(v));
+ }
+}
+
+void CmdText::addObject(const char *objName) {
+ if (_isReversed) {
+ char temp[MAX_COMMAND_LEN];
+
+ strcpy(temp, _command);
+ strcpy(_command, objName);
+ strcat(_command, " ");
+ strcat(_command, temp);
+ } else {
+ strcat(_command, " ");
+ strcat(_command, objName);
+ }
+}
+
+bool CmdText::isEmpty() const {
+ return _command[0] == 0;
+}
+
+void CmdState::init() {
+ commandLevel = 1;
+ oldVerb = verb = action = VERB_NONE;
+ oldNoun = noun = subject[0] = subject[1] = 0;
+
+ selAction = VERB_NONE;
+ selNoun = 0;
+}
+
+Command::Command(QueenEngine *vm)
+ : _cmdList(NULL), _cmdArea(NULL), _cmdObject(NULL), _cmdInventory(NULL), _cmdGameState(NULL),
+ _cmdText((vm->resource()->getLanguage() == HEBREW), CmdText::COMMAND_Y_POS, vm), _vm(vm) {
+}
+
+Command::~Command() {
+ delete[] _cmdList;
+ delete[] _cmdArea;
+ delete[] _cmdObject;
+ delete[] _cmdInventory;
+ delete[] _cmdGameState;
+}
+
+void Command::clear(bool clearTexts) {
+ debug(6, "Command::clear(%d)", clearTexts);
+ _cmdText.clear();
+ if (clearTexts) {
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+ }
+ _parse = false;
+ _state.init();
+}
+
+void Command::executeCurrentAction() {
+ _vm->logic()->entryObj(0);
+
+ if (_mouseKey == Input::MOUSE_RBUTTON && _state.subject[0] > 0) {
+
+ ObjectData *od = _vm->logic()->objectData(_state.subject[0]);
+ if (od == NULL || od->name <= 0) {
+ cleanupCurrentAction();
+ return;
+ }
+
+ _state.verb = State::findDefaultVerb(od->state);
+ _state.selAction = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
+ _cmdText.setVerb(_state.selAction);
+ _cmdText.addObject(_vm->logic()->objectName(od->name));
+ }
+
+ // always highlight the current command when actioned
+ _cmdText.display(INK_CMD_SELECT);
+
+ _state.selNoun = _state.noun;
+ _state.commandLevel = 1;
+
+ if (handleWrongAction()) {
+ cleanupCurrentAction();
+ return;
+ }
+
+ // get the commands associated with this object/item
+ uint16 comMax = 0;
+ uint16 matchingCmds[MAX_MATCHING_CMDS];
+ CmdListData *cmdList = &_cmdList[1];
+ uint16 i;
+ for (i = 1; i <= _numCmdList; ++i, ++cmdList) {
+ if (cmdList->match(_state.selAction, _state.subject[0], _state.subject[1])) {
+ assert(comMax < MAX_MATCHING_CMDS);
+ matchingCmds[comMax] = i;
+ ++comMax;
+ }
+ }
+
+ debug(6, "Command::executeCurrentAction() - comMax=%d subj1=%X subj2=%X", comMax, _state.subject[0], _state.subject[1]);
+
+ if (comMax == 0) {
+ sayInvalidAction(_state.selAction, _state.subject[0], _state.subject[1]);
+ clear(true);
+ cleanupCurrentAction();
+ return;
+ }
+
+ // process each associated command for the Object, until all done
+ // or one of the Gamestate tests fails...
+ int16 cond = 0;
+ CmdListData *com = &_cmdList[0];
+ uint16 comId = 0;
+ for (i = 1; i <= comMax; ++i) {
+
+ comId = matchingCmds[i - 1];
+ com = &_cmdList[comId];
+
+ // check the Gamestates and set them if necessary
+ cond = 0;
+ if (com->setConditions) {
+ cond = setConditions(comId, (i == comMax));
+ }
+
+ if (cond == -1 && i == comMax) {
+ // only exit on a condition fail if at last command
+ // Joe hasnt spoken, so do normal LOOK command
+ break;
+ } else if (cond == -2 && i == comMax) {
+ // only exit on a condition fail if at last command
+ // Joe has spoken, so skip LOOK command
+ cleanupCurrentAction();
+ return;
+ } else if (cond >= 0) {
+ // we've had a successful Gamestate check, so we must now exit
+ cond = executeCommand(comId, cond);
+ break;
+ }
+ }
+
+ if (_state.selAction == VERB_USE_JOURNAL) {
+ clear(true);
+ } else {
+ if (cond <= 0 && _state.selAction == VERB_LOOK_AT) {
+ lookAtSelectedObject();
+ } else {
+ // only play song if it's a PLAY AFTER type
+ if (com->song < 0) {
+ _vm->sound()->playSong(-com->song);
+ }
+ clear(true);
+ }
+ cleanupCurrentAction();
+ }
+}
+
+void Command::updatePlayer() {
+ if (_vm->logic()->joeWalk() != JWM_MOVE) {
+ int16 cx = _vm->input()->mousePosX();
+ int16 cy = _vm->input()->mousePosY();
+ lookForCurrentObject(cx, cy);
+ lookForCurrentIcon(cx, cy);
+ }
+
+ if (_vm->input()->keyVerb() != VERB_NONE) {
+ if (_vm->input()->keyVerb() == VERB_USE_JOURNAL) {
+ _vm->logic()->useJournal();
+ } else if (_vm->input()->keyVerb() != VERB_SKIP_TEXT) {
+ _state.verb = _vm->input()->keyVerb();
+ if (isVerbInv(_state.verb)) {
+ _state.noun = _state.selNoun = 0;
+ _state.oldNoun = 0;
+ _state.oldVerb = VERB_NONE;
+ grabSelectedItem();
+ } else {
+ grabSelectedVerb();
+ }
+ }
+ _vm->input()->clearKeyVerb();
+ }
+
+ _mouseKey = _vm->input()->mouseButton();
+ _vm->input()->clearMouseButton();
+ if (_mouseKey > 0) {
+ grabCurrentSelection();
+ }
+}
+
+void Command::readCommandsFrom(byte *&ptr) {
+ uint16 i;
+
+ _numCmdList = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdList = new CmdListData[_numCmdList + 1];
+ if (_numCmdList == 0) {
+ _cmdList[0].readFromBE(ptr);
+ } else {
+ memset(&_cmdList[0], 0, sizeof(CmdListData));
+ for (i = 1; i <= _numCmdList; i++) {
+ _cmdList[i].readFromBE(ptr);
+ }
+ }
+
+ _numCmdArea = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdArea = new CmdArea[_numCmdArea + 1];
+ if (_numCmdArea == 0) {
+ _cmdArea[0].readFromBE(ptr);
+ } else {
+ memset(&_cmdArea[0], 0, sizeof(CmdArea));
+ for (i = 1; i <= _numCmdArea; i++) {
+ _cmdArea[i].readFromBE(ptr);
+ }
+ }
+
+ _numCmdObject = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdObject = new CmdObject[_numCmdObject + 1];
+ if (_numCmdObject == 0) {
+ _cmdObject[0].readFromBE(ptr);
+ } else {
+ memset(&_cmdObject[0], 0, sizeof(CmdObject));
+ for (i = 1; i <= _numCmdObject; i++) {
+ _cmdObject[i].readFromBE(ptr);
+ }
+ }
+
+ _numCmdInventory = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdInventory = new CmdInventory[_numCmdInventory + 1];
+ if (_numCmdInventory == 0) {
+ _cmdInventory[0].readFromBE(ptr);
+ } else {
+ memset(&_cmdInventory[0], 0, sizeof(CmdInventory));
+ for (i = 1; i <= _numCmdInventory; i++) {
+ _cmdInventory[i].readFromBE(ptr);
+ }
+ }
+
+ _numCmdGameState = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdGameState = new CmdGameState[_numCmdGameState + 1];
+ if (_numCmdGameState == 0) {
+ _cmdGameState[0].readFromBE(ptr);
+ } else {
+ memset(&_cmdGameState[0], 0, sizeof(CmdGameState));
+ for (i = 1; i <= _numCmdGameState; i++) {
+ _cmdGameState[i].readFromBE(ptr);
+ }
+ }
+}
+
+ObjectData *Command::findObjectData(uint16 objRoomNum) const {
+ ObjectData *od = NULL;
+ if (objRoomNum != 0) {
+ objRoomNum += _vm->logic()->currentRoomData();
+ od = _vm->logic()->objectData(objRoomNum);
+ }
+ return od;
+}
+
+ItemData *Command::findItemData(Verb invNum) const {
+ ItemData *id = NULL;
+ uint16 itNum = _vm->logic()->findInventoryItem(invNum - VERB_INV_FIRST);
+ if (itNum != 0) {
+ id = _vm->logic()->itemData(itNum);
+ }
+ return id;
+}
+
+int16 Command::executeCommand(uint16 comId, int16 condResult) {
+ // execute.c l.313-452
+ debug(6, "Command::executeCommand() - cond = %X, com = %X", condResult, comId);
+
+ CmdListData *com = &_cmdList[comId];
+
+ if (com->setAreas) {
+ setAreas(comId);
+ }
+
+ // don't try to grab if action is TALK or WALK
+ if (_state.selAction != VERB_TALK_TO && _state.selAction != VERB_WALK_TO) {
+ int i;
+ for (i = 0; i < 2; ++i) {
+ int16 obj = _state.subject[i];
+ if (obj > 0) {
+ _vm->logic()->joeGrab(State::findGrab(_vm->logic()->objectData(obj)->state));
+ }
+ }
+ }
+
+ bool cutDone = false;
+ if (condResult > 0) {
+ // check for cutaway/dialogs before updating Objects
+ const char *desc = _vm->logic()->objectTextualDescription(condResult);
+ if (executeIfCutaway(desc)) {
+ condResult = 0;
+ cutDone = true;
+ } else if (executeIfDialog(desc)) {
+ condResult = 0;
+ }
+ }
+
+ int16 oldImage = 0;
+ if (_state.subject[0] > 0) {
+ // an object (not an item)
+ oldImage = _vm->logic()->objectData(_state.subject[0])->image;
+ }
+
+ if (com->setObjects) {
+ setObjects(comId);
+ }
+
+ if (com->setItems) {
+ setItems(comId);
+ }
+
+ if (com->imageOrder != 0 && _state.subject[0] > 0) {
+ ObjectData *od = _vm->logic()->objectData(_state.subject[0]);
+ // we must update the graphic image of the object
+ if (com->imageOrder < 0) {
+ // instead of setting to -1 or -2, flag as negative
+ if (od->image > 0) {
+ // make sure that object is not already updated
+ od->image = -(od->image + 10);
+ }
+ } else {
+ od->image = com->imageOrder;
+ }
+ _vm->graphics()->refreshObject(_state.subject[0]);
+ } else {
+ // this object is not being updated by command list, see if
+ // it has another image copied to it
+ if (_state.subject[0] > 0) {
+ // an object (not an item)
+ if (_vm->logic()->objectData(_state.subject[0])->image != oldImage) {
+ _vm->graphics()->refreshObject(_state.subject[0]);
+ }
+ }
+ }
+
+ // don't play music on an OPEN/CLOSE command - in case the command fails
+ if (_state.selAction != VERB_NONE &&
+ _state.selAction != VERB_OPEN &&
+ _state.selAction != VERB_CLOSE) {
+ // only play song if it's a PLAY BEFORE type
+ if (com->song > 0) {
+ _vm->sound()->playSong(com->song);
+ }
+ }
+
+ // do a special hardcoded section
+ // l.419-452 execute.c
+ switch (com->specialSection) {
+ case 1:
+ _vm->logic()->useJournal();
+ _state.selAction = VERB_USE_JOURNAL;
+ return condResult;
+ case 2:
+ _vm->logic()->joeUseDress(true);
+ break;
+ case 3:
+ _vm->logic()->joeUseClothes(true);
+ break;
+ case 4:
+ _vm->logic()->joeUseUnderwear();
+ break;
+ }
+
+ if (_state.subject[0] > 0)
+ changeObjectState(_state.selAction, _state.subject[0], com->song, cutDone);
+
+ if (condResult > 0) {
+ _vm->logic()->makeJoeSpeak(condResult, true);
+ }
+ return condResult;
+}
+
+int16 Command::makeJoeWalkTo(int16 x, int16 y, int16 objNum, Verb v, bool mustWalk) {
+ // Check to see if object is actually an exit to another
+ // room. If so, then set up new room
+ ObjectData *objData = _vm->logic()->objectData(objNum);
+ if (objData->x != 0 || objData->y != 0) {
+ x = objData->x;
+ y = objData->y;
+ }
+ if (v == VERB_WALK_TO) {
+ _vm->logic()->entryObj(objData->entryObj);
+ if (objData->entryObj > 0) {
+ _vm->logic()->newRoom(_vm->logic()->objectData(objData->entryObj)->room);
+ // because this is an exit object, see if there is
+ // a walk off point and set (x,y) accordingly
+ WalkOffData *wod = _vm->logic()->walkOffPointForObject(objNum);
+ if (wod != NULL) {
+ x = wod->x;
+ y = wod->y;
+ }
+ }
+ } else {
+ _vm->logic()->entryObj(0);
+ _vm->logic()->newRoom(0);
+ }
+
+ debug(6, "Command::makeJoeWalkTo() - x=%d y=%d newRoom=%d", x, y, _vm->logic()->newRoom());
+
+ int16 p = 0;
+ if (mustWalk) {
+ // determine which way for Joe to face Object
+ uint16 facing = State::findDirection(objData->state);
+ BobSlot *bobJoe = _vm->graphics()->bob(0);
+ if (x == bobJoe->x && y == bobJoe->y) {
+ _vm->logic()->joeFacing(facing);
+ _vm->logic()->joeFace();
+ } else {
+ p = _vm->walk()->moveJoe(facing, x, y, false);
+ if (p != 0) {
+ _vm->logic()->newRoom(0); // cancel makeJoeWalkTo, that should be equivalent to cr10 fix
+ }
+ }
+ }
+ return p;
+}
+
+void Command::grabCurrentSelection() {
+ _selPosX = _vm->input()->mousePosX();
+ _selPosY = _vm->input()->mousePosY();
+
+ uint16 zone = _vm->grid()->findObjectUnderCursor(_selPosX, _selPosY);
+ _state.noun = _vm->grid()->findObjectNumber(zone);
+ _state.verb = _vm->grid()->findVerbUnderCursor(_selPosX, _selPosY);
+
+ _selPosX += _vm->display()->horizontalScroll();
+
+ if (isVerbAction(_state.verb) || isVerbInvScroll(_state.verb)) {
+ grabSelectedVerb();
+ } else if (isVerbInv(_state.verb)) {
+ grabSelectedItem();
+ } else if (_state.noun != 0) {
+ grabSelectedNoun();
+ } else if (_selPosY < ROOM_ZONE_HEIGHT && _state.verb == VERB_NONE) {
+ // select without a command, do a WALK
+ clear(true);
+ _vm->logic()->joeWalk(JWM_EXECUTE);
+ }
+}
+
+void Command::grabSelectedObject(int16 objNum, uint16 objState, uint16 objName) {
+ if (_state.action != VERB_NONE) {
+ _cmdText.addObject(_vm->logic()->objectName(objName));
+ }
+
+ _state.subject[_state.commandLevel - 1] = objNum;
+
+ // if first noun and it's a 2 level command then set up action word
+ if (_state.action == VERB_USE && _state.commandLevel == 1) {
+ if (State::findUse(objState) == STATE_USE_ON) {
+ // object supports 2 levels, command not fully constructed
+ _state.commandLevel = 2;
+ _cmdText.addLinkWord(VERB_PREP_WITH);
+ _cmdText.display(INK_CMD_NORMAL);
+ _parse = false;
+ } else {
+ _parse = true;
+ }
+ } else if (_state.action == VERB_GIVE && _state.commandLevel == 1) {
+ // command not fully constructed
+ _state.commandLevel = 2;
+ _cmdText.addLinkWord(VERB_PREP_TO);
+ _cmdText.display(INK_CMD_NORMAL);
+ _parse = false;
+ } else {
+ _parse = true;
+ }
+
+ if (_parse) {
+ _state.verb = VERB_NONE;
+ _vm->logic()->joeWalk(JWM_EXECUTE);
+ _state.selAction = _state.action;
+ _state.action = VERB_NONE;
+ }
+}
+
+void Command::grabSelectedItem() {
+ ItemData *id = findItemData(_state.verb);
+ if (id == NULL || id->name <= 0) {
+ return;
+ }
+
+ int16 item = _vm->logic()->findInventoryItem(_state.verb - VERB_INV_FIRST);
+
+ // If we've selected via keyboard, and there is no VERB then do
+ // the ITEMs default, otherwise keep constructing!
+
+ if (_mouseKey == Input::MOUSE_LBUTTON ||
+ (_vm->input()->keyVerb() != VERB_NONE && _state.verb != VERB_NONE)) {
+ if (_state.action == VERB_NONE) {
+ if (_vm->input()->keyVerb() != VERB_NONE) {
+ // We've selected via the keyboard, no command is being
+ // constructed, so we shall find the item's default
+ _state.verb = State::findDefaultVerb(id->state);
+ if (_state.verb == VERB_NONE) {
+ // set to Look At
+ _state.verb = VERB_LOOK_AT;
+ _cmdText.setVerb(VERB_LOOK_AT);
+ }
+ _state.action = _state.verb;
+ } else {
+ // Action>0 ONLY if command has been constructed
+ // Left Mouse Button pressed just do Look At
+ _state.action = VERB_LOOK_AT;
+ _cmdText.setVerb(VERB_LOOK_AT);
+ }
+ }
+ _state.verb = VERB_NONE;
+ } else {
+ if (_cmdText.isEmpty()) {
+ _state.verb = VERB_LOOK_AT;
+ _state.action = VERB_LOOK_AT;
+ _cmdText.setVerb(VERB_LOOK_AT);
+ } else {
+ if (_state.commandLevel == 2 && _parse)
+ _state.verb = _state.action;
+ else
+ _state.verb = State::findDefaultVerb(id->state);
+ if (_state.verb == VERB_NONE) {
+ // No match made, so command not yet completed. Redefine as LOOK AT
+ _state.action = VERB_LOOK_AT;
+ _cmdText.setVerb(VERB_LOOK_AT);
+ } else {
+ _state.action = _state.verb;
+ }
+ _state.verb = VERB_NONE;
+ }
+ }
+
+ grabSelectedObject(-item, id->state, id->name);
+}
+
+void Command::grabSelectedNoun() {
+ ObjectData *od = findObjectData(_state.noun);
+ if (od == NULL || od->name <= 0) {
+ // selected a turned off object, so just walk
+ clear(true);
+ _state.noun = 0;
+ _vm->logic()->joeWalk(JWM_EXECUTE);
+ return;
+ }
+
+ if (_state.verb == VERB_NONE) {
+ if (_mouseKey == Input::MOUSE_LBUTTON) {
+ if ((_state.commandLevel != 2 && _state.action == VERB_NONE) ||
+ (_state.commandLevel == 2 && _parse)) {
+ _state.verb = VERB_WALK_TO;
+ _state.action = VERB_WALK_TO;
+ _cmdText.setVerb(VERB_WALK_TO);
+ }
+ } else if (_mouseKey == Input::MOUSE_RBUTTON) {
+ if (_cmdText.isEmpty()) {
+ _state.verb = State::findDefaultVerb(od->state);
+ _state.selAction = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
+ _cmdText.setVerb(_state.selAction);
+ _cmdText.addObject(_vm->logic()->objectName(od->name));
+ } else {
+ if ((_state.commandLevel == 2 && !_parse) || _state.action != VERB_NONE) {
+ _state.verb = _state.action;
+ } else {
+ _state.verb = State::findDefaultVerb(od->state);
+ }
+ _state.action = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
+ _state.verb = VERB_NONE;
+ }
+ }
+ }
+
+ _state.selNoun = 0;
+ int16 objNum = _vm->logic()->currentRoomData() + _state.noun;
+ grabSelectedObject(objNum, od->state, od->name);
+}
+
+void Command::grabSelectedVerb() {
+ if (isVerbInvScroll(_state.verb)) {
+ // move through inventory (by four if right mouse button)
+ uint16 scroll = (_mouseKey == Input::MOUSE_RBUTTON) ? 4 : 1;
+ _vm->logic()->inventoryScroll(scroll, _state.verb == VERB_SCROLL_UP);
+ } else {
+ _state.action = _state.verb;
+ _state.subject[0] = 0;
+ _state.subject[1] = 0;
+
+ if (_vm->logic()->joeWalk() == JWM_MOVE && _state.verb != VERB_NONE) {
+ _vm->logic()->joeWalk(JWM_NORMAL);
+ }
+ _state.commandLevel = 1;
+ _state.oldVerb = VERB_NONE;
+ _state.oldNoun = 0;
+ _cmdText.setVerb(_state.verb);
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+}
+
+bool Command::executeIfCutaway(const char *description) {
+ if (strlen(description) > 4 &&
+ scumm_stricmp(description + strlen(description) - 4, ".cut") == 0) {
+
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+
+ char nextCutaway[20];
+ memset(nextCutaway, 0, sizeof(nextCutaway));
+ _vm->logic()->playCutaway(description, nextCutaway);
+ while (nextCutaway[0] != '\0') {
+ _vm->logic()->playCutaway(nextCutaway, nextCutaway);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Command::executeIfDialog(const char *description) {
+ if (strlen(description) > 4 &&
+ scumm_stricmp(description + strlen(description) - 4, ".dog") == 0) {
+
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+
+ char cutaway[20];
+ memset(cutaway, 0, sizeof(cutaway));
+ _vm->logic()->startDialogue(description, _state.selNoun, cutaway);
+
+ while (cutaway[0] != '\0') {
+ char currentCutaway[20];
+ strcpy(currentCutaway, cutaway);
+ _vm->logic()->playCutaway(currentCutaway, cutaway);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Command::handleWrongAction() {
+ // l.96-141 execute.c
+ uint16 objMax = _vm->grid()->objMax(_vm->logic()->currentRoom());
+ uint16 roomData = _vm->logic()->currentRoomData();
+
+ // select without a command or WALK TO ; do a WALK
+ if ((_state.selAction == VERB_WALK_TO || _state.selAction == VERB_NONE) &&
+ (_state.selNoun > objMax || _state.selNoun == 0)) {
+ if (_state.selAction == VERB_NONE) {
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+ }
+ _vm->walk()->moveJoe(0, _selPosX, _selPosY, false);
+ return true;
+ }
+
+ // check to see if one of the objects is hidden
+ int i;
+ for (i = 0; i < 2; ++i) {
+ int16 obj = _state.subject[i];
+ if (obj > 0 && _vm->logic()->objectData(obj)->name <= 0) {
+ return true;
+ }
+ }
+
+ // check for USE command on exists
+ if (_state.selAction == VERB_USE &&
+ _state.subject[0] > 0 && _vm->logic()->objectData(_state.subject[0])->entryObj > 0) {
+ _state.selAction = VERB_WALK_TO;
+ }
+
+ if (_state.selNoun > 0 && _state.selNoun <= objMax) {
+ uint16 objNum = roomData + _state.selNoun;
+ if (makeJoeWalkTo(_selPosX, _selPosY, objNum, _state.selAction, true) != 0) {
+ return true;
+ }
+ if (_state.selAction == VERB_WALK_TO && _vm->logic()->objectData(objNum)->entryObj < 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Command::sayInvalidAction(Verb action, int16 subj1, int16 subj2) {
+ // l.158-272 execute.c
+ switch (action) {
+
+ case VERB_LOOK_AT:
+ lookAtSelectedObject();
+ break;
+
+ case VERB_OPEN:
+ // 'it doesn't seem to open'
+ _vm->logic()->makeJoeSpeak(1);
+ break;
+
+ case VERB_USE:
+ if (subj1 < 0) {
+ uint16 k = _vm->logic()->itemData(-subj1)->sfxDescription;
+ if (k > 0) {
+ _vm->logic()->makeJoeSpeak(k, true);
+ } else {
+ _vm->logic()->makeJoeSpeak(2);
+ }
+ } else {
+ _vm->logic()->makeJoeSpeak(2);
+ }
+ break;
+
+ case VERB_TALK_TO:
+ _vm->logic()->makeJoeSpeak(24 + _vm->randomizer.getRandomNumber(2));
+ break;
+
+ case VERB_CLOSE:
+ _vm->logic()->makeJoeSpeak(2);
+ break;
+
+ case VERB_MOVE:
+ // 'I can't move it'
+ if (subj1 > 0) {
+ int16 img = _vm->logic()->objectData(subj1)->image;
+ if (img == -4 || img == -3) {
+ _vm->logic()->makeJoeSpeak(18);
+ } else {
+ _vm->logic()->makeJoeSpeak(3);
+ }
+ } else {
+ _vm->logic()->makeJoeSpeak(3);
+ }
+ break;
+
+ case VERB_GIVE:
+ // 'I can't give the subj1 to subj2'
+ if (subj1 < 0) {
+ if (subj2 > 0) {
+ int16 img = _vm->logic()->objectData(subj2)->image;
+ if (img == -4 || img == -3) {
+ _vm->logic()->makeJoeSpeak(27 + _vm->randomizer.getRandomNumber(2));
+ }
+ } else {
+ _vm->logic()->makeJoeSpeak(11);
+ }
+ } else {
+ _vm->logic()->makeJoeSpeak(12);
+ }
+ break;
+
+ case VERB_PICK_UP:
+ if (subj1 < 0) {
+ _vm->logic()->makeJoeSpeak(14);
+ } else {
+ int16 img = _vm->logic()->objectData(subj1)->image;
+ if (img == -4 || img == -3) {
+ // Trying to get a person
+ _vm->logic()->makeJoeSpeak(20);
+ } else {
+ // 5 : 'I can't pick that up'
+ // 6 : 'I don't think I need that'
+ // 7 : 'I'd rather leave it here'
+ // 8 : 'I don't think I'd have any use for that'
+ _vm->logic()->makeJoeSpeak(5 + _vm->randomizer.getRandomNumber(3));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Command::changeObjectState(Verb action, int16 obj, int16 song, bool cutDone) {
+ // l.456-533 execute.c
+ ObjectData *objData = _vm->logic()->objectData(obj);
+
+ if (action == VERB_OPEN && !cutDone) {
+ if (State::findOn(objData->state) == STATE_ON_ON) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ State::alterDefaultVerb(&objData->state, VERB_NONE);
+
+ // play music if it exists... (or SFX for open/close door)
+ if (song != 0) {
+ _vm->sound()->playSong(ABS(song));
+ }
+
+ if (objData->entryObj != 0) {
+ // if it's a door, then update door that it links to
+ openOrCloseAssociatedObject(action, ABS(objData->entryObj));
+ objData->entryObj = ABS(objData->entryObj);
+ }
+ } else {
+ // 'it's already open !'
+ _vm->logic()->makeJoeSpeak(9);
+ }
+ } else if (action == VERB_CLOSE && !cutDone) {
+ if (State::findOn(objData->state) == STATE_ON_OFF) {
+ State::alterOn(&objData->state, STATE_ON_ON);
+ State::alterDefaultVerb(&objData->state, VERB_OPEN);
+
+ // play music if it exists... (or SFX for open/close door)
+ if (song != 0) {
+ _vm->sound()->playSong(ABS(song));
+ }
+
+ if (objData->entryObj != 0) {
+ // if it's a door, then update door that it links to
+ openOrCloseAssociatedObject(action, ABS(objData->entryObj));
+ objData->entryObj = -ABS(objData->entryObj);
+ }
+ } else {
+ // 'it's already closed !'
+ _vm->logic()->makeJoeSpeak(10);
+ }
+ } else if (action == VERB_MOVE) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ }
+}
+
+void Command::cleanupCurrentAction() {
+ // l.595-597 execute.c
+ _vm->logic()->joeFace();
+ _state.oldNoun = 0;
+ _state.oldVerb = VERB_NONE;
+}
+
+void Command::openOrCloseAssociatedObject(Verb action, int16 otherObj) {
+ CmdListData *cmdList = &_cmdList[1];
+ uint16 com = 0;
+ uint16 i;
+ for (i = 1; i <= _numCmdList && com == 0; ++i, ++cmdList) {
+ if (cmdList->match(action, otherObj, 0)) {
+ if (cmdList->setConditions) {
+ CmdGameState *cmdGs = _cmdGameState;
+ uint16 j;
+ for (j = 1; j <= _numCmdGameState; ++j) {
+ if (cmdGs[j].id == i && cmdGs[j].gameStateSlot > 0) {
+ if (_vm->logic()->gameState(cmdGs[j].gameStateSlot) == cmdGs[j].gameStateValue) {
+ com = i;
+ break;
+ }
+ }
+ }
+ } else {
+ com = i;
+ break;
+ }
+ }
+ }
+
+ if (com != 0) {
+
+ debug(6, "Command::openOrCloseAssociatedObject() com=%X", com);
+
+ cmdList = &_cmdList[com];
+ ObjectData *objData = _vm->logic()->objectData(otherObj);
+
+ if (cmdList->imageOrder != 0) {
+ objData->image = cmdList->imageOrder;
+ }
+
+ if (action == VERB_OPEN) {
+ if (State::findOn(objData->state) == STATE_ON_ON) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ State::alterDefaultVerb(&objData->state, VERB_NONE);
+ objData->entryObj = ABS(objData->entryObj);
+ }
+ } else if (action == VERB_CLOSE) {
+ if (State::findOn(objData->state) == STATE_ON_OFF) {
+ State::alterOn(&objData->state, STATE_ON_ON);
+ State::alterDefaultVerb(&objData->state, VERB_OPEN);
+ objData->entryObj = -ABS(objData->entryObj);
+ }
+ }
+ }
+}
+
+int16 Command::setConditions(uint16 command, bool lastCmd) {
+ debug(9, "Command::setConditions(%d, %d)", command, lastCmd);
+
+ int16 ret = 0;
+ uint16 cmdState[21];
+ memset(cmdState, 0, sizeof(cmdState));
+ uint16 cmdStateCount = 0;
+ uint16 i;
+ CmdGameState *cmdGs = &_cmdGameState[1];
+ for (i = 1; i <= _numCmdGameState; ++i, ++cmdGs) {
+ if (cmdGs->id == command) {
+ if (cmdGs->gameStateSlot > 0) {
+ if (_vm->logic()->gameState(cmdGs->gameStateSlot) != cmdGs->gameStateValue) {
+ debug(6, "Command::setConditions() - GS[%d] == %d (should be %d)", cmdGs->gameStateSlot, _vm->logic()->gameState(cmdGs->gameStateSlot), cmdGs->gameStateValue);
+ // failed test
+ ret = i;
+ break;
+ }
+ } else {
+ cmdState[cmdStateCount] = i;
+ ++cmdStateCount;
+ }
+ }
+ }
+
+ if (ret > 0) {
+ // we've failed, so see if we need to make Joe speak
+ cmdGs = &_cmdGameState[ret];
+ if (cmdGs->speakValue > 0 && lastCmd) {
+ // check to see if fail state is in fact a cutaway
+ const char *objDesc = _vm->logic()->objectTextualDescription(cmdGs->speakValue);
+ if (!executeIfCutaway(objDesc) && !executeIfDialog(objDesc)) {
+ _vm->logic()->makeJoeSpeak(cmdGs->speakValue, true);
+ }
+ ret = -2;
+ } else {
+ // return -1 so Joe will be able to speak a normal description
+ ret = -1;
+ }
+ } else {
+ ret = 0;
+ // all tests were okay, now set gamestates
+ for (i = 0; i < cmdStateCount; ++i) {
+ cmdGs = &_cmdGameState[cmdState[i]];
+ _vm->logic()->gameState(ABS(cmdGs->gameStateSlot), cmdGs->gameStateValue);
+ // set return value for Joe to say something
+ ret = cmdGs->speakValue;
+ }
+ }
+ return ret;
+}
+
+void Command::setAreas(uint16 command) {
+ debug(9, "Command::setAreas(%d)", command);
+
+ CmdArea *cmdArea = &_cmdArea[1];
+ for (uint16 i = 1; i <= _numCmdArea; ++i, ++cmdArea) {
+ if (cmdArea->id == command) {
+ uint16 areaNum = ABS(cmdArea->area);
+ Area *area = _vm->grid()->area(cmdArea->room, areaNum);
+ if (cmdArea->area > 0) {
+ // turn on area
+ area->mapNeighbours = ABS(area->mapNeighbours);
+ } else {
+ // turn off area
+ area->mapNeighbours = -ABS(area->mapNeighbours);
+ }
+ }
+ }
+}
+
+void Command::setObjects(uint16 command) {
+ debug(9, "Command::setObjects(%d)", command);
+
+ CmdObject *cmdObj = &_cmdObject[1];
+ for (uint16 i = 1; i <= _numCmdObject; ++i, ++cmdObj) {
+ if (cmdObj->id == command) {
+
+ // found an object
+ uint16 dstObj = ABS(cmdObj->dstObj);
+ ObjectData *objData = _vm->logic()->objectData(dstObj);
+
+ debug(6, "Command::setObjects() - dstObj=%X srcObj=%X _state.subject[0]=%X", cmdObj->dstObj, cmdObj->srcObj, _state.subject[0]);
+
+ if (cmdObj->dstObj > 0) {
+ // show the object
+ objData->name = ABS(objData->name);
+ // test that the object has not already been deleted
+ // by checking if it is not equal to zero
+ if (cmdObj->srcObj == -1 && objData->name != 0) {
+ // delete object by setting its name to 0 and
+ // turning off graphic image
+ objData->name = 0;
+ if (objData->room == _vm->logic()->currentRoom()) {
+ if (dstObj != _state.subject[0]) {
+ // if the new object we have updated is on screen and is not the
+ // current object, then we can update. This is because we turn
+ // current object off ourselves by COM_LIST(com, 8)
+ if (objData->image != -3 && objData->image != -4) {
+ // it is a normal object (not a person)
+ // turn the graphic image off for the object
+ objData->image = -(objData->image + 10);
+ }
+ }
+ // invalidate object area
+ uint16 objZone = dstObj - _vm->logic()->currentRoomData();
+ _vm->grid()->setZone(GS_ROOM, objZone, 0, 0, 1, 1);
+ }
+ }
+
+ if (cmdObj->srcObj > 0) {
+ // copy data from dummy object to object
+ int16 image1 = objData->image;
+ int16 image2 = _vm->logic()->objectData(cmdObj->srcObj)->image;
+ _vm->logic()->objectCopy(cmdObj->srcObj, dstObj);
+ if (image1 != 0 && image2 == 0 && objData->room == _vm->logic()->currentRoom()) {
+ uint16 bobNum = _vm->logic()->findBob(dstObj);
+ if (bobNum != 0) {
+ _vm->graphics()->bob(bobNum)->clear();
+ }
+ }
+ }
+
+ if (dstObj != _state.subject[0]) {
+ // if the new object we have updated is on screen and
+ // is not current object then update it
+ _vm->graphics()->refreshObject(dstObj);
+ }
+ } else {
+ // hide the object
+ if (objData->name > 0) {
+ objData->name = -objData->name;
+ // may need to turn BOBs off for objects to be hidden on current
+ // screen ! if the new object we have updated is on screen and
+ // is not current object then update it
+ _vm->graphics()->refreshObject(dstObj);
+ }
+ }
+ }
+ }
+}
+
+void Command::setItems(uint16 command) {
+ debug(9, "Command::setItems(%d)", command);
+
+ ItemData *items = _vm->logic()->itemData(0);
+ CmdInventory *cmdInv = &_cmdInventory[1];
+ for (uint16 i = 1; i <= _numCmdInventory; ++i, ++cmdInv) {
+ if (cmdInv->id == command) {
+ uint16 dstItem = ABS(cmdInv->dstItem);
+ // found an item
+ if (cmdInv->dstItem > 0) {
+ // add item to inventory
+ if (cmdInv->srcItem > 0) {
+ // copy data from source item to item, then enable it
+ items[dstItem] = items[cmdInv->srcItem];
+ items[dstItem].name = ABS(items[dstItem].name);
+ }
+ _vm->logic()->inventoryInsertItem(cmdInv->dstItem);
+ } else {
+ // delete item
+ if (items[dstItem].name > 0) {
+ _vm->logic()->inventoryDeleteItem(dstItem);
+ }
+ if (cmdInv->srcItem > 0) {
+ // copy data from source item to item, then disable it
+ items[dstItem] = items[cmdInv->srcItem];
+ items[dstItem].name = -ABS(items[dstItem].name);
+ }
+ }
+ }
+ }
+}
+
+uint16 Command::nextObjectDescription(ObjectDescription* objDesc, uint16 firstDesc) {
+ // l.69-103 select.c
+ uint16 i;
+ uint16 diff = objDesc->lastDescription - firstDesc;
+ debug(6, "Command::nextObjectDescription() - diff = %d, type = %d", diff, objDesc->type);
+ switch (objDesc->type) {
+ case 0:
+ // random type, start with first description
+ if (objDesc->lastSeenNumber == 0) {
+ // first time look at called
+ objDesc->lastSeenNumber = firstDesc;
+ break;
+ }
+ // already displayed first, do a random
+ case 1:
+ i = objDesc->lastSeenNumber;
+ while (i == objDesc->lastSeenNumber) {
+ i = firstDesc + _vm->randomizer.getRandomNumber(diff);
+ }
+ objDesc->lastSeenNumber = i;
+ break;
+ case 2:
+ // sequential, but loop
+ ++objDesc->lastSeenNumber;
+ if (objDesc->lastSeenNumber > objDesc->lastDescription) {
+ objDesc->lastSeenNumber = firstDesc;
+ }
+ break;
+ case 3:
+ // sequential without looping
+ if (objDesc->lastSeenNumber != objDesc->lastDescription) {
+ ++objDesc->lastSeenNumber;
+ }
+ break;
+ }
+ return objDesc->lastSeenNumber;
+}
+
+void Command::lookAtSelectedObject() {
+ uint16 desc;
+ if (_state.subject[0] < 0) {
+ desc = _vm->logic()->itemData(-_state.subject[0])->description;
+ } else {
+ ObjectData *objData = _vm->logic()->objectData(_state.subject[0]);
+ if (objData->name <= 0) {
+ return;
+ }
+ desc = objData->description;
+ }
+
+ debug(6, "Command::lookAtSelectedObject() - desc = %X, _state.subject[0] = %X", desc, _state.subject[0]);
+
+ // check to see if the object/item has a series of description
+ ObjectDescription *objDesc = _vm->logic()->objectDescription(1);
+ uint16 i;
+ for (i = 1; i <= _vm->logic()->objectDescriptionCount(); ++i, ++objDesc) {
+ if (objDesc->object == _state.subject[0]) {
+ desc = nextObjectDescription(objDesc, desc);
+ break;
+ }
+ }
+
+ _vm->logic()->makeJoeSpeak(desc, true);
+ _vm->logic()->joeFace();
+}
+
+void Command::lookForCurrentObject(int16 cx, int16 cy) {
+ uint16 obj = _vm->grid()->findObjectUnderCursor(cx, cy);
+ _state.noun = _vm->grid()->findObjectNumber(obj);
+
+ if (_state.oldNoun == _state.noun) {
+ return;
+ }
+
+ ObjectData *od = findObjectData(_state.noun);
+ if (od == NULL || od->name <= 0) {
+ _state.oldNoun = _state.noun;
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+ if (_state.action != VERB_NONE) {
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ return;
+ }
+
+ // if no command yet selected, then use DEFAULT command, if any
+ if (_state.action == VERB_NONE) {
+ Verb v = State::findDefaultVerb(od->state);
+ _cmdText.setVerb((v == VERB_NONE) ? VERB_WALK_TO : v);
+ if (_state.noun == 0) {
+ _cmdText.clear();
+ }
+ }
+ const char *name = _vm->logic()->objectName(od->name);
+ _cmdText.displayTemp(INK_CMD_NORMAL, name);
+ _state.oldNoun = _state.noun;
+}
+
+void Command::lookForCurrentIcon(int16 cx, int16 cy) {
+ _state.verb = _vm->grid()->findVerbUnderCursor(cx, cy);
+ if (_state.oldVerb != _state.verb) {
+
+ if (_state.action == VERB_NONE) {
+ _cmdText.clear();
+ }
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+
+ if (isVerbInv(_state.verb)) {
+ ItemData *id = findItemData(_state.verb);
+ if (id != NULL && id->name > 0) {
+ if (_state.action == VERB_NONE) {
+ Verb v = State::findDefaultVerb(id->state);
+ _cmdText.setVerb((v == VERB_NONE) ? VERB_LOOK_AT : v);
+ }
+ const char *name = _vm->logic()->objectName(id->name);
+ _cmdText.displayTemp(INK_CMD_NORMAL, name);
+ }
+ } else if (isVerbAction(_state.verb)) {
+ _cmdText.displayTemp(INK_CMD_NORMAL, _state.verb);
+ } else if (_state.verb == VERB_NONE) {
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ _state.oldVerb = _state.verb;
+ }
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/command.h b/engines/queen/command.h
new file mode 100644
index 0000000000..3ef848b24d
--- /dev/null
+++ b/engines/queen/command.h
@@ -0,0 +1,234 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENCOMMAND_H
+#define QUEENCOMMAND_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+class QueenEngine;
+
+struct CmdText {
+
+ CmdText(bool reversed, uint8 y, QueenEngine *vm);
+
+ //! reset the command sentence
+ void clear();
+
+ //! display the command sentence using the specified color
+ void display(uint8 color);
+
+ //! display a temporary command sentence using the specified parameters
+ void displayTemp(uint8 color, Verb v, const char *name = NULL, bool outlined = false);
+
+ //! display a temporary command sentence using the specified parameters
+ void displayTemp(uint8 color, const char *name, bool outlined = false);
+
+ //! set the verb for the command sentence
+ void setVerb(Verb v);
+
+ //! set the link word (between verb and object) for the command sentence
+ void addLinkWord(Verb v);
+
+ //! add an object name to the command sentence
+ void addObject(const char *objName);
+
+ //! returns true if the command sentence is empty
+ bool isEmpty() const;
+
+ enum {
+ MAX_COMMAND_LEN = 256,
+ COMMAND_Y_POS = 151
+ };
+
+ uint8 _y;
+
+ //! flag indicating if the words in the sentence are reversed (hebrew version)
+ bool _isReversed;
+
+ //! buffer containing the current command sentence
+ char _command[MAX_COMMAND_LEN];
+
+ QueenEngine *_vm;
+};
+
+struct CmdState {
+
+ void init();
+
+ Verb oldVerb, verb;
+ Verb action;
+ int16 oldNoun, noun;
+ int commandLevel;
+ int16 subject[2];
+
+ Verb selAction;
+ int16 selNoun;
+};
+
+class Command {
+public:
+
+ Command(QueenEngine *vm);
+ ~Command();
+
+ //! initialise command construction
+ void clear(bool clearTexts);
+
+ //! execute last constructed command
+ void executeCurrentAction();
+
+ //! get player input and construct command from it
+ void updatePlayer();
+
+ //! read all command arrays from stream
+ void readCommandsFrom(byte *&ptr);
+
+ enum {
+ MAX_MATCHING_CMDS = 50
+ };
+
+private:
+
+ //! get a reference to the ObjectData for the specified room object
+ ObjectData *findObjectData(uint16 objRoomNum) const;
+
+ //! get a reference to the ItemData for the specified inventory object
+ ItemData *findItemData(Verb invNum) const;
+
+ //! execute the current command
+ int16 executeCommand(uint16 comId, int16 condResult);
+
+ //! move Joe to the specified position, handling new room switching
+ int16 makeJoeWalkTo(int16 x, int16 y, int16 objNum, Verb v, bool mustWalk);
+
+ //! update command state with current selected action
+ void grabCurrentSelection();
+
+ //! update command state with current selected object
+ void grabSelectedObject(int16 objNum, uint16 objState, uint16 objName);
+
+ //! update command state with current selected inventory object
+ void grabSelectedItem();
+
+ //! update command state with current selected room object
+ void grabSelectedNoun();
+
+ //! update command state with current selected verb
+ void grabSelectedVerb();
+
+ //! if the description is a cutaway file, execute it
+ bool executeIfCutaway(const char *description);
+
+ //! if the description is a dialog file, execute it
+ bool executeIfDialog(const char *description);
+
+ //! handle a wrong/invalid user action
+ bool handleWrongAction();
+
+ //! make Joe speak something for a wrong/invalid action
+ void sayInvalidAction(Verb action, int16 subj1, int16 subj2);
+
+ //! update an object state
+ void changeObjectState(Verb action, int16 obj, int16 song, bool cutDone);
+
+ //! reset current action
+ void cleanupCurrentAction();
+
+ //! OPEN_CLOSE_OTHER(OBJECT_DATA[S][4])
+ void openOrCloseAssociatedObject(Verb action, int16 obj);
+
+ //! update gamestates - P1_SET_CONDITIONS
+ int16 setConditions(uint16 command, bool lastCmd);
+
+ //! turn on/off areas - P2_SET_AREAS
+ void setAreas(uint16 command);
+
+ //! hide/show objects, redisplay if in the same room as Joe - P3_SET_OBJECTS
+ void setObjects(uint16 command);
+
+ //! inserts/deletes items (inventory) - P4_SET_ITEMS
+ void setItems(uint16 command);
+
+ //! update description for object and returns description number to use
+ uint16 nextObjectDescription(ObjectDescription *objDesc, uint16 firstDesc);
+
+ //! speak description of selected object
+ void lookAtSelectedObject();
+
+ //! get the current object under the cursor
+ void lookForCurrentObject(int16 cx, int16 cy);
+
+ //! get the current icon panel under the cursor (inventory item or verb)
+ void lookForCurrentIcon(int16 cx, int16 cy);
+
+ //! returns true if the verb is an action verb
+ bool isVerbAction(Verb v) const { return (v >= VERB_PANEL_COMMAND_FIRST && v <= VERB_PANEL_COMMAND_LAST) || (v == VERB_WALK_TO); };
+
+ //! return true if the verb is an inventory item
+ bool isVerbInv(Verb v) const { return v >= VERB_INV_FIRST && v <= VERB_INV_LAST; }
+
+ //! returns true if the specified verb is an inventory scroll
+ bool isVerbInvScroll(Verb v) const { return v == VERB_SCROLL_UP || v == VERB_SCROLL_DOWN; }
+
+ //! commands list for each possible action
+ CmdListData *_cmdList;
+ uint16 _numCmdList;
+
+ //! commands list for areas
+ CmdArea *_cmdArea;
+ uint16 _numCmdArea;
+
+ //! commands list for objects
+ CmdObject *_cmdObject;
+ uint16 _numCmdObject;
+
+ //! commands list for inventory
+ CmdInventory *_cmdInventory;
+ uint16 _numCmdInventory;
+
+ //! commands list for gamestate
+ CmdGameState *_cmdGameState;
+ uint16 _numCmdGameState;
+
+ //! textual form of the command (displayed between room and panel areas)
+ CmdText _cmdText;
+
+ //! flag indicating that the current command is fully constructed
+ bool _parse;
+
+ //! state of current constructed command
+ CmdState _state;
+
+ //! last user selection
+ int _mouseKey, _selPosX, _selPosY;
+
+ QueenEngine *_vm;
+};
+
+} // End of namespace Queen
+
+#endif
+
diff --git a/engines/queen/credits.cpp b/engines/queen/credits.cpp
new file mode 100644
index 0000000000..a88c67e587
--- /dev/null
+++ b/engines/queen/credits.cpp
@@ -0,0 +1,145 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/credits.h"
+
+#include "queen/display.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+
+namespace Queen {
+
+Credits::Credits(QueenEngine *vm, const char* filename) :
+ _vm(vm), _running(true), _count(0), _pause(0), _justify(0), _fontSize(0), _color(0), _zone(0) {
+ uint32 size;
+ char *buf = (char *)_vm->resource()->loadFile(filename, 0, &size);
+ _credits = new LineReader(buf, size);
+}
+
+Credits::~Credits() {
+ delete _credits;
+}
+
+void Credits::nextRoom() {
+ if (-1 == _pause) {
+ _pause = 0;
+ _vm->display()->clearTexts(0, 199);
+ }
+}
+
+void Credits::update() {
+ if (!_running)
+ return;
+
+ if (_pause > 0) {
+ _pause--;
+ if (!_pause)
+ _vm->display()->clearTexts(0, 199);
+ return;
+ }
+
+ /* wait until next room */
+ if (-1 == _pause)
+ return;
+
+ for (;;) {
+ const char *line = _credits->nextLine();
+
+ if (0 == memcmp(line, "EN", 2)) {
+ _running = false;
+ return;
+ }
+
+ if ('.' == line[0]) {
+ int i;
+
+ switch (tolower(line[1])) {
+ case 'l' :
+ _justify = 0;
+ break;
+ case 'c' :
+ _justify = 1;
+ break;
+ case 'r' :
+ _justify = 2;
+ break;
+ case 's' :
+ _fontSize = 0;
+ break;
+ case 'b' :
+ _fontSize = 1;
+ break;
+ case 'p' :
+ _pause = atoi(&line[3]);
+ _pause *= 10;
+ /* wait until next room */
+ if (0 == _pause)
+ _pause = -1;
+ for (i = 0; i < _count; i++) {
+ _vm->display()->textCurrentColor(_list[i].color);
+ _vm->display()->setText(_list[i].x, _list[i].y, _list[i].text);
+ }
+ _count = 0;
+ return;
+ case 'i' :
+ _color = atoi(&line[3]);
+ break;
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ _zone = line[1] - '1';
+ break;
+ }
+ } else {
+ assert(_count < ARRAYSIZE(_list));
+ _list[_count].text = line;
+ _list[_count].color = _color;
+ _list[_count].fontSize = _fontSize;
+ switch (_justify) {
+ case 0:
+ _list[_count].x = (_zone % 3) * (320 / 3) + 8;
+ break;
+ case 1:
+ _list[_count].x = (_zone % 3) * (320 / 3) + 54 - _vm->display()->textWidth(line) / 2;
+ if (_list[_count].x < 8)
+ _list[_count].x = 8;
+ break;
+ case 2:
+ _list[_count].x = (_zone % 3) * (320 / 3) + 100 - _vm->display()->textWidth(line);
+ break;
+ }
+ _list[_count].y = (_zone / 3) * (200 / 3) + (_count * 10);
+ _count++;
+ }
+ }
+}
+
+
+} // End of namespace Queen
+
diff --git a/engines/queen/credits.h b/engines/queen/credits.h
new file mode 100644
index 0000000000..4f34772c28
--- /dev/null
+++ b/engines/queen/credits.h
@@ -0,0 +1,88 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef CREDITS_H
+#define CREDITS_H
+
+#include "common/util.h"
+#include "queen/defs.h"
+
+namespace Queen {
+
+class QueenEngine;
+class LineReader;
+
+class Credits {
+public:
+
+ Credits(QueenEngine *vm, const char* filename);
+ ~Credits();
+
+ //! update/display credits for current room
+ void update();
+
+ //! handles room switching
+ void nextRoom();
+
+ //! returns true if the credits are running
+ bool running() const { return _running; }
+
+private:
+
+ struct Line {
+ short x, y, color, fontSize;
+ const char *text;
+ };
+
+ //! contains the formatted lines of texts to display
+ Line _list[19];
+
+ //! true if end of credits description hasn't been reached
+ bool _running;
+
+ //! number of elements in _list array
+ int _count;
+
+ //! pause counts for next room
+ int _pause;
+
+ //! current text justification mode
+ int _justify;
+
+ //! current font size (unused ?)
+ int _fontSize;
+
+ //! current text color
+ int _color;
+
+ //! current text position
+ int _zone;
+
+ //! contains the credits description
+ LineReader *_credits;
+
+ QueenEngine *_vm;
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/cutaway.cpp b/engines/queen/cutaway.cpp
new file mode 100644
index 0000000000..dc24d5b627
--- /dev/null
+++ b/engines/queen/cutaway.cpp
@@ -0,0 +1,1324 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/cutaway.h"
+
+#include "queen/bankman.h"
+#include "queen/display.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/input.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+#include "queen/talk.h"
+#include "queen/walk.h"
+
+namespace Queen {
+
+void Cutaway::run(
+ const char *filename,
+ char *nextFilename,
+ QueenEngine *vm) {
+ Cutaway *cutaway = new Cutaway(filename, vm);
+ cutaway->run(nextFilename);
+ delete cutaway;
+}
+
+Cutaway::Cutaway(
+ const char *filename,
+ QueenEngine *vm)
+ : _vm(vm), _personDataCount(0), _personFaceCount(0), _lastSong(0), _songBeforeComic(0) {
+ memset(&_bankNames, 0, sizeof(_bankNames));
+ _vm->input()->cutawayQuitReset();
+ load(filename);
+}
+
+Cutaway::~Cutaway() {
+ delete[] _fileData;
+}
+
+void Cutaway::load(const char *filename) {
+ byte *ptr;
+
+ debug(6, "----- Cutaway::load(\"%s\") -----", filename);
+
+ ptr = _fileData = _vm->resource()->loadFile(filename, 20);
+
+ if (0 == scumm_stricmp(filename, "comic.cut"))
+ _songBeforeComic = _vm->sound()->lastOverride();
+
+ strcpy(_basename, filename);
+ _basename[strlen(_basename)-4] = '\0';
+
+ _comPanel = READ_BE_UINT16(ptr);
+ ptr += 2;
+ debug(6, "_comPanel = %i", _comPanel);
+ _cutawayObjectCount = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ debug(6, "_cutawayObjectCount = %i", _cutawayObjectCount);
+
+ if (_cutawayObjectCount < 0) {
+ _cutawayObjectCount = -_cutawayObjectCount;
+ _vm->input()->canQuit(false);
+ } else
+ _vm->input()->canQuit(true);
+
+ int16 flags1 = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+ debug(6, "flags1 = %i", flags1);
+
+ if (flags1 < 0) {
+ _vm->logic()->entryObj(0);
+ _finalRoom = -flags1;
+ } else
+ _finalRoom = PREVIOUS_ROOM;
+
+ _anotherCutaway = (flags1 == 1);
+
+ debug(6, "[Cutaway::load] _finalRoom = %i", _finalRoom);
+ debug(6, "[Cutaway::load] _anotherCutaway = %i", _anotherCutaway);
+
+ /*
+ Pointers to other places in the cutaway data
+ */
+
+ _gameStatePtr = _fileData + READ_BE_UINT16(ptr);
+ ptr += 2;
+
+ _nextSentenceOff = READ_BE_UINT16(ptr);
+ ptr += 2;
+
+ uint16 bankNamesOff = READ_BE_UINT16(ptr);
+ ptr += 2;
+
+ _objectData = ptr;
+
+ loadStrings(bankNamesOff);
+
+ if (_bankNames[0][0]) {
+ debug(6, "Loading bank '%s'", _bankNames[0]);
+ _vm->bankMan()->load(_bankNames[0], CUTAWAY_BANK);
+ }
+
+ char entryString[MAX_STRING_SIZE];
+ Talk::getString(_fileData, _nextSentenceOff, entryString, MAX_STRING_LENGTH);
+ debug(6, "Entry string = '%s'", entryString);
+
+ _vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
+ _vm->logic()->joeFace();
+
+ if (entryString[0] == '*' &&
+ entryString[1] == 'F' &&
+ entryString[3] == '\0') {
+ switch (entryString[2]) {
+ case 'L':
+ _vm->logic()->joeCutFacing(DIR_LEFT);
+ break;
+ case 'R':
+ _vm->logic()->joeCutFacing(DIR_RIGHT);
+ break;
+ case 'F':
+ _vm->logic()->joeCutFacing(DIR_FRONT);
+ break;
+ case 'B':
+ _vm->logic()->joeCutFacing(DIR_BACK);
+ break;
+ }
+ }
+
+}
+
+void Cutaway::loadStrings(uint16 offset) {
+ int bankNameCount = READ_BE_UINT16(_fileData + offset);
+ offset += 2;
+
+ debug(6, "Bank name count = %i", bankNameCount);
+
+ /*
+ The _bankNames zero-based array is the one-based BANK_NAMEstr array in
+ the original source code.
+ */
+
+ for (int i = 0, j = 0; i < bankNameCount; i++) {
+ Talk::getString(_fileData, offset, _bankNames[j], MAX_FILENAME_LENGTH);
+ if (_bankNames[j][0]) {
+ debug(6, "Bank name %i = '%s'", j, _bankNames[j]);
+ j++;
+ }
+ }
+
+ debug(6, "Getting talk file");
+ Talk::getString(_fileData, offset, _talkFile, MAX_FILENAME_LENGTH);
+ debug(6, "Talk file = '%s'", _talkFile);
+
+ _talkTo = (int16)READ_BE_INT16(_fileData + offset);
+ debug(6, "_talkTo = %i", _talkTo);
+}
+
+const byte *Cutaway::getCutawayObject(const byte *ptr, CutawayObject &object)
+{
+ const byte *oldPtr = ptr;
+
+ object.objectNumber = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.moveToX = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.moveToY = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.bank = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.animList = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.execute = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.limitBobX1 = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.limitBobY1 = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.limitBobX2 = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.limitBobY2 = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.animType = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.bobStartX = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.bobStartY = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.room = (int16)READ_BE_INT16(ptr); ptr += 2;
+ object.scale = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ if ((ptr - oldPtr) != 17*sizeof(int16))
+ error("Wrong number of values read");
+
+ // Make ugly reuse of data less ugly
+ if (object.limitBobX1 < 0) {
+ object.song = -object.limitBobX1;
+ object.limitBobX1 = 0;
+ } else
+ object.song = 0;
+
+ return ptr;
+}
+
+void Cutaway::dumpCutawayObject(int index, CutawayObject &object)
+{
+ debug(6, "----- CutawayObject[%i] -----", index);
+
+ const char *objectNumberStr;
+
+ switch (object.objectNumber) {
+ case -1:
+ objectNumberStr = "MESSAGE";
+ break;
+ case 0:
+ objectNumberStr = "Joe";
+ break;
+ default:
+ if (object.objectNumber > 0)
+ objectNumberStr = _vm->logic()->objectName(ABS(_vm->logic()->objectData(object.objectNumber)->name));
+ else
+ objectNumberStr = "Unknown!";
+ break;
+ }
+
+ debug(6, "objectNumber = %i (%s)", object.objectNumber, objectNumberStr);
+
+ if (object.moveToX) debug(6, "moveToX = %i", object.moveToX);
+ if (object.moveToY) debug(6, "moveToY = %i", object.moveToY);
+ if (object.bank) debug(6, "bank = %i", object.bank);
+ if (object.animList) debug(6, "animList = %i", object.animList);
+ if (object.execute) debug(6, "execute = %i", object.execute);
+ if (object.limitBobX1) debug(6, "limitBobX1 = %i", object.limitBobX1);
+ if (object.limitBobY1) debug(6, "limitBobY1 = %i", object.limitBobY1);
+ if (object.limitBobX2) debug(6, "limitBobX2 = %i", object.limitBobX2);
+ if (object.limitBobY2) debug(6, "limitBobY2 = %i", object.limitBobY2);
+ if (object.specialMove) debug(6, "specialMove = %i", object.specialMove);
+ if (object.animType) debug(6, "animType = %i", object.animType);
+ if (object.fromObject) debug(6, "fromObject = %i", object.fromObject);
+ if (object.bobStartX) debug(6, "bobStartX = %i", object.bobStartX);
+ if (object.bobStartY) debug(6, "bobStartY = %i", object.bobStartY);
+ if (object.room) debug(6, "room = %i", object.room);
+ if (object.scale) debug(6, "scale = %i", object.scale);
+
+}
+
+
+const byte *Cutaway::turnOnPeople(const byte *ptr, CutawayObject &object) {
+ // Lines 1248-1259 in cutaway.c
+ object.personCount = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ if (object.personCount > MAX_PERSON_COUNT)
+ error("[Cutaway::turnOnPeople] object.personCount > MAX_PERSON_COUNT");
+
+ for (int i = 0; i < object.personCount; i++) {
+ object.person[i] = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+ debug(7, "[%i] Turn on person %i", i, object.person[i]);
+ }
+
+ return ptr;
+}
+
+void Cutaway::limitBob(CutawayObject &object) {
+ if (object.limitBobX1) {
+
+ if (object.objectNumber < 0) {
+ warning("QueenCutaway::limitBob called with objectNumber = %i", object.objectNumber);
+ return;
+ }
+
+ BobSlot *bob =
+ _vm->graphics()->bob( _vm->logic()->findBob(object.objectNumber) );
+
+ if (!bob) {
+ warning("Failed to find bob");
+ return;
+ }
+
+ bob->box.x1 = object.limitBobX1;
+ bob->box.y1 = object.limitBobY1;
+ bob->box.x2 = object.limitBobX2;
+ bob->box.y2 = object.limitBobY2;
+ }
+}
+
+void Cutaway::restorePersonData() {
+ for (int i = 0; i < _personDataCount; i++) {
+ int index = _personData[i].index;
+ ObjectData *objectData = _vm->logic()->objectData(index);
+ objectData->name = _personData[i].name;
+ objectData->image = _personData[i].image;
+ }
+}
+
+void Cutaway::changeRooms(CutawayObject &object) {
+ // Lines 1291-1385 in cutaway.c
+
+ debug(6, "Changing from room %i to room %i",
+ _temporaryRoom,
+ object.room);
+
+ restorePersonData();
+ _personDataCount = 0;
+
+ if (_finalRoom != object.room) {
+ int firstObjectInRoom = _vm->logic()->roomData(object.room) + 1;
+ int lastObjectInRoom = _vm->logic()->roomData(object.room) + _vm->grid()->objMax(object.room);
+
+ for (int i = firstObjectInRoom; i <= lastObjectInRoom; i++) {
+ ObjectData *objectData = _vm->logic()->objectData(i);
+
+ if (objectData->image == -3 || objectData->image == -4) {
+
+ assert(_personDataCount < MAX_PERSON_COUNT);
+ // The object is a person! So record the details...
+ _personData[_personDataCount].index = i;
+ _personData[_personDataCount].name = objectData->name;
+ _personData[_personDataCount].image = objectData->image;
+ _personDataCount++;
+
+ // Now, check to see if we need to keep the person on
+ bool on = false;
+ for (int j = 0; j < object.personCount; j++) {
+ if (object.person[j] == i) {
+ on = true;
+ break;
+ }
+ }
+
+ if (on) {
+ // It is needed, so ensure it's ON
+ objectData->name = ABS(objectData->name);
+ } else {
+ // Not needed, so switch off!
+ objectData->name = -ABS(objectData->name);
+ }
+
+ }
+ } // for ()
+ }
+
+ // set coordinates for Joe if he is on screen
+
+ _vm->logic()->joePos(0, 0);
+
+ for (int i = 0; i < object.personCount; i++) {
+ if (PERSON_JOE == object.person[i]) {
+ _vm->logic()->joePos(object.bobStartX, object.bobStartY);
+ }
+ }
+
+ _vm->logic()->oldRoom(_initialRoom);
+
+ // FIXME - the first cutaway is played at the end of the command 0x178. This
+ // command setups some persons and associates bob slots to them. They should be
+ // hidden as their y coordinate is > 150, but they aren't ! A (temporary)
+ // workaround is to display the room with the panel area enabled. Same problem
+ // for cutaway c62c.
+ int16 comPanel = _comPanel;
+ if ((strcmp(_basename, "c41f") == 0 && _temporaryRoom == 106 && object.room == 41) ||
+ (strcmp(_basename, "c62c") == 0 && _temporaryRoom == 105 && object.room == 41)) {
+ comPanel = 1;
+ }
+
+ // FIXME - in the original engine, panel is hidden once the 'head room' is displayed, we
+ // do it before (ie before palette fading)
+ if (object.room == FAYE_HEAD || object.room == AZURA_HEAD || object.room == FRANK_HEAD) {
+ comPanel = 2;
+ }
+
+ RoomDisplayMode mode;
+
+ if (!_vm->logic()->joeX() && !_vm->logic()->joeY()) {
+ mode = RDM_FADE_NOJOE;
+ } else {
+ // We need to display Joe on screen
+ if (_roomFade)
+ mode = RDM_NOFADE_JOE;
+ else
+ mode = RDM_FADE_JOE_XY;
+ }
+
+ _vm->logic()->displayRoom(_vm->logic()->currentRoom(), mode, object.scale, comPanel, true);
+
+ _currentImage = _vm->graphics()->numFrames();
+
+ _temporaryRoom = _vm->logic()->currentRoom();
+
+ restorePersonData();
+}
+
+Cutaway::ObjectType Cutaway::getObjectType(CutawayObject &object) {
+ // Lines 1387-1449 in cutaway.c
+
+ ObjectType objectType = OBJECT_TYPE_ANIMATION;
+
+ if (object.objectNumber > 0) {
+ if (!object.animList) {
+ // No anim frames, so treat as a PERSON, ie. allow to speak/walk
+ ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
+ if (objectData->image == -3 || objectData->image == -4)
+ objectType = OBJECT_TYPE_PERSON;
+ }
+ } else if (object.objectNumber == OBJECT_JOE) {
+ // It's Joe. See if he's to be treated as a person.
+ if (!object.animList) {
+ // There's no animation list, so Joe must be talking.
+ objectType = OBJECT_TYPE_PERSON;
+ }
+ }
+
+ if (object.fromObject > 0) {
+ /* Copy FROM_OBJECT into OBJECT */
+
+ if (object.objectNumber != object.fromObject) {
+ _vm->logic()->objectCopy(object.fromObject, object.objectNumber);
+ } else {
+ // Same object, so just turn it on!
+ ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
+ objectData->name = ABS(objectData->name);
+ }
+
+ _vm->graphics()->refreshObject(object.objectNumber);
+
+ // Skip doing any anim stuff
+ objectType = OBJECT_TYPE_NO_ANIMATION;
+ }
+
+ switch (object.objectNumber) {
+ case -2:
+ // Text to be spoken
+ objectType = OBJECT_TYPE_TEXT_SPEAK;
+ break;
+ case -3:
+ // Text to be displayed AND spoken
+ objectType = OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK;
+ break;
+ case -4:
+ // Text to be displayed only (not spoken)
+ objectType = OBJECT_TYPE_TEXT_DISPLAY;
+ break;
+ }
+
+ if (OBJECT_TYPE_ANIMATION == objectType && !object.execute) {
+ // Execute is not on, and it's an object, so ignore any Anims
+ objectType = OBJECT_TYPE_NO_ANIMATION;
+ }
+
+ return objectType;
+}
+
+const byte *Cutaway::getCutawayAnim(const byte *ptr, int header, CutawayAnim &anim) {
+ // lines 1531-1607 in cutaway.c
+
+ //debug(6, "[Cutaway::getCutawayAnim] header=%i", header);
+
+ anim.currentFrame = 0;
+ anim.originalFrame = 0;
+
+ if (-1 == header)
+ header = 0;
+
+ if (0 == header) {
+ anim.object = 0;
+ anim.originalFrame = 31;
+ } else {
+ anim.object = _vm->logic()->findBob(header);
+ anim.originalFrame = _vm->logic()->findFrame(header);
+ }
+
+ anim.unpackFrame = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ anim.speed = ((int16)READ_BE_INT16(ptr)) / 3 + 1;
+ ptr += 2;
+
+ anim.bank = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ if (anim.bank == 0) {
+ anim.bank = 15;
+ } else {
+ if (anim.bank != 13) {
+ _vm->bankMan()->load(_bankNames[anim.bank-1], CUTAWAY_BANK);
+ anim.bank = 8;
+ } else {
+ // Make sure we ref correct JOE bank (7)
+ anim.bank = 7;
+ }
+ }
+
+ anim.mx = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ anim.my = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ anim.cx = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ anim.cy = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ anim.scale = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ if (_vm->resource()->isDemo()) {
+ anim.song = 0;
+ } else {
+ anim.song = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+ }
+
+ // Extract information that depend on the signedness of values
+ if (anim.unpackFrame < 0) {
+ anim.flip = true;
+ anim.unpackFrame = -anim.unpackFrame;
+ } else
+ anim.flip = false;
+
+ return ptr;
+}
+
+void Cutaway::dumpCutawayAnim(CutawayAnim &anim) {
+ debug(6, "----- CutawayAnim -----");
+ if (anim.object) debug(6, "object = %i", anim.object);
+ if (anim.unpackFrame) debug(6, "unpackFrame = %i", anim.unpackFrame);
+ if (anim.speed) debug(6, "speed = %i", anim.speed);
+ if (anim.bank) debug(6, "bank = %i", anim.bank);
+ if (anim.mx) debug(6, "mx = %i", anim.mx);
+ if (anim.my) debug(6, "my = %i", anim.my);
+ if (anim.cx) debug(6, "cx = %i", anim.cx);
+ if (anim.cy) debug(6, "cy = %i", anim.cy);
+ if (anim.scale) debug(6, "scale = %i", anim.scale);
+ if (anim.currentFrame) debug(6, "currentFrame = %i", anim.currentFrame);
+ if (anim.originalFrame) debug(6, "originalFrame = %i", anim.originalFrame);
+ if (anim.song) debug(6, "song = %i", anim.song);
+}
+
+const byte *Cutaway::handleAnimation(const byte *ptr, CutawayObject &object) {
+ // lines 1517-1770 in cutaway.c
+ int frameCount = 0;
+ int header = 0;
+ int i;
+
+ CutawayAnim objAnim[56];
+
+ // Read animation frames
+ for (;;) {
+
+ header = (int16)READ_BE_INT16(ptr);
+ ptr += 2;
+
+ if (-2 == header)
+ break;
+
+ //debug(6, "Animation frame %i, header = %i", frameCount, header);
+
+ if (header > 1000)
+ error("Header too large");
+
+ ptr = getCutawayAnim(ptr, header, objAnim[frameCount]);
+ //dumpCutawayAnim(objAnim[frameCount]);
+
+ frameCount++;
+
+ if (_vm->input()->cutawayQuit())
+ return NULL;
+ }
+
+ if (object.animType == 1) {
+ // lines 1615-1636 in cutaway.c
+
+ debug(6, "----- Complex cutaway animation (animType = %i) -----", object.animType);
+
+ if ((_vm->logic()->currentRoom() == 47 || _vm->logic()->currentRoom() == 63) &&
+ objAnim[0].object == 1) {
+ //CR 2 - 3/3/95, Special harcoded section to make Oracle work...
+ makeComplexAnimation(_vm->graphics()->personFrames(1) - 1, objAnim, frameCount);
+ } else {
+ _currentImage = makeComplexAnimation(_currentImage, objAnim, frameCount);
+ }
+
+ if (object.bobStartX || object.bobStartY) {
+ BobSlot *bob = _vm->graphics()->bob(objAnim[0].object);
+ bob->x = object.bobStartX;
+ bob->y = object.bobStartY;
+ }
+ }
+
+ // Setup the SYNCHRO bob channels
+
+ for (i = 0; i < frameCount; i++) {
+ if (objAnim[i].mx || objAnim[i].my) {
+ BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
+ bob->frameNum = objAnim[i].originalFrame;
+ bob->move(objAnim[i].mx, objAnim[i].my, (object.specialMove > 0) ? object.specialMove : 4);
+ // Boat room hard coded
+ if (_vm->logic()->currentRoom() == ROOM_TEMPLE_OUTSIDE) {
+ BobSlot *bobJoe = _vm->graphics()->bob(0);
+ if (bobJoe->x < 320) {
+ bobJoe->move(bobJoe->x + 346, bobJoe->y, 4);
+ }
+ }
+ }
+ }
+
+ // Normal cutaway
+
+ if (object.animType != 1) {
+ // lines 1657-1761 in cutaway.c
+
+ debug(6, "----- Normal cutaway animation (animType = %i) -----", object.animType);
+
+ for (i = 0; i < frameCount; i++) {
+ //debug(6, "===== Animating frame %i =====", i);
+ //dumpCutawayAnim(objAnim[i]);
+
+ BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
+ bob->active = true;
+ if (bob->animating) {
+ bob->animating = false;
+ bob->frameNum = objAnim[i].originalFrame;
+ }
+
+ if (objAnim[i].object < 4)
+ bob->frameNum = 31 + objAnim[i].object;
+
+ if (objAnim[i].unpackFrame == 0) {
+ // Turn off the bob
+ bob->active = false;
+ } else {
+ if (object.animType == 2 || object.animType == 0) {
+ // Unpack animation, but do not unpack moving people
+
+ if (!((objAnim[i].mx > 0 || objAnim[i].my > 0) && inRange(objAnim[i].object, 1, 3))) {
+ _vm->bankMan()->unpack(
+ objAnim[i].unpackFrame,
+ objAnim[i].originalFrame,
+ objAnim[i].bank);
+ }
+
+ if (0 == objAnim[i].object) {
+ // Scale Joe
+ bob->scale = scale(object);
+ }
+ }
+
+ if (objAnim[i].cx || objAnim[i].cy) {
+ bob->x = objAnim[i].cx;
+ bob->y = objAnim[i].cy;
+ }
+
+ // Only flip if we are not moving or it is not a person object
+ if (!(objAnim[i].object > 0 && objAnim[i].object < 4) ||
+ !(objAnim[i].mx || objAnim[i].my) )
+ bob->xflip = objAnim[i].flip;
+
+ // Add frame alteration
+ if (!(objAnim[i].object > 0 && objAnim[i].object < 4)) {
+ bob->frameNum = objAnim[i].originalFrame;
+ }
+
+ int j;
+ for (j = 0; j < objAnim[i].speed; j++)
+ _vm->update();
+ }
+
+ if (_vm->input()->cutawayQuit())
+ return NULL;
+
+ if (objAnim[i].song > 0)
+ _vm->sound()->playSong(objAnim[i].song);
+
+ } // for ()
+ }
+
+ bool moving = true;
+
+ while (moving) {
+ moving = false;
+ _vm->update();
+
+ for (i = 0; i < frameCount; i++) {
+ BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
+ if (bob->moving) {
+ moving = true;
+ break;
+ }
+ }
+
+ if (_vm->input()->cutawayQuit())
+ return NULL;
+ }
+
+ return ptr;
+}
+
+static void findCdCut(const char *basename, int index, char *result) {
+ strcpy(result, basename);
+ for (int i = strlen(basename); i < 5; i++)
+ result[i] = '_';
+ snprintf(result + 5, 3, "%02i", index);
+}
+
+void Cutaway::handlePersonRecord(
+ int index,
+ CutawayObject &object,
+ const char *sentence) {
+ // Lines 1455-1516 in cutaway.c
+
+ Person p;
+
+ if (object.objectNumber == OBJECT_JOE) {
+ if (object.moveToX || object.moveToY) {
+ _vm->walk()->moveJoe(0, object.moveToX, object.moveToY, true);
+ }
+ } else {
+ _vm->logic()->initPerson(
+ object.objectNumber - _vm->logic()->currentRoomData(),
+ "", true, &p);
+
+ if (object.bobStartX || object.bobStartY) {
+ BobSlot *bob = _vm->graphics()->bob(p.actor->bobNum);
+ bob->scale = scale(object);
+ bob->x = object.bobStartX;
+ bob->y = object.bobStartY;
+ }
+
+ if (object.moveToX || object.moveToY)
+ _vm->walk()->movePerson(
+ &p,
+ object.moveToX, object.moveToY,
+ _currentImage + 1,
+ _vm->logic()->objectData(object.objectNumber)->image
+ );
+ }
+
+ if (_vm->input()->cutawayQuit())
+ return;
+
+ if (0 != strcmp(sentence, "*")) {
+ if (sentence[0] == '#') {
+ debug(4, "Starting credits '%s'", sentence + 1);
+ _vm->logic()->startCredits(sentence + 1);
+ } else {
+ if (object.objectNumber > 0) {
+ bool foundPerson = false;
+
+ for (int i = 1; i <= _personFaceCount; i++) {
+ if (_personFace[i].index == object.objectNumber) {
+ foundPerson = true;
+ break;
+ }
+ }
+
+ if (!foundPerson) {
+ _personFaceCount++;
+ assert(_personFaceCount < MAX_PERSON_FACE_COUNT);
+ _personFace[_personFaceCount].index = object.objectNumber;
+ _personFace[_personFaceCount].image = _vm->logic()->objectData(object.objectNumber)->image;
+ }
+ }
+
+ char voiceFilePrefix[MAX_STRING_SIZE];
+ findCdCut(_basename, index, voiceFilePrefix);
+ _vm->logic()->makePersonSpeak(sentence, (object.objectNumber == OBJECT_JOE) ? NULL : &p, voiceFilePrefix);
+ }
+
+ }
+
+ if (_vm->input()->cutawayQuit())
+ return;
+}
+
+void Cutaway::run(char *nextFilename) {
+ int i;
+ nextFilename[0] = '\0';
+
+ _currentImage = _vm->graphics()->numFrames();
+
+ BobSlot *joeBob = _vm->graphics()->bob(0);
+ int initialJoeX = joeBob->x;
+ int initialJoeY = joeBob->y;
+ debug(6, "[Cutaway::run] Joe started at (%i, %i)", initialJoeX, initialJoeY);
+
+ _vm->input()->cutawayRunning(true);
+
+ _initialRoom = _temporaryRoom = _vm->logic()->currentRoom();
+
+ _vm->display()->screenMode(_comPanel, true);
+
+ if (_comPanel == 0 || _comPanel == 2) {
+ _vm->logic()->sceneStart();
+ }
+
+ memset(_personFace, 0, sizeof(_personFace));
+ _personFaceCount = 0;
+
+ const byte *ptr = _objectData;
+
+ for (i = 0; i < _cutawayObjectCount; i++) {
+ CutawayObject object;
+ ptr = getCutawayObject(ptr, object);
+ //dumpCutawayObject(i, object);
+
+ if (!object.moveToX &&
+ !object.moveToY &&
+ object.specialMove > 0 &&
+ object.objectNumber >= 0) {
+ _vm->logic()->executeSpecialMove(object.specialMove);
+ object.specialMove = 0;
+ }
+
+ if (CURRENT_ROOM == object.room) {
+ // Get current room
+ object.room = _vm->logic()->currentRoom();
+ } else {
+ // Change current room
+ _vm->logic()->currentRoom(object.room);
+ }
+
+ ptr = turnOnPeople(ptr, object);
+
+ limitBob(object);
+
+ char sentence[MAX_STRING_SIZE];
+ Talk::getString(_fileData, _nextSentenceOff, sentence, MAX_STRING_LENGTH);
+
+ if (OBJECT_ROOMFADE == object.objectNumber) {
+ _roomFade = true;
+ object.objectNumber = OBJECT_JOE;
+ } else {
+ _roomFade = false;
+ }
+
+ if (object.room != _temporaryRoom)
+ changeRooms(object);
+
+ ObjectType objectType = getObjectType(object);
+
+ if (object.song)
+ _vm->sound()->playSong(object.song);
+
+ switch (objectType) {
+ case OBJECT_TYPE_ANIMATION:
+ ptr = handleAnimation(ptr, object);
+ break;
+ case OBJECT_TYPE_PERSON:
+ handlePersonRecord(i + 1, object, sentence);
+ break;
+ case OBJECT_TYPE_NO_ANIMATION:
+ // Do nothing?
+ break;
+ case OBJECT_TYPE_TEXT_SPEAK:
+ case OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK:
+ case OBJECT_TYPE_TEXT_DISPLAY:
+ handleText(i + 1, objectType, object, sentence);
+ break;
+ default:
+ warning("Unhandled object type: %i", objectType);
+ break;
+ }
+
+ if (_vm->input()->cutawayQuit())
+ break;
+
+ if (_roomFade) {
+ _vm->update();
+ BobSlot *j = _vm->graphics()->bob(0);
+ _vm->display()->palFadeIn(_vm->logic()->currentRoom(), j->active, j->x, j->y);
+ _roomFade = false;
+ }
+
+ } // for ()
+
+ _vm->display()->clearTexts(0, 198);
+ // XXX lines 1887-1895 in cutaway.c
+
+ stop();
+
+ updateGameState();
+
+ _vm->bankMan()->close(CUTAWAY_BANK);
+
+ talk(nextFilename);
+
+ if (_comPanel == 0 || (_comPanel == 2 && !_anotherCutaway)) {
+ _vm->logic()->sceneStop();
+ _comPanel = 0;
+ }
+
+ if (nextFilename[0] == '\0' && !_anotherCutaway && _vm->logic()->currentRoom() != ROOM_ENDING_CREDITS) {
+ _vm->display()->fullscreen(false);
+
+ // Lines 2138-2182 in cutaway.c
+ if (_finalRoom) {
+ _vm->logic()->newRoom(0);
+ _vm->logic()->entryObj(0);
+ } else {
+ /// No need to stay in current room, so return to previous room
+ // if one exists. Reset Joe's X,Y coords to those when first entered
+
+ restorePersonData();
+
+ debug(6, "_vm->logic()->entryObj() = %i", _vm->logic()->entryObj());
+ if (_vm->logic()->entryObj() > 0) {
+ _initialRoom = _vm->logic()->objectData(_vm->logic()->entryObj())->room;
+ } else {
+ // We're not returning to new room, so return to old Joe X,Y coords
+ debug(6, "[Cutaway::run] Moving joe to (%i, %i)", initialJoeX, initialJoeY);
+ _vm->logic()->joePos(initialJoeX, initialJoeY);
+ }
+
+ if (_vm->logic()->currentRoom() != _initialRoom) {
+ _vm->logic()->currentRoom(_initialRoom);
+ _vm->logic()->changeRoom();
+ if (_vm->logic()->currentRoom() == _vm->logic()->newRoom()) {
+ _vm->logic()->newRoom(0);
+ }
+ }
+ _vm->logic()->joePos(0, 0);
+ }
+
+ _vm->logic()->joeCutFacing(0);
+ _comPanel = 0;
+
+ int k = 0;
+ for (i = _vm->logic()->roomData(_vm->logic()->currentRoom());
+ i <= _vm->logic()->roomData(_vm->logic()->currentRoom() + 1); i++) {
+
+ ObjectData *object = _vm->logic()->objectData(i);
+ if (object->image == -3 || object->image == -4) {
+ k++;
+ if (object->name > 0) {
+ _vm->graphics()->resetPersonAnim(k);
+ }
+ }
+ }
+
+ _vm->logic()->removeHotelItemsFromInventory();
+ }
+
+ joeBob->animating = 0;
+ joeBob->moving = 0;
+
+ // if the cutaway has been cancelled, we must stop the speech and the sfx as well
+ if (_vm->input()->cutawayQuit()) {
+ if (_vm->sound()->isSpeechActive())
+ _vm->sound()->stopSpeech();
+ _vm->sound()->stopSfx();
+ }
+
+ _vm->input()->cutawayRunning(false);
+ _vm->input()->cutawayQuitReset();
+ _vm->input()->quickSaveReset();
+ _vm->input()->quickLoadReset();
+
+ if (_songBeforeComic > 0)
+ _vm->sound()->playSong(_songBeforeComic);
+ else if (_lastSong > 0)
+ _vm->sound()->playSong(_lastSong);
+}
+
+void Cutaway::stop() {
+ // Lines 1901-2032 in cutaway.c
+ byte *ptr = _gameStatePtr;
+
+ // Skipping GAMESTATE data
+ int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
+ if (gameStateCount > 0)
+ ptr += (gameStateCount * 12);
+
+ // Get the final room and Joe's final position
+
+ int16 joeRoom = READ_BE_UINT16(ptr); ptr += 2;
+ int16 joeX = READ_BE_UINT16(ptr); ptr += 2;
+ int16 joeY = READ_BE_UINT16(ptr); ptr += 2;
+
+ debug(6, "[Cutaway::stop] Final position is room %i and coordinates (%i, %i)",
+ joeRoom, joeX, joeY);
+
+ if ((!_vm->input()->cutawayQuit() || (!_anotherCutaway && joeRoom == _finalRoom)) &&
+ joeRoom != _temporaryRoom &&
+ joeRoom != 0) {
+
+ debug(6, "[Cutaway::stop] Changing rooms and moving Joe");
+
+ _vm->logic()->joePos(joeX, joeY);
+ _vm->logic()->currentRoom(joeRoom);
+ _vm->logic()->oldRoom(_initialRoom);
+ _vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE_XY, 0, _comPanel, true);
+ }
+
+ if (_vm->input()->cutawayQuit()) {
+ // Lines 1927-2032 in cutaway.c
+ int i;
+
+ // Stop the credits from running
+ _vm->logic()->stopCredits();
+
+ _vm->graphics()->stopBobs();
+
+ for (i = 1; i <= _personFaceCount; i++) {
+ int index = _personFace[i].index;
+ if (index > 0) {
+ _vm->logic()->objectData(_personFace[i].index)->image = _personFace[i].image;
+
+ _vm->graphics()->bob(_vm->logic()->findBob(index))->xflip =
+ (_personFace[i].image != -4);
+ }
+ }
+
+ int quitObjectCount = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ for (i = 0; i < quitObjectCount; i++) {
+ int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 fromIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 x = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 y = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 room = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 frame = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 bank = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ int bobIndex = _vm->logic()->findBob(objectIndex);
+ ObjectData *object = _vm->logic()->objectData(objectIndex);
+
+ if (fromIndex > 0) {
+ if (fromIndex == objectIndex) {
+ // Enable object
+ object->name = ABS(object->name);
+ } else {
+ _vm->logic()->objectCopy(fromIndex, objectIndex);
+
+ ObjectData *from = _vm->logic()->objectData(fromIndex);
+ if (object->image && !from->image && bobIndex && _vm->logic()->currentRoom() == object->room)
+ _vm->graphics()->bob(bobIndex)->clear();
+ }
+
+ if (_vm->logic()->currentRoom() == room)
+ _vm->graphics()->refreshObject(objectIndex);
+ }
+
+ if (_vm->logic()->currentRoom() == object->room) {
+ BobSlot *pbs = _vm->graphics()->bob(bobIndex);
+
+ if (x || y) {
+ pbs->x = x;
+ pbs->y = y;
+ if (inRange(object->image, -4, -3))
+ pbs->scale = _vm->grid()->findScale(x, y);
+ }
+
+ if (frame) {
+ if (0 == bank)
+ bank = 15;
+ else if (bank != 13) {
+ _vm->bankMan()->load(_bankNames[bank-1], CUTAWAY_BANK);
+ bank = 8;
+ }
+
+ int objectFrame = _vm->logic()->findFrame(objectIndex);
+
+ if (objectFrame == 1000) {
+ _vm->graphics()->bob(bobIndex)->clear();
+ } else if (objectFrame) {
+ _vm->bankMan()->unpack(ABS(frame), objectFrame, bank);
+ pbs->frameNum = objectFrame;
+ if (frame < 0)
+ pbs->xflip = true;
+
+ }
+ }
+ }
+ } // for ()
+
+ int16 specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
+ if (specialMove > 0)
+ _vm->logic()->executeSpecialMove(specialMove);
+
+ _lastSong = (int16)READ_BE_INT16(ptr); ptr += 2;
+ }
+
+ if (joeRoom == _temporaryRoom &&
+ joeRoom != 37 && joeRoom != 105 && joeRoom != 106 &&
+ (joeX || joeY)) {
+ BobSlot *joeBob = _vm->graphics()->bob(0);
+
+ debug(6, "[Cutaway::stop] Moving Joe");
+
+ joeBob->x = joeX;
+ joeBob->y = joeY;
+ _vm->logic()->joeScale(_vm->grid()->findScale(joeX, joeY));
+ _vm->logic()->joeFace();
+ }
+}
+
+void Cutaway::updateGameState() {
+ // Lines 2047-2115 in cutaway.c
+ byte *ptr = _gameStatePtr;
+
+ int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ for (int i = 0; i < gameStateCount; i++) {
+ int16 stateIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 stateValue = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 areaIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 areaSubIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ int16 fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ bool update = false;
+
+ if (stateIndex > 0) {
+ if (_vm->logic()->gameState(stateIndex) == stateValue)
+ update = true;
+ } else {
+ _vm->logic()->gameState(ABS(stateIndex), stateValue);
+ update = true;
+ }
+
+ if (update) {
+
+ if (objectIndex > 0) { // Show the object
+ ObjectData *objectData = _vm->logic()->objectData(objectIndex);
+ objectData->name = ABS(objectData->name);
+ if (fromObject > 0)
+ _vm->logic()->objectCopy(fromObject, objectIndex);
+ _vm->graphics()->refreshObject(objectIndex);
+ } else if (objectIndex < 0) { // Hide the object
+ objectIndex = -objectIndex;
+ ObjectData *objectData = _vm->logic()->objectData(objectIndex);
+ objectData->name = -ABS(objectData->name);
+ _vm->graphics()->refreshObject(objectIndex);
+ }
+
+ if (areaIndex > 0) {
+
+ // Turn area on or off
+
+ if (areaSubIndex > 0) {
+ Area *area = _vm->grid()->area(areaIndex, areaSubIndex);
+ area->mapNeighbours = ABS(area->mapNeighbours);
+ } else {
+ Area *area = _vm->grid()->area(areaIndex, ABS(areaSubIndex));
+ area->mapNeighbours = -ABS(area->mapNeighbours);
+ }
+ }
+
+ }
+ } // for ()
+}
+
+void Cutaway::talk(char *nextFilename) {
+ const char *p = strrchr(_talkFile, '.');
+ if (p && 0 == scumm_stricmp(p, ".dog")) {
+ nextFilename[0] = '\0';
+ assert(_talkTo > 0);
+ int personInRoom = _talkTo - _vm->logic()->roomData(_vm->logic()->currentRoom());
+ _vm->logic()->startDialogue(_talkFile, personInRoom, nextFilename);
+ }
+}
+
+int Cutaway::makeComplexAnimation(int16 currentImage, Cutaway::CutawayAnim *objAnim, int frameCount) {
+ int frameIndex[256];
+ int i;
+ assert(frameCount < 30);
+ AnimFrame cutAnim[30];
+
+ memset(frameIndex, 0, sizeof(frameIndex));
+ debug(6, "[Cutaway::makeComplexAnimation] currentImage = %i", currentImage);
+
+ for (i = 0; i < frameCount; i++) {
+ cutAnim[i].frame = objAnim[i].unpackFrame;
+ cutAnim[i].speed = objAnim[i].speed;
+ frameIndex[objAnim[i].unpackFrame] = 1;
+ }
+
+ cutAnim[frameCount].frame = 0;
+ cutAnim[frameCount].speed = 0;
+
+ int nextFrameIndex = 1;
+
+ for (i = 1; i < 256; i++)
+ if (frameIndex[i])
+ frameIndex[i] = nextFrameIndex++;
+
+ for (i = 0; i < frameCount; i++) {
+ cutAnim[i].frame = currentImage + frameIndex[objAnim[i].unpackFrame];
+ }
+
+ for (i = 1; i < 256; i++) {
+ if (frameIndex[i]) {
+ currentImage++;
+ _vm->bankMan()->unpack(i, currentImage, objAnim[0].bank);
+ }
+ }
+
+ _vm->graphics()->setBobCutawayAnim(objAnim[0].object, objAnim[0].flip, cutAnim, frameCount + 1);
+ return currentImage;
+}
+
+void Cutaway::handleText(
+ int index,
+ ObjectType type,
+ CutawayObject &object,
+ const char *sentence) {
+ // lines 1776-1863 in cutaway.c
+
+ int spaces = countSpaces(type, sentence);
+
+ int x;
+ int flags;
+
+ if (OBJECT_TYPE_TEXT_DISPLAY == type) {
+ x = _vm->display()->textCenterX(sentence);
+ flags = 2;
+ } else {
+ x = object.bobStartX;
+ flags = 1;
+ }
+
+ BobSlot *bob =
+ _vm->graphics()->bob( _vm->logic()->findBob(ABS(object.objectNumber)) );
+
+ _vm->graphics()->setBobText(bob, sentence, x, object.bobStartY, object.specialMove, flags);
+
+ if (OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) {
+ if (_vm->sound()->speechOn()) {
+ char voiceFileName[MAX_STRING_SIZE];
+ findCdCut(_basename, index, voiceFileName);
+ strcat(voiceFileName, "1");
+ _vm->sound()->playSfx(voiceFileName, true);
+ }
+
+ if (OBJECT_TYPE_TEXT_SPEAK == type && _vm->sound()->speechOn() && !_vm->subtitles())
+ _vm->display()->clearTexts(0, 150);
+ }
+
+ while (1) {
+ _vm->update();
+
+ if (_vm->input()->cutawayQuit())
+ return;
+
+ if (_vm->input()->keyVerb() == VERB_SKIP_TEXT) {
+ _vm->input()->clearKeyVerb();
+ break;
+ }
+
+ if ((OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) && _vm->sound()->speechOn() && _vm->sound()->speechSfxExists()) {
+ if (!_vm->sound()->isSpeechActive()) {
+ break;
+ }
+ } else {
+ --spaces;
+ if (spaces <= 0) {
+ break;
+ }
+ }
+ }
+
+ _vm->display()->clearTexts(0, 198);
+ _vm->update();
+}
+
+int Cutaway::countSpaces(ObjectType type, const char *segment) {
+ int tmp = 0;
+
+ while (*segment++)
+ tmp++;
+
+ if (tmp < 50)
+ tmp = 50;
+
+ if (OBJECT_TYPE_TEXT_DISPLAY == type)
+ tmp *= 3;
+
+ return (tmp * 2) / (_vm->talkSpeed() / 3);
+
+}
+
+int Cutaway::scale(CutawayObject &object) {
+ int scaling = 100;
+
+ if (object.scale > 0)
+ scaling = object.scale;
+ else if (!object.objectNumber) {
+ // Only scale Joe
+ int x, y;
+
+ if (object.bobStartX > 0 || object.bobStartY > 0) {
+ x = object.bobStartX;
+ y = object.bobStartY;
+ } else {
+ BobSlot *bob = _vm->graphics()->bob(0);
+ x = bob->x;
+ y = bob->y;
+ }
+
+ int zone = _vm->grid()->findAreaForPos(GS_ROOM, x, y);
+ if (zone > 0) {
+ Area *area = _vm->grid()->area(_vm->logic()->currentRoom(), zone);
+ scaling = area->calcScale(y);
+ }
+ }
+
+ return scaling;
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/cutaway.h b/engines/queen/cutaway.h
new file mode 100644
index 0000000000..bbf5ec0652
--- /dev/null
+++ b/engines/queen/cutaway.h
@@ -0,0 +1,265 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENCUTAWAY_H
+#define QUEENCUTAWAY_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+class QueenEngine;
+
+class Cutaway {
+public:
+
+ //! Public interface to run a cutaway from a file
+ static void run(const char *filename, char *nextFilename, QueenEngine *vm);
+
+ //! Collection of constants used by QueenCutaway
+ enum {
+ PREVIOUS_ROOM = 0,
+ CURRENT_ROOM = 0,
+ OBJECT_ROOMFADE = -1,
+ PERSON_JOE = -1,
+ OBJECT_JOE = 0,
+ MAX_PERSON_COUNT = 6,
+ CUTAWAY_BANK = 8,
+ MAX_BANK_NAME_COUNT = 5,
+ MAX_FILENAME_LENGTH = 12,
+ MAX_FILENAME_SIZE = (MAX_FILENAME_LENGTH + 1),
+ MAX_PERSON_FACE_COUNT = 13,
+ MAX_STRING_LENGTH = 255,
+ MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
+ LEFT = 1,
+ RIGHT = 2,
+ FRONT = 3,
+ BACK = 4
+ };
+
+ //! Different kinds of cutaway objects
+ enum ObjectType {
+ OBJECT_TYPE_ANIMATION = 0,
+ OBJECT_TYPE_PERSON = 1,
+ OBJECT_TYPE_NO_ANIMATION = 2,
+ OBJECT_TYPE_TEXT_SPEAK = 3,
+ OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK = 4,
+ OBJECT_TYPE_TEXT_DISPLAY = 5
+ };
+
+private:
+ //! Data for a cutaway object
+ struct CutawayObject {
+ int16 objectNumber; // 0 = JOE, -1 = MESSAGE
+ int16 moveToX;
+ int16 moveToY;
+ int16 bank; // 0 = PBOB, 13 = Joe Bank, else BANK NAMEstr()
+ int16 animList;
+ int16 execute; // 1 Yes, 0 No
+ int16 limitBobX1;
+ int16 limitBobY1;
+ int16 limitBobX2;
+ int16 limitBobY2;
+ int16 specialMove;
+ int16 animType; // 0 - Packet, 1 - Amal, 2 - Unpack
+ int16 fromObject;
+ int16 bobStartX;
+ int16 bobStartY;
+ int16 room;
+ int16 scale;
+ // Variables derived from the variables above
+ int song;
+
+ //! People to turn on
+ int person[MAX_PERSON_COUNT];
+
+ //! Number of elements used in _person array
+ int personCount;
+ };
+
+ struct CutawayAnim {
+ int16 object;
+ int16 unpackFrame; // Frame to unpack
+ int16 speed;
+ int16 bank;
+ int16 mx;
+ int16 my;
+ int16 cx;
+ int16 cy;
+ int16 scale;
+ int16 currentFrame; // Index to Current Frame
+ int16 originalFrame; // Index to Original Object Frame
+ int16 song;
+ bool flip; // set this if unpackFrame is negative
+ };
+
+ struct ObjectDataBackup {
+ int index;
+ int16 name;
+ int16 image;
+ };
+
+ struct PersonFace {
+ int16 index;
+ int16 image;
+ };
+
+ QueenEngine *_vm;
+
+ //! Raw .cut file data (without 20 byte header)
+ byte *_fileData;
+
+ //! COMPANEL
+ int16 _comPanel;
+
+ //! Game state data inside of _fileDat
+ byte *_gameStatePtr;
+
+ //! Actual cutaway data inside of _fileData
+ byte *_objectData;
+
+ //! Pointer to next sentence string in _fileData
+ uint16 _nextSentenceOff;
+
+ //! ???
+ bool _roomFade;
+
+ //! Number of cutaway objects at _cutawayData
+ int16 _cutawayObjectCount;
+
+ //! This cutaway is followed by another
+ bool _anotherCutaway;
+
+ //! Room before cutaway
+ int _initialRoom;
+
+ //! Temporary room for cutaway
+ int _temporaryRoom;
+
+ //! Room to stay in
+ int _finalRoom;
+
+ //! Bank names
+ char _bankNames[MAX_BANK_NAME_COUNT][MAX_FILENAME_SIZE];
+
+ //! Filename without ".cut"
+ char _basename[MAX_FILENAME_SIZE];
+
+ //! Name of .dog file
+ char _talkFile[MAX_FILENAME_SIZE];
+
+ //! Person to talk to
+ int16 _talkTo;
+
+ //! Used by changeRooms
+ ObjectDataBackup _personData[MAX_PERSON_COUNT];
+
+ //! Number of elements used in _personData array
+ int _personDataCount;
+
+ //! Used by handlePersonRecord()
+ PersonFace _personFace[MAX_PERSON_FACE_COUNT];
+
+ //! Number of entries in _personFace array
+ int _personFaceCount;
+
+ //! Play this song when leaving cutaway
+ int16 _lastSong;
+
+ //! Song played before running comic.cut
+ int16 _songBeforeComic;
+
+ int16 _currentImage;
+
+ Cutaway(const char *filename, QueenEngine *vm);
+ ~Cutaway();
+
+ //! Run this cutaway object
+ void run(char *nextFilename);
+
+ //! Load cutaway data from file
+ void load(const char *filename);
+
+ //! Used by load to read string data
+ void loadStrings(uint16 offset);
+
+ //! Get persons
+ const byte *turnOnPeople(const byte *ptr, CutawayObject &object);
+
+ //! Limit the BOB
+ void limitBob(CutawayObject &object);
+
+ //! This cutaway object occurs in another room
+ void changeRooms(CutawayObject &object);
+
+ //! Get the object type for this CutawayObject
+ ObjectType getObjectType(CutawayObject &object);
+
+ //! Perform actions for an animation
+ const byte *handleAnimation(const byte *ptr, CutawayObject &object);
+
+ //! Perform actions for a person record
+ void handlePersonRecord(int index, CutawayObject &object, const char *sentence);
+
+ //! Perform text actions
+ void handleText(int index, ObjectType type, CutawayObject &object, const char *sentence);
+
+ //! Restore Logic::_objectData from _personData
+ void restorePersonData();
+
+ //! Stop the cutaway
+ void stop();
+
+ //! Update game state after cutaway
+ void updateGameState();
+
+ //! Prepare for talk after cutaway
+ void talk(char *nextFilename);
+
+ //! Get CutawayAnim data from ptr and return new ptr
+ const byte *getCutawayAnim(const byte *ptr, int header, CutawayAnim &anim);
+
+ //! Special animation
+ int makeComplexAnimation(int16 currentImage, CutawayAnim *objAnim, int frameCount);
+
+ //! Read a CutawayObject from ptr and return new ptr
+ static const byte *getCutawayObject(const byte *ptr, CutawayObject &object);
+
+ //! Dump a CutawayObject with debug()
+ void dumpCutawayObject(int index, CutawayObject &object);
+
+ //! Used by handleText()
+ int countSpaces(ObjectType type, const char *segment);
+
+ //! Scale Joe
+ int scale(CutawayObject &object);
+
+ //! Dump CutawayAnum data with debug()
+ static void dumpCutawayAnim(CutawayAnim &anim);
+
+ bool inRange(int16 x, int16 l, int16 h) const { return (x <= h && x >= l); }
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/debug.cpp b/engines/queen/debug.cpp
new file mode 100644
index 0000000000..63fc40f444
--- /dev/null
+++ b/engines/queen/debug.cpp
@@ -0,0 +1,219 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/debug.h"
+
+#include "queen/graphics.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+
+#include "common/debugger.cpp"
+
+namespace Queen {
+
+Debugger::Debugger(QueenEngine *vm)
+ : _vm(vm), _flags(0) {
+
+ DCmd_Register("exit", &Debugger::Cmd_Exit);
+ DCmd_Register("help", &Debugger::Cmd_Help);
+ DCmd_Register("areas", &Debugger::Cmd_Areas);
+ DCmd_Register("asm", &Debugger::Cmd_Asm);
+ DCmd_Register("bob", &Debugger::Cmd_Bob);
+ DCmd_Register("bobs", &Debugger::Cmd_PrintBobs);
+ DCmd_Register("gs", &Debugger::Cmd_GameState);
+ DCmd_Register("info", &Debugger::Cmd_Info);
+ DCmd_Register("items", &Debugger::Cmd_Items);
+ DCmd_Register("room", &Debugger::Cmd_Room);
+ DCmd_Register("song", &Debugger::Cmd_Song);
+}
+
+Debugger::~Debugger() {} // we need this here for __SYMBIAN32__
+void Debugger::preEnter() {
+}
+
+void Debugger::postEnter() {
+ _vm->graphics()->setupMouseCursor();
+}
+
+bool Debugger::Cmd_Exit(int argc, const char **argv) {
+ _detach_now = true;
+ return false;
+}
+
+bool Debugger::Cmd_Help(int argc, const char **argv) {
+ // console normally has 39 line width
+ // wrap around nicely
+ int width = 0, size, i;
+
+ DebugPrintf("Commands are:\n");
+ for (i = 0 ; i < _dcmd_count ; i++) {
+ size = strlen(_dcmds[i].name) + 1;
+
+ if ((width + size) >= 39) {
+ DebugPrintf("\n");
+ width = size;
+ } else
+ width += size;
+
+ DebugPrintf("%s ", _dcmds[i].name);
+ }
+ DebugPrintf("\n");
+ return true;
+}
+
+bool Debugger::Cmd_Asm(int argc, const char **argv) {
+ if (argc == 2) {
+ uint16 sm = atoi(argv[1]);
+ _vm->logic()->executeSpecialMove(sm);
+ return false;
+ } else {
+ DebugPrintf("Usage: %s smnum\n", argv[0]);
+ }
+ return true;
+}
+
+bool Debugger::Cmd_Areas(int argc, const char **argv) {
+ _flags ^= DF_DRAW_AREAS;
+ DebugPrintf("Room areas display %s\n", (_flags & DF_DRAW_AREAS) != 0 ? "on" : "off");
+ return true;
+}
+
+bool Debugger::Cmd_Bob(int argc, const char **argv) {
+ if (argc >= 3) {
+ int bobNum = atoi(argv[1]);
+ if (bobNum >= Graphics::MAX_BOBS_NUMBER) {
+ DebugPrintf("Bob %d is out of range (range: 0 - %d)\n", bobNum, Graphics::MAX_BOBS_NUMBER);
+ } else {
+ int param = (argc > 3) ? atoi(argv[3]) : 0;
+ BobSlot *bob = _vm->graphics()->bob(bobNum);
+ if (!strcmp(argv[2], "toggle")) {
+ bob->active = !bob->active;
+ DebugPrintf("bob[%d].active = %d\n", bobNum, bob->active);
+ } else if (!strcmp(argv[2], "x")) {
+ bob->x = param;
+ DebugPrintf("bob[%d].x = %d\n", bobNum, bob->x);
+ } else if (!strcmp(argv[2], "y")) {
+ bob->y = param;
+ DebugPrintf("bob[%d].y = %d\n", bobNum, bob->y);
+ } else if (!strcmp(argv[2], "frame")) {
+ bob->frameNum = param;
+ DebugPrintf("bob[%d].frameNum = %d\n", bobNum, bob->frameNum);
+ } else if (!strcmp(argv[2], "speed")) {
+ bob->speed = param;
+ DebugPrintf("bob[%d].speed = %d\n", bobNum, bob->speed);
+ } else {
+ DebugPrintf("Unknown bob command '%s'\n", argv[2]);
+ }
+ }
+ } else {
+ DebugPrintf("Usage: %s bobnum command parameter\n", argv[0]);
+ }
+ return true;
+}
+
+bool Debugger::Cmd_GameState(int argc, const char **argv) {
+ uint16 slot;
+ switch (argc) {
+ case 2:
+ slot = atoi(argv[1]);
+ DebugPrintf("GAMESTATE[%d] ", slot);
+ DebugPrintf("is %d\n", _vm->logic()->gameState(slot));
+ break;
+ case 3:
+ slot = atoi(argv[1]);
+ DebugPrintf("GAMESTATE[%d] ", slot);
+ DebugPrintf("was %d ", _vm->logic()->gameState(slot));
+ _vm->logic()->gameState(slot, atoi(argv[2]));
+ DebugPrintf("now %d\n", _vm->logic()->gameState(slot));
+ break;
+ default:
+ DebugPrintf("Usage: %s slotnum value\n", argv[0]);
+ break;
+ }
+ return true;
+}
+
+bool Debugger::Cmd_Info(int argc, const char **argv) {
+ DebugPrintf("Version: %s\n", _vm->resource()->JASVersion());
+ DebugPrintf("Audio compression: %d\n", _vm->resource()->compression());
+ return true;
+}
+
+bool Debugger::Cmd_Items(int argc, const char **argv) {
+ int n = _vm->logic()->itemDataCount();
+ ItemData *item = _vm->logic()->itemData(1);
+ while (n--) {
+ item->name = ABS(item->name);
+ ++item;
+ }
+ DebugPrintf("Enabled all inventory items\n");
+ return true;
+}
+
+bool Debugger::Cmd_PrintBobs(int argc, const char**argv) {
+ int i;
+ BobSlot *bob = _vm->graphics()->bob(0);
+ DebugPrintf("+--------------------------------+\n");
+ DebugPrintf("|# | x| y|f|scl|frm|a|m| ex| ey|\n");
+ DebugPrintf("+--+---+---+-+---+---+-+-+---+---+\n");
+ for (i = 0; i < Graphics::MAX_BOBS_NUMBER; ++i, ++bob) {
+ if (bob->active) {
+ DebugPrintf("|%2d|%3d|%3d|%1d|%3d|%3d|%1d|%1d|%3d|%3d|\n",
+ i, bob->x, bob->y, bob->xflip, bob->scale, bob->frameNum,
+ bob->animating, bob->moving, bob->speed, bob->endx, bob->endy);
+ }
+ }
+ DebugPrintf("+--------------------------------+\n");
+ return true;
+}
+
+bool Debugger::Cmd_Room(int argc, const char **argv) {
+ if (argc == 2) {
+ uint16 roomNum = atoi(argv[1]);
+ _vm->logic()->joePos(0, 0);
+ _vm->logic()->newRoom(roomNum);
+ _vm->logic()->entryObj(_vm->logic()->roomData(roomNum) + 1);
+ return false;
+ } else {
+ DebugPrintf("Current room: %d (%s), use '%s <roomnum>' to switch\n",
+ _vm->logic()->currentRoom(),
+ _vm->logic()->roomName(_vm->logic()->currentRoom()),
+ argv[0]);
+ }
+ return true;
+}
+
+bool Debugger::Cmd_Song(int argc, const char **argv) {
+ if (argc == 2) {
+ int16 songNum = atoi(argv[1]);
+ _vm->sound()->playSong(songNum);
+ DebugPrintf("Playing song %d\n", songNum);
+ } else {
+ DebugPrintf("Usage: %s songnum\n", argv[0]);
+ }
+ return true;
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/debug.h b/engines/queen/debug.h
new file mode 100644
index 0000000000..40cb8bb6ff
--- /dev/null
+++ b/engines/queen/debug.h
@@ -0,0 +1,69 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENDEBUG_H
+#define QUEENDEBUG_H
+
+#include "common/debugger.h"
+
+namespace Queen {
+
+class QueenEngine;
+
+class Debugger : public Common::Debugger<Debugger> {
+public:
+
+ Debugger(QueenEngine *vm);
+ virtual ~Debugger(); // we need this here for __SYMBIAN32__ archaic gcc/UIQ
+
+ int flags() const { return _flags; }
+
+ enum {
+ DF_DRAW_AREAS = 1 << 0
+ };
+
+protected:
+
+ virtual void preEnter();
+ virtual void postEnter();
+
+ bool Cmd_Exit(int argc, const char **argv);
+ bool Cmd_Help(int argc, const char **argv);
+ bool Cmd_Areas(int argc, const char **argv);
+ bool Cmd_Asm(int argc, const char **argv);
+ bool Cmd_Bob(int argc, const char **argv);
+ bool Cmd_GameState(int argc, const char **argv);
+ bool Cmd_Info(int argc, const char **argv);
+ bool Cmd_Items(int argc, const char **argv);
+ bool Cmd_PrintBobs(int argc, const char **argv);
+ bool Cmd_Room(int argc, const char **argv);
+ bool Cmd_Song(int argc, const char **argv);
+
+private:
+
+ QueenEngine *_vm;
+ int _flags;
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/defs.h b/engines/queen/defs.h
new file mode 100644
index 0000000000..223e539894
--- /dev/null
+++ b/engines/queen/defs.h
@@ -0,0 +1,322 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENDEFS_H
+#define QUEENDEFS_H
+
+namespace Queen {
+
+#define SAVEGAME_SIZE 24622
+
+enum {
+ COMPRESSION_NONE = 0,
+ COMPRESSION_MP3 = 1,
+ COMPRESSION_OGG = 2,
+ COMPRESSION_FLAC = 3
+};
+
+enum {
+ GAME_SCREEN_WIDTH = 320,
+ GAME_SCREEN_HEIGHT = 200,
+ ROOM_ZONE_HEIGHT = 150,
+ PANEL_ZONE_HEIGHT = 50
+};
+
+
+enum {
+ FRAMES_JOE = 38,
+ FRAMES_JOURNAL = 40
+};
+
+
+enum Direction {
+ DIR_LEFT = 1,
+ DIR_RIGHT = 2,
+ DIR_FRONT = 3,
+ DIR_BACK = 4
+};
+
+
+enum {
+ INK_BG_PANEL = 226,
+ INK_JOURNAL = 248,
+ INK_PINNACLE_ROOM = 243,
+ INK_CMD_SELECT = 255,
+ INK_CMD_NORMAL = 225,
+ INK_CMD_LOCK = 234,
+ INK_TALK_NORMAL = 7,
+ INK_JOE = 14,
+ INK_OUTLINED_TEXT = 16
+};
+
+
+enum {
+ ITEM_NONE = 0,
+ ITEM_BAT,
+ ITEM_JOURNAL,
+ ITEM_KNIFE,
+ ITEM_COCONUT_HALVES,
+ ITEM_BEEF_JERKY,
+ ITEM_PROPELLER,
+ ITEM_BANANA,
+ ITEM_VINE,
+ ITEM_SLOTH_HAIR,
+ ITEM_COMIC_BOOK,
+ ITEM_FLOWER,
+ ITEM_BEETLE,
+ ITEM_ORCHID,
+ ITEM_DICTIONARY,
+ ITEM_DEATH_MASH,
+ ITEM_PERFUME,
+ ITEM_TYRANNO_HORN,
+ ITEM_LOTION,
+ ITEM_RECORD,
+ ITEM_VACUUM_CLEANER,
+ ITEM_NET,
+ ITEM_ALCOHOL,
+ ITEM_ROCKET_PACK,
+ ITEM_SOME_MONEY,
+ ITEM_CHEESE_BITZ,
+ ITEM_DOG_FOOD,
+ ITEM_CAN_OPENER,
+ ITEM_LETTER,
+ ITEM_SQUEAKY_TOY,
+ ITEM_KEY,
+ ITEM_BOOK,
+ ITEM_PIECE_OF_PAPER,
+ ITEM_ROCKET_PLAN,
+ ITEM_PADLOCK_KEY,
+ ITEM_RIB_CAGE,
+ ITEM_SKULL,
+ ITEM_LEG_BONE,
+ ITEM_BAT2,
+ ITEM_MAKESHIFT_TOCH,
+ ITEM_LIGHTER,
+ ITEM_GREEN_JEWEL,
+ ITEM_PICK,
+ ITEM_STONE_KEY,
+ ITEM_BLUE_JEWEL,
+ ITEM_CRYSTAL_SKULL,
+ ITEM_TREE_SAP,
+ ITEM_DINO_RAY_GUN,
+ ITEM_BRANCHES,
+ ITEM_WIG,
+ ITEM_TOWEL,
+ ITEM_OTHER_SHEET,
+ ITEM_SHEET,
+ ITEM_SHEET_ROPE,
+ ITEM_CROWBAR,
+ ITEM_COMEDY_BREASTS,
+ ITEM_DRESS,
+ ITEM_KEY2,
+ ITEM_CLOTHES,
+ ITEM_HAY,
+ ITEM_OIL,
+ ITEM_CHICKEN,
+ ITEM_LIT_TORCH,
+ ITEM_OPENED_DOG_FOOD,
+ ITEM_SOME_MONEY2,
+ ITEM_SOME_MORE_MONEY,
+ ITEM_PEELED_BANANA,
+ ITEM_STONE_DISC,
+ ITEM_GNARLED_VINE,
+ ITEM_FLINT,
+ ITEM_LIGHTER2,
+ ITEM_REST_OF_BEEF_JERKY,
+ ITEM_LOTS_OF_MONEY,
+ ITEM_HEAPS_OF_MONEY,
+ ITEM_OPEN_BOOK,
+ ITEM_REST_OF_THE_CHEESE_BITZ,
+ ITEM_SCISSORS,
+ ITEM_PENCIL,
+ ITEM_SUPER_WEENIE_SERUM,
+ ITEM_MUMMY_WRAPPINGS,
+ ITEM_COCONUT,
+ ITEM_ID_CARD,
+ ITEM_BIT_OF_STONE,
+ ITEM_CHUNK_OF_ROCK,
+ ITEM_BIG_STICK,
+ ITEM_STICKY_BIT_OF_STONE,
+ ITEM_STICKY_CHUNK_OF_ROCK,
+ ITEM_DEATH_MASK2,
+ ITEM_CHEFS_SURPRISE,
+ ITEM_STICKY_BAT,
+ ITEM_REST_OF_WRAPPINGS,
+ ITEM_BANANA2,
+ ITEM_MUG,
+ ITEM_FILE,
+ ITEM_POCKET_ROCKET_BLUEPRINTS,
+ ITEM_HAND_PUPPET,
+ ITEM_ARM_BONE,
+ ITEM_CROWN,
+ ITEM_COMIC_COUPON,
+ ITEM_TORN_PAGE
+};
+
+enum {
+ ROOM_JUNGLE_INSIDE_PLANE = 1,
+ ROOM_JUNGLE_OUTSIDE_PLANE = 2,
+ ROOM_JUNGLE_BRIDGE = 4,
+ ROOM_JUNGLE_GORILLA_1 = 6,
+ ROOM_JUNGLE_PINNACLE = 7,
+ ROOM_JUNGLE_SLOTH = 8,
+ ROOM_JUNGLE_BUD_SKIP = 9,
+ ROOM_JUNGLE_BEETLE = 11,
+ ROOM_JUNGLE_MISSIONARY = 13,
+ ROOM_JUNGLE_GORILLA_2 = 14,
+
+ ROOM_AMAZON_ENTRANCE = 16,
+ ROOM_AMAZON_HIDEOUT = 17,
+ ROOM_AMAZON_THRONE = 18,
+ ROOM_AMAZON_JAIL = 19,
+
+ ROOM_VILLAGE = 20,
+ ROOM_TRADER_BOBS = 21,
+
+ ROOM_FLODA_OUTSIDE = 22,
+ ROOM_FLODA_KITCHEN = 26,
+ ROOM_FLODA_LOCKERROOM = 27,
+ ROOM_FLODA_KLUNK = 30,
+ ROOM_FLODA_HENRY = 32,
+ ROOM_FLODA_OFFICE = 35,
+ ROOM_FLODA_JAIL = 41,
+ ROOM_FLODA_FRONTDESK = 103,
+
+ ROOM_TEMPLE_OUTSIDE = 43,
+ ROOM_TEMPLE_MUMMIES = 46,
+ ROOM_TEMPLE_ZOMBIES = 50,
+ ROOM_TEMPLE_TREE = 51,
+ ROOM_TEMPLE_SNAKE = 53,
+ ROOM_TEMPLE_LIZARD_LASER = 55,
+ ROOM_TEMPLE_MAZE = 58,
+ ROOM_TEMPLE_MAZE_2 = 59,
+ ROOM_TEMPLE_MAZE_3 = 60,
+ ROOM_TEMPLE_MAZE_4 = 61,
+ ROOM_TEMPLE_MAZE_5 = 100,
+ ROOM_TEMPLE_MAZE_6 = 101,
+
+ ROOM_VALLEY_CARCASS = 67,
+
+ ROOM_HOTEL_UPSTAIRS = 70,
+ ROOM_HOTEL_DOWNSTAIRS = 71,
+ ROOM_HOTEL_LOLA = 72,
+ ROOM_HOTEL_LOBBY = 73,
+
+ ROOM_CAR_CHASE = 74,
+
+ ROOM_FINAL_FIGHT = 69,
+
+ ROOM_INTRO_RITA_JOE_HEADS = 116,
+ ROOM_INTRO_EXPLOSION = 123,
+
+ //special
+ SPARKY_OUTSIDE_HOTEL = 77,
+ DEATH_MASK = 79,
+ IBI_LOGO = 82,
+ COMIC_1 = 87,
+ COMIC_2 = 88,
+ COMIC_3 = 89,
+ ROOM_UNUSED_INTRO_1 = 90,
+ ROOM_UNUSED_INTRO_2 = 91,
+ ROOM_UNUSED_INTRO_3 = 92,
+ ROOM_UNUSED_INTRO_4 = 93,
+ ROOM_UNUSED_INTRO_5 = 94,
+ FOTAQ_LOGO = 95,
+ WARNER_LOGO = 126,
+
+ FAYE_HEAD = 37,
+ AZURA_HEAD = 106,
+ FRANK_HEAD = 107,
+
+ ROOM_ENDING_CREDITS = 110,
+
+ ROOM_JOURNAL = 200 // dummy value to keep Display methods happy
+};
+
+
+//! GameState vars
+enum {
+ VAR_HOTEL_ITEMS_REMOVED = 3,
+ VAR_JOE_DRESSING_MODE = 19,
+ VAR_BYPASS_ZOMBIES = 21,
+ VAR_BYPASS_FLODA_RECEPTIONIST = 35,
+ VAR_GUARDS_TURNED_ON = 85,
+ VAR_HOTEL_ESCAPE_STATE = 93,
+ VAR_INTRO_PLAYED = 117,
+ VAR_AZURA_IN_LOVE = 167
+};
+
+
+enum Language {
+ ENGLISH = 'E',
+ FRENCH = 'F',
+ GERMAN = 'G',
+ HEBREW = 'H',
+ ITALIAN = 'I',
+ SPANISH = 'S'
+};
+
+
+enum Verb {
+ VERB_NONE = 0,
+
+ VERB_PANEL_COMMAND_FIRST = 1,
+ VERB_OPEN = 1,
+ VERB_CLOSE = 2,
+ VERB_MOVE = 3,
+ // no verb 4
+ VERB_GIVE = 5,
+ VERB_USE = 6,
+ VERB_PICK_UP = 7,
+ VERB_LOOK_AT = 9,
+ VERB_TALK_TO = 8,
+ VERB_PANEL_COMMAND_LAST = 9,
+
+ VERB_WALK_TO = 10,
+ VERB_SCROLL_UP = 11,
+ VERB_SCROLL_DOWN = 12,
+
+ VERB_DIGIT_FIRST = 13,
+ VERB_DIGIT_1 = 13,
+ VERB_DIGIT_2 = 14,
+ VERB_DIGIT_3 = 15,
+ VERB_DIGIT_4 = 16,
+ VERB_DIGIT_LAST = 16,
+
+ VERB_INV_FIRST = VERB_DIGIT_FIRST,
+ VERB_INV_1 = VERB_DIGIT_1,
+ VERB_INV_2 = VERB_DIGIT_2,
+ VERB_INV_3 = VERB_DIGIT_3,
+ VERB_INV_4 = VERB_DIGIT_4,
+ VERB_INV_LAST = VERB_DIGIT_LAST,
+
+ VERB_USE_JOURNAL = 20,
+ VERB_SKIP_TEXT = 101,
+
+ VERB_PREP_WITH = 11,
+ VERB_PREP_TO = 12
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp
new file mode 100644
index 0000000000..d56e472e30
--- /dev/null
+++ b/engines/queen/display.cpp
@@ -0,0 +1,1307 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "queen/display.h"
+
+#include "queen/input.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+
+namespace Queen {
+
+#ifdef PALMOS_68K
+static const uint8 *_fontRegular;
+static const uint8 *_fontHebrew;
+static const uint8 *_palJoeClothes;
+static const uint8 *_palJoeDress;
+#endif
+
+Display::Display(QueenEngine *vm, OSystem *system)
+ : _fullscreen(true), _horizontalScroll(0), _bdWidth(0), _bdHeight(0),
+ _system(system), _vm(vm) {
+
+ if (vm->resource()->getLanguage() == HEBREW)
+ _font = _fontHebrew;
+ else
+ _font = _fontRegular;
+
+ initFont();
+
+ _screenBuf = new uint8[SCREEN_W * SCREEN_H];
+ _panelBuf = new uint8[PANEL_W * PANEL_H];
+ _backdropBuf = new uint8[BACKDROP_W * BACKDROP_H];
+ memset(_screenBuf, 0, SCREEN_W * SCREEN_H);
+ memset(_panelBuf, 0, PANEL_W * PANEL_H);
+ memset(_backdropBuf, 0, BACKDROP_W * BACKDROP_H);
+
+ _fullRefresh = 1;
+ _dirtyBlocksWidth = SCREEN_W / D_BLOCK_W;
+ _dirtyBlocksHeight = SCREEN_H / D_BLOCK_H;
+ _dirtyBlocks = new uint8[_dirtyBlocksWidth * _dirtyBlocksHeight];
+ memset(_dirtyBlocks, 0, _dirtyBlocksWidth * _dirtyBlocksHeight);
+
+ _pal.room = new uint8[ 256 * 3 ];
+ _pal.screen = new uint8[ 256 * 3 ];
+ _pal.panel = new uint8[ 112 * 3 ];
+ memset(_pal.room, 0, 256 * 3);
+ memset(_pal.screen, 0, 256 * 3);
+ memset(_pal.panel, 0, 112 * 3);
+ _pal.dirtyMin = 0;
+ _pal.dirtyMax = 255;
+ _pal.scrollable = true;
+
+ memset(&_dynalum, 0, sizeof(_dynalum));
+}
+
+Display::~Display() {
+ delete[] _backdropBuf;
+ delete[] _panelBuf;
+ delete[] _screenBuf;
+
+ delete[] _dirtyBlocks;
+
+ delete[] _pal.room;
+ delete[] _pal.screen;
+ delete[] _pal.panel;
+
+ delete[] _dynalum.mskBuf;
+ delete[] _dynalum.lumBuf;
+}
+
+void Display::dynalumInit(const char *roomName, uint16 roomNum) {
+ debug(9, "Display::dynalumInit(%s, %d)", roomName, roomNum);
+
+ _dynalum.valid = false;
+ delete[] _dynalum.mskBuf;
+ _dynalum.mskBuf = NULL;
+ delete[] _dynalum.lumBuf;
+ _dynalum.lumBuf = NULL;
+
+ if (!isPalFadingDisabled(roomNum)) {
+ char filename[20];
+ sprintf(filename, "%s.msk", roomName);
+ if (_vm->resource()->fileExists(filename)) {
+ _dynalum.mskBuf = (uint8 *)_vm->resource()->loadFile(filename, 0, &_dynalum.mskSize);
+ sprintf(filename, "%s.lum", roomName);
+ if (_vm->resource()->fileExists(filename)) {
+ _dynalum.lumBuf = (int8 *)_vm->resource()->loadFile(filename, 0, &_dynalum.lumSize);
+ _dynalum.valid = true;
+ _dynalum.prevColMask = 0xFF;
+ }
+ }
+ }
+}
+
+void Display::dynalumUpdate(int16 x, int16 y) {
+ if (!_dynalum.valid)
+ return;
+
+ if (x < 0) {
+ x = 0;
+ } else if (x > _bdWidth) {
+ x = _bdWidth;
+ }
+ if (y < 0) {
+ y = 0;
+ } else if (y > ROOM_ZONE_HEIGHT - 1) {
+ y = ROOM_ZONE_HEIGHT - 1;
+ }
+
+ uint32 offset = (y / 4) * 160 + (x / 4);
+ assert(offset < _dynalum.mskSize);
+
+ uint8 colMask = _dynalum.mskBuf[offset];
+ debug(9, "Display::dynalumUpdate(%d, %d) - colMask = %d", x, y, colMask);
+ if (colMask != _dynalum.prevColMask) {
+ for (int i = 144; i < 160; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int16 c = (int16)(_pal.room[i * 3 + j] + _dynalum.lumBuf[colMask * 3 + j] * 4);
+ if (c < 0) {
+ c = 0;
+ } else if (c > 255) {
+ c = 255;
+ }
+ _pal.screen[i * 3 + j] = (uint8)c;
+ }
+ }
+ _pal.dirtyMin = MIN(_pal.dirtyMin, 144);
+ _pal.dirtyMax = MAX(_pal.dirtyMax, 159);
+ _dynalum.prevColMask = colMask;
+ }
+}
+
+void Display::palSet(const uint8 *pal, int start, int end, bool updateScreen) {
+ debug(9, "Display::palSet(%d, %d)", start, end);
+ const int numColors = end - start + 1;
+ uint8 tempPal[256 * 4];
+ for (int i = 0; i < numColors; i++) {
+ tempPal[4 * i + 0] = *pal++;
+ tempPal[4 * i + 1] = *pal++;
+ tempPal[4 * i + 2] = *pal++;
+ tempPal[4 * i + 3] = 0;
+ }
+ _system->setPalette(tempPal, start, numColors);
+ if (updateScreen) {
+ _system->updateScreen();
+ _vm->input()->delay(20);
+ }
+}
+
+void Display::palSetJoeDress() {
+ memcpy(_pal.room + 144 * 3, _palJoeDress, 16 * 3);
+ memcpy(_pal.screen + 144 * 3, _palJoeDress, 16 * 3);
+ palSet(_pal.screen, 144, 159, true);
+}
+
+void Display::palSetJoeNormal() {
+ memcpy(_pal.room + 144 * 3, _palJoeClothes, 16 * 3);
+ memcpy(_pal.screen + 144 * 3, _palJoeClothes, 16 * 3);
+ palSet(_pal.screen, 144, 159, true);
+}
+
+void Display::palSetPanel() {
+ memcpy(_pal.room + 144 * 3, _pal.panel, (256 - 144) * 3);
+ memcpy(_pal.screen + 144 * 3, _pal.panel, (256 - 144) * 3);
+}
+
+void Display::palFadeIn(uint16 roomNum, bool dynalum, int16 dynaX, int16 dynaY) {
+ debug(9, "Display::palFadeIn(%d)", roomNum);
+ int n = getNumColorsForRoom(roomNum);
+ memcpy(_pal.screen, _pal.room, n * 3);
+ if (!isPalFadingDisabled(roomNum)) {
+ if (dynalum) {
+ dynalumUpdate(dynaX, dynaY);
+ }
+ uint8 tempPal[256 * 3];
+ for (int i = 0; i <= FADE_SPEED; ++i) {
+ for (int j = 0; j < n * 3; ++j) {
+ tempPal[j] = _pal.screen[j] * i / FADE_SPEED;
+ }
+ palSet(tempPal, 0, n - 1, true);
+ }
+ }
+ _pal.dirtyMin = 0;
+ _pal.dirtyMax = n - 1;
+ _pal.scrollable = true;
+}
+
+void Display::palFadeOut(uint16 roomNum) {
+ debug(9, "Display::palFadeOut(%d)", roomNum);
+ _pal.scrollable = false;
+ int n = getNumColorsForRoom(roomNum);
+ if (isPalFadingDisabled(roomNum)) {
+ memset(_pal.screen, 0, n * 3);
+ palSet(_pal.screen, 0, n - 1, true);
+ } else {
+ uint8 tempPal[256 * 3];
+ memcpy(tempPal, _pal.screen, n * 3);
+ for (int i = FADE_SPEED; i >= 0; --i) {
+ for (int j = 0; j < n * 3; ++j) {
+ _pal.screen[j] = tempPal[j] * i / FADE_SPEED;
+ }
+ palSet(_pal.screen, 0, n - 1, true);
+ }
+ }
+}
+
+void Display::palGreyPanel() {
+ debug(9, "Display::palGreyPanel()");
+ uint8 tempPal[256 * 3];
+ for (int i = 224 * 3; i < 256 * 3; i += 3) {
+ tempPal[i] = tempPal[i + 1] = tempPal[i + 2] = _pal.screen[i + 1] * 2 / 3;
+ }
+ palSet(tempPal, 224, 255, true);
+}
+
+void Display::palScroll(int start, int end) {
+ debug(9, "Display::palScroll(%d, %d)", start, end);
+
+ uint8 *palEnd = _pal.screen + end * 3;
+ uint8 *palStart = _pal.screen + start * 3;
+
+ uint8 r = *palEnd++;
+ uint8 g = *palEnd++;
+ uint8 b = *palEnd;
+
+ int n = (end - start) * 3;
+ while (n--) {
+ *palEnd = *(palEnd - 3);
+ --palEnd;
+ }
+
+ *palStart++ = r;
+ *palStart++ = g;
+ *palStart = b;
+}
+
+void Display::palCustomColors(uint16 roomNum) {
+ debug(9, "Display::palCustomColors(%d)", roomNum);
+ int i;
+ switch (roomNum) {
+ case 31:
+ for (i = 72; i < 84; i++) {
+ _pal.room[i * 3 + 1] = _pal.room[i * 3 + 1] * 90 / 100;
+ _pal.room[i * 3 + 2] = _pal.room[i * 3 + 2] * 70 / 100;
+ }
+ break;
+ case 29:
+ for (i = 72; i < 84; i++) {
+ _pal.room[i * 3 + 1] = _pal.room[i * 3 + 1] * 60 / 100;
+ _pal.room[i * 3 + 2] = _pal.room[i * 3 + 2] * 60 / 100;
+ }
+ break;
+ case 30:
+ for (i = 72; i < 84; i++) {
+ _pal.room[i * 3 + 0] = _pal.room[i * 3 + 0] * 60 / 100;
+ _pal.room[i * 3 + 1] = _pal.room[i * 3 + 1] * 80 / 100;
+ }
+ break;
+ case 28:
+ for (i = 72; i < 84; i++) {
+ _pal.room[i * 3 + 0] = _pal.room[i * 3 + 0] * 80 / 100;
+ _pal.room[i * 3 + 2] = _pal.room[i * 3 + 1] * 60 / 100;
+ }
+ break;
+ }
+}
+
+void Display::palCustomScroll(uint16 roomNum) {
+ debug(9, "Display::palCustomScroll(%d)", roomNum);
+ static int16 scrollx = 0;
+
+ if (!_pal.scrollable) {
+ return;
+ }
+
+ int hiPal = 0;
+ int loPal = 255;
+ int i;
+
+ ++scrollx;
+ switch (roomNum) {
+ case 123: {
+ static int16 j = 0, jdir = 2;
+ for (i = 96; i < 111; ++i) {
+ _pal.screen[i * 3 + 0] = MIN(255, _pal.room[i * 3 + 0] + j * 8);
+ _pal.screen[i * 3 + 1] = MIN(255, _pal.room[i * 3 + 1] + j * 4);
+ }
+ j += jdir;
+ if (j <= 0 || j >= 18) {
+ jdir = -jdir;
+ }
+ loPal = 96;
+ hiPal = 111;
+ }
+ break;
+ case 124: {
+ static int16 j = 0,jdir = 2;
+ for (i = 80; i < 144; ++i) {
+ _pal.screen[i * 3 + 0] = MIN(255, _pal.room[i * 3 + 0] + j * 8);
+ _pal.screen[i * 3 + 1] = MIN(255, _pal.room[i * 3 + 1] + j * 4);
+ }
+ j += jdir;
+ if (j <= 0 || j >= 14) {
+ jdir = -jdir;
+ if (_rnd.getRandomNumber(1)) {
+ if (ABS(jdir) == 1) {
+ jdir *= 2;
+ } else {
+ jdir /= 2;
+ }
+ }
+ }
+ loPal = 80;
+ hiPal = 143;
+ }
+ break;
+ case 125:
+ palScroll(32, 63);
+ palScroll(64, 95);
+ loPal = 32;
+ hiPal = 95;
+ break;
+ case 100:
+ if (scrollx & 1) {
+ palScroll(128, 132);
+ palScroll(133, 137);
+ palScroll(138, 143);
+ loPal = 128;
+ hiPal = 143;
+ }
+ break;
+ case 102:
+ if (scrollx & 1) {
+ palScroll(112, 127);
+ loPal = 112;
+ hiPal = 127;
+ }
+ break;
+ case 62:
+ if (scrollx & 1) {
+ palScroll(108, 119);
+ loPal = 108;
+ hiPal = 119;
+ }
+ break;
+ case 25:
+ palScroll(116, 123);
+ loPal = 116;
+ hiPal = 123;
+ break;
+ case 59:
+ if (scrollx & 1) {
+ palScroll(56, 63);
+ loPal = 56;
+ hiPal = 63;
+ }
+ break;
+ case 39:
+ palScroll(112, 143);
+ loPal = 112;
+ hiPal = 143;
+ break;
+ case 74:
+ palScroll(28, 31);
+ palScroll(88, 91);
+ palScroll(92, 95);
+ palScroll(128, 135);
+ if (scrollx & 1) {
+ palScroll(136, 143);
+ }
+ loPal = 28;
+ hiPal = 143;
+ break;
+ case 40:
+ if (scrollx & 1) {
+ palScroll(96, 103);
+ }
+ if (scrollx & 3) {
+ palScroll(104, 107);
+ }
+ loPal = 96;
+ hiPal = 107;
+ break;
+ case 97:
+ if (scrollx & 1) {
+ palScroll(96, 107);
+ palScroll(108, 122);
+ loPal = 96;
+ hiPal = 122;
+ }
+ break;
+ case 55:
+ palScroll(128, 143);
+ loPal = 128;
+ hiPal = 143;
+ break;
+ case 57:
+ palScroll(128, 143);
+ if (scrollx & 1) {
+ palScroll(96, 103);
+ }
+ loPal = 96;
+ hiPal = 143;
+ break;
+ case 76:
+ palScroll(88, 95);
+ loPal = 88;
+ hiPal = 95;
+ break;
+ case 2:
+ if (scrollx & 1) {
+ palScroll(120, 127);
+ loPal = 120;
+ hiPal = 127;
+ }
+ break;
+ case 3:
+ case 5:
+ if (scrollx & 1) {
+ palScroll(128, 135);
+ palScroll(136, 143);
+ loPal = 128;
+ hiPal = 143;
+ }
+ break;
+ case 7:
+ if (scrollx & 1) {
+ palScroll(119, 127);
+ loPal = 119;
+ hiPal = 127;
+ }
+ break;
+ case 42:
+ if (scrollx & 1) {
+ palScroll(118, 127);
+ palScroll(136, 143);
+ loPal = 118;
+ hiPal = 143;
+ }
+ break;
+ case 4:
+ if (scrollx & 1) {
+ palScroll(32,47);
+ }
+ palScroll(64, 70);
+ palScroll(71, 79);
+ loPal = 32;
+ hiPal = 79;
+ break;
+ case 8:
+ if (scrollx & 1) {
+ palScroll(120, 127);
+ }
+ loPal = 120;
+ hiPal = 127;
+ break;
+ case 12:
+ case 64:
+ if (scrollx & 1) {
+ palScroll(112, 119);
+ palScroll(120, 127);
+ loPal = 112;
+ hiPal = 127;
+ }
+ break;
+ case 49:
+ palScroll(101, 127);
+ loPal = 101;
+ hiPal = 127;
+ break;
+ }
+ _pal.dirtyMin = MIN(_pal.dirtyMin, loPal);
+ _pal.dirtyMax = MAX(_pal.dirtyMax, hiPal);
+}
+
+void Display::palCustomFlash() {
+ uint8 tempPal[256 * 3];
+ memset(tempPal, 255, 17 * 3);
+ memset(tempPal + 17 * 3, 0, 67 * 3);
+ memset(tempPal + 67 * 3, 255, 172 * 3);
+ // set flash palette
+ palSet(tempPal, 0, 255, true);
+ // restore original palette
+ palSet(_pal.screen, 0, 255, true);
+}
+
+void Display::palCustomLightsOff(uint16 roomNum) {
+ int end = 223;
+ int start = (roomNum == ROOM_FLODA_FRONTDESK) ? 32 : 16;
+ int n = end - start + 1;
+
+ memset(_pal.screen + start * 3, 0, n * 3);
+ palSet(_pal.screen, start, end, true);
+
+ _pal.scrollable = false;
+}
+
+void Display::palCustomLightsOn(uint16 roomNum) {
+ int end = 223;
+ int start = (roomNum == ROOM_FLODA_FRONTDESK) ? 32 : 0;
+ int n = end - start + 1;
+
+ memcpy(_pal.screen + start * 3, _pal.room + start * 3, n * 3);
+ palSet(_pal.screen, start, end, true);
+
+ _pal.dirtyMin = 0;
+ _pal.dirtyMax = 223;
+ _pal.scrollable = true;
+}
+
+int Display::getNumColorsForRoom(uint16 room) const {
+ int n = 224;
+ if (room >= 114 && room <= 125) {
+ n = 256;
+ }
+ return n;
+}
+
+bool Display::isPalFadingDisabled(uint16 room) const {
+ // introduction rooms don't fade palette
+ return (room >= 90 && room <= 94) || (room >= 115 && room <= 125);
+}
+
+void Display::screenMode(int comPanel, bool inCutaway) {
+ debug(6, "Display::screenMode(%d, %d)", comPanel, inCutaway);
+
+ if (comPanel == 2 && inCutaway) {
+ fullscreen((_bdHeight == GAME_SCREEN_HEIGHT));
+ } else if (comPanel == 1) {
+ fullscreen(false);
+ }
+}
+
+void Display::prepareUpdate() {
+ int h = GAME_SCREEN_HEIGHT;
+ if (!_fullscreen) {
+ h = ROOM_ZONE_HEIGHT;
+ memcpy(_screenBuf + SCREEN_W * ROOM_ZONE_HEIGHT, _panelBuf, PANEL_W * PANEL_H);
+ }
+ uint8 *dst = _screenBuf;
+ const uint8 *src = _backdropBuf + _horizontalScroll;
+
+ while (h--) {
+ memcpy(dst, src, SCREEN_W);
+ dst += SCREEN_W;
+ src += BACKDROP_W;
+ }
+}
+
+void Display::update(bool dynalum, int16 dynaX, int16 dynaY) {
+ drawTexts();
+ if (_pal.scrollable && dynalum) {
+ dynalumUpdate(dynaX, dynaY);
+ }
+ if (_pal.dirtyMin != 144 || _pal.dirtyMax != 144) {
+ palSet(_pal.screen, _pal.dirtyMin, _pal.dirtyMax);
+ _pal.dirtyMin = 144;
+ _pal.dirtyMax = 144;
+ }
+ // uncomment this line to disable the dirty blocks rendering
+// _fullRefresh = 1;
+ if (_fullRefresh) {
+ _system->copyRectToScreen(_screenBuf, SCREEN_W, 0, 0, SCREEN_W, SCREEN_H);
+ _system->updateScreen();
+ --_fullRefresh;
+ if (_fullRefresh) {
+ memset(_dirtyBlocks, 0, _dirtyBlocksWidth * _dirtyBlocksHeight);
+ }
+ debug(7, "Display::update() - Full blit (%d)", _fullRefresh);
+ } else {
+ uint16 count = 0;
+ uint8 *scrBuf = _screenBuf;
+ uint8 *dbBuf = _dirtyBlocks;
+ for (int j = 0; j < _dirtyBlocksHeight; ++j) {
+ uint16 accW = 0;
+ for (int i = 0; i < _dirtyBlocksWidth; ++i) {
+ if (dbBuf[i] != 0) {
+ --dbBuf[i];
+ ++accW;
+ } else if (accW != 0) {
+ int x = (i - accW) * D_BLOCK_W;
+ _system->copyRectToScreen(scrBuf + x, SCREEN_W, x, j * D_BLOCK_H, accW * D_BLOCK_W, D_BLOCK_H);
+ accW = 0;
+ ++count;
+ }
+ }
+ if (accW != 0) {
+ int x = (_dirtyBlocksWidth - accW) * D_BLOCK_W;
+ _system->copyRectToScreen(scrBuf + x, SCREEN_W, x, j * D_BLOCK_H, accW * D_BLOCK_W, D_BLOCK_H);
+ ++count;
+ }
+ dbBuf += _dirtyBlocksWidth;
+ scrBuf += SCREEN_W * D_BLOCK_H;
+ }
+ if (count != 0) {
+ _system->updateScreen();
+ }
+ debug(7, "Display::update() - Dirtyblocks blit (%d)", count);
+ }
+}
+
+void Display::setupPanel() {
+ uint32 size;
+ uint8 *pcxBuf = _vm->resource()->loadFile("panel.pcx", 0, &size);
+ uint8 *dst = _panelBuf + PANEL_W * 10;
+ readPCX(dst, PANEL_W, pcxBuf + 128, PANEL_W, PANEL_H - 10);
+ const uint8 *pal = pcxBuf + size - 768 + 144 * 3;
+ memcpy(_pal.panel, pal, (256 - 144) * 3);
+ delete[] pcxBuf;
+
+ palSetPanel();
+}
+
+void Display::setupNewRoom(const char *name, uint16 room) {
+ dynalumInit(name, room);
+ uint32 size;
+ char filename[20];
+ sprintf(filename, "%s.PCX", name);
+ uint8 *pcxBuf = _vm->resource()->loadFile(filename, 0, &size);
+ _bdWidth = READ_LE_UINT16(pcxBuf + 12);
+ _bdHeight = READ_LE_UINT16(pcxBuf + 14);
+ readPCX(_backdropBuf, BACKDROP_W, pcxBuf + 128, _bdWidth, _bdHeight);
+ int n = getNumColorsForRoom(room);
+ if (n != 256) {
+ n = 144;
+ }
+ memcpy(_pal.room, pcxBuf + size - 768, n * 3);
+ delete[] pcxBuf;
+
+ palCustomColors(room);
+
+ forceFullRefresh();
+}
+
+void Display::drawBobSprite(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch, bool xflip) {
+ blit(_screenBuf, SCREEN_W, x, y, data, pitch, w, h, xflip, true);
+ setDirtyBlock(xflip ? (x - w + 1) : x, y, w, h);
+}
+
+void Display::drawBobPasteDown(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h) {
+ blit(_backdropBuf, BACKDROP_W, x, y, data, w, w, h, false, true);
+}
+
+void Display::drawInventoryItem(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h) {
+ if (data != NULL) {
+ blit(_panelBuf, PANEL_W, x, y, data, w, w, h, false, false);
+ } else {
+ fill(_panelBuf, PANEL_W, x, y, w, h, INK_BG_PANEL);
+ }
+ setDirtyBlock(x, 150 + y, w, h);
+}
+
+void Display::blit(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, const uint8 *srcBuf, uint16 srcPitch, uint16 w, uint16 h, bool xflip, bool masked) {
+ assert(w <= dstPitch);
+ dstBuf += dstPitch * y + x;
+
+ if (!masked) { // Unmasked always unflipped
+ while (h--) {
+ memcpy(dstBuf, srcBuf, w);
+ srcBuf += srcPitch;
+ dstBuf += dstPitch;
+ }
+ } else if (!xflip) { // Masked bitmap unflipped
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ uint8 b = *(srcBuf + i);
+ if (b != 0) {
+ *(dstBuf + i) = b;
+ }
+ }
+ srcBuf += srcPitch;
+ dstBuf += dstPitch;
+ }
+ } else { // Masked bitmap flipped
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ uint8 b = *(srcBuf + i);
+ if (b != 0) {
+ *(dstBuf - i) = b;
+ }
+ }
+ srcBuf += srcPitch;
+ dstBuf += dstPitch;
+ }
+ }
+}
+
+void Display::fill(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, uint16 w, uint16 h, uint8 color) {
+ assert(w <= dstPitch);
+ dstBuf += dstPitch * y + x;
+ while (h--) {
+ memset(dstBuf, color, w);
+ dstBuf += dstPitch;
+ }
+}
+
+void Display::readPCX(uint8 *dst, uint16 dstPitch, const uint8 *src, uint16 w, uint16 h) {
+ while (h--) {
+ uint8 *p = dst;
+ while (p < dst + w) {
+ uint8 col = *src++;
+ if ((col & 0xC0) == 0xC0) {
+ uint8 len = col & 0x3F;
+ memset(p, *src++, len);
+ p += len;
+ } else {
+ *p++ = col;
+ }
+ }
+ dst += dstPitch;
+ }
+}
+
+void Display::horizontalScrollUpdate(int16 xCamera) {
+ debug(9, "Display::horizontalScrollUpdate(%d)", xCamera);
+ if (_bdWidth <= 320) {
+ horizontalScroll(0);
+ } else {
+ if (xCamera > 160 && xCamera < 480) {
+ horizontalScroll(xCamera - 160);
+ } else if (xCamera >= 480) {
+ horizontalScroll(320);
+ } else {
+ horizontalScroll(0);
+ }
+ }
+}
+
+void Display::horizontalScroll(int16 scroll) {
+ if (_horizontalScroll != scroll) {
+ _fullRefresh = 2;
+ _horizontalScroll = scroll;
+ }
+}
+
+void Display::setDirtyBlock(uint16 x, uint16 y, uint16 w, uint16 h) {
+ if (_fullRefresh < 2) {
+ uint16 ex = (x + w - 1) / D_BLOCK_W;
+ uint16 ey = (y + h - 1) / D_BLOCK_H;
+ x /= D_BLOCK_W;
+ y /= D_BLOCK_H;
+ uint16 cy = ey - y + 1;
+ uint16 cx = ex - x + 1;
+ if (cy >= _dirtyBlocksHeight) cy = _dirtyBlocksHeight - 1;
+ if (cx >= _dirtyBlocksWidth) cx = _dirtyBlocksWidth - 1;
+ uint8 *p = _dirtyBlocks + _dirtyBlocksWidth * y + x;
+ while (cy--) {
+ for (uint16 i = 0; i < cx; ++i) {
+ p[i] = 2;
+ }
+ p += _dirtyBlocksWidth;
+ }
+ }
+}
+
+void Display::setMouseCursor(uint8 *buf, uint16 w, uint16 h) {
+ _system->setMouseCursor(buf, w, h, 1, 1, 0);
+}
+
+void Display::showMouseCursor(bool show) {
+ _system->showMouse(show);
+}
+
+void Display::initFont() {
+ // calculate font justification sizes
+ for (int i = 0; i < 256; ++i) {
+ _charWidth[i] = 0;
+ for (int y = 0; y < 8; ++y) {
+ uint8 c = _font[i * 8 + y];
+ for (int x = 0; x < 8; ++x) {
+ if ((c & (0x80 >> x)) && (x > _charWidth[i])) {
+ _charWidth[i] = x;
+ }
+ }
+ }
+ _charWidth[i] += 2;
+ }
+ _charWidth[0x20] = 4;
+ --_charWidth[0x5E];
+}
+
+void Display::setText(uint16 x, uint16 y, const char *text, bool outlined) {
+ if (y < GAME_SCREEN_HEIGHT) {
+ if (x == 0) x = 1;
+ if (y == 0) y = 1;
+ TextSlot *pts = &_texts[y];
+ pts->x = x;
+ pts->color = _curTextColor;
+ pts->outlined = outlined;
+ pts->text = text;
+ }
+}
+
+void Display::setTextCentered(uint16 y, const char *text, bool outlined) {
+ int len = strlen(text);
+ int16 x;
+ while ((x = (GAME_SCREEN_WIDTH - textWidth(text, len)) / 2) <= 0) {
+ ++text;
+ len -= 2;
+ }
+ assert(y < GAME_SCREEN_HEIGHT);
+ TextSlot *pts = &_texts[y];
+ pts->x = x;
+ pts->color = _curTextColor;
+ pts->outlined = outlined;
+ pts->text = Common::String(text, len);
+}
+
+void Display::drawTexts() {
+ for (int y = GAME_SCREEN_HEIGHT - 1; y > 0; --y) {
+ const TextSlot *pts = &_texts[y];
+ if (!pts->text.isEmpty()) {
+ drawText(pts->x, y, pts->color, pts->text.c_str(), pts->outlined);
+ }
+ }
+}
+
+void Display::clearTexts(uint16 y1, uint16 y2) {
+ assert(y1 <= y2 && y2 < GAME_SCREEN_HEIGHT);
+ while (y1 <= y2) {
+ _texts[y1].text.clear();
+ ++y1;
+ }
+}
+
+int Display::textCenterX(const char *text) const {
+ return (GAME_SCREEN_WIDTH - textWidth(text)) / 2;
+}
+
+uint16 Display::textWidth(const char *text) const {
+ return textWidth(text, strlen(text));
+}
+
+uint16 Display::textWidth(const char *text, uint16 len) const {
+ assert(len <= strlen(text));
+ uint16 width = 0;
+ for (uint16 i = 0; i < len; ++i) {
+ width += _charWidth[ (uint8)text[i] ];
+ }
+ return width;
+}
+
+void Display::drawChar(uint16 x, uint16 y, uint8 color, const uint8 *chr) {
+ uint8 *dstBuf = _screenBuf + SCREEN_W * y + x;
+ for (int j = 0; j < 8; ++j) {
+ uint8 *p = dstBuf;
+ uint8 c = *chr++;
+ if (c != 0) {
+ for (int i = 0; i < 8; ++i) {
+ if (c & 0x80) {
+ *p = color;
+ }
+ ++p;
+ c <<= 1;
+ }
+ }
+ dstBuf += SCREEN_W;
+ }
+}
+
+void Display::drawText(uint16 x, uint16 y, uint8 color, const char *text, bool outlined) {
+ static const int dx[] = { -1, 0, 1, 1, 1, 0, -1, -1 };
+ static const int dy[] = { -1, -1, -1, 0, 1, 1, 1, 0 };
+ const uint8 *str = (const uint8 *)text;
+ uint16 xs = x;
+ while (*str && x < SCREEN_W) {
+ const uint8 ch = *str++;
+ const uint8 *ftch = _font + ch * 8;
+ if (outlined) {
+ for (int i = 0; i < 8; ++i) {
+ drawChar(x + dx[i], y + dy[i], INK_OUTLINED_TEXT, ftch);
+ }
+ }
+ drawChar(x, y, color, ftch);
+ x += _charWidth[ch];
+ }
+ setDirtyBlock(xs - 1, y - 1, x - xs + 2, 8 + 2);
+}
+
+void Display::drawBox(int16 x1, int16 y1, int16 x2, int16 y2, uint8 col) {
+ int i;
+ for (i = y1; i <= y2; ++i) {
+ _screenBuf[i * SCREEN_W + x1] = _screenBuf[i * SCREEN_W + x2] = col;
+ }
+ setDirtyBlock(x1, y1, 1, y2 - y1);
+ setDirtyBlock(x2, y1, 1, y2 - y1);
+ for (i = x1; i <= x2; ++i) {
+ _screenBuf[y1 * SCREEN_W + i] = _screenBuf[y2 * SCREEN_W + i] = col;
+ }
+ setDirtyBlock(x1, y1, x2 - x1, 1);
+ setDirtyBlock(x1, y2, x2 - x1, 1);
+}
+
+void Display::shake(bool reset) {
+ _system->setShakePos(reset ? 0 : 3);
+}
+
+void Display::blankScreen() {
+ static int current = 0;
+ typedef void (Display::*BlankerEffect)();
+ static const BlankerEffect effects[] = {
+ &Display::blankScreenEffect1,
+ &Display::blankScreenEffect2,
+ &Display::blankScreenEffect3
+ };
+ (this->*effects[current])();
+ current = (current + 1) % ARRAYSIZE(effects);
+ forceFullRefresh();
+}
+
+void Display::blankScreenEffect1() {
+ uint8 buf[32 * 32];
+ while (_vm->input()->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
+ for (int i = 0; i < 2; ++i) {
+ int x = _rnd.getRandomNumber(SCREEN_W - 32 - 2) + 1;
+ int y = _rnd.getRandomNumber(SCREEN_H - 32 - 2) + 1;
+ const uint8 *p = _screenBuf + SCREEN_W * y + x;
+ for (int j = 0; j < 32; ++j) {
+ memcpy(buf + j * 32, p, 32);
+ p += SCREEN_W;
+ }
+ if (_rnd.getRandomNumber(1)) {
+ ++x;
+ } else {
+ --x;
+ }
+ if (_rnd.getRandomNumber(1)) {
+ ++y;
+ } else {
+ --y;
+ }
+ _system->copyRectToScreen(buf, 32, x, y, 32, 32);
+ _system->updateScreen();
+ _vm->input()->delay(10);
+ }
+ }
+}
+
+void Display::blankScreenEffect2() {
+ while (_vm->input()->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
+ int x = _rnd.getRandomNumber(SCREEN_W - 2);
+ int y = _rnd.getRandomNumber(SCREEN_H - 2);
+ uint8 *p = _screenBuf + y * SCREEN_W + x;
+ uint8 c = 0;
+ switch (_rnd.getRandomNumber(3)) {
+ case 0:
+ c = *p;
+ break;
+ case 1:
+ c = *(p + 1);
+ break;
+ case 2:
+ c = *(p + SCREEN_W);
+ break;
+ case 3:
+ c = *(p + SCREEN_W + 1);
+ break;
+ }
+ memset(p, c, 2);
+ memset(p + SCREEN_W, c, 2);
+ _system->copyRectToScreen(p, SCREEN_W, x, y, 2, 2);
+ _system->updateScreen();
+ _vm->input()->delay(10);
+ }
+}
+
+void Display::blankScreenEffect3() {
+ uint32 i = 0;
+ while (_vm->input()->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
+ if (i > 4000000) {
+ memset(_screenBuf, 0, SCREEN_W * SCREEN_H);
+ _system->copyRectToScreen(_screenBuf, SCREEN_W, 0, 0, SCREEN_W, SCREEN_H);
+ } else {
+ int x = _rnd.getRandomNumber(SCREEN_W - 2);
+ int y = _rnd.getRandomNumber(SCREEN_H - 2);
+ uint8 *p = _screenBuf + SCREEN_W * y + x;
+ int sum = *p + *(p + 1) + *(p + SCREEN_W) + *(p + SCREEN_W + 1);
+ uint8 c = (uint8)(sum / 4);
+ memset(p, c, 2);
+ memset(p + SCREEN_W, c, 2);
+ ++i;
+ _system->copyRectToScreen(p, SCREEN_W, x, y, 2, 2);
+ }
+ _system->updateScreen();
+ _vm->input()->delay(10);
+ }
+}
+
+#ifndef PALMOS_68K
+const uint8 Display::_fontRegular[] = {
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00,
+ 0xD8, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+ 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+ 0x38, 0x6C, 0x68, 0x36, 0xDC, 0xCC, 0x76, 0x00, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x60, 0xC0, 0xC0, 0xC0, 0x60, 0x30, 0x00, 0xC0, 0x60, 0x30, 0x30, 0x30, 0x60, 0xC0, 0x00,
+ 0x00, 0x6C, 0x38, 0xFE, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
+ 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x30, 0x70, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xCC, 0x0C, 0x78, 0xC0, 0xC0, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+ 0x1C, 0x3C, 0x6C, 0xCC, 0xFC, 0x0C, 0x0C, 0x00, 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+ 0x78, 0xCC, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00,
+ 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0xC0,
+ 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00,
+ 0xC0, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC0, 0x00, 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x38, 0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xCC, 0xCC, 0xF8, 0x00, 0x78, 0xCC, 0xC0, 0xC0, 0xC0, 0xCC, 0x78, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xF8, 0x00, 0xFC, 0xC0, 0xC0, 0xF0, 0xC0, 0xC0, 0xFC, 0x00,
+ 0xFC, 0xC0, 0xC0, 0xF0, 0xC0, 0xC0, 0xC0, 0x00, 0x78, 0xCC, 0xC0, 0xDC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0xC6, 0xCC, 0xD8, 0xF8, 0xD8, 0xCC, 0xC6, 0x00,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0x00, 0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, 0xC0, 0xC0, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x0C,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xD8, 0xCC, 0xCC, 0x00, 0x78, 0xCC, 0xC0, 0x78, 0x0C, 0xCC, 0x78, 0x00,
+ 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x10, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+ 0xC6, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x30, 0x00,
+ 0xFC, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xFC, 0x00, 0xF0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xF0, 0x00,
+ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x30, 0xF0, 0x00,
+ 0xE8, 0x4D, 0x4A, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0xC0, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7C, 0x00,
+ 0xC0, 0xC0, 0xF8, 0xCC, 0xCC, 0xCC, 0xF8, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+ 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x7C, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0x38, 0x6C, 0x60, 0xF8, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
+ 0xC0, 0xC0, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0xC0, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+ 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0x78, 0xC0, 0xC0, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0x00,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0xCC, 0xEE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, 0xC0, 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C,
+ 0x00, 0x00, 0xF8, 0xCC, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0x78, 0x00,
+ 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0x6C, 0x6C, 0x00,
+ 0x00, 0x00, 0xCC, 0x78, 0x30, 0x78, 0xCC, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0xE0,
+ 0x00, 0x00, 0xFC, 0x18, 0x30, 0x60, 0xFC, 0x00, 0x38, 0x60, 0x60, 0xC0, 0x60, 0x60, 0x38, 0x00,
+ 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0xC0, 0x00, 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
+ 0x38, 0x44, 0xBA, 0xAA, 0xBA, 0x44, 0x38, 0x00, 0x00, 0x98, 0x30, 0x60, 0xC8, 0x98, 0x30, 0x00,
+ 0x1E, 0x30, 0x60, 0x60, 0x30, 0x1E, 0x0C, 0x18, 0x00, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x0C, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x18, 0x66, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x60, 0x60, 0x30, 0x1E, 0x0C, 0x18,
+ 0x18, 0x66, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x66, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x30, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x00, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x30, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x00, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x30, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x18, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7C, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x30, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x18, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0x71, 0x8E, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x00, 0x71, 0xCE, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x3C, 0x06, 0x3C, 0x00,
+ 0x18, 0x00, 0x18, 0x30, 0x60, 0x66, 0x3C, 0x00, 0x3F, 0x40, 0x4E, 0x58, 0x4E, 0x40, 0x3F, 0x00,
+ 0x1C, 0xA4, 0xC4, 0xBC, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+ 0x3E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+ 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0x81, 0x7E, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
+ 0xF0, 0x18, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x18, 0x30, 0x18, 0xF0, 0x00, 0x00, 0x00,
+ 0x30, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xFE, 0xC0,
+ 0x3E, 0x7A, 0x7A, 0x3A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
+ 0x38, 0x44, 0x44, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+ 0x40, 0xC6, 0x4C, 0x58, 0x32, 0x66, 0xCF, 0x02, 0x40, 0xC6, 0x4C, 0x58, 0x3E, 0x62, 0xC4, 0x0E,
+ 0xC0, 0x23, 0x66, 0x2C, 0xD9, 0x33, 0x67, 0x01, 0x18, 0x00, 0x18, 0x30, 0x60, 0x66, 0x3C, 0x00,
+ 0x60, 0x30, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x0C, 0x18, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x38, 0xC6, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x71, 0x8E, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x38, 0x44, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x1F, 0x3C, 0x3C, 0x6F, 0x7C, 0xCC, 0xCF, 0x00, 0x1E, 0x30, 0x60, 0x60, 0x30, 0x1E, 0x0C, 0x18,
+ 0x60, 0x30, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00, 0x18, 0x30, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00,
+ 0x30, 0xCC, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00, 0xCC, 0x00, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00,
+ 0x60, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0x18, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x30, 0xCC, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x78, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0x78, 0x00, 0x71, 0xCE, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0x00,
+ 0x30, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x0C, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0x18, 0x66, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0xC3, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00,
+ 0x3F, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0xFC, 0x00, 0x30, 0x18, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x0C, 0x18, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x18, 0x24, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x06, 0x08, 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x00,
+ 0x60, 0x60, 0x7E, 0x63, 0x7E, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x66, 0x6C, 0x66, 0x66, 0x6C, 0x60,
+ 0x30, 0x18, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x0C, 0x18, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x18, 0x66, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x71, 0x8E, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x66, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x18, 0x24, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x00, 0x00, 0x7E, 0x1B, 0x7F, 0xD8, 0x77, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x18,
+ 0x30, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x0C, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x18, 0x66, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x66, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x30, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x60, 0xFC, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x00,
+ 0x30, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x0C, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x18, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x00, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x02, 0x7C, 0xCE, 0xD6, 0xE6, 0x7C, 0x80, 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x0C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x18, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x00, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x0C, 0x18, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x30,
+ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, 0x66, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x30
+};
+
+const uint8 Display::_fontHebrew[] = {
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00, 0xF8, 0xB0, 0xB0, 0x80, 0xB0, 0xB0, 0xC0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0x00,
+ 0xD8, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+ 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+ 0x38, 0x6C, 0x68, 0x36, 0xDC, 0xCC, 0x76, 0x00, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x60, 0xC0, 0xC0, 0xC0, 0x60, 0x30, 0x00, 0xC0, 0x60, 0x30, 0x30, 0x30, 0x60, 0xC0, 0x00,
+ 0x00, 0x6C, 0x38, 0xFE, 0x38, 0x6C, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
+ 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x30, 0x70, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xCC, 0x0C, 0x78, 0xC0, 0xC0, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+ 0x1C, 0x3C, 0x6C, 0xCC, 0xFC, 0x0C, 0x0C, 0x00, 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+ 0x78, 0xCC, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00,
+ 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0xC0,
+ 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00,
+ 0xC0, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC0, 0x00, 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x38, 0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xCC, 0xCC, 0xF8, 0x00, 0x78, 0xCC, 0xC0, 0xC0, 0xC0, 0xCC, 0x78, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xF8, 0x00, 0xFC, 0xC0, 0xC0, 0xF0, 0xC0, 0xC0, 0xFC, 0x00,
+ 0xFC, 0xC0, 0xC0, 0xF0, 0xC0, 0xC0, 0xC0, 0x00, 0x78, 0xCC, 0xC0, 0xDC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0xC6, 0xCC, 0xD8, 0xF8, 0xD8, 0xCC, 0xC6, 0x00,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0x00, 0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, 0xC0, 0xC0, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x0C,
+ 0xF8, 0xCC, 0xCC, 0xF8, 0xD8, 0xCC, 0xCC, 0x00, 0x78, 0xCC, 0xC0, 0x78, 0x0C, 0xCC, 0x78, 0x00,
+ 0xFC, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x10, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+ 0xC6, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x30, 0x00,
+ 0xFC, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xFC, 0x00, 0xF0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xF0, 0x00,
+ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00, 0xF0, 0x30, 0x30, 0x30, 0x30, 0x30, 0xF0, 0x00,
+ 0xE8, 0x4D, 0x4A, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0xC0, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7C, 0x00,
+ 0xC0, 0xC0, 0xF8, 0xCC, 0xCC, 0xCC, 0xF8, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+ 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x7C, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+ 0x38, 0x6C, 0x60, 0xF8, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
+ 0xC0, 0xC0, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0xC0, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+ 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0x78, 0xC0, 0xC0, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0x00,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0xCC, 0xEE, 0xD6, 0xC6, 0xC6, 0x00,
+ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+ 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, 0xC0, 0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C,
+ 0x00, 0x00, 0xF8, 0xCC, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0x78, 0x00,
+ 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0x6C, 0x6C, 0x00,
+ 0x00, 0x00, 0xCC, 0x78, 0x30, 0x78, 0xCC, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0xE0,
+ 0x00, 0x00, 0xFC, 0x18, 0x30, 0x60, 0xFC, 0x00, 0x38, 0x60, 0x60, 0xC0, 0x60, 0x60, 0x38, 0x00,
+ 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0xC0, 0xC0, 0x00, 0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
+ 0x38, 0x44, 0xBA, 0xAA, 0xBA, 0x44, 0x38, 0x00, 0x00, 0x98, 0x30, 0x60, 0xC8, 0x98, 0x30, 0x00,
+ 0xCC, 0x66, 0x76, 0xBC, 0x98, 0x8C, 0xE6, 0x00, 0xFC, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xFE, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x38, 0x78, 0xD8, 0x00, 0xFE, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xFE, 0x06, 0x06, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x7C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0xFE, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+ 0xDC, 0x66, 0xE6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0xF0, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFE, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xF8, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xF8, 0x00,
+ 0xC0, 0xFE, 0x06, 0x06, 0x0C, 0x18, 0x18, 0x00, 0xFE, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00,
+ 0xFC, 0x76, 0x66, 0x66, 0x66, 0x66, 0x6E, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 0xFE, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0xEE, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0xFE, 0xC6, 0xC6, 0xF6, 0x06, 0x06, 0x06, 0x06,
+ 0xFE, 0xC6, 0xC6, 0xFE, 0x06, 0x06, 0xFE, 0x00, 0xFE, 0x66, 0x6C, 0x78, 0x60, 0x60, 0x60, 0x60,
+ 0xEE, 0x66, 0x3C, 0x18, 0x0C, 0x06, 0xFE, 0x00, 0xFE, 0x06, 0x0E, 0xD8, 0xF0, 0xF0, 0xC0, 0xC0,
+ 0xFC, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0xEE, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0x7C, 0x00,
+ 0xFF, 0x67, 0x67, 0x67, 0x67, 0x67, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x0C, 0x3E, 0x6C, 0x3E, 0x0C, 0x00, 0x00, 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xFC, 0x00,
+ 0x42, 0x3C, 0x66, 0x3C, 0x42, 0x00, 0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0x3C, 0x60, 0x3C, 0x66, 0x3C, 0x06, 0x3C, 0x00,
+ 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x4E, 0x58, 0x4E, 0x40, 0x3F, 0x00,
+ 0x1C, 0xA4, 0xC4, 0xBC, 0x80, 0xFE, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+ 0x3E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+ 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0x81, 0x7E, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
+ 0xF0, 0x18, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x18, 0x30, 0x18, 0xF0, 0x00, 0x00, 0x00,
+ 0x30, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xFE, 0xC0,
+ 0x3E, 0x7A, 0x7A, 0x3A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
+ 0x38, 0x44, 0x44, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+ 0x40, 0xC6, 0x4C, 0x58, 0x32, 0x66, 0xCF, 0x02, 0x40, 0xC6, 0x4C, 0x58, 0x3E, 0x62, 0xC4, 0x0E,
+ 0xC0, 0x23, 0x66, 0x2C, 0xD9, 0x33, 0x67, 0x01, 0x18, 0x00, 0x18, 0x30, 0x60, 0x66, 0x3C, 0x00,
+ 0x60, 0x30, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x0C, 0x18, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x38, 0xC6, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x71, 0x8E, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x38, 0x44, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+ 0x1F, 0x3C, 0x3C, 0x6F, 0x7C, 0xCC, 0xCF, 0x00, 0x1E, 0x30, 0x60, 0x60, 0x30, 0x1E, 0x0C, 0x18,
+ 0x60, 0x30, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00, 0x18, 0x30, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00,
+ 0x30, 0xCC, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00, 0xCC, 0x00, 0xFC, 0xC0, 0xF0, 0xC0, 0xFC, 0x00,
+ 0x60, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0x18, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x30, 0xCC, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00, 0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x78, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0x78, 0x00, 0x71, 0xCE, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0x00,
+ 0x30, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x0C, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0x18, 0x66, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+ 0xC3, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00,
+ 0x3F, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0xFC, 0x00, 0x30, 0x18, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x0C, 0x18, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x18, 0x24, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x06, 0x08, 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x00,
+ 0x60, 0x60, 0x7E, 0x63, 0x7E, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x66, 0x6C, 0x66, 0x66, 0x6C, 0x60,
+ 0x30, 0x18, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x0C, 0x18, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x18, 0x66, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x71, 0x8E, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x66, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x18, 0x24, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
+ 0x00, 0x00, 0x7E, 0x1B, 0x7F, 0xD8, 0x77, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x18,
+ 0x30, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x0C, 0x18, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x18, 0x66, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x66, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+ 0x30, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x60, 0xFC, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x00,
+ 0x30, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x0C, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x18, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x71, 0x8E, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+ 0x00, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x02, 0x7C, 0xCE, 0xD6, 0xE6, 0x7C, 0x80, 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x0C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x18, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00,
+ 0x00, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x0C, 0x18, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x30,
+ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, 0x66, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x30
+};
+
+const uint8 Display::_palJoeClothes[] = {
+ 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x87, 0x87, 0x87, 0xB0, 0xB0, 0xB0, 0xDA, 0xDA, 0xDA, 0x43,
+ 0x34, 0x20, 0x77, 0x33, 0x1F, 0xA3, 0x43, 0x27, 0x80, 0x45, 0x45, 0x9E, 0x5D, 0x5B, 0xB9, 0x78,
+ 0x75, 0xDF, 0x97, 0x91, 0x17, 0x27, 0x63, 0x1F, 0x3F, 0x83, 0x27, 0x5B, 0xA7, 0x98, 0xD4, 0xFF
+};
+
+const uint8 Display::_palJoeDress[] = {
+ 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0x70, 0x70, 0x70, 0x90, 0x90, 0x90, 0xC6, 0xC6, 0xC6, 0xFF,
+ 0xFF, 0xFF, 0x30, 0x30, 0x90, 0x47, 0x49, 0xD0, 0x40, 0x24, 0x00, 0x79, 0x34, 0x0B, 0xB2, 0x3D,
+ 0x22, 0xED, 0x42, 0x42, 0x80, 0x45, 0x45, 0xA3, 0x5F, 0x5F, 0xC8, 0x7C, 0x7C, 0xEC, 0x9C, 0x9C
+};
+
+#endif
+
+} // End of namespace Queen
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Queen_Display)
+_GSETPTR(Queen::_fontRegular, GBVARS_DISPLAYFONTREGULAR_INDEX, uint8, GBVARS_QUEEN)
+_GSETPTR(Queen::_fontHebrew, GBVARS_DISPLAYFONTHEBREW_INDEX, uint8, GBVARS_QUEEN)
+_GSETPTR(Queen::_palJoeClothes, GBVARS_DISPLAYPALJOECLOTHES_INDEX, uint8, GBVARS_QUEEN)
+_GSETPTR(Queen::_palJoeDress, GBVARS_DISPLAYPALJOEDRESS_INDEX, uint8, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Queen_Display)
+_GRELEASEPTR(GBVARS_DISPLAYFONTREGULAR_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_DISPLAYFONTHEBREW_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_DISPLAYPALJOECLOTHES_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_DISPLAYPALJOEDRESS_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/queen/display.h b/engines/queen/display.h
new file mode 100644
index 0000000000..87608a57e3
--- /dev/null
+++ b/engines/queen/display.h
@@ -0,0 +1,246 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENDISPLAY_H
+#define QUEENDISPLAY_H
+
+#include "common/str.h"
+#include "common/util.h"
+#include "queen/defs.h"
+
+class OSystem;
+
+namespace Queen {
+
+class QueenEngine;
+
+class Display {
+public:
+
+ Display(QueenEngine *vm, OSystem *system);
+ ~Display();
+
+ //! initialise dynalum for the specified room
+ void dynalumInit(const char *roomName, uint16 roomNum);
+
+ //! update dynalum for the current room
+ void dynalumUpdate(int16 x, int16 y);
+
+ //! update the palette
+ void palSet(const uint8 *pal, int start, int end, bool updateScreen = false);
+
+ //! setup palette for Joe's dress
+ void palSetJoeDress();
+
+ //! setup palette for Joe's normal clothes
+ void palSetJoeNormal();
+
+ //! setup palette for panel and inventory objects
+ void palSetPanel();
+
+ //! fade the current palette in
+ void palFadeIn(uint16 roomNum, bool dynalum = false, int16 dynaX = 0, int16 dynaY = 0);
+
+ //! fade the current palette out
+ void palFadeOut(uint16 roomNum);
+
+ //! grey the panel area (used when panel is disabled)
+ void palGreyPanel();
+
+ //! scroll some palette colors
+ void palScroll(int start, int end);
+
+ //! custom palette effect for the specified room
+ void palCustomColors(uint16 roomNum);
+
+ //! custom palette scroll for the specified room
+ void palCustomScroll(uint16 roomNum);
+
+ //! process a 'palette flash' effect
+ void palCustomFlash();
+
+ void palCustomLightsOff(uint16 roomNum);
+ void palCustomLightsOn(uint16 roomNum);
+
+ //! mark all palette entries as dirty
+ void palSetAllDirty() { _pal.dirtyMin = 0; _pal.dirtyMax = 255; }
+
+ //! returns the number of colors used by the room
+ int getNumColorsForRoom(uint16 room) const;
+
+ //! returns true if we shouldn't fade the palette in the specified room
+ bool isPalFadingDisabled(uint16 room) const;
+
+ //! change fullscreen/panel mode
+ void screenMode(int comPanel, bool inCutaway);
+
+ void prepareUpdate();
+ void update(bool dynalum = false, int16 dynaX = 0, int16 dynaY = 0);
+
+ void setupPanel();
+ void setupNewRoom(const char *name, uint16 room);
+
+ void drawBobSprite(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch, bool xflip);
+ void drawBobPasteDown(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h);
+ void drawInventoryItem(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h);
+
+ void blit(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, const uint8 *srcBuf, uint16 srcPitch, uint16 w, uint16 h, bool xflip, bool masked);
+ void fill(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, uint16 w, uint16 h, uint8 color);
+
+ //! decode a PCX stream
+ void readPCX(uint8 *dst, uint16 dstPitch, const uint8 *src, uint16 w, uint16 h);
+
+ void horizontalScrollUpdate(int16 xCamera);
+ void horizontalScroll(int16 scroll);
+ int16 horizontalScroll() const { return _horizontalScroll; }
+
+ void fullscreen(bool fs) { _fullRefresh = 2; _fullscreen = fs; }
+ bool fullscreen() const { return _fullscreen; }
+
+ //! mark the specified block as dirty
+ void setDirtyBlock(uint16 x, uint16 y, uint16 w, uint16 h);
+
+ //! force a full refresh (bypassing the dirtyblocks rendering), on next screen update
+ void forceFullRefresh() { _fullRefresh = 2; }
+
+ //! change mouse cursor bitmap
+ void setMouseCursor(uint8 *buf, uint16 w, uint16 h);
+
+ //! show/hide mouse cursor
+ void showMouseCursor(bool show);
+
+ //! initialise font, compute justification sizes
+ void initFont();
+
+ //! add the specified text to the texts list
+ void setText(uint16 x, uint16 y, const char *text, bool outlined = true);
+
+ //! add the specified text to the texts list
+ void setTextCentered(uint16 y, const char *text, bool outlined = true);
+
+ //! draw the text lists
+ void drawTexts();
+
+ //! remove entries from the texts list
+ void clearTexts(uint16 y1, uint16 y2);
+
+ //! change the current text color
+ void textCurrentColor(uint8 color) { _curTextColor = color; }
+
+ //! change the text color for the specified texts list entry
+ void textColor(uint16 y, uint8 color) { _texts[y].color = color; }
+
+ int textCenterX(const char *text) const;
+ uint16 textWidth(const char *text) const;
+ uint16 textWidth(const char *text, uint16 len) const;
+ void drawChar(uint16 x, uint16 y, uint8 color, const uint8 *chr);
+ void drawText(uint16 x, uint16 y, uint8 color, const char *text, bool outlined = true);
+ void drawBox(int16 x1, int16 y1, int16 x2, int16 y2, uint8 col);
+
+ void shake(bool reset);
+
+ void blankScreen();
+ void blankScreenEffect1();
+ void blankScreenEffect2();
+ void blankScreenEffect3();
+
+private:
+
+ enum {
+ FADE_SPEED = 16,
+ D_BLOCK_W = 8,
+ D_BLOCK_H = 8
+ };
+
+ enum BufferDimension {
+ BACKDROP_W = 640,
+ BACKDROP_H = 200,
+ SCREEN_W = 320,
+ SCREEN_H = 200,
+ PANEL_W = 320,
+ PANEL_H = 50
+ };
+
+ struct {
+ uint8 *room;
+ uint8 *screen;
+ uint8 *panel;
+ int dirtyMin, dirtyMax;
+ bool scrollable;
+ } _pal;
+
+ struct Dynalum {
+ bool valid;
+ uint8 *mskBuf;
+ uint32 mskSize;
+ int8 *lumBuf;
+ uint32 lumSize;
+ uint8 prevColMask;
+ };
+
+ struct TextSlot {
+ uint16 x;
+ uint8 color;
+ Common::String text;
+ bool outlined;
+ };
+
+ uint8 *_screenBuf;
+ uint8 *_panelBuf;
+ uint8 *_backdropBuf;
+
+ uint8 _fullRefresh;
+ uint8 *_dirtyBlocks;
+ uint16 _dirtyBlocksWidth, _dirtyBlocksHeight;
+
+ bool _fullscreen;
+
+ uint16 _horizontalScroll;
+ uint16 _bdWidth, _bdHeight;
+
+ //! texts list
+ TextSlot _texts[GAME_SCREEN_HEIGHT];
+
+ //! current text color to use for display
+ uint8 _curTextColor;
+
+ //! font justification sizes
+ uint8 _charWidth[256];
+
+ Common::RandomSource _rnd;
+ Dynalum _dynalum;
+ OSystem *_system;
+ QueenEngine *_vm;
+
+ const uint8 *_font;
+#ifndef PALMOS_68K
+ static const uint8 _fontRegular[];
+ static const uint8 _fontHebrew[];
+ static const uint8 _palJoeClothes[];
+ static const uint8 _palJoeDress[];
+#endif
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/graphics.cpp b/engines/queen/graphics.cpp
new file mode 100644
index 0000000000..be2f8d6017
--- /dev/null
+++ b/engines/queen/graphics.cpp
@@ -0,0 +1,1537 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/graphics.h"
+
+#include "queen/bankman.h"
+#include "queen/display.h"
+#include "queen/grid.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+
+namespace Queen {
+
+#ifdef PALMOS_68K
+static const BamScene::BamDataBlock *_carData;
+static const BamScene::BamDataBlock *_fight1Data;
+static const BamScene::BamDataBlock *_fight2Data;
+static const BamScene::BamDataBlock *_fight3Data;
+#endif
+
+const Box BobSlot::_defaultBox(-1, -1, -1, -1);
+
+void BobSlot::curPos(int16 xx, int16 yy) {
+ active = true;
+ x = xx;
+ y = yy;
+}
+
+void BobSlot::move(int16 dstx, int16 dsty, int16 spd) {
+ active = true;
+ moving = true;
+
+ endx = dstx;
+ endy = dsty;
+
+ speed = (spd < 1) ? 1 : spd;
+
+ int16 deltax = endx - x;
+ if (deltax < 0) {
+ dx = -deltax;
+ xdir = -1;
+ } else {
+ dx = deltax;
+ xdir = 1;
+ }
+ int16 deltay = endy - y;
+ if (deltay < 0) {
+ dy = -deltay;
+ ydir = -1;
+ } else {
+ dy = deltay;
+ ydir = 1;
+ }
+
+ if (dx > dy) {
+ total = dy / 2;
+ xmajor = true;
+ } else {
+ total = dx / 2;
+ xmajor = false;
+ }
+
+ // move one step along line to avoid glitching
+ moveOneStep();
+}
+
+void BobSlot::moveOneStep() {
+ if (xmajor) {
+ if (x == endx) {
+ y = endy;
+ moving = false;
+ } else {
+ x += xdir;
+ total += dy;
+ if (total > dx) {
+ y += ydir;
+ total -= dx;
+ }
+ }
+ } else {
+ if (y == endy) {
+ x = endx;
+ moving = false;
+ } else {
+ y += ydir;
+ total += dx;
+ if (total > dy) {
+ x += xdir;
+ total -= dy;
+ }
+ }
+ }
+}
+
+void BobSlot::animOneStep() {
+ if (anim.string.buffer != NULL) {
+ --anim.speed;
+ if (anim.speed <= 0) {
+ // jump to next entry
+ ++anim.string.curPos;
+ uint16 nextFrame = anim.string.curPos->frame;
+ if (nextFrame == 0) {
+ anim.string.curPos = anim.string.buffer;
+ frameNum = anim.string.curPos->frame;
+ } else {
+ frameNum = nextFrame;
+ }
+ anim.speed = anim.string.curPos->speed / 4;
+ }
+ } else {
+ // normal looping animation
+ --anim.speed;
+ if (anim.speed == 0) {
+ anim.speed = anim.speedBak;
+
+ int16 nextFrame = frameNum + frameDir;
+ if (nextFrame > anim.normal.lastFrame || nextFrame < anim.normal.firstFrame) {
+ if (anim.normal.rebound) {
+ frameDir *= -1;
+ } else {
+ frameNum = anim.normal.firstFrame - 1;
+ }
+ }
+ frameNum += frameDir;
+ }
+ }
+}
+
+void BobSlot::animString(const AnimFrame *animBuf) {
+ active = true;
+ animating = true;
+ anim.string.buffer = animBuf;
+ anim.string.curPos = animBuf;
+ frameNum = animBuf->frame;
+ anim.speed = animBuf->speed / 4;
+}
+
+void BobSlot::animNormal(uint16 firstFrame, uint16 lastFrame, uint16 spd, bool rebound, bool flip) {
+ active = true;
+ animating = true;
+ frameNum = firstFrame;
+ anim.speed = spd;
+ anim.speedBak = spd;
+ anim.string.buffer = NULL;
+ anim.normal.firstFrame = firstFrame;
+ anim.normal.lastFrame = lastFrame;
+ anim.normal.rebound = rebound;
+ frameDir = 1;
+ xflip = flip;
+}
+
+void BobSlot::scaleWalkSpeed(uint16 ms) {
+ if (!xmajor) {
+ ms /= 2;
+ }
+ speed = scale * ms / 100;
+ if (speed == 0) {
+ speed = 1;
+ }
+}
+
+void BobSlot::clear() {
+ active = false;
+ xflip = false;
+ animating = false;
+ anim.string.buffer = NULL;
+ moving = false;
+ scale = 100;
+
+#ifdef PALMOS_ARM
+ Box *tmp = (Box *)&_defaultBox;
+ tmp->x1 = -1;
+ tmp->y1 = -1;
+ tmp->x2 = -1;
+ tmp->y2 = -1;
+#endif
+ box = _defaultBox;
+}
+
+static int compareBobDrawOrder(const void *a, const void *b) {
+ const BobSlot *bob1 = *(const BobSlot * const *)a;
+ const BobSlot *bob2 = *(const BobSlot * const *)b;
+ int d = bob1->y - bob2->y;
+ // As the qsort() function may reorder "equal" elements,
+ // we use the bob slot number when needed. This is required
+ // during the introduction, to hide a crate behind the clock.
+ if (d == 0) {
+ d = bob1 - bob2;
+ }
+ return d;
+}
+
+const Box Graphics::_gameScreenBox(0, 0, GAME_SCREEN_WIDTH - 1, ROOM_ZONE_HEIGHT - 1);
+const Box Graphics::_fullScreenBox(0, 0, GAME_SCREEN_WIDTH - 1, GAME_SCREEN_HEIGHT - 1);
+
+Graphics::Graphics(QueenEngine *vm)
+ : _cameraBob(0), _vm(vm) {
+ memset(_bobs, 0, sizeof(_bobs));
+ memset(_sortedBobs, 0, sizeof(_sortedBobs));
+ _sortedBobsCount = 0;
+ _shrinkBuffer.data = new uint8[ BOB_SHRINK_BUF_SIZE ];
+
+#ifdef PALMOS_ARM
+ Box *tmp1 = (Box *)&BobSlot::_defaultBox;
+ tmp1->x1 = -1;
+ tmp1->y1 = -1;
+ tmp1->x2 = -1;
+ tmp1->y2 = -1;
+ Box *tmp2 = (Box *)&_gameScreenBox;
+ tmp2->x1 = 0;
+ tmp2->y1 = 0;
+ tmp2->x2 = GAME_SCREEN_WIDTH - 1;
+ tmp2->y2 = ROOM_ZONE_HEIGHT - 1;
+ Box *tmp3 = (Box *)&_fullScreenBox;
+ tmp3->x1 = 0;
+ tmp3->y1 = 0;
+ tmp3->x2 = GAME_SCREEN_WIDTH - 1;
+ tmp3->y2 = GAME_SCREEN_HEIGHT - 1;
+#endif
+}
+
+Graphics::~Graphics() {
+ delete[] _shrinkBuffer.data;
+}
+
+void Graphics::unpackControlBank() {
+ _vm->bankMan()->load("control.BBK",17);
+ _vm->bankMan()->unpack(1, 1, 17); // Mouse pointer
+ // unpack arrows frames and change hotspot to be always on top
+ for (int i = 3; i <= 4; ++i) {
+ _vm->bankMan()->unpack(i, i, 17);
+ BobFrame *bf = _vm->bankMan()->fetchFrame(i);
+ bf->yhotspot += 200;
+ }
+ _vm->bankMan()->close(17);
+}
+
+void Graphics::setupArrows() {
+ int scrollX = _vm->display()->horizontalScroll();
+ BobSlot *arrow;
+ arrow = bob(ARROW_BOB_UP);
+ arrow->curPos(303 + 8 + scrollX, 150 + 1 + 200);
+ arrow->frameNum = 3;
+ arrow = bob(ARROW_BOB_DOWN);
+ arrow->curPos(303 + scrollX, 175 + 200);
+ arrow->frameNum = 4;
+}
+
+void Graphics::setupMouseCursor() {
+ BobFrame *bf = _vm->bankMan()->fetchFrame(1);
+ _vm->display()->setMouseCursor(bf->data, bf->width, bf->height);
+}
+
+void Graphics::drawBob(const BobSlot *bs, const BobFrame *bf, const Box *bbox, int16 x, int16 y) {
+ debug(9, "Graphics::drawBob(%d, %d, %d)", bs->frameNum, x, y);
+
+ uint16 w, h;
+ if (bs->scale < 100) {
+ shrinkFrame(bf, bs->scale);
+ bf = &_shrinkBuffer;
+ }
+ w = bf->width;
+ h = bf->height;
+
+ const Box *box = (bs->box == BobSlot::_defaultBox) ? bbox : &bs->box;
+
+ if (w != 0 && h != 0 && box->intersects(x, y, w, h)) {
+ uint8 *src = bf->data;
+ uint16 x_skip = 0;
+ uint16 y_skip = 0;
+ uint16 w_new = w;
+ uint16 h_new = h;
+
+ // compute bounding box intersection with frame
+ if (x < box->x1) {
+ x_skip = box->x1 - x;
+ w_new -= x_skip;
+ x = box->x1;
+ }
+
+ if (y < box->y1) {
+ y_skip = box->y1 - y;
+ h_new -= y_skip;
+ y = box->y1;
+ }
+
+ if (x + w_new > box->x2 + 1) {
+ w_new = box->x2 - x + 1;
+ }
+
+ if (y + h_new > box->y2 + 1) {
+ h_new = box->y2 - y + 1;
+ }
+
+ src += w * y_skip;
+ if (!bs->xflip) {
+ src += x_skip;
+ } else {
+ src += w - w_new - x_skip;
+ x += w_new - 1;
+ }
+ _vm->display()->drawBobSprite(src, x, y, w_new, h_new, w, bs->xflip);
+ }
+}
+
+void Graphics::drawInventoryItem(uint32 frameNum, uint16 x, uint16 y) {
+ if (frameNum != 0) {
+ BobFrame *bf = _vm->bankMan()->fetchFrame(frameNum);
+ _vm->display()->drawInventoryItem(bf->data, x, y, bf->width, bf->height);
+ } else {
+ _vm->display()->drawInventoryItem(NULL, x, y, 32, 32);
+ }
+}
+
+void Graphics::pasteBob(uint16 objNum, uint16 image) {
+ GraphicData *pgd = _vm->logic()->graphicData(objNum);
+ _vm->bankMan()->unpack(pgd->firstFrame, image, 15);
+ BobFrame *bf = _vm->bankMan()->fetchFrame(image);
+ _vm->display()->drawBobPasteDown(bf->data, pgd->x, pgd->y, bf->width, bf->height);
+ _vm->bankMan()->eraseFrame(image);
+}
+
+void Graphics::shrinkFrame(const BobFrame *bf, uint16 percentage) {
+ // computing new size, rounding to upper value
+ uint16 new_w = (bf->width * percentage + 50) / 100;
+ uint16 new_h = (bf->height * percentage + 50) / 100;
+ assert(new_w * new_h < BOB_SHRINK_BUF_SIZE);
+
+ if (new_w != 0 && new_h != 0) {
+ _shrinkBuffer.width = new_w;
+ _shrinkBuffer.height = new_h;
+
+ uint16 x, y;
+ uint16 sh[GAME_SCREEN_WIDTH];
+ for (x = 0; x < MAX(new_h, new_w); ++x) {
+ sh[x] = x * 100 / percentage;
+ }
+ uint8* dst = _shrinkBuffer.data;
+ for (y = 0; y < new_h; ++y) {
+ uint8 *p = bf->data + sh[y] * bf->width;
+ for (x = 0; x < new_w; ++x) {
+ *dst++ = *(p + sh[x]);
+ }
+ }
+ }
+}
+
+void Graphics::sortBobs() {
+ _sortedBobsCount = 0;
+
+ // animate/move the bobs
+ for (int32 i = 0; i < ARRAYSIZE(_bobs); ++i) {
+ BobSlot *pbs = &_bobs[i];
+ if (pbs->active) {
+ _sortedBobs[_sortedBobsCount] = pbs;
+ ++_sortedBobsCount;
+
+ if (pbs->animating) {
+ pbs->animOneStep();
+ if (pbs->frameNum > 500) { // SFX frame
+ _vm->sound()->playSfx(_vm->logic()->currentRoomSfx(), false);
+ pbs->frameNum -= 500;
+ }
+ }
+ if (pbs->moving) {
+ int16 j;
+ for (j = 0; pbs->moving && j < pbs->speed; ++j) {
+ pbs->moveOneStep();
+ }
+ }
+ }
+ }
+ qsort(_sortedBobs, _sortedBobsCount, sizeof(BobSlot *), compareBobDrawOrder);
+}
+
+void Graphics::drawBobs() {
+ const Box *bobBox = _vm->display()->fullscreen() ? &_fullScreenBox : &_gameScreenBox;
+ for (int i = 0; i < _sortedBobsCount; ++i) {
+ BobSlot *pbs = _sortedBobs[i];
+ if (pbs->active) {
+
+ BobFrame *pbf = _vm->bankMan()->fetchFrame(pbs->frameNum);
+ uint16 xh, yh, x, y;
+
+ xh = pbf->xhotspot;
+ yh = pbf->yhotspot;
+
+ if (pbs->xflip) {
+ xh = pbf->width - xh;
+ }
+
+ // adjusts hot spots when object is scaled
+ if (pbs->scale != 100) {
+ xh = (xh * pbs->scale) / 100;
+ yh = (yh * pbs->scale) / 100;
+ }
+
+ // adjusts position to hot-spot and screen scroll
+ x = pbs->x - xh - _vm->display()->horizontalScroll();
+ y = pbs->y - yh;
+
+ drawBob(pbs, pbf, bobBox, x, y);
+ }
+ }
+}
+
+void Graphics::clearBobs() {
+ for (int32 i = 0; i < ARRAYSIZE(_bobs); ++i) {
+ _bobs[i].clear();
+ }
+}
+
+void Graphics::stopBobs() {
+ for (int32 i = 0; i < ARRAYSIZE(_bobs); ++i) {
+ _bobs[i].moving = false;
+ }
+}
+
+BobSlot *Graphics::bob(int index) {
+ assert(index < MAX_BOBS_NUMBER);
+ return &_bobs[index];
+}
+
+void Graphics::setBobText(const BobSlot *pbs, const char *text, int textX, int textY, int color, int flags) {
+
+ if (text[0] == '\0')
+ return;
+
+ // Duplicate string and append zero if needed
+
+ char textCopy[MAX_STRING_SIZE];
+
+ int length = strlen(text);
+ memcpy(textCopy, text, length);
+
+ if (textCopy[length - 1] >= 'A')
+ textCopy[length++] = '.';
+
+ textCopy[length] = '\0';
+
+ // Split text into lines
+
+ char lines[8][MAX_STRING_SIZE];
+ int lineCount = 0;
+ int lineLength = 0;
+ int i;
+
+ // Hebrew strings are written from right to left and should be cut
+ // to lines in reverse
+ if (_vm->resource()->getLanguage() == HEBREW) {
+ for (i = length - 1; i >= 0; i--) {
+ lineLength++;
+
+ if ((lineLength > 20 && textCopy[i] == ' ') || i == 0) {
+ memcpy(lines[lineCount], textCopy + i, lineLength);
+ lines[lineCount][lineLength] = '\0';
+ lineCount++;
+ lineLength = 0;
+ }
+ }
+ } else {
+ for (i = 0; i < length; i++) {
+ lineLength++;
+
+ if ((lineLength > 20 && textCopy[i] == ' ') || i == (length-1)) {
+ memcpy(lines[lineCount], textCopy + i + 1 - lineLength, lineLength);
+ lines[lineCount][lineLength] = '\0';
+ lineCount++;
+ lineLength = 0;
+ }
+ }
+ }
+
+ // Find width of widest line
+
+ int maxLineWidth = 0;
+
+ for (i = 0; i < lineCount; i++) {
+ int width = _vm->display()->textWidth(lines[i]);
+ if (maxLineWidth < width)
+ maxLineWidth = width;
+ }
+
+ // Calc text position
+
+ short x, y, width, height;
+
+ if (flags) {
+ if (flags == 2)
+ x = 160 - maxLineWidth / 2;
+ else
+ x = textX;
+
+ y = textY;
+
+ width = 0;
+ } else {
+ x = pbs->x;
+ y = pbs->y;
+
+ BobFrame *pbf = _vm->bankMan()->fetchFrame(pbs->frameNum);
+
+ width = (pbf->width * pbs->scale) / 100;
+ height = (pbf->height * pbs->scale) / 100;
+
+ y = y - height - 16 - lineCount * 9;
+ }
+
+ x -= _vm->display()->horizontalScroll();
+
+ if (y < 0) {
+ y = 0;
+
+ if (x < 160)
+ x += width / 2;
+ else
+ x -= width / 2 + maxLineWidth;
+ } else if (!flags)
+ x -= maxLineWidth / 2;
+
+ if (x < 0)
+ x = 4;
+ else if ((x + maxLineWidth) > 320)
+ x = 320 - maxLineWidth - 4;
+
+ _vm->display()->textCurrentColor(color);
+
+ for (i = 0; i < lineCount; i++) {
+ int lineX = x + (maxLineWidth - _vm->display()->textWidth(lines[i])) / 2;
+
+ debug(7, "Setting text '%s' at (%i, %i)", lines[i], lineX, y + 9 * i);
+ _vm->display()->setText(lineX, y + 9 * i, lines[i]);
+ }
+}
+
+void Graphics::handleParallax(uint16 roomNum) {
+ uint16 screenScroll = _vm->display()->horizontalScroll();
+ switch (roomNum) {
+ case ROOM_AMAZON_HIDEOUT:
+ _bobs[8].x = 250 - screenScroll / 2;
+ break;
+ case ROOM_TEMPLE_MAZE_5:
+ _bobs[5].x = 410 - screenScroll / 2;
+ _bobs[6].x = 790 - screenScroll / 2;
+ break;
+ case ROOM_TEMPLE_OUTSIDE:
+ _bobs[5].x = 320 - screenScroll / 2;
+ break;
+ case ROOM_TEMPLE_TREE:
+ _bobs[5].x = 280 - screenScroll / 2;
+ break;
+ case ROOM_VALLEY_CARCASS:
+ _bobs[5].x = 600 - screenScroll / 2;
+ break;
+ case ROOM_UNUSED_INTRO_1:
+ _bobs[5].x = 340 - screenScroll / 2;
+ _bobs[6].x = 50 - screenScroll / 2;
+ _bobs[7].x = 79 - screenScroll / 2;
+ break;
+ case ROOM_CAR_CHASE:
+ _vm->bam()->updateCarAnimation();
+ break;
+ case ROOM_FINAL_FIGHT:
+ _vm->bam()->updateFightAnimation();
+ break;
+ case ROOM_INTRO_RITA_JOE_HEADS:
+ _cameraBob = -1;
+ if (screenScroll < 80) {
+ _vm->display()->horizontalScroll(screenScroll + 4);
+ // Joe's body and head
+ _bobs[ 1].x += 4;
+ _bobs[20].x += 4;
+ // Rita's body and head
+ _bobs[ 2].x -= 2;
+ _bobs[21].x -= 2;
+ }
+ break;
+ case ROOM_INTRO_EXPLOSION:
+ _bobs[21].x += 2;
+ _bobs[21].y += 2;
+ break;
+ }
+}
+
+void Graphics::setupNewRoom(const char *room, uint16 roomNum, int16 *furniture, uint16 furnitureCount) {
+ // reset sprites table
+ clearBobs();
+
+ // load/setup objects associated to this room
+ char filename[20];
+ sprintf(filename, "%s.BBK", room);
+ _vm->bankMan()->load(filename, 15);
+
+ _numFrames = FRAMES_JOE + 1;
+ setupRoomFurniture(furniture, furnitureCount);
+ setupRoomObjects();
+
+ if (roomNum >= 90) {
+ putCameraOnBob(0);
+ }
+}
+
+void Graphics::setBobCutawayAnim(uint16 bobNum, bool xflip, const AnimFrame *af, uint8 frameCount) {
+ assert(bobNum < 21 && frameCount < 30);
+ memcpy(_cutAnim[bobNum], af, sizeof(AnimFrame) * frameCount);
+ _bobs[bobNum].xflip = xflip;
+ _bobs[bobNum].animString(_cutAnim[bobNum]);
+}
+
+void Graphics::fillAnimBuffer(const char *anim, AnimFrame *af) {
+ for (;;) {
+ // anim frame format is "%3hu,%3hu," (frame number, frame speed)
+ af->frame = atoi(anim);
+ anim += 4;
+ af->speed = atoi(anim);
+ anim += 4;
+ if (af->frame == 0)
+ break;
+ ++af;
+ }
+}
+
+uint16 Graphics::countAnimFrames(const char *anim) {
+ AnimFrame afbuf[30];
+ fillAnimBuffer(anim, afbuf);
+
+ bool frames[256];
+ memset(frames, 0, sizeof(frames));
+ uint16 count = 0;
+ AnimFrame *af = afbuf;
+ for ( ; af->frame != 0; ++af) {
+ uint16 frameNum = af->frame;
+ if (frameNum > 500) {
+ frameNum -= 500;
+ }
+ if (!frames[frameNum]) {
+ frames[frameNum] = true;
+ ++count;
+ }
+ }
+ return count;
+}
+
+void Graphics::setupObjectAnim(const GraphicData *gd, uint16 firstImage, uint16 bobNum, bool visible) {
+ int16 tempFrames[20];
+ memset(tempFrames, 0, sizeof(tempFrames));
+ uint16 numTempFrames = 0;
+ uint16 i, j;
+ for (i = 1; i <= _vm->logic()->graphicAnimCount(); ++i) {
+ const GraphicAnim *pga = _vm->logic()->graphicAnim(i);
+ if (pga->keyFrame == gd->firstFrame) {
+ int16 frame = pga->frame;
+ if (frame > 500) { // SFX
+ frame -= 500;
+ }
+ bool foundMatchingFrame = false;
+ for (j = 0; j < numTempFrames; ++j) {
+ if (tempFrames[j] == frame) {
+ foundMatchingFrame = true;
+ break;
+ }
+ }
+ if (!foundMatchingFrame) {
+ assert(numTempFrames < 20);
+ tempFrames[numTempFrames] = frame;
+ ++numTempFrames;
+ }
+ }
+ }
+
+ // sort found frames ascending
+ bool swap = true;
+ while (swap) {
+ swap = false;
+ for (i = 0; i < numTempFrames - 1; ++i) {
+ if (tempFrames[i] > tempFrames[i + 1]) {
+ SWAP(tempFrames[i], tempFrames[i + 1]);
+ swap = true;
+ }
+ }
+ }
+
+ // queen.c l.962-980 / l.1269-1294
+ for (i = 0; i < gd->lastFrame; ++i) {
+ _vm->bankMan()->unpack(ABS(tempFrames[i]), firstImage + i, 15);
+ }
+ BobSlot *pbs = bob(bobNum);
+ pbs->animating = false;
+ if (visible) {
+ pbs->curPos(gd->x, gd->y);
+ if (tempFrames[0] < 0) {
+ pbs->xflip = true;
+ }
+ AnimFrame *paf = _newAnim[bobNum];
+ for (i = 1; i <= _vm->logic()->graphicAnimCount(); ++i) {
+ const GraphicAnim *pga = _vm->logic()->graphicAnim(i);
+ if (pga->keyFrame == gd->firstFrame) {
+ uint16 frameNr = 0;
+ for (j = 1; j <= gd->lastFrame; ++j) {
+ if (pga->frame > 500) {
+ if (pga->frame - 500 == tempFrames[j - 1]) {
+ frameNr = j + firstImage - 1 + 500;
+ }
+ } else if (pga->frame == tempFrames[j - 1]) {
+ frameNr = j + firstImage - 1;
+ }
+ }
+ paf->frame = frameNr;
+ paf->speed = pga->speed;
+ ++paf;
+ }
+ }
+ paf->frame = 0;
+ paf->speed = 0;
+ pbs->animString(_newAnim[bobNum]);
+ }
+}
+
+uint16 Graphics::setupPersonAnim(const ActorData *ad, const char *anim, uint16 curImage) {
+ debug(9, "Graphics::setupPersonAnim(%s, %d)", anim, curImage);
+ _personFrames[ad->bobNum] = curImage + 1;
+
+ AnimFrame *animFrames = _newAnim[ad->bobNum];
+ fillAnimBuffer(anim, animFrames);
+ uint16 frameCount[256];
+ memset(frameCount, 0, sizeof(frameCount));
+ AnimFrame *af = animFrames;
+ for ( ; af->frame != 0; ++af) {
+ uint16 frameNum = af->frame;
+ if (frameNum > 500) {
+ frameNum -= 500;
+ }
+ if (!frameCount[frameNum]) {
+ frameCount[frameNum] = 1;
+ }
+ }
+ uint16 i, n = 1;
+ for (i = 1; i < 256; ++i) {
+ if (frameCount[i]) {
+ frameCount[i] = n;
+ ++n;
+ }
+ }
+ af = animFrames;
+ for ( ; af->frame != 0; ++af) {
+ if (af->frame > 500) {
+ af->frame = curImage + frameCount[af->frame - 500] + 500;
+ } else {
+ af->frame = curImage + frameCount[af->frame];
+ }
+ }
+
+ // unpack necessary frames
+ for (i = 1; i < 256; ++i) {
+ if (frameCount[i]) {
+ ++curImage;
+ _vm->bankMan()->unpack(i, curImage, ad->bankNum);
+ }
+ }
+
+ // start animation
+ bob(ad->bobNum)->animString(animFrames);
+ return curImage;
+}
+
+void Graphics::resetPersonAnim(uint16 bobNum) {
+ if (_newAnim[bobNum][0].frame != 0) {
+ bob(bobNum)->animString(_newAnim[bobNum]);
+ }
+}
+
+void Graphics::erasePersonAnim(uint16 bobNum) {
+ _newAnim[bobNum][0].frame = 0;
+ BobSlot *pbs = bob(bobNum);
+ pbs->animating = false;
+ pbs->anim.string.buffer = NULL;
+}
+
+void Graphics::eraseAllAnims() {
+ for (int i = 1; i <= 16; ++i) {
+ _newAnim[i][0].frame = 0;
+ }
+}
+
+uint16 Graphics::refreshObject(uint16 obj) {
+ debug(6, "Graphics::refreshObject(%X)", obj);
+ uint16 curImage = _numFrames;
+
+ ObjectData *pod = _vm->logic()->objectData(obj);
+ if (pod->image == 0) {
+ return curImage;
+ }
+
+ // check the object is in the current room
+ if (pod->room != _vm->logic()->currentRoom()) {
+ return curImage;
+ }
+
+ // find bob for the object
+ uint16 curBob = _vm->logic()->findBob(obj);
+ BobSlot *pbs = bob(curBob);
+
+ if (pod->image == -3 || pod->image == -4) {
+ // a person object
+ if (pod->name <= 0) {
+ pbs->clear();
+ } else {
+ // find person number
+ uint16 pNum = _vm->logic()->findPersonNumber(obj, _vm->logic()->currentRoom());
+ curImage = _personFrames[pNum] - 1;
+ if (_personFrames[pNum] == 0) {
+ _personFrames[pNum] = curImage = _numFrames;
+ }
+ curImage = setupPerson(obj - _vm->logic()->currentRoomData(), curImage);
+ }
+ return curImage;
+ }
+
+ // find frame used for object
+ curImage = _vm->logic()->findFrame(obj);
+
+ if (pod->name < 0 || pod->image < 0) {
+ // object is hidden or disabled
+ pbs->clear();
+ return curImage;
+ }
+
+ int image = pod->image;
+ if (image > 5000) {
+ image -= 5000;
+ }
+
+ GraphicData *pgd = _vm->logic()->graphicData(image);
+ bool rebound = false;
+ int16 lastFrame = pgd->lastFrame;
+ if (lastFrame < 0) {
+ lastFrame = -lastFrame;
+ rebound = true;
+ }
+ if (pgd->firstFrame < 0) {
+ setupObjectAnim(pgd, curImage, curBob, pod->name != 0);
+ curImage += pgd->lastFrame - 1;
+ } else if (lastFrame != 0) {
+ // turn on an animated bob
+ pbs->animating = false;
+ uint16 firstImage = curImage;
+ --curImage;
+ uint16 j;
+ for (j = pgd->firstFrame; j <= lastFrame; ++j) {
+ ++curImage;
+ _vm->bankMan()->unpack(j, curImage, 15);
+ }
+ pbs->curPos(pgd->x, pgd->y);
+ pbs->frameNum = firstImage;
+ if (pgd->speed > 0) {
+ pbs->animNormal(firstImage, curImage, pgd->speed / 4, rebound, false);
+ }
+ } else {
+ _vm->bankMan()->unpack(pgd->firstFrame, curImage, 15);
+ pbs->curPos(pgd->x, pgd->y);
+ pbs->frameNum = curImage;
+ }
+
+ return curImage;
+}
+
+void Graphics::setupRoomFurniture(int16 *furniture, uint16 furnitureCount) {
+ uint16 i;
+ uint16 curImage = FRAMES_JOE;
+
+ // unpack the static bobs
+ _numFurnitureStatic = 0;
+ for (i = 1; i <= furnitureCount; ++i) {
+ int16 obj = furniture[i];
+ if (obj > 0 && obj <= 5000) {
+ GraphicData *pgd = _vm->logic()->graphicData(obj);
+ if (pgd->lastFrame == 0) {
+ ++_numFurnitureStatic;
+ ++curImage;
+ _vm->bankMan()->unpack(pgd->firstFrame, curImage, 15);
+ ++_numFrames;
+ BobSlot *pbs = bob(19 + _numFurnitureStatic);
+ pbs->curPos(pgd->x, pgd->y);
+ pbs->frameNum = curImage;
+ }
+ }
+ }
+
+ // unpack the animated bobs
+ _numFurnitureAnimated = 0;
+ _numFurnitureAnimatedLen = 0;
+ uint16 curBob = 0;
+ for (i = 1; i <= furnitureCount; ++i) {
+ int16 obj = furniture[i];
+ if (obj > 0 && obj <= 5000) {
+ GraphicData *pgd = _vm->logic()->graphicData(obj);
+
+ bool rebound = false;
+ int16 lastFrame = pgd->lastFrame;
+ if (lastFrame < 0) {
+ rebound = true;
+ lastFrame = -lastFrame;
+ }
+
+ if (lastFrame > 0) {
+ _numFurnitureAnimatedLen += lastFrame - pgd->firstFrame + 1;
+ ++_numFurnitureAnimated;
+ uint16 image = curImage + 1;
+ int k;
+ for (k = pgd->firstFrame; k <= lastFrame; ++k) {
+ ++curImage;
+ _vm->bankMan()->unpack(k, curImage, 15);
+ ++_numFrames;
+ }
+ BobSlot *pbs = bob(5 + curBob);
+ pbs->animNormal(image, curImage, pgd->speed / 4, rebound, false);
+ pbs->curPos(pgd->x, pgd->y);
+ ++curBob;
+ }
+ }
+ }
+
+ // unpack the paste downs
+ for (i = 1; i <= furnitureCount; ++i) {
+ if (furniture[i] > 5000) {
+ pasteBob(furniture[i] - 5000, curImage + 1);
+ }
+ }
+}
+
+void Graphics::setupRoomObjects() {
+ uint16 i;
+ // furniture frames are reserved in ::setupRoomFurniture(), we append objects
+ // frames after the furniture ones.
+ uint16 curImage = FRAMES_JOE + _numFurnitureStatic + _numFurnitureAnimatedLen;
+ uint16 firstRoomObj = _vm->logic()->currentRoomData() + 1;
+ uint16 lastRoomObj = _vm->logic()->roomData(_vm->logic()->currentRoom() + 1);
+ uint16 numObjectStatic = 0;
+ uint16 numObjectAnimated = 0;
+ uint16 curBob;
+
+ // invalidates all Bobs for persons (except Joe's one)
+ for (i = 1; i <= 3; ++i) {
+ _bobs[i].active = false;
+ }
+
+ // static/animated Bobs
+ for (i = firstRoomObj; i <= lastRoomObj; ++i) {
+ ObjectData *pod = _vm->logic()->objectData(i);
+ // setup blanks bobs for turned off objects (in case
+ // you turn them on again)
+ if (pod->image == -1) {
+ // static OFF Bob
+ curBob = 20 + _numFurnitureStatic + numObjectStatic;
+ ++numObjectStatic;
+ // create a blank frame for the OFF object
+ ++_numFrames;
+ ++curImage;
+ } else if (pod->image == -2) {
+ // animated OFF Bob
+ curBob = 5 + _numFurnitureAnimated + numObjectAnimated;
+ ++numObjectAnimated;
+ } else if (pod->image > 0 && pod->image < 5000) {
+ GraphicData *pgd = _vm->logic()->graphicData(pod->image);
+ int16 lastFrame = pgd->lastFrame;
+ bool rebound = false;
+ if (lastFrame < 0) {
+ lastFrame = -lastFrame;
+ rebound = true;
+ }
+ if (pgd->firstFrame < 0) {
+ curBob = 5 + _numFurnitureAnimated;
+ setupObjectAnim(pgd, curImage + 1, curBob + numObjectAnimated, pod->name > 0);
+ curImage += pgd->lastFrame;
+ ++numObjectAnimated;
+ } else if (lastFrame != 0) {
+ // animated objects
+ uint16 j;
+ uint16 firstFrame = curImage + 1;
+ for (j = pgd->firstFrame; j <= lastFrame; ++j) {
+ ++curImage;
+ _vm->bankMan()->unpack(j, curImage, 15);
+ ++_numFrames;
+ }
+ curBob = 5 + _numFurnitureAnimated + numObjectAnimated;
+ if (pod->name > 0) {
+ BobSlot *pbs = bob(curBob);
+ pbs->curPos(pgd->x, pgd->y);
+ pbs->frameNum = firstFrame;
+ if (pgd->speed > 0) {
+ pbs->animNormal(firstFrame, curImage, pgd->speed / 4, rebound, false);
+ }
+ }
+ ++numObjectAnimated;
+ } else {
+ // static objects
+ curBob = 20 + _numFurnitureStatic + numObjectStatic;
+ ++curImage;
+ bob(curBob)->clear();
+
+ _vm->bankMan()->unpack(pgd->firstFrame, curImage, 15);
+ ++_numFrames;
+ if (pod->name > 0) {
+ BobSlot *pbs = bob(curBob);
+ pbs->curPos(pgd->x, pgd->y);
+ pbs->frameNum = curImage;
+ }
+ ++numObjectStatic;
+ }
+ }
+ }
+
+ // persons Bobs
+ for (i = firstRoomObj; i <= lastRoomObj; ++i) {
+ ObjectData *pod = _vm->logic()->objectData(i);
+ if (pod->image == -3 || pod->image == -4) {
+ debug(6, "Graphics::setupRoomObjects() - Setting up person %X, name=%X", i, pod->name);
+ uint16 noun = i - _vm->logic()->currentRoomData();
+ if (pod->name > 0) {
+ curImage = setupPerson(noun, curImage);
+ } else {
+ curImage = allocPerson(noun, curImage);
+ }
+ }
+ }
+
+ // paste downs list
+ ++curImage;
+ _numFrames = curImage;
+ for (i = firstRoomObj; i <= lastRoomObj; ++i) {
+ ObjectData *pod = _vm->logic()->objectData(i);
+ if (pod->name > 0 && pod->image > 5000) {
+ pasteBob(pod->image - 5000, curImage);
+ }
+ }
+}
+
+uint16 Graphics::setupPerson(uint16 noun, uint16 curImage) {
+ if (noun == 0) {
+ warning("Trying to setup person 0");
+ return curImage;
+ }
+
+ Person p;
+ if (!_vm->logic()->initPerson(noun, "", true, &p)) {
+ return curImage;
+ }
+
+ const ActorData *pad = p.actor;
+ uint16 scale = 100;
+ uint16 a = _vm->grid()->findAreaForPos(GS_ROOM, pad->x, pad->y);
+ if (a != 0) {
+ // person is not standing in the area box, scale it accordingly
+ scale = _vm->grid()->area(_vm->logic()->currentRoom(), a)->calcScale(pad->y);
+ }
+
+ _vm->bankMan()->unpack(pad->bobFrameStanding, p.bobFrame, p.actor->bankNum);
+ uint16 obj = _vm->logic()->currentRoomData() + noun;
+ BobSlot *pbs = bob(pad->bobNum);
+ pbs->curPos(pad->x, pad->y);
+ pbs->scale = scale;
+ pbs->frameNum = p.bobFrame;
+ pbs->xflip = (_vm->logic()->objectData(obj)->image == -3); // person is facing left
+
+ debug(6, "Graphics::setupPerson(%d, %d) - bob = %d name = %s", noun, curImage, pad->bobNum, p.name);
+
+ if (p.anim != NULL) {
+ curImage = setupPersonAnim(pad, p.anim, curImage);
+ } else {
+ erasePersonAnim(pad->bobNum);
+ }
+ return curImage;
+}
+
+uint16 Graphics::allocPerson(uint16 noun, uint16 curImage) {
+ Person p;
+ if (_vm->logic()->initPerson(noun, "", false, &p) && p.anim != NULL) {
+ curImage += countAnimFrames(p.anim);
+ _personFrames[p.actor->bobNum] = curImage + 1;
+ }
+ return curImage;
+}
+
+void Graphics::update(uint16 room) {
+ sortBobs();
+ if (_cameraBob >= 0) {
+ _vm->display()->horizontalScrollUpdate(_bobs[_cameraBob].x);
+ }
+ handleParallax(room);
+ _vm->display()->prepareUpdate();
+ drawBobs();
+}
+
+
+BamScene::BamScene(QueenEngine *vm)
+ : _flag(F_STOP), _screenShaked(false), _fightData(_fight1Data), _vm(vm) {
+}
+
+void BamScene::playSfx() {
+ // FIXME - we don't play all sfx here. This is only necessary for
+ // the fight bam, where the number of 'sfx bam frames' is too much
+ // important / too much closer. The original game does not have
+ // this problem since their playSfx() function returns immediately
+ // if a sound is already being played.
+ if (_lastSoundIndex == 0 || _index - _lastSoundIndex >= SFX_SKIP) {
+ _vm->sound()->playSfx(_vm->logic()->currentRoomSfx(), false);
+ _lastSoundIndex = _index;
+ }
+}
+
+void BamScene::prepareAnimation() {
+ _obj1 = _vm->graphics()->bob(BOB_OBJ1);
+ _obj1->clear();
+ _obj1->active = true;
+
+ _obj2 = _vm->graphics()->bob(BOB_OBJ2);
+ _obj2->clear();
+ _obj2->active = true;
+
+ _objfx = _vm->graphics()->bob(BOB_FX);
+ _objfx->clear();
+ _objfx->active = true;
+
+ _index = 0;
+ _lastSoundIndex = 0;
+}
+
+void BamScene::updateCarAnimation() {
+ if (_flag != F_STOP) {
+ const BamDataBlock *bdb = &_carData[_index];
+
+ // Truck
+ _obj1->curPos(bdb->obj1.x, bdb->obj1.y);
+ _obj1->frameNum = 40 + bdb->obj1.frame;
+
+ // Rico
+ _obj2->curPos(bdb->obj2.x, bdb->obj2.y);
+ _obj2->frameNum = 30 + bdb->obj2.frame;
+
+ // FX
+ _objfx->curPos(bdb->fx.x, bdb->fx.y);
+ _objfx->frameNum = 41 + bdb->fx.frame;
+
+ if (bdb->sfx < 0) {
+ _vm->sound()->playSong(-bdb->sfx);
+ }
+
+ if (bdb->sfx == 99) {
+ _lastSoundIndex = _index = 0;
+ } else {
+ ++_index;
+ }
+
+ if (bdb->sfx == 2) {
+ playSfx();
+ }
+ }
+}
+
+void BamScene::updateFightAnimation() {
+ static const BamDataBlock *fightDataBlocks[] = {
+ _fight1Data,
+ _fight2Data,
+ _fight3Data
+ };
+ if (_flag != F_STOP) {
+ const BamDataBlock *bdb = &_fightData[_index];
+
+ // Frank
+ _obj1->curPos(bdb->obj1.x, bdb->obj1.y);
+ _obj1->frameNum = 40 + ABS(bdb->obj1.frame);
+ _obj1->xflip = (bdb->obj1.frame < 0);
+
+ // Robot
+ _obj2->curPos(bdb->obj2.x, bdb->obj2.y);
+ _obj2->frameNum = 40 + ABS(bdb->obj2.frame);
+ _obj2->xflip = (bdb->obj2.frame < 0);
+
+ // FX
+ _objfx->curPos(bdb->fx.x, bdb->fx.y);
+ _objfx->frameNum = 40 + ABS(bdb->fx.frame);
+ _objfx->xflip = (bdb->fx.frame < 0);
+
+ if (bdb->sfx < 0) {
+ _vm->sound()->playSong(-bdb->sfx);
+ }
+
+ ++_index;
+ switch (bdb->sfx) {
+ case 0: // nothing, so reset shaked screen if necessary
+ if (_screenShaked) {
+ _vm->display()->shake(true);
+ _screenShaked = false;
+ }
+ break;
+ case 1: // shake screen
+ _vm->display()->shake(false);
+ _screenShaked = true;
+ break;
+ case 2: // play background sfx
+ playSfx();
+ break;
+ case 3: // play background sfx and shake screen
+ playSfx();
+ _vm->display()->shake(false);
+ _screenShaked = true;
+ break;
+ case 99: // end of BAM data
+ _lastSoundIndex = _index = 0;
+ _fightData = fightDataBlocks[_vm->randomizer.getRandomNumber(2)];
+ if (_flag == F_REQ_STOP) {
+ _flag = F_STOP;
+ }
+ break;
+ }
+ }
+}
+
+void BamScene::saveState(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, _flag); ptr += 2;
+}
+
+void BamScene::loadState(uint32 ver, byte *&ptr) {
+ _flag = READ_BE_UINT16(ptr); ptr += 2;
+}
+
+#ifndef PALMOS_68K
+const BamScene::BamDataBlock BamScene::_carData[] = {
+ { { 310, 105, 1 }, { 314, 106, 17 }, { 366, 101, 1 }, 0 },
+ { { 303, 105, 1 }, { 307, 106, 17 }, { 214, 0, 10 }, 0 },
+ { { 297, 104, 1 }, { 301, 105, 17 }, { 214, 0, 10 }, 0 },
+ { { 294, 103, 1 }, { 298, 104, 17 }, { 214, 0, 10 }, 0 },
+ { { 291, 102, 1 }, { 295, 103, 18 }, { 214, 0, 10 }, 0 },
+ { { 287, 101, 1 }, { 291, 102, 18 }, { 266, 51, 10 }, 2 },
+ { { 283, 100, 1 }, { 287, 101, 19 }, { 279, 47, 11 }, 0 },
+ { { 279, 99, 1 }, { 283, 100, 20 }, { 294, 46, 12 }, 0 },
+ { { 274, 98, 1 }, { 278, 99, 20 }, { 305, 44, 13 }, 0 },
+ { { 269, 98, 1 }, { 273, 99, 20 }, { 320, 42, 14 }, 0 },
+ { { 264, 98, 1 }, { 268, 99, 17 }, { 214, 0, 10 }, 0 },
+ { { 261, 98, 1 }, { 265, 99, 17 }, { 214, 0, 10 }, 0 },
+ { { 259, 98, 1 }, { 263, 99, 17 }, { 214, 0, 10 }, 0 },
+ { { 258, 98, 1 }, { 262, 99, 17 }, { 214, 0, 10 }, 0 },
+ { { 257, 98, 2 }, { 260, 99, 17 }, { 214, 0, 10 }, 0 },
+ { { 255, 99, 3 }, { 258, 100, 17 }, { 214, 0, 10 }, 0 },
+ { { 258, 99, 4 }, { 257, 100, 17 }, { 214, 0, 10 }, 0 },
+ { { 264, 102, 4 }, { 263, 103, 17 }, { 214, 0, 10 }, 0 },
+ { { 272, 105, 5 }, { 274, 106, 17 }, { 214, 0, 10 }, 0 },
+ { { 276, 107, 5 }, { 277, 108, 17 }, { 214, 0, 10 }, 0 },
+ { { 283, 108, 5 }, { 284, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 288, 109, 5 }, { 288, 110, 17 }, { 214, 0, 10 }, 0 },
+ { { 293, 110, 5 }, { 293, 111, 18 }, { 266, 59, 10 }, 2 },
+ { { 298, 110, 5 }, { 299, 111, 18 }, { 277, 56, 11 }, 0 },
+ { { 303, 110, 5 }, { 304, 111, 19 }, { 285, 55, 12 }, 0 },
+ { { 308, 110, 4 }, { 307, 111, 20 }, { 296, 54, 13 }, 0 },
+ { { 309, 110, 3 }, { 312, 111, 20 }, { 304, 53, 14 }, 0 },
+ { { 310, 110, 3 }, { 313, 111, 20 }, { 214, 0, 10 }, 0 },
+ { { 311, 110, 3 }, { 314, 111, 17 }, { 214, 0, 10 }, 0 },
+ { { 309, 110, 2 }, { 312, 111, 17 }, { 214, 0, 10 }, 0 },
+ { { 304, 111, 2 }, { 307, 112, 17 }, { 214, 0, 10 }, 0 },
+ { { 300, 110, 2 }, { 303, 111, 17 }, { 214, 0, 10 }, 0 },
+ { { 296, 109, 2 }, { 299, 110, 17 }, { 214, 0, 10 }, 0 },
+ { { 292, 108, 1 }, { 296, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 285, 107, 2 }, { 289, 108, 17 }, { 214, 0, 10 }, 0 },
+ { { 282, 107, 3 }, { 285, 108, 17 }, { 214, 0, 10 }, 0 },
+ { { 278, 107, 4 }, { 277, 108, 18 }, { 214, 0, 10 }, 0 },
+ { { 279, 108, 4 }, { 278, 109, 18 }, { 252, 57, 10 }, 2 },
+ { { 281, 108, 5 }, { 283, 109, 18 }, { 265, 55, 11 }, 0 },
+ { { 284, 109, 5 }, { 285, 110, 19 }, { 277, 55, 12 }, 0 },
+ { { 287, 110, 5 }, { 288, 111, 20 }, { 288, 54, 13 }, 0 },
+ { { 289, 111, 5 }, { 290, 112, 20 }, { 299, 54, 14 }, 0 },
+ { { 291, 112, 4 }, { 290, 113, 20 }, { 214, 0, 10 }, 0 },
+ { { 293, 113, 3 }, { 295, 114, 17 }, { 214, 0, 10 }, 0 },
+ { { 296, 114, 2 }, { 299, 115, 17 }, { 214, 0, 10 }, 0 },
+ { { 295, 115, 2 }, { 298, 116, 17 }, { 214, 0, 10 }, 0 },
+ { { 293, 116, 1 }, { 297, 117, 17 }, { 214, 0, 10 }, 0 },
+ { { 289, 116, 1 }, { 292, 117, 17 }, { 214, 0, 10 }, 0 },
+ { { 285, 115, 1 }, { 289, 116, 17 }, { 214, 0, 10 }, 0 },
+ { { 281, 114, 1 }, { 284, 115, 17 }, { 214, 0, 10 }, 0 },
+ { { 277, 113, 1 }, { 280, 114, 17 }, { 214, 0, 10 }, 0 },
+ { { 274, 112, 1 }, { 277, 113, 17 }, { 214, 0, 10 }, 0 },
+ { { 271, 111, 1 }, { 274, 112, 17 }, { 214, 0, 10 }, 0 },
+ { { 267, 110, 1 }, { 270, 111, 17 }, { 214, 0, 10 }, 0 },
+ { { 263, 109, 1 }, { 266, 110, 17 }, { 214, 0, 10 }, 0 },
+ { { 260, 108, 1 }, { 263, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 254, 108, 2 }, { 256, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 252, 107, 3 }, { 254, 108, 17 }, { 214, 0, 10 }, 0 },
+ { { 253, 108, 3 }, { 255, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 255, 109, 3 }, { 257, 110, 18 }, { 231, 59, 10 }, 2 },
+ { { 258, 111, 3 }, { 260, 112, 18 }, { 242, 57, 11 }, 0 },
+ { { 263, 112, 4 }, { 262, 113, 19 }, { 256, 57, 12 }, 0 },
+ { { 270, 111, 4 }, { 269, 112, 20 }, { 267, 57, 13 }, 0 },
+ { { 274, 112, 5 }, { 276, 113, 20 }, { 281, 56, 14 }, 0 },
+ { { 280, 111, 6 }, { 282, 112, 19 }, { 214, 0, 10 }, 0 },
+ { { 284, 109, 6 }, { 285, 110, 17 }, { 214, 0, 10 }, 0 },
+ { { 289, 108, 6 }, { 291, 109, 17 }, { 214, 0, 10 }, 0 },
+ { { 294, 107, 6 }, { 296, 108, 17 }, { 214, 0, 10 }, 0 },
+ { { 294, 107, 5 }, { 296, 108, 18 }, { 272, 57, 10 }, 2 },
+ { { 295, 107, 5 }, { 297, 108, 18 }, { 282, 57, 11 }, 0 },
+ { { 296, 108, 5 }, { 298, 109, 19 }, { 295, 57, 12 }, 0 },
+ { { 300, 108, 4 }, { 299, 109, 20 }, { 303, 57, 13 }, 0 },
+ { { 303, 108, 3 }, { 306, 109, 20 }, { 313, 57, 14 }, 0 },
+ { { 307, 109, 2 }, { 311, 110, 17 }, { 214, 0, 10 }, 0 },
+ { { 310, 110, 1 }, { 314, 111, 17 }, { 214, 0, 10 }, 99 }
+};
+
+const BamScene::BamDataBlock BamScene::_fight1Data[] = {
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 2 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 3 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 4 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 2 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 3 }, { 187, 96, -23 }, { 58, 37, 46 }, 0 },
+ { { 75, 96, 4 }, { 187, 96, -24 }, { 58, 37, 46 }, 0 },
+ { { 79, 96, 1 }, { 187, 96, -24 }, { 58, 37, 46 }, 0 },
+ { { 85, 96, 2 }, { 187, 96, -24 }, { 58, 37, 46 }, 0 },
+ { { 94, 96, 3 }, { 187, 96, -24 }, { 58, 37, 46 }, 0 },
+ { { 100, 96, 4 }, { 187, 96, -24 }, { 58, 37, 46 }, 0 },
+ { { 113, 96, 1 }, { 187, 96, -25 }, { 58, 37, 46 }, 0 },
+ { { 121, 96, 1 }, { 187, 96, -25 }, { 58, 37, 46 }, 0 },
+ { { 136, 96, 16 }, { 187, 96, -26 }, { 58, 37, 46 }, 0 },
+ { { 151, 93, 6 }, { 187, 96, -27 }, { 58, 37, 46 }, 0 },
+ { { 159, 83, 16 }, { 187, 96, -28 }, { 58, 37, 46 }, 0 },
+ { { 170, 73, 16 }, { 187, 96, -29 }, { 182, 96, 48 }, 3 },
+ { { 176, 69, 13 }, { 187, 96, -31 }, { 182, 94, 49 }, 1 },
+ { { 168, 66, 13 }, { 187, 98, -32 }, { 182, 92, 50 }, 0 },
+ { { 155, 75, 13 }, { 187, 96, -32 }, { 182, 88, 51 }, 3 },
+ { { 145, 86, 13 }, { 187, 98, -32 }, { 182, 85, 52 }, 0 },
+ { { 127, 104, 13 }, { 187, 98, -32 }, { 182, 25, 52 }, 1 },
+ { { 122, 108, 13 }, { 187, 98, -32 }, { 182, 25, 52 }, 1 },
+ { { 120, 104, 14 }, { 187, 96, -34 }, { 107, 145, 42 }, 2 },
+ { { 111, 103, 13 }, { 187, 96, -23 }, { 107, 144, 43 }, 0 },
+ { { 102, 105, 13 }, { 187, 96, -23 }, { 107, 142, 43 }, 0 },
+ { { 97, 107, 13 }, { 187, 96, -23 }, { 107, 139, 44 }, 0 },
+ { { 92, 101, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 3 },
+ { { 90, 105, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 0 },
+ { { 88, 104, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 0 },
+ { { 87, 105, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 0 },
+ { { 86, 105, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 0 },
+ { { 86, 105, 14 }, { 187, 96, -23 }, { 107, 34, 47 }, 0 },
+ { { 86, 105, 15 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 85, 98, 16 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 92, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 92, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 89, 96, 4 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 86, 96, 3 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 83, 96, 2 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 81, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 78, 96, 4 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 75, 96, 3 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 0 },
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 0, 0, 0 }, 99 }
+};
+
+const BamScene::BamDataBlock BamScene::_fight2Data[] = {
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 150, 45, 35 }, 0 },
+ { { 78, 96, 2 }, { 187, 96, -23 }, { 150, 45, 35 }, 0 },
+ { { 81, 96, 3 }, { 189, 96, -18 }, { 150, 45, 35 }, 0 },
+ { { 84, 96, 4 }, { 183, 96, -19 }, { 150, 45, 35 }, 0 },
+ { { 87, 96, 1 }, { 181, 96, -20 }, { 150, 45, 35 }, 0 },
+ { { 90, 96, 2 }, { 177, 96, -21 }, { 150, 45, 35 }, 0 },
+ { { 93, 96, 3 }, { 171, 96, -22 }, { 150, 45, 35 }, 0 },
+ { { 96, 96, 4 }, { 169, 96, -17 }, { 150, 45, 35 }, 0 },
+ { { 99, 96, 1 }, { 165, 96, -18 }, { 150, 45, 35 }, 0 },
+ { { 102, 96, 2 }, { 159, 96, -19 }, { 150, 45, 35 }, 0 },
+ { { 105, 96, 3 }, { 157, 96, -20 }, { 150, 45, 35 }, 0 },
+ { { 108, 96, 4 }, { 153, 96, -21 }, { 150, 45, 35 }, 0 },
+ { { 111, 96, 1 }, { 147, 96, -22 }, { 150, 45, 35 }, 0 },
+ { { 114, 96, 2 }, { 147, 96, -23 }, { 150, 45, 35 }, 0 },
+ { { 117, 96, 3 }, { 147, 96, -23 }, { 150, 45, 35 }, 0 },
+ { { 120, 96, 4 }, { 147, 96, -24 }, { 150, 45, 35 }, 0 },
+ { { 123, 96, 1 }, { 147, 96, -25 }, { 150, 45, 35 }, 0 },
+ { { 125, 96, 2 }, { 147, 96, -25 }, { 150, 45, 35 }, 0 },
+ { { 127, 96, 12 }, { 147, 96, -69 }, { 122, 94, 36 }, 3 },
+ { { 127, 95, 11 }, { 147, 96, -70 }, { 122, 94, 41 }, 0 },
+ { { 127, 96, 12 }, { 147, 96, -71 }, { 122, 100, 36 }, 3 },
+ { { 127, 97, 11 }, { 147, 96, -69 }, { 122, 100, 41 }, 0 },
+ { { 127, 96, 12 }, { 147, 96, -70 }, { 127, 103, 36 }, 3 },
+ { { 127, 95, 11 }, { 147, 96, -71 }, { 127, 103, 41 }, 0 },
+ { { 127, 94, 12 }, { 147, 96, -69 }, { 123, 94, 36 }, 3 },
+ { { 127, 95, 11 }, { 147, 96, -70 }, { 123, 94, 41 }, 0 },
+ { { 127, 96, 12 }, { 147, 96, -71 }, { 120, 99, 36 }, 3 },
+ { { 127, 96, 12 }, { 147, 96, -71 }, { 115, 98, 41 }, 0 },
+ { { 117, 93, 11 }, { 147, 96, -25 }, { 115, 134, 42 }, 0 },
+ { { 110, 92, 11 }, { 147, 96, -25 }, { 114, 133, 42 }, 0 },
+ { { 102, 93, 11 }, { 147, 96, -25 }, { 114, 131, 43 }, 0 },
+ { { 92, 93, 11 }, { 147, 96, -25 }, { 114, 130, 43 }, 0 },
+ { { 82, 94, 11 }, { 147, 96, -25 }, { 114, 128, 44 }, 0 },
+ { { 76, 95, 11 }, { 147, 96, -25 }, { 114, 127, 44 }, 0 },
+ { { 70, 96, 11 }, { 147, 96, -25 }, { 114, 126, 45 }, 0 },
+ { { 75, 96, 5 }, { 147, 96, -25 }, { 114, 125, 46 }, 1 },
+ { { 75, 96, 6 }, { 147, 96, -25 }, { 114, 43, 46 }, 0 },
+ { { 75, 96, 6 }, { 147, 96, -25 }, { 114, 43, 46 }, 0 },
+ { { 75, 96, 5 }, { 147, 96, -25 }, { 114, 43, 46 }, 0 },
+ { { 75, 96, 7 }, { 147, 96, -25 }, { 114, 43, 46 }, 0 },
+ { { 75, 96, 68 }, { 147, 96, -25 }, { 114, 43, 46 }, 0 },
+ { { 75, 96, 68 }, { 147, 96, -25 }, { 89, 104, 36 }, 2 },
+ { { 75, 96, 68 }, { 147, 96, -25 }, { 94, 103, 62 }, 0 },
+ { { 75, 96, 68 }, { 147, 96, -25 }, { 122, 103, 63 }, 0 },
+ { { 75, 96, 68 }, { 147, 96, -25 }, { 141, 103, 64 }, 0 },
+ { { 75, 96, 68 }, { 147, 96, -30 }, { 150, 103, 65 }, 3 },
+ { { 75, 96, 68 }, { 156, 96, -30 }, { 160, 103, 66 }, 0 },
+ { { 75, 96, 7 }, { 164, 96, -30 }, { 169, 103, 67 }, 0 },
+ { { 75, 96, 5 }, { 169, 96, -30 }, { 177, 103, 48 }, 3 },
+ { { 75, 96, 5 }, { 173, 96, -30 }, { 185, 103, 49 }, 0 },
+ { { 75, 96, 6 }, { 178, 96, -30 }, { 198, 103, 50 }, 0 },
+ { { 75, 96, 6 }, { 181, 96, -30 }, { 207, 103, 51 }, 1 },
+ { { 75, 96, 5 }, { 184, 96, -30 }, { 221, 103, 52 }, 0 },
+ { { 75, 96, 5 }, { 186, 96, -30 }, { 224, 53, 53 }, 0 },
+ { { 75, 96, 5 }, { 187, 96, -23 }, { 224, 53, 53 }, 99 }
+};
+
+const BamScene::BamDataBlock BamScene::_fight3Data[] = {
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 150, 45, 35 }, 0 },
+ { { 77, 96, 2 }, { 187, 96, -22 }, { 150, 45, 35 }, 0 },
+ { { 80, 96, 3 }, { 185, 96, -17 }, { 150, 45, 35 }, 0 },
+ { { 83, 96, 4 }, { 181, 96, -18 }, { 150, 45, 35 }, 0 },
+ { { 86, 96, 1 }, { 175, 96, -19 }, { 150, 45, 35 }, 0 },
+ { { 88, 96, 2 }, { 173, 96, -20 }, { 150, 45, 35 }, 0 },
+ { { 91, 96, 3 }, { 169, 96, -21 }, { 150, 45, 35 }, 0 },
+ { { 94, 96, 4 }, { 163, 96, -22 }, { 150, 45, 35 }, 0 },
+ { { 97, 96, 1 }, { 161, 96, -17 }, { 150, 45, 35 }, 0 },
+ { { 99, 96, 2 }, { 157, 96, -18 }, { 150, 45, 35 }, 0 },
+ { { 102, 96, 3 }, { 151, 96, -19 }, { 150, 45, 35 }, 0 },
+ { { 105, 96, 4 }, { 149, 96, -20 }, { 150, 45, 35 }, 0 },
+ { { 108, 96, 1 }, { 145, 96, -21 }, { 150, 45, 35 }, 0 },
+ { { 110, 96, 2 }, { 145, 96, -25 }, { 150, 45, 35 }, 0 },
+ { { 113, 96, 3 }, { 145, 96, -26 }, { 132, 96, 36 }, 2 },
+ { { 117, 96, 7 }, { 145, 96, -27 }, { 122, 97, 36 }, 0 },
+ { { 117, 96, 7 }, { 145, 96, -28 }, { 117, 97, 37 }, 0 },
+ { { 116, 96, 12 }, { 145, 96, -24 }, { 110, 96, 38 }, 3 },
+ { { 109, 96, 12 }, { 145, 96, -24 }, { 103, 95, 39 }, 0 },
+ { { 105, 96, 12 }, { 145, 96, -24 }, { 95, 90, 40 }, 1 },
+ { { 96, 96, 11 }, { 145, 96, -24 }, { 86, 80, 41 }, 0 },
+ { { 92, 96, 11 }, { 145, 96, -24 }, { 86, 80, 41 }, 0 },
+ { { 93, 96, 5 }, { 145, 96, -24 }, { 86, 38, 41 }, 0 },
+ { { 91, 96, 5 }, { 145, 96, -24 }, { 86, 38, 41 }, 0 },
+ { { 89, 96, 5 }, { 145, 96, -24 }, { 86, 38, 41 }, 0 },
+ { { 88, 96, 5 }, { 145, 96, -24 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -24 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 5 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 5 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 5 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 5 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -23 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -26 }, { 86, 38, 41 }, 0 },
+ { { 87, 96, 6 }, { 145, 96, -27 }, { 132, 97, 36 }, 2 },
+ { { 87, 96, 5 }, { 145, 96, -28 }, { 118, 97, 36 }, 0 },
+ { { 87, 96, 7 }, { 145, 96, -24 }, { 107, 97, 36 }, 0 },
+ { { 87, 96, 8 }, { 145, 96, -24 }, { 101, 97, 36 }, 0 },
+ { { 87, 96, 9 }, { 145, 96, -23 }, { 102, 97, 66 }, 3 },
+ { { 87, 96, 10 }, { 145, 96, -23 }, { 120, 97, 67 }, 0 },
+ { { 87, 96, 10 }, { 145, 96, -30 }, { 139, 97, 67 }, 1 },
+ { { 87, 96, 7 }, { 146, 96, -30 }, { 144, 97, 62 }, 2 },
+ { { 86, 96, 4 }, { 160, 96, -30 }, { 144, 97, 48 }, 1 },
+ { { 83, 96, 3 }, { 170, 96, -31 }, { 154, 93, 49 }, 0 },
+ { { 80, 96, 2 }, { 174, 96, -31 }, { 161, 89, 50 }, 0 },
+ { { 78, 96, 1 }, { 178, 99, -31 }, { 169, 85, 51 }, 0 },
+ { { 75, 96, 4 }, { 183, 104, -31 }, { 175, 79, 52 }, 0 },
+ { { 75, 96, 1 }, { 185, 99, -32 }, { 180, 144, 42 }, 3 },
+ { { 75, 96, 1 }, { 185, 106, -31 }, { 181, 141, 42 }, 0 },
+ { { 75, 96, 5 }, { 185, 104, -31 }, { 181, 138, 43 }, 0 },
+ { { 75, 96, 5 }, { 188, 106, -31 }, { 182, 135, 43 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 131, 44 }, 3 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 127, 45 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 184, 121, 46 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 115, 46 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 99, -32 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 195, 98, -33 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 96, -34 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 193, 96, -25 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 193, 96, -24 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 193, 96, -24 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 5 }, { 193, 96, -24 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 191, 96, -18 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 190, 96, -19 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 6 }, { 187, 96, -20 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 183, 41, 47 }, 0 },
+ { { 75, 96, 1 }, { 187, 96, -23 }, { 183, 41, 47 }, 99 }
+};
+#endif
+
+} // End of namespace Queen
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Queen_Graphics)
+_GSETPTR(Queen::_carData, GBVARS_GRAPHICSCARDATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN)
+_GSETPTR(Queen::_fight1Data, GBVARS_GRAPHICSFIGHT1DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN)
+_GSETPTR(Queen::_fight2Data, GBVARS_GRAPHICSFIGHT2DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN)
+_GSETPTR(Queen::_fight3Data, GBVARS_GRAPHICSFIGHT3DATA_INDEX, Queen::BamScene::BamDataBlock, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Queen_Graphics)
+_GRELEASEPTR(GBVARS_GRAPHICSCARDATA_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_GRAPHICSFIGHT1DATA_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_GRAPHICSFIGHT2DATA_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_GRAPHICSFIGHT3DATA_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/queen/graphics.h b/engines/queen/graphics.h
new file mode 100644
index 0000000000..b2899a5036
--- /dev/null
+++ b/engines/queen/graphics.h
@@ -0,0 +1,293 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENGRAPHICS_H
+#define QUEENGRAPHICS_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+struct BobSlot {
+ bool active;
+ //! current position
+ int16 x, y;
+ //! bounding box
+ Box box;
+ bool xflip;
+ //! shrinking percentage
+ uint16 scale;
+ //! associated BobFrame
+ uint16 frameNum;
+ //! 'direction' for the next frame (-1, 1)
+ int frameDir;
+
+ //! animation stuff
+ bool animating;
+ struct {
+ int16 speed, speedBak;
+
+ //! string based animation
+ struct {
+ const AnimFrame *buffer;
+ const AnimFrame *curPos;
+ } string;
+
+ //! normal moving animation
+ struct {
+ bool rebound;
+ uint16 firstFrame, lastFrame;
+ } normal;
+
+ } anim;
+
+ bool moving;
+ //! moving speed
+ int16 speed;
+ //! move along x axis instead of y
+ bool xmajor;
+ //! moving direction
+ int8 xdir, ydir;
+ //! destination point
+ int16 endx, endy;
+ uint16 dx, dy;
+ uint16 total;
+
+ void curPos(int16 xx, int16 yy);
+ void move(int16 dstx, int16 dsty, int16 spd);
+ void moveOneStep();
+ void animOneStep();
+
+ void animString(const AnimFrame *animBuf);
+ void animNormal(uint16 firstFrame, uint16 lastFrame, uint16 speed, bool rebound, bool xflip);
+
+ void scaleWalkSpeed(uint16 ms);
+
+ void clear();
+
+ static const Box _defaultBox;
+};
+
+class QueenEngine;
+
+class Graphics {
+public:
+
+ Graphics(QueenEngine *vm);
+ ~Graphics();
+
+ //! unpacks control frames (ie. arrows)
+ void unpackControlBank();
+
+ //! setup dialog arrows
+ void setupArrows();
+
+ //! setup mouse cursor
+ void setupMouseCursor();
+
+ //! draw a bob
+ void drawBob(const BobSlot *bs, const BobFrame *bf, const Box *box, int16 x, int16 y);
+
+ //! draw an inventory item
+ void drawInventoryItem(uint32 frameNum, uint16 x, uint16 y);
+
+ //! draw a bob directly on the backdrop bitmap
+ void pasteBob(uint16 objNum, uint16 image);
+
+ //! resize a bobframe
+ void shrinkFrame(const BobFrame *bf, uint16 percentage);
+
+ //! animate/move bobs and sort them
+ void sortBobs();
+
+ //! draw all the sorted bobs
+ void drawBobs();
+
+ //! clear all setup bobs
+ void clearBobs();
+
+ //! stop all animating/movings bobs
+ void stopBobs();
+
+ //! returns a reference to the specified bob
+ BobSlot *bob(int index);
+
+ //! display a text 'near' the specified bob
+ void setBobText(const BobSlot *bob, const char *text, int textX, int textY, int color, int flags);
+
+ //! handles parallax scrolling for the specified room
+ void handleParallax(uint16 roomNum);
+
+ void setupNewRoom(const char *room, uint16 roomNum, int16 *furniture, uint16 furnitureCount);
+
+ void setBobCutawayAnim(uint16 bobNum, bool xflip, const AnimFrame *af, uint8 frameCount);
+ void fillAnimBuffer(const char *anim, AnimFrame *af);
+ uint16 countAnimFrames(const char *anim);
+ void setupObjectAnim(const GraphicData *gd, uint16 firstImage, uint16 bobNum, bool visible);
+ uint16 setupPersonAnim(const ActorData *ad, const char *anim, uint16 curImage);
+ void resetPersonAnim(uint16 bobNum);
+ void erasePersonAnim(uint16 bobNum);
+ void eraseAllAnims();
+
+ uint16 refreshObject(uint16 obj);
+
+ void setupRoomFurniture(int16 *furniture, uint16 furnitureCount);
+ void setupRoomObjects();
+
+ uint16 setupPerson(uint16 noun, uint16 curImage);
+ uint16 allocPerson(uint16 noun, uint16 curImage);
+
+ uint16 personFrames(uint16 bobNum) const { return _personFrames[bobNum]; }
+ void clearPersonFrames() { memset(_personFrames, 0, sizeof(_personFrames)); }
+ uint16 numFrames() const { return _numFrames; }
+ uint16 numStaticFurniture() const { return _numFurnitureStatic; }
+ uint16 numAnimatedFurniture() const { return _numFurnitureAnimated; }
+ uint16 numFurnitureFrames() const { return _numFurnitureStatic + _numFurnitureAnimatedLen; }
+
+ void putCameraOnBob(int bobNum) { _cameraBob = bobNum; }
+
+ void update(uint16 room);
+
+ enum {
+ ARROW_BOB_UP = 62,
+ ARROW_BOB_DOWN = 63,
+ MAX_BOBS_NUMBER = 64,
+ MAX_STRING_LENGTH = 255,
+ MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
+ BOB_SHRINK_BUF_SIZE = 60000
+ };
+
+
+private:
+
+ BobSlot _bobs[MAX_BOBS_NUMBER];
+
+ //! bobs to display
+ BobSlot *_sortedBobs[MAX_BOBS_NUMBER];
+
+ //! number of bobs to display
+ uint16 _sortedBobsCount;
+
+ //! used to scale a BobFrame
+ BobFrame _shrinkBuffer;
+
+ //! in-game objects/persons animations
+ AnimFrame _newAnim[17][30];
+
+ //! cutaway objects/persons animations
+ AnimFrame _cutAnim[21][30];
+
+ uint16 _personFrames[4];
+
+ //! number of animated furniture in current room
+ uint16 _numFurnitureAnimated;
+
+ //! number of static furniture in current room
+ uint16 _numFurnitureStatic;
+
+ //! total number of frames for the animated furniture
+ uint16 _numFurnitureAnimatedLen;
+
+ //! current number of frames unpacked
+ uint16 _numFrames;
+
+ //! bob number followed by camera
+ int _cameraBob;
+
+ QueenEngine *_vm;
+
+ static const Box _gameScreenBox;
+ static const Box _fullScreenBox;
+};
+
+class BamScene {
+public:
+
+ BamScene(QueenEngine *vm);
+
+ void playSfx();
+ void prepareAnimation();
+ void updateCarAnimation();
+ void updateFightAnimation();
+
+ void saveState(byte *&ptr);
+ void loadState(uint32 ver, byte *&ptr);
+
+ enum {
+ BOB_OBJ1 = 5,
+ BOB_OBJ2 = 6,
+ BOB_FX = 7
+ };
+
+ enum {
+ F_STOP = 0,
+ F_PLAY = 1,
+ F_REQ_STOP = 2
+ };
+
+ enum {
+ SFX_SKIP = 8
+ };
+
+ uint16 _flag, _index;
+
+private:
+
+ struct BamDataObj {
+ int16 x, y;
+ int16 frame;
+ };
+
+#ifdef PALMOS_68K
+public:
+#endif
+ struct BamDataBlock {
+ BamDataObj obj1; // truck / Frank
+ BamDataObj obj2; // Rico / robot
+ BamDataObj fx;
+ int16 sfx;
+ };
+#ifdef PALMOS_68K
+private:
+#endif
+
+ BobSlot *_obj1;
+ BobSlot *_obj2;
+ BobSlot *_objfx;
+ bool _screenShaked;
+ const BamDataBlock *_fightData;
+ uint16 _lastSoundIndex;
+
+ QueenEngine *_vm;
+
+#ifndef PALMOS_68K
+ static const BamDataBlock _carData[];
+ static const BamDataBlock _fight1Data[];
+ static const BamDataBlock _fight2Data[];
+ static const BamDataBlock _fight3Data[];
+#endif
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/grid.cpp b/engines/queen/grid.cpp
new file mode 100644
index 0000000000..cb8ed4696b
--- /dev/null
+++ b/engines/queen/grid.cpp
@@ -0,0 +1,255 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/grid.h"
+
+#include "queen/display.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+
+namespace Queen {
+
+Grid::Grid(QueenEngine *vm)
+ : _vm(vm) {
+ memset(_zones, 0, sizeof(_zones));
+}
+
+Grid::~Grid() {
+ delete[] _objMax;
+ delete[] _areaMax;
+ delete[] _area;
+ delete[] _objectBox;
+}
+
+void Grid::readDataFrom(uint16 numObjects, uint16 numRooms, byte *&ptr) {
+ uint16 i, j;
+
+ _numRoomAreas = numRooms;
+
+ _objMax = new int16[_numRoomAreas + 1];
+ _areaMax = new int16[_numRoomAreas + 1];
+ _area = new Area[_numRoomAreas + 1][MAX_AREAS_NUMBER];
+
+ _objMax[0] = 0;
+ _areaMax[0] = 0;
+ memset(&_area[0], 0, sizeof(Area) * MAX_AREAS_NUMBER);
+ for (i = 1; i <= _numRoomAreas; i++) {
+ _objMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _areaMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ memset(&_area[i][0], 0, sizeof(Area));
+ for (j = 1; j <= _areaMax[i]; j++) {
+ assert(j < MAX_AREAS_NUMBER);
+ _area[i][j].readFromBE(ptr);
+ }
+ }
+
+ _objectBox = new Box[numObjects + 1];
+ memset(&_objectBox[0], 0, sizeof(Box));
+ for (i = 1; i <= numObjects; i++) {
+ _objectBox[i].readFromBE(ptr);
+ }
+}
+
+void Grid::setZone(GridScreen screen, uint16 zoneNum, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, x1, y1, x2, y2);
+ ZoneSlot *pzs = &_zones[screen][zoneNum];
+ pzs->valid = true;
+ pzs->box.x1 = x1;
+ pzs->box.y1 = y1;
+ pzs->box.x2 = x2;
+ pzs->box.y2 = y2;
+}
+
+void Grid::setZone(GridScreen screen, uint16 zoneNum, const Box &box) {
+ debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, box.x1, box.y1, box.x2, box.y2);
+ ZoneSlot *pzs = &_zones[screen][zoneNum];
+ pzs->valid = true;
+ pzs->box = box;
+}
+
+uint16 Grid::findZoneForPos(GridScreen screen, uint16 x, uint16 y) const {
+ debug(9, "Logic::findZoneForPos(%d, (%d,%d))", screen, x, y);
+ int i;
+ if (screen == GS_PANEL) {
+ y -= ROOM_ZONE_HEIGHT;
+ }
+ for (i = 1; i < MAX_ZONES_NUMBER; ++i) {
+ const ZoneSlot *pzs = &_zones[screen][i];
+ if (pzs->valid && pzs->box.contains(x, y)) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+uint16 Grid::findAreaForPos(GridScreen screen, uint16 x, uint16 y) const {
+ uint16 room = _vm->logic()->currentRoom();
+ uint16 zoneNum = findZoneForPos(screen, x, y);
+ if (zoneNum <= _objMax[room]) {
+ zoneNum = 0;
+ } else {
+ zoneNum -= _objMax[room];
+ }
+ return zoneNum;
+}
+
+void Grid::clear(GridScreen screen) {
+ debug(9, "Grid::clear(%d)", screen);
+ for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
+ _zones[screen][i].valid = false;
+ }
+}
+
+void Grid::setupNewRoom(uint16 room, uint16 firstRoomObjNum) {
+ debug(9, "Grid::setupNewRoom()");
+ clear(GS_ROOM);
+
+ uint16 i;
+ uint16 zoneNum;
+
+ // setup objects zones
+ uint16 maxObjRoom = _objMax[room];
+ zoneNum = 1;
+ for (i = firstRoomObjNum + 1; i <= firstRoomObjNum + maxObjRoom; ++i) {
+ if (_vm->logic()->objectData(i)->name != 0) {
+ setZone(GS_ROOM, zoneNum, _objectBox[i]);
+ }
+ ++zoneNum;
+ }
+
+ // setup room zones (areas)
+ uint16 maxAreaRoom = _areaMax[room];
+ for (zoneNum = 1; zoneNum <= maxAreaRoom; ++zoneNum) {
+ setZone(GS_ROOM, maxObjRoom + zoneNum, _area[room][zoneNum].box);
+ }
+}
+
+void Grid::setupPanel() {
+ for (int i = 0; i <= 7; ++i) {
+ uint16 x = i * 20;
+ setZone(GS_PANEL, i + 1, x, 10, x + 19, 49);
+ }
+
+ // inventory scrolls
+ setZone(GS_PANEL, 9, 160, 10, 179, 29);
+ setZone(GS_PANEL, 10, 160, 30, 179, 49);
+
+ // inventory items
+ setZone(GS_PANEL, 11, 180, 10, 213, 49);
+ setZone(GS_PANEL, 12, 214, 10, 249, 49);
+ setZone(GS_PANEL, 13, 250, 10, 284, 49);
+ setZone(GS_PANEL, 14, 285, 10, 320, 49);
+}
+
+void Grid::drawZones() {
+ for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
+ const ZoneSlot *pzs = &_zones[GS_ROOM][i];
+ if (pzs->valid) {
+ const Box *b = &pzs->box;
+ _vm->display()->drawBox(b->x1, b->y1, b->x2, b->y2, 3);
+ }
+ }
+}
+
+const Box *Grid::zone(GridScreen screen, uint16 index) const {
+ const ZoneSlot *zs = &_zones[screen][index];
+ assert(zs->valid);
+ return &zs->box;
+}
+
+Verb Grid::findVerbUnderCursor(int16 cursorx, int16 cursory) const {
+ static const Verb pv[] = {
+ VERB_NONE,
+ VERB_OPEN,
+ VERB_CLOSE,
+ VERB_MOVE,
+ VERB_GIVE,
+ VERB_LOOK_AT,
+ VERB_PICK_UP,
+ VERB_TALK_TO,
+ VERB_USE,
+ VERB_SCROLL_UP,
+ VERB_SCROLL_DOWN,
+ VERB_INV_1,
+ VERB_INV_2,
+ VERB_INV_3,
+ VERB_INV_4,
+ };
+ return pv[findZoneForPos(GS_PANEL, cursorx, cursory)];
+}
+
+uint16 Grid::findObjectUnderCursor(int16 cursorx, int16 cursory) const {
+ uint16 roomObj = 0;
+ if (cursory < ROOM_ZONE_HEIGHT) {
+ int16 x = cursorx + _vm->display()->horizontalScroll();
+ roomObj = findZoneForPos(GS_ROOM, x, cursory);
+ }
+ return roomObj;
+}
+
+uint16 Grid::findObjectNumber(uint16 zoneNum) const {
+ // l.316-327 select.c
+ uint16 room = _vm->logic()->currentRoom();
+ uint16 obj = zoneNum;
+ uint16 objectMax = _objMax[room];
+ debug(9, "Grid::findObjectNumber(%X, %X)", zoneNum, objectMax);
+ if (zoneNum > objectMax) {
+ // this is an area box, check for associated object
+ obj = _area[room][zoneNum - objectMax].object;
+ if (obj != 0) {
+ // there is an object, get its number
+ obj -= _vm->logic()->currentRoomData();
+ }
+ }
+ return obj;
+}
+
+uint16 Grid::findScale(uint16 x, uint16 y) const {
+ uint16 room = _vm->logic()->currentRoom();
+ uint16 scale = 100;
+ uint16 areaNum = findAreaForPos(GS_ROOM, x, y);
+ if (areaNum != 0) {
+ scale = _area[room][areaNum].calcScale(y);
+ }
+ return scale;
+}
+
+void Grid::saveState(byte *&ptr) {
+ uint16 i, j;
+ for (i = 1; i <= _numRoomAreas; ++i) {
+ for (j = 1; j <= _areaMax[i]; ++j) {
+ _area[i][j].writeToBE(ptr);
+ }
+ }
+}
+
+void Grid::loadState(uint32 ver, byte *&ptr) {
+ uint16 i, j;
+ for (i = 1; i <= _numRoomAreas; ++i) {
+ for (j = 1; j <= _areaMax[i]; ++j) {
+ _area[i][j].readFromBE(ptr);
+ }
+ }
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/grid.h b/engines/queen/grid.h
new file mode 100644
index 0000000000..d6e148eec2
--- /dev/null
+++ b/engines/queen/grid.h
@@ -0,0 +1,136 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENGRID_H
+#define QUEENGRID_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+enum GridScreen {
+ GS_ROOM = 0,
+ GS_PANEL = 1,
+ GS_COUNT = 2
+};
+
+class QueenEngine;
+
+class Grid {
+public:
+
+ Grid(QueenEngine *vm);
+ ~Grid();
+
+ //! read areas data from specified stream
+ void readDataFrom(uint16 numObjects, uint16 numRooms, byte *&ptr);
+
+ //! defines a new zone
+ void setZone(GridScreen screen, uint16 zoneNum, uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+
+ //! defines a new zone
+ void setZone(GridScreen screen, uint16 zoneNum, const Box &box);
+
+ //! find the zone number containing the specified point
+ uint16 findZoneForPos(GridScreen screen, uint16 x, uint16 y) const;
+
+ //! find the area number containing the specified point
+ uint16 findAreaForPos(GridScreen screen, uint16 x, uint16 y) const;
+
+ //! clear the zones for current room
+ void clear(GridScreen screen);
+
+ //! setup objects zones for the specified room
+ void setupNewRoom(uint16 room, uint16 firstRoomObjNum);
+
+ //! setup panel zones
+ void setupPanel();
+
+ //! draw the zones for current room (debug only)
+ void drawZones();
+
+ //! retuns a reference to the specified zone
+ const Box *zone(GridScreen screen, uint16 index) const;
+
+ //! get the verb for the specified cursor position
+ Verb findVerbUnderCursor(int16 cursorx, int16 cursory) const;
+
+ //! get the object for the specified cursor position
+ uint16 findObjectUnderCursor(int16 cursorx, int16 cursory) const;
+
+ //! get the object for the specified zone number
+ uint16 findObjectNumber(uint16 zoneNum) const;
+
+ //! get scale for the specified position
+ uint16 findScale(uint16 x, uint16 y) const;
+
+ //! returns a reference to the specfied room area
+ Area *area(int room, int num) const { return &_area[room][num]; }
+
+ //! returns the number of areas in this room
+ uint16 areaMax(int room) const { return _areaMax[room]; }
+
+ //! returns the number of objects in this room
+ uint16 objMax(int room) const { return _objMax[room]; }
+
+ void saveState(byte *&ptr);
+ void loadState(uint32 ver, byte *&ptr);
+
+ enum {
+ MAX_ZONES_NUMBER = 32,
+ MAX_AREAS_NUMBER = 11
+ };
+
+
+private:
+
+ struct ZoneSlot {
+ bool valid;
+ Box box;
+ };
+
+ //! current room zones
+ ZoneSlot _zones[GS_COUNT][MAX_ZONES_NUMBER];
+
+ //! number of objects for each room
+ int16 *_objMax;
+
+ //! number of areas for each room
+ int16 *_areaMax;
+
+ //! areas for each room
+ Area (*_area)[MAX_AREAS_NUMBER];
+
+ //! total number of room areas
+ uint16 _numRoomAreas;
+
+ //! box/zone for each objects
+ Box *_objectBox;
+
+ QueenEngine *_vm;
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/input.cpp b/engines/queen/input.cpp
new file mode 100644
index 0000000000..7ae2e2abce
--- /dev/null
+++ b/engines/queen/input.cpp
@@ -0,0 +1,213 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/system.h"
+
+#include "queen/input.h"
+
+namespace Queen {
+
+const char *Input::_commandKeys[LANGUAGE_COUNT] = {
+ "ocmglptu", // English
+ "osbgpnre", // German
+ "ofdnepau", // French
+ "acsdgpqu", // Italian
+ "ocmglptu", // Hebrew
+ "acodmthu" // Spanish
+};
+
+const Verb Input::_verbKeys[8] = {
+ VERB_OPEN,
+ VERB_CLOSE,
+ VERB_MOVE,
+ VERB_GIVE,
+ VERB_LOOK_AT,
+ VERB_PICK_UP,
+ VERB_TALK_TO,
+ VERB_USE
+};
+
+Input::Input(Language language, OSystem *system) :
+ _system(system), _fastMode(false), _keyVerb(VERB_NONE),
+ _cutawayRunning(false), _canQuit(false), _cutawayQuit(false),
+ _dialogueRunning(false), _talkQuit(false), _quickSave(false),
+ _quickLoad(false), _debugger(false), _inKey(0), _mouse_x(0),
+ _mouse_y(0), _mouseButton(0), _idleTime(0) {
+
+ switch (language) {
+ case ENGLISH:
+ _currentCommandKeys = _commandKeys[0];
+ break;
+ case GERMAN:
+ _currentCommandKeys = _commandKeys[1];
+ break;
+ case FRENCH:
+ _currentCommandKeys = _commandKeys[2];
+ break;
+ case ITALIAN:
+ _currentCommandKeys = _commandKeys[3];
+ break;
+ case HEBREW:
+ _currentCommandKeys = _commandKeys[4];
+ break;
+ case SPANISH:
+ _currentCommandKeys = _commandKeys[5];
+ break;
+ default:
+ error("Unknown language");
+ break;
+ }
+}
+
+void Input::delay() {
+ delay(_fastMode ? DELAY_SHORT : DELAY_NORMAL);
+}
+
+void Input::delay(uint amount) {
+ if (_idleTime < DELAY_SCREEN_BLANKER) {
+ _idleTime += amount;
+ }
+ uint32 end = _system->getMillis() + amount;
+ do {
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ _idleTime = 0;
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ if (event.kbd.flags == OSystem::KBD_CTRL) {
+ if (event.kbd.keycode == 'd') {
+ _debugger = true;
+ } else if (event.kbd.keycode == 'f') {
+ _fastMode = !_fastMode;
+ }
+ } else {
+ _inKey = event.kbd.keycode;
+ }
+ break;
+
+ case OSystem::EVENT_MOUSEMOVE:
+ _mouse_x = event.mouse.x;
+ _mouse_y = event.mouse.y;
+ break;
+
+ case OSystem::EVENT_LBUTTONDOWN:
+ _mouseButton |= MOUSE_LBUTTON;
+ _mouse_x = event.mouse.x;
+ _mouse_y = event.mouse.y;
+ break;
+
+ case OSystem::EVENT_RBUTTONDOWN:
+ _mouseButton |= MOUSE_RBUTTON;
+ _mouse_x = event.mouse.x;
+ _mouse_y = event.mouse.y;
+ break;
+
+ case OSystem::EVENT_QUIT:
+ _system->quit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (amount == 0)
+ break;
+
+ _system->delayMillis((amount > 20) ? 20 : amount);
+ } while (_system->getMillis() < end);
+}
+
+int Input::checkKeys() {
+
+ if (_inKey)
+ debug(6, "[Input::checkKeys] _inKey = %i", _inKey);
+
+ switch (_inKey) {
+ case KEY_SPACE:
+ _keyVerb = VERB_SKIP_TEXT;
+ break;
+ case KEY_COMMA:
+ _keyVerb = VERB_SCROLL_UP;
+ break;
+ case KEY_DOT:
+ _keyVerb = VERB_SCROLL_DOWN;
+ break;
+ case KEY_DIGIT_1:
+ _keyVerb = VERB_DIGIT_1;
+ break;
+ case KEY_DIGIT_2:
+ _keyVerb = VERB_DIGIT_2;
+ break;
+ case KEY_DIGIT_3:
+ _keyVerb = VERB_DIGIT_3;
+ break;
+ case KEY_DIGIT_4:
+ _keyVerb = VERB_DIGIT_4;
+ break;
+ case KEY_ESCAPE: // slip cutaway / dialogue
+ if (_canQuit) {
+ if (_cutawayRunning) {
+ debug(6, "[Input::checkKeys] Setting _cutawayQuit to true!");
+ _cutawayQuit = true;
+ }
+ if (_dialogueRunning)
+ _talkQuit = true;
+ }
+ break;
+ case KEY_F1: // use Journal
+ case KEY_F5:
+ if (_cutawayRunning) {
+ if (_canQuit) {
+ _keyVerb = VERB_USE_JOURNAL;
+ _cutawayQuit = _talkQuit = true;
+ }
+ } else {
+ _keyVerb = VERB_USE_JOURNAL;
+ if (_canQuit)
+ _talkQuit = true;
+ }
+ break;
+ case KEY_F11: // quicksave
+ _quickSave = true;
+ break;
+ case KEY_F12: // quickload
+ _quickLoad = true;
+ break;
+ default:
+ for (int i = 0; i < ARRAYSIZE(_verbKeys); ++i) {
+ if (_inKey == _currentCommandKeys[i]) {
+ _keyVerb = _verbKeys[i];
+ break;
+ }
+ }
+ break;
+ }
+
+ int inKey = _inKey;
+ _inKey = 0; // reset
+ return inKey;
+}
+
+
+} // End of namespace Queen
diff --git a/engines/queen/input.h b/engines/queen/input.h
new file mode 100644
index 0000000000..d1e86016c9
--- /dev/null
+++ b/engines/queen/input.h
@@ -0,0 +1,178 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef INPUT_H
+#define INPUT_H
+
+#include "common/util.h"
+#include "queen/defs.h"
+
+class OSystem;
+
+namespace Queen {
+
+class Input {
+public:
+
+ //! Adjust here to change delays!
+ enum {
+ DELAY_SHORT = 10,
+ DELAY_NORMAL = 100,
+ DELAY_SCREEN_BLANKER = 5 * 60 * 1000
+ };
+ enum {
+ MOUSE_LBUTTON = 1,
+ MOUSE_RBUTTON = 2
+ };
+
+ Input(Language language, OSystem *system);
+
+ //! calls the other delay() with a value adjusted depending on _fastMode
+ void delay();
+
+ //! moved QueenEngine::delay() here
+ void delay(uint amount);
+
+ //! convert input to verb
+ int checkKeys();
+
+ //! use instead of KEYVERB=0
+ void clearKeyVerb() { _keyVerb = VERB_NONE; }
+
+ void canQuit(bool cq) { _canQuit = cq; }
+
+ bool cutawayRunning() const { return _cutawayRunning; }
+ void cutawayRunning(bool running) { _cutawayRunning = running; }
+
+ bool cutawayQuit() const { return _cutawayQuit; }
+ void cutawayQuitReset() { _cutawayQuit = false; }
+
+ void dialogueRunning(bool running) { _dialogueRunning = running; }
+
+ bool talkQuit() const { return _talkQuit; }
+ void talkQuitReset() { _talkQuit = false; }
+
+ bool quickSave() const { return _quickSave; }
+ void quickSaveReset() { _quickSave = false; }
+ bool quickLoad() const { return _quickLoad; }
+ void quickLoadReset() { _quickLoad = false; }
+ bool debugger() const { return _debugger; }
+ void debuggerReset() { _debugger = false; }
+
+ bool fastMode() const { return _fastMode; }
+ void fastMode(bool fm) { _fastMode = fm; }
+
+ Verb keyVerb() const { return _keyVerb; }
+
+ int mousePosX() const { return _mouse_x; }
+ int mousePosY() const { return _mouse_y; }
+
+ int mouseButton() const { return _mouseButton; }
+ void clearMouseButton() { _mouseButton = 0; }
+
+ //! returns user idle time (used by Display, to trigger the screensaver)
+ uint32 idleTime() const { return _idleTime; }
+
+private:
+
+ enum KeyCode {
+ KEY_SPACE = ' ',
+ KEY_COMMA = ',',
+ KEY_DOT = '.',
+
+ KEY_DIGIT_1 = '1',
+ KEY_DIGIT_2 = '2',
+ KEY_DIGIT_3 = '3',
+ KEY_DIGIT_4 = '4',
+
+ KEY_ESCAPE = 27,
+ KEY_RETURN = 13,
+ KEY_BACKSPACE = 8,
+
+ KEY_F1 = 282,
+ KEY_F11 = KEY_F1 + 10,
+ KEY_F5 = KEY_F1 + 4,
+ KEY_F12
+ };
+
+ enum {
+ LANGUAGE_COUNT = 6
+ };
+
+ //! used to get keyboard and mouse events
+ OSystem *_system;
+
+ //! some cutaways require update() run faster
+ bool _fastMode;
+
+ //! the current verb received from keyboard
+ Verb _keyVerb;
+
+ //! set if a cutaway is running
+ bool _cutawayRunning;
+
+ //! set this if we can quit
+ bool _canQuit;
+
+ //! moved Cutaway::_quit here
+ bool _cutawayQuit;
+
+ //! set if a dialogue is running
+ bool _dialogueRunning;
+
+ //! moved Talk::_quit here
+ bool _talkQuit;
+
+ //! set if quicksave requested
+ bool _quickSave;
+
+ //! set if quickload requested
+ bool _quickLoad;
+
+ //! set if debugger requested
+ bool _debugger;
+
+ //! set by delay();
+ int _inKey;
+
+ //! set by delay();
+ int _mouse_x, _mouse_y;
+
+ //! set by delay();
+ int _mouseButton;
+
+ //! user idle time
+ uint32 _idleTime;
+
+ //! command keys for current language
+ const char *_currentCommandKeys;
+
+ //! command keys for all languages
+ static const char *_commandKeys[LANGUAGE_COUNT];
+
+ //! verbs matching the command keys
+ static const Verb _verbKeys[8];
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/journal.cpp b/engines/queen/journal.cpp
new file mode 100644
index 0000000000..0aeb71e083
--- /dev/null
+++ b/engines/queen/journal.cpp
@@ -0,0 +1,587 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "queen/journal.h"
+
+#include "queen/bankman.h"
+#include "queen/display.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/logic.h"
+#include "queen/music.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+
+namespace Queen {
+
+Journal::Journal(QueenEngine *vm)
+ : _vm(vm) {
+ _currentSavePage = 0;
+ _currentSaveSlot = 0;
+}
+
+void Journal::use() {
+ BobSlot *joe = _vm->graphics()->bob(0);
+ _prevJoeX = joe->x;
+ _prevJoeY = joe->y;
+
+ _panelMode = PM_NORMAL;
+ _system = &OSystem::instance();
+
+ _panelTextCount = 0;
+ memset(_panelTextY, 0, sizeof(_panelTextY));
+ memset(&_textField, 0, sizeof(_textField));
+
+ memset(_saveDescriptions, 0, sizeof(_saveDescriptions));
+ _vm->findGameStateDescriptions(_saveDescriptions);
+
+ setup();
+ redraw();
+ update();
+ _vm->display()->palFadeIn(ROOM_JOURNAL);
+
+ _quitMode = QM_LOOP;
+ while (_quitMode == QM_LOOP) {
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ handleKeyDown(event.kbd.ascii, event.kbd.keycode);
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ handleMouseDown(event.mouse.x, event.mouse.y);
+ break;
+ case OSystem::EVENT_WHEELUP:
+ handleMouseWheel(-1);
+ break;
+ case OSystem::EVENT_WHEELDOWN:
+ handleMouseWheel(1);
+ break;
+ case OSystem::EVENT_QUIT:
+ _system->quit();
+ break;
+ default:
+ break;
+ }
+ }
+ _system->delayMillis(20);
+ _system->updateScreen();
+ }
+
+ _vm->writeOptionSettings();
+
+ _vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
+ _vm->graphics()->putCameraOnBob(0);
+ if (_quitMode == QM_CONTINUE) {
+ continueGame();
+ }
+}
+
+void Journal::continueGame() {
+ _vm->display()->fullscreen(false);
+ _vm->display()->forceFullRefresh();
+
+ _vm->logic()->joePos(_prevJoeX, _prevJoeY);
+ _vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
+
+ _vm->logic()->oldRoom(_vm->logic()->currentRoom());
+ _vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE, 0, 0, false);
+}
+
+void Journal::setup() {
+ _vm->display()->palFadeOut(_vm->logic()->currentRoom());
+ _vm->display()->horizontalScroll(0);
+ _vm->display()->fullscreen(true);
+ _vm->graphics()->clearBobs();
+ _vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
+ _vm->bankMan()->eraseFrames(false);
+ _vm->display()->textCurrentColor(INK_JOURNAL);
+
+ _vm->grid()->clear(GS_ROOM);
+ for (int i = 0; i < MAX_ZONES; ++i) {
+ const Zone *zn = &_zones[i];
+ _vm->grid()->setZone(GS_ROOM, zn->num, zn->x1, zn->y1, zn->x2, zn->y2);
+ }
+
+ _vm->display()->setupNewRoom("journal", ROOM_JOURNAL);
+ _vm->bankMan()->load("journal.BBK", JOURNAL_BANK);
+ for (int f = 1; f <= 20; ++f) {
+ int frameNum = JOURNAL_FRAMES + f;
+ _vm->bankMan()->unpack(f, frameNum, JOURNAL_BANK);
+ BobFrame *bf = _vm->bankMan()->fetchFrame(frameNum);
+ bf->xhotspot = 0;
+ bf->yhotspot = 0;
+ if (f == FRAME_INFO_BOX) { // adjust info box hot spot to put it always on top
+ bf->yhotspot = 200;
+ }
+ }
+ _vm->bankMan()->close(JOURNAL_BANK);
+
+ _textField.x = 136;
+ _textField.y = 9;
+ _textField.w = 146;
+ _textField.h = 13;
+}
+
+void Journal::redraw() {
+ drawNormalPanel();
+ drawConfigPanel();
+ drawSaveDescriptions();
+ drawSaveSlot();
+}
+
+void Journal::update() {
+ _vm->graphics()->sortBobs();
+ _vm->display()->prepareUpdate();
+ _vm->graphics()->drawBobs();
+ if (_textField.enabled) {
+ int16 x = _textField.x + _textField.posCursor;
+ int16 y = _textField.y + _currentSaveSlot * _textField.h + 8;
+ _vm->display()->drawBox(x, y, x + 6, y, INK_JOURNAL);
+ }
+ _vm->display()->forceFullRefresh();
+ _vm->display()->update();
+ _system->updateScreen();
+}
+
+void Journal::showBob(int bobNum, int16 x, int16 y, int frameNum) {
+ BobSlot *bob = _vm->graphics()->bob(bobNum);
+ bob->curPos(x, y);
+ bob->frameNum = JOURNAL_FRAMES + frameNum;
+}
+
+void Journal::hideBob(int bobNum) {
+ _vm->graphics()->bob(bobNum)->active = false;
+}
+
+void Journal::drawSaveDescriptions() {
+ for (int i = 0; i < NUM_SAVES_PER_PAGE; ++i) {
+ int n = _currentSavePage * 10 + i;
+ char nb[4];
+ sprintf(nb, "%d", n + 1);
+ int y = _textField.y + i * _textField.h;
+ _vm->display()->setText(_textField.x, y, _saveDescriptions[n], false);
+ _vm->display()->setText(_textField.x - 27, y + 1, nb, false);
+ }
+ // highlight current page
+ showBob(BOB_SAVE_PAGE, 300, 3 + _currentSavePage * 15, 6 + _currentSavePage);
+}
+
+void Journal::drawSaveSlot() {
+ showBob(BOB_SAVE_DESC, 130, 6 + _currentSaveSlot * 13, 17);
+}
+
+void Journal::enterYesNoPanelMode(int16 prevZoneNum, int titleNum) {
+ _panelMode = PM_YES_NO;
+ _prevZoneNum = prevZoneNum;
+ drawYesNoPanel(titleNum);
+}
+
+void Journal::exitYesNoPanelMode() {
+ _panelMode = PM_NORMAL;
+ if (_prevZoneNum == ZN_MAKE_ENTRY) {
+ closeTextField();
+ }
+ redraw();
+}
+
+void Journal::enterInfoPanelMode() {
+ _panelMode = PM_INFO_BOX;
+ _vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
+ drawInfoPanel();
+}
+
+void Journal::exitInfoPanelMode() {
+ _vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
+ hideBob(BOB_INFO_BOX);
+ redraw();
+ _panelMode = PM_NORMAL;
+}
+
+void Journal::handleKeyDown(uint16 ascii, int keycode) {
+ switch (_panelMode) {
+ case PM_INFO_BOX:
+ break;
+ case PM_YES_NO:
+ if (keycode == 27) {
+ exitYesNoPanelMode();
+ } else if (_textField.enabled) {
+ updateTextField(ascii, keycode);
+ }
+ break;
+ case PM_NORMAL:
+ if (keycode == 27) {
+ _quitMode = QM_CONTINUE;
+ }
+ break;
+ }
+}
+
+void Journal::handleMouseWheel(int inc) {
+ if (_panelMode == PM_NORMAL) {
+ int curSave = _currentSavePage * NUM_SAVES_PER_PAGE + _currentSaveSlot + inc;
+ if (curSave >= 0 && curSave < NUM_SAVES_PER_PAGE * 10) {
+ _currentSavePage = curSave / NUM_SAVES_PER_PAGE;
+ _currentSaveSlot = curSave % NUM_SAVES_PER_PAGE;
+ drawSaveDescriptions();
+ drawSaveSlot();
+ update();
+ }
+ }
+}
+
+void Journal::handleMouseDown(int x, int y) {
+ int val;
+ int16 zoneNum = _vm->grid()->findZoneForPos(GS_ROOM, x, y);
+ switch (_panelMode) {
+ case PM_INFO_BOX:
+ exitInfoPanelMode();
+ break;
+ case PM_YES_NO:
+ if (zoneNum == ZN_YES) {
+ _panelMode = PM_NORMAL;
+ int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
+ switch (_prevZoneNum) {
+ case ZN_REVIEW_ENTRY:
+ if (_saveDescriptions[currentSlot][0]) {
+ _vm->graphics()->clearBobs();
+ _vm->display()->palFadeOut(ROOM_JOURNAL);
+ _vm->music()->stopSong();
+ _vm->loadGameState(currentSlot);
+ _vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
+ _quitMode = QM_RESTORE;
+ } else {
+ exitYesNoPanelMode();
+ }
+ break;
+ case ZN_MAKE_ENTRY:
+ if (_textField.text[0]) {
+ closeTextField();
+ _vm->saveGameState(currentSlot, _textField.text);
+ _quitMode = QM_CONTINUE;
+ } else {
+ exitYesNoPanelMode();
+ }
+ break;
+ case ZN_GIVEUP:
+ _quitMode = QM_CONTINUE;
+ _vm->quitGame();
+ break;
+ }
+ } else if (zoneNum == ZN_NO) {
+ exitYesNoPanelMode();
+ }
+ break;
+ case PM_NORMAL:
+ switch (zoneNum) {
+ case ZN_REVIEW_ENTRY:
+ enterYesNoPanelMode(zoneNum, TXT_REVIEW_ENTRY);
+ break;
+ case ZN_MAKE_ENTRY:
+ initTextField(_saveDescriptions[_currentSavePage * 10 + _currentSaveSlot]);
+ enterYesNoPanelMode(zoneNum, TXT_MAKE_ENTRY);
+ break;
+ case ZN_CLOSE:
+ _quitMode = QM_CONTINUE;
+ break;
+ case ZN_GIVEUP:
+ enterYesNoPanelMode(zoneNum, TXT_GIVE_UP);
+ break;
+ case ZN_TEXT_SPEED:
+ val = (x - 136) * QueenEngine::MAX_TEXT_SPEED / (266 - 136);
+ _vm->talkSpeed(val);
+ drawConfigPanel();
+ break;
+ case ZN_SFX_TOGGLE:
+ _vm->sound()->toggleSfx();
+ drawConfigPanel();
+ break;
+ case ZN_MUSIC_VOLUME:
+ val = (x - 136) * QueenEngine::MAX_MUSIC_VOLUME / (266 - 136);
+ _vm->music()->setVolume(val);
+ drawConfigPanel();
+ break;
+ case ZN_DESC_1:
+ case ZN_DESC_2:
+ case ZN_DESC_3:
+ case ZN_DESC_4:
+ case ZN_DESC_5:
+ case ZN_DESC_6:
+ case ZN_DESC_7:
+ case ZN_DESC_8:
+ case ZN_DESC_9:
+ case ZN_DESC_10:
+ _currentSaveSlot = zoneNum - ZN_DESC_1;
+ drawSaveSlot();
+ break;
+ case ZN_PAGE_A:
+ case ZN_PAGE_B:
+ case ZN_PAGE_C:
+ case ZN_PAGE_D:
+ case ZN_PAGE_E:
+ case ZN_PAGE_F:
+ case ZN_PAGE_G:
+ case ZN_PAGE_H:
+ case ZN_PAGE_I:
+ case ZN_PAGE_J:
+ _currentSavePage = zoneNum - ZN_PAGE_A;
+ drawSaveDescriptions();
+ break;
+ case ZN_INFO_BOX:
+ enterInfoPanelMode();
+ break;
+ case ZN_MUSIC_TOGGLE:
+ _vm->sound()->toggleMusic();
+ if (_vm->sound()->musicOn()) {
+ _vm->sound()->playLastSong();
+ } else {
+ _vm->music()->stopSong();
+ }
+ drawConfigPanel();
+ break;
+ case ZN_VOICE_TOGGLE:
+ _vm->sound()->toggleSpeech();
+ drawConfigPanel();
+ break;
+ case ZN_TEXT_TOGGLE:
+ _vm->subtitles(!_vm->subtitles());
+ drawConfigPanel();
+ break;
+ }
+ break;
+ }
+ update();
+}
+
+void Journal::drawPanelText(int y, const char *text) {
+ debug(7, "Journal::drawPanelText(%d, '%s')", y, text);
+ char s[80];
+ strcpy(s, text);
+ char *p = strchr(s, ' ');
+ if (p == NULL) {
+ int x = (128 - _vm->display()->textWidth(s)) / 2;
+ _vm->display()->setText(x, y, s, false);
+ assert(_panelTextCount < MAX_PANEL_TEXTS);
+ _panelTextY[_panelTextCount++] = y;
+ } else {
+ *p++ = '\0';
+ if (_vm->resource()->getLanguage() == HEBREW) {
+ drawPanelText(y - 5, p);
+ drawPanelText(y + 5, s);
+ } else {
+ drawPanelText(y - 5, s);
+ drawPanelText(y + 5, p);
+ }
+ }
+}
+
+void Journal::drawCheckBox(bool active, int bobNum, int16 x, int16 y, int frameNum) {
+ if (active) {
+ showBob(bobNum, x, y, frameNum);
+ } else {
+ hideBob(bobNum);
+ }
+}
+
+void Journal::drawSlideBar(int value, int maxValue, int bobNum, int16 y, int frameNum) {
+ showBob(bobNum, 136 + value * (266 - 136) / maxValue, y, frameNum);
+}
+
+void Journal::drawPanel(const int *frames, const int *titles, int n) {
+ for (int i = 0; i < _panelTextCount; ++i) {
+ _vm->display()->clearTexts(_panelTextY[i], _panelTextY[i]);
+ }
+ _panelTextCount = 0;
+ int bobNum = 1;
+ int y = 8;
+ while (n--) {
+ showBob(bobNum++, 32, y, *frames++);
+ drawPanelText(y + 12, _vm->logic()->joeResponse(*titles++));
+ y += 48;
+ }
+}
+
+void Journal::drawNormalPanel() {
+ static const int frames[] = { FRAME_BLUE_1, FRAME_BLUE_2, FRAME_BLUE_1, FRAME_ORANGE };
+ static const int titles[] = { TXT_REVIEW_ENTRY, TXT_MAKE_ENTRY, TXT_CLOSE, TXT_GIVE_UP };
+ drawPanel(frames, titles, 4);
+}
+
+void Journal::drawYesNoPanel(int titleNum) {
+ static const int frames[] = { FRAME_GREY, FRAME_BLUE_1, FRAME_BLUE_2 };
+ const int titles[] = { titleNum, TXT_YES, TXT_NO };
+ drawPanel(frames, titles, 3);
+
+ hideBob(BOB_LEFT_RECT_4);
+ hideBob(BOB_TALK_SPEED);
+ hideBob(BOB_SFX_TOGGLE);
+ hideBob(BOB_MUSIC_VOLUME);
+ hideBob(BOB_SPEECH_TOGGLE);
+ hideBob(BOB_TEXT_TOGGLE);
+ hideBob(BOB_MUSIC_TOGGLE);
+}
+
+void Journal::drawConfigPanel() {
+ _vm->checkOptionSettings();
+
+ drawSlideBar(_vm->talkSpeed(), QueenEngine::MAX_TEXT_SPEED, BOB_TALK_SPEED, 164, FRAME_BLUE_PIN);
+ drawSlideBar(_vm->music()->volume(), QueenEngine::MAX_MUSIC_VOLUME, BOB_MUSIC_VOLUME, 177, FRAME_GREEN_PIN);
+
+ drawCheckBox(_vm->sound()->sfxOn(), BOB_SFX_TOGGLE, 221, 155, FRAME_CHECK_BOX);
+ drawCheckBox(_vm->sound()->speechOn(), BOB_SPEECH_TOGGLE, 158, 155, FRAME_CHECK_BOX);
+ drawCheckBox(_vm->subtitles(), BOB_TEXT_TOGGLE, 125, 167, FRAME_CHECK_BOX);
+ drawCheckBox(_vm->sound()->musicOn(), BOB_MUSIC_TOGGLE, 125, 181, FRAME_CHECK_BOX);
+}
+
+void Journal::drawInfoPanel() {
+ showBob(BOB_INFO_BOX, 72, 221, FRAME_INFO_BOX);
+ const char *ver = _vm->resource()->JASVersion();
+ switch (ver[0]) {
+ case 'P':
+ _vm->display()->setTextCentered(132, "PC Hard Drive", false);
+ break;
+ case 'C':
+ _vm->display()->setTextCentered(132, "PC CD-ROM", false);
+ break;
+ case 'a':
+ _vm->display()->setTextCentered(132, "Amiga A500/600", false);
+ break;
+ case 'A':
+ _vm->display()->setTextCentered(132, "Amiga A1200", false);
+ break;
+ case 'c':
+ _vm->display()->setTextCentered(132, "Amiga CD-32", false);
+ break;
+ }
+ switch (ver[1]) {
+ case 'E':
+ _vm->display()->setTextCentered(144, "English", false);
+ break;
+ case 'F' :
+ _vm->display()->setTextCentered(144, "Fran\x87""ais", false);
+ break;
+ case 'G':
+ _vm->display()->setTextCentered(144, "Deutsch", false);
+ break;
+ case 'H':
+ _vm->display()->setTextCentered(144, "Hebrew", false);
+ break;
+ case 'I':
+ _vm->display()->setTextCentered(144, "Italiano", false);
+ break;
+ case 'S':
+ _vm->display()->setTextCentered(144, "Espa\xA4""ol", false);
+ break;
+ }
+ char versionId[13];
+ sprintf(versionId, "Version %c.%c%c", ver[2], ver[3], ver[4]);
+ _vm->display()->setTextCentered(156, versionId, false);
+}
+
+void Journal::initTextField(const char *desc) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ _textField.enabled = true;
+ _textField.posCursor = _vm->display()->textWidth(desc);
+ _textField.textCharsCount = strlen(desc);
+ memset(_textField.text, 0, sizeof(_textField.text));
+ strcpy(_textField.text, desc);
+}
+
+void Journal::updateTextField(uint16 ascii, int keycode) {
+ bool dirty = false;
+ switch (keycode) {
+ case 8: // backspace
+ if (_textField.textCharsCount > 0) {
+ --_textField.textCharsCount;
+ _textField.text[_textField.textCharsCount] = '\0';
+ dirty = true;
+ }
+ break;
+ case '\n':
+ case '\r':
+ if (_textField.text[0]) {
+ closeTextField();
+ int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
+ _vm->saveGameState(currentSlot, _textField.text);
+ _quitMode = QM_CONTINUE;
+ }
+ break;
+ default:
+ if (isprint((char)ascii) &&
+ _textField.textCharsCount < (sizeof(_textField.text) - 1) &&
+ _vm->display()->textWidth(_textField.text) < _textField.w) {
+ _textField.text[_textField.textCharsCount] = (char)ascii;
+ ++_textField.textCharsCount;
+ dirty = true;
+ }
+ break;
+ }
+ if (dirty) {
+ _vm->display()->setText(_textField.x, _textField.y + _currentSaveSlot * _textField.h, _textField.text, false);
+ _textField.posCursor = _vm->display()->textWidth(_textField.text);
+ update();
+ }
+}
+
+void Journal::closeTextField() {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+ _textField.enabled = false;
+}
+
+const Journal::Zone Journal::_zones[] = {
+ { ZN_REVIEW_ENTRY, 32, 8, 96, 40 },
+ { ZN_MAKE_ENTRY, 32, 56, 96, 88 }, // == ZN_YES
+ { ZN_CLOSE, 32, 104, 96, 136 }, // == ZN_NO
+ { ZN_GIVEUP, 32, 152, 96, 184 },
+ { ZN_TEXT_SPEED, 136, 169, 265, 176 },
+ { ZN_SFX_TOGGLE, 197, 155, 231, 164 },
+ { ZN_MUSIC_VOLUME, 136, 182, 265, 189 },
+ { ZN_DESC_1, 131, 7, 290, 18 },
+ { ZN_DESC_2, 131, 20, 290, 31 },
+ { ZN_DESC_3, 131, 33, 290, 44 },
+ { ZN_DESC_4, 131, 46, 290, 57 },
+ { ZN_DESC_5, 131, 59, 290, 70 },
+ { ZN_DESC_6, 131, 72, 290, 83 },
+ { ZN_DESC_7, 131, 85, 290, 96 },
+ { ZN_DESC_8, 131, 98, 290, 109 },
+ { ZN_DESC_9, 131, 111, 290, 122 },
+ { ZN_DESC_10, 131, 124, 290, 135 },
+ { ZN_PAGE_A, 300, 4, 319, 17 },
+ { ZN_PAGE_B, 300, 19, 319, 32 },
+ { ZN_PAGE_C, 300, 34, 319, 47 },
+ { ZN_PAGE_D, 300, 49, 319, 62 },
+ { ZN_PAGE_E, 300, 64, 319, 77 },
+ { ZN_PAGE_F, 300, 79, 319, 92 },
+ { ZN_PAGE_G, 300, 94, 319, 107 },
+ { ZN_PAGE_H, 300, 109, 319, 122 },
+ { ZN_PAGE_I, 300, 124, 319, 137 },
+ { ZN_PAGE_J, 300, 139, 319, 152 },
+ { ZN_INFO_BOX, 273, 146, 295, 189 },
+ { ZN_MUSIC_TOGGLE, 109, 181, 135, 190 },
+ { ZN_VOICE_TOGGLE, 134, 155, 168, 164 },
+ { ZN_TEXT_TOGGLE, 109, 168, 135, 177 }
+};
+
+} // End of namespace Queen
diff --git a/engines/queen/journal.h b/engines/queen/journal.h
new file mode 100644
index 0000000000..ab3e2a0ecd
--- /dev/null
+++ b/engines/queen/journal.h
@@ -0,0 +1,208 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENJOURNAL_H
+#define QUEENJOURNAL_H
+
+#include "common/util.h"
+
+class OSystem;
+
+namespace Queen {
+
+class QueenEngine;
+
+class Journal {
+public:
+
+ Journal(QueenEngine *vm);
+ void use();
+
+ enum {
+ JOURNAL_BANK = 8,
+ JOURNAL_FRAMES = 40
+ };
+
+ enum {
+ ZN_REVIEW_ENTRY = 1,
+ ZN_MAKE_ENTRY = 2,
+ ZN_YES = ZN_MAKE_ENTRY,
+ ZN_CLOSE = 3,
+ ZN_NO = ZN_CLOSE,
+ ZN_GIVEUP = 4,
+ ZN_TEXT_SPEED = 5,
+ ZN_SFX_TOGGLE = 6,
+ ZN_MUSIC_VOLUME = 7,
+ ZN_DESC_1 = 8,
+ ZN_DESC_2 = 9,
+ ZN_DESC_3 = 10,
+ ZN_DESC_4 = 11,
+ ZN_DESC_5 = 12,
+ ZN_DESC_6 = 13,
+ ZN_DESC_7 = 14,
+ ZN_DESC_8 = 15,
+ ZN_DESC_9 = 16,
+ ZN_DESC_10 = 17,
+ ZN_PAGE_A = 18,
+ ZN_PAGE_B = 19,
+ ZN_PAGE_C = 20,
+ ZN_PAGE_D = 21,
+ ZN_PAGE_E = 22,
+ ZN_PAGE_F = 23,
+ ZN_PAGE_G = 24,
+ ZN_PAGE_H = 25,
+ ZN_PAGE_I = 26,
+ ZN_PAGE_J = 27,
+ ZN_INFO_BOX = 28,
+ ZN_MUSIC_TOGGLE = 29,
+ ZN_VOICE_TOGGLE = 30,
+ ZN_TEXT_TOGGLE = 31
+ };
+
+ enum {
+ BOB_LEFT_RECT_1 = 1,
+ BOB_LEFT_RECT_2 = 2,
+ BOB_LEFT_RECT_3 = 3,
+ BOB_LEFT_RECT_4 = 4,
+ BOB_TALK_SPEED = 5,
+ BOB_SFX_TOGGLE = 6,
+ BOB_MUSIC_VOLUME = 7,
+ BOB_SAVE_DESC = 8,
+ BOB_SAVE_PAGE = 9,
+ BOB_SPEECH_TOGGLE = 10,
+ BOB_TEXT_TOGGLE = 11,
+ BOB_MUSIC_TOGGLE = 12,
+ BOB_INFO_BOX = 13
+ };
+
+ enum {
+ FRAME_BLUE_1 = 1,
+ FRAME_BLUE_2 = 2,
+ FRAME_ORANGE = 3,
+ FRAME_GREY = 5,
+ FRAME_CHECK_BOX = 16,
+ FRAME_BLUE_PIN = 18,
+ FRAME_GREEN_PIN = 19,
+ FRAME_INFO_BOX = 20
+ };
+
+ enum {
+ TXT_CLOSE = 30,
+ TXT_GIVE_UP = 31,
+ TXT_MAKE_ENTRY = 32,
+ TXT_REVIEW_ENTRY = 33,
+ TXT_YES = 34,
+ TXT_NO = 35
+ };
+
+ enum {
+ NUM_SAVES_PER_PAGE = 10,
+ MAX_PANEL_TEXTS = 8,
+ MAX_ZONES = 31
+ };
+
+ enum PanelMode {
+ PM_NORMAL,
+ PM_INFO_BOX,
+ PM_YES_NO
+ };
+
+ enum QuitMode {
+ QM_LOOP,
+ QM_RESTORE,
+ QM_CONTINUE
+ };
+
+
+private:
+
+ void continueGame();
+
+ void setup();
+ void redraw();
+ void update();
+
+ void showBob(int bobNum, int16 x, int16 y, int frameNum);
+ void hideBob(int bobNum);
+
+ void drawSaveDescriptions();
+ void drawSaveSlot();
+
+ void enterYesNoPanelMode(int16 prevZoneNum, int titleNum);
+ void exitYesNoPanelMode();
+ void enterInfoPanelMode();
+ void exitInfoPanelMode();
+
+ void handleMouseWheel(int inc);
+ void handleMouseDown(int x, int y);
+ void handleKeyDown(uint16 ascii, int keycode);
+
+ void drawPanelText(int y, const char *text);
+ void drawCheckBox(bool active, int bobNum, int16 x, int16 y, int frameNum);
+ void drawSlideBar(int value, int maxValue, int bobNum, int16 y, int frameNum);
+ void drawPanel(const int *frames, const int *titles, int n);
+ void drawNormalPanel();
+ void drawYesNoPanel(int titleNum);
+ void drawConfigPanel();
+ void drawInfoPanel();
+
+ void initTextField(const char *desc);
+ void updateTextField(uint16 ascii, int keycode);
+ void closeTextField();
+
+ struct TextField {
+ bool enabled;
+ int posCursor;
+ uint textCharsCount;
+ char text[32];
+ int x, y;
+ int w, h;
+ };
+
+ struct Zone {
+ int num;
+ int16 x1, y1, x2, y2;
+ };
+
+ PanelMode _panelMode;
+ QuitMode _quitMode;
+
+ int _currentSavePage;
+ int _currentSaveSlot;
+
+ int _prevJoeX, _prevJoeY;
+
+ int _panelTextCount;
+ int _panelTextY[MAX_PANEL_TEXTS];
+ TextField _textField;
+ uint16 _prevZoneNum;
+ char _saveDescriptions[100][32];
+
+ OSystem *_system;
+ QueenEngine *_vm;
+
+ static const Zone _zones[MAX_ZONES];
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/logic.cpp b/engines/queen/logic.cpp
new file mode 100644
index 0000000000..a535907dd9
--- /dev/null
+++ b/engines/queen/logic.cpp
@@ -0,0 +1,2221 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/logic.h"
+
+#include "common/config-manager.h"
+#include "queen/bankman.h"
+#include "queen/command.h"
+#include "queen/credits.h"
+#include "queen/cutaway.h"
+#include "queen/debug.h"
+#include "queen/defs.h"
+#include "queen/display.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/input.h"
+#include "queen/journal.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+#include "queen/state.h"
+#include "queen/talk.h"
+#include "queen/walk.h"
+
+namespace Queen {
+
+static Common::String trim(const Common::String &s) {
+ const char *p;
+
+ p = s.c_str();
+ while (*p == ' ') ++p;
+ int start = p - s.c_str();
+
+ p = s.c_str() + s.size() - 1;
+ while (p != s.c_str() && *p == ' ') --p;
+ int end = p - s.c_str();
+
+ return Common::String(s.c_str() + start, end - start + 1);
+}
+
+Logic::Logic(QueenEngine *vm)
+ : _credits(NULL), _objectData(NULL), _roomData(NULL), _sfxName(NULL),
+ _itemData(NULL), _graphicData(NULL), _walkOffData(NULL), _objectDescription(NULL),
+ _furnitureData(NULL), _actorData(NULL), _graphicAnim(NULL), _vm(vm) {
+ _joe.x = _joe.y = 0;
+ _joe.scale = 100;
+ _joe.walk = JWM_NORMAL;
+ memset(_gameState, 0, sizeof(_gameState));
+ memset(_talkSelected, 0, sizeof(_talkSelected));
+ _puzzleAttemptCount = 0;
+ _journal = new Journal(vm);
+ _scene = 0;
+ initialise();
+}
+
+Logic::~Logic() {
+ delete _journal;
+ delete _credits;
+ delete[] _objectData;
+ delete[] _roomData;
+ delete[] _sfxName;
+ delete[] _itemData;
+ delete[] _graphicData;
+ delete[] _walkOffData;
+ delete[] _objectDescription;
+ delete[] _furnitureData;
+ delete[] _actorData;
+ delete[] _graphicAnim;
+}
+
+void Logic::initialise() {
+ int16 i;
+
+ uint8 *jas = _vm->resource()->loadFile("QUEEN.JAS", 20);
+ uint8 *ptr = jas;
+
+ _numRooms = READ_BE_UINT16(ptr); ptr += 2;
+ _numNames = READ_BE_UINT16(ptr); ptr += 2;
+ _numObjects = READ_BE_UINT16(ptr); ptr += 2;
+ _numDescriptions = READ_BE_UINT16(ptr); ptr += 2;
+
+ _objectData = new ObjectData[_numObjects + 1];
+ memset(&_objectData[0], 0, sizeof(ObjectData));
+ for (i = 1; i <= _numObjects; i++) {
+ _objectData[i].readFromBE(ptr);
+ }
+
+ _roomData = new uint16[_numRooms + 2];
+ _roomData[0] = 0;
+ for (i = 1; i <= (_numRooms + 1); i++) {
+ _roomData[i] = READ_BE_UINT16(ptr); ptr += 2;
+ }
+ _roomData[_numRooms + 1] = _numObjects;
+
+ if (_vm->resource()->isDemo()) {
+ _sfxName = NULL;
+ } else {
+ _sfxName = new uint16[_numRooms + 1];
+ _sfxName[0] = 0;
+ for (i = 1; i <= _numRooms; i++) {
+ _sfxName[i] = READ_BE_UINT16(ptr); ptr += 2;
+ }
+ }
+
+ _numItems = READ_BE_UINT16(ptr); ptr += 2;
+ _itemData = new ItemData[_numItems + 1];
+ memset(&_itemData[0], 0, sizeof(ItemData));
+ for (i = 1; i <= _numItems; i++) {
+ _itemData[i].readFromBE(ptr);
+ }
+
+ _numGraphics = READ_BE_UINT16(ptr); ptr += 2;
+ _graphicData = new GraphicData[_numGraphics + 1];
+ memset(&_graphicData[0], 0, sizeof(GraphicData));
+ for (i = 1; i <= _numGraphics; i++) {
+ _graphicData[i].readFromBE(ptr);
+ }
+
+ _vm->grid()->readDataFrom(_numObjects, _numRooms, ptr);
+
+ _numWalkOffs = READ_BE_UINT16(ptr); ptr += 2;
+ _walkOffData = new WalkOffData[_numWalkOffs + 1];
+ memset(&_walkOffData[0], 0, sizeof(WalkOffData));
+ for (i = 1; i <= _numWalkOffs; i++) {
+ _walkOffData[i].readFromBE(ptr);
+ }
+
+ _numObjDesc = READ_BE_UINT16(ptr); ptr += 2;
+ _objectDescription = new ObjectDescription[_numObjDesc + 1];
+ memset(&_objectDescription[0], 0, sizeof(ObjectDescription));
+ for (i = 1; i <= _numObjDesc; i++) {
+ _objectDescription[i].readFromBE(ptr);
+ }
+
+ _vm->command()->readCommandsFrom(ptr);
+
+ _entryObj = READ_BE_UINT16(ptr); ptr += 2;
+
+ _numFurniture = READ_BE_UINT16(ptr); ptr += 2;
+ _furnitureData = new FurnitureData[_numFurniture + 1];
+ memset(&_furnitureData[0], 0, sizeof(FurnitureData));
+ for (i = 1; i <= _numFurniture; i++) {
+ _furnitureData[i].readFromBE(ptr);
+ }
+
+ // Actors
+ _numActors = READ_BE_UINT16(ptr); ptr += 2;
+ _numAAnim = READ_BE_UINT16(ptr); ptr += 2;
+ _numAName = READ_BE_UINT16(ptr); ptr += 2;
+ _numAFile = READ_BE_UINT16(ptr); ptr += 2;
+
+ _actorData = new ActorData[_numActors + 1];
+ memset(&_actorData[0], 0, sizeof(ActorData));
+ for (i = 1; i <= _numActors; i++) {
+ _actorData[i].readFromBE(ptr);
+ }
+
+ _numGraphicAnim = READ_BE_UINT16(ptr); ptr += 2;
+
+ _graphicAnim = new GraphicAnim[_numGraphicAnim + 1];
+ if (_numGraphicAnim == 0) {
+ _graphicAnim[0].readFromBE(ptr);
+ } else {
+ memset(&_graphicAnim[0], 0, sizeof(GraphicAnim));
+ for (i = 1; i <= _numGraphicAnim; i++) {
+ _graphicAnim[i].readFromBE(ptr);
+ }
+ }
+
+ _currentRoom = _objectData[_entryObj].room;
+ _entryObj = 0;
+
+ if (memcmp(ptr, _vm->resource()->JASVersion(), 5) != 0) {
+ warning("Unexpected queen.jas file format");
+ }
+
+ delete[] jas;
+
+ uint32 size;
+ char *buf = (char *)_vm->resource()->loadFile("QUEEN2.JAS", 0, &size);
+ LineReader queen2jas(buf, size);
+
+ _objDescription.push_back("");
+ for (i = 1; i <= _numDescriptions; i++) {
+ _objDescription.push_back(queen2jas.nextLine());
+ }
+
+ // Patch for German text bug
+ if (_vm->resource()->getLanguage() == GERMAN) {
+ _objDescription[296] = "Es bringt nicht viel, das festzubinden.";
+ }
+
+ _objName.push_back("");
+ for (i = 1; i <= _numNames; i++) {
+ _objName.push_back(queen2jas.nextLine());
+ }
+
+ _roomName.push_back("");
+ for (i = 1; i <= _numRooms; i++) {
+ _roomName.push_back(queen2jas.nextLine());
+ }
+
+ _verbName.push_back("");
+ for (i = 1; i <= 12; i++) {
+ _verbName.push_back(queen2jas.nextLine());
+ }
+
+ _joeResponse.push_back("");
+ for (i = 1; i <= JOE_RESPONSE_MAX; i++) {
+ _joeResponse.push_back(queen2jas.nextLine());
+ }
+
+ // FIXME - the spanish version adds some space characters (0x20) at the
+ // beginning and the end of the journal button captions. As we don't need
+ // that 'trick' to center horizontally the texts, we simply trim them.
+ if (_vm->resource()->getLanguage() == SPANISH) {
+ for (i = 30; i <= 35; i++) {
+ _joeResponse[i] = trim(_joeResponse[i]);
+ }
+ }
+
+ _aAnim.push_back("");
+ for (i = 1; i <= _numAAnim; i++) {
+ _aAnim.push_back(queen2jas.nextLine());
+ }
+
+ _aName.push_back("");
+ for (i = 1; i <= _numAName; i++) {
+ _aName.push_back(queen2jas.nextLine());
+ }
+
+ _aFile.push_back("");
+ for (i = 1; i <= _numAFile; i++) {
+ _aFile.push_back(queen2jas.nextLine());
+ }
+}
+
+void Logic::start() {
+ _vm->command()->clear(false);
+ _vm->display()->setupPanel();
+ _vm->graphics()->unpackControlBank();
+ _vm->graphics()->setupMouseCursor();
+ setupJoe();
+ _vm->grid()->setupPanel();
+ inventorySetup();
+
+ _oldRoom = 0;
+ _newRoom = _currentRoom;
+}
+
+ObjectData* Logic::objectData(int index) const {
+ assert(index >= 0 && index <= _numObjects);
+ return &_objectData[index];
+}
+
+uint16 Logic::findBob(uint16 obj) const {
+ assert(obj <= _numObjects);
+
+ uint16 room = _objectData[obj].room;
+ assert(room <= _numRooms);
+
+ uint16 bobnum = 0;
+ int16 img = _objectData[obj].image;
+ if (img != 0) {
+ if (img == -3 || img == -4) {
+ // a person object
+ bobnum = findPersonNumber(obj, room);
+ } else {
+ uint16 bobtype = 0; // 1 for animated, 0 for static
+
+ if (img <= -10) {
+ // object has been turned off, but the image order hasn't been updated
+ if (_graphicData[-(img + 10)].lastFrame != 0) {
+ bobtype = 1;
+ }
+ } else if (img == -2) {
+ // -1 static, -2 animated
+ bobtype = 1;
+ } else if (img > 0) {
+ if (_graphicData[img].lastFrame != 0) {
+ bobtype = 1;
+ }
+ }
+
+ uint16 idxAnimated = 0;
+ uint16 idxStatic = 0;
+ for (uint16 i = _roomData[room] + 1; i <= obj; ++i) {
+ img = _objectData[i].image;
+ if (img <= -10) {
+ if (_graphicData[-(img + 10)].lastFrame != 0) {
+ ++idxAnimated;
+ } else {
+ ++idxStatic;
+ }
+ } else if (img > 0) {
+ if (img > 5000) {
+ img -= 5000;
+ }
+
+ assert (img <= _numGraphics);
+
+ if (_graphicData[img].lastFrame != 0) {
+ ++idxAnimated;
+ } else {
+ ++idxStatic;
+ }
+ } else if (img == -1) {
+ ++idxStatic;
+ } else if (img == -2) {
+ ++idxAnimated;
+ }
+ }
+ if (bobtype == 0) {
+ // static bob
+ if (idxStatic > 0) {
+ bobnum = 19 + _vm->graphics()->numStaticFurniture() + idxStatic;
+ }
+ } else {
+ // animated bob
+ if (idxAnimated > 0) {
+ bobnum = 4 + _vm->graphics()->numAnimatedFurniture() + idxAnimated;
+ }
+ }
+ }
+ }
+ return bobnum;
+}
+
+uint16 Logic::findFrame(uint16 obj) const {
+ uint16 framenum = 0;
+ uint16 room = _objectData[obj].room;
+ int16 img = _objectData[obj].image;
+ if (img == -3 || img == -4) {
+ uint16 bobnum = findPersonNumber(obj, room);
+ if (bobnum <= 3) {
+ framenum = 31 + bobnum;
+ }
+ } else {
+ uint16 idx = 0;
+ for (uint16 i = _roomData[room] + 1; i < obj; ++i) {
+ img = _objectData[i].image;
+ if (img <= -10) {
+ const GraphicData* pgd = &_graphicData[-(img + 10)];
+ if (pgd->lastFrame != 0) {
+ // skip all the frames of the animation
+ idx += ABS(pgd->lastFrame) - pgd->firstFrame + 1;
+ } else {
+ // static bob, skip one frame
+ ++idx;
+ }
+ } else if (img == -1) {
+ ++idx;
+ } else if (img > 0) {
+ if (img > 5000) {
+ img -= 5000;
+ }
+ const GraphicData* pgd = &_graphicData[img];
+ uint16 lastFrame = ABS(pgd->lastFrame);
+ if (pgd->firstFrame < 0) {
+ idx += lastFrame;
+ } else if (lastFrame != 0) {
+ idx += (lastFrame - pgd->firstFrame) + 1;
+ } else {
+ ++idx;
+ }
+ }
+ }
+
+ img = _objectData[obj].image;
+ if (img <= -10) {
+ const GraphicData* pgd = &_graphicData[-(img + 10)];
+ if (pgd->lastFrame != 0) {
+ idx += ABS(pgd->lastFrame) - pgd->firstFrame + 1;
+ } else {
+ ++idx;
+ }
+ } else if (img == -1 || img > 0) {
+ ++idx;
+ }
+
+ // calculate only if there are person frames
+ if (idx > 0) {
+ framenum = FRAMES_JOE + _vm->graphics()->numFurnitureFrames() + idx;
+ }
+ }
+ return framenum;
+}
+
+uint16 Logic::objectForPerson(uint16 bobNum) const {
+ uint16 bobcur = 0;
+ // first object number in the room
+ uint16 cur = currentRoomData() + 1;
+ // last object number in the room
+ uint16 last = _roomData[_currentRoom + 1];
+ for (; cur <= last; ++cur) {
+ int16 image = _objectData[cur].image;
+ if (image == -3 || image == -4) {
+ // the object is a bob
+ ++bobcur;
+ }
+ if (bobcur == bobNum) {
+ return cur;
+ }
+ }
+ return 0;
+}
+
+WalkOffData *Logic::walkOffPointForObject(int16 obj) const {
+ for (uint16 i = 1; i <= _numWalkOffs; ++i) {
+ if (_walkOffData[i].entryObj == obj) {
+ return &_walkOffData[i];
+ }
+ }
+ return NULL;
+}
+
+void Logic::joeWalk(JoeWalkMode walking) {
+ _joe.walk = walking;
+ // Do this so that Input doesn't need to know the walk value
+ _vm->input()->dialogueRunning(JWM_SPEAK == walking);
+}
+
+int16 Logic::gameState(int index) const {
+ assert(index >= 0 && index < GAME_STATE_COUNT);
+ return _gameState[index];
+}
+
+void Logic::gameState(int index, int16 newValue) {
+ assert(index >= 0 && index < GAME_STATE_COUNT);
+ debug(8, "Logic::gameState() [%d] = %d", index, newValue);
+ _gameState[index] = newValue;
+}
+
+const char *Logic::roomName(uint16 roomNum) const {
+ assert(roomNum >= 1 && roomNum <= _numRooms);
+ return _roomName[roomNum].c_str();
+}
+
+const char *Logic::objectName(uint16 objNum) const {
+ assert(objNum >= 1 && objNum <= _numNames);
+ return _objName[objNum].c_str();
+}
+
+const char *Logic::objectTextualDescription(uint16 objNum) const {
+ assert(objNum >= 1 && objNum <= _numDescriptions);
+ return _objDescription[objNum].c_str();
+}
+
+const char *Logic::joeResponse(int i) const {
+ assert(i >= 1 && i <= JOE_RESPONSE_MAX);
+ return _joeResponse[i].c_str();
+}
+
+const char *Logic::verbName(Verb v) const {
+ assert(v >= 0 && v <= 12);
+ return _verbName[v].c_str();
+}
+
+void Logic::eraseRoom() {
+ _vm->bankMan()->eraseFrames(false);
+ _vm->bankMan()->close(15);
+ _vm->bankMan()->close(11);
+ _vm->bankMan()->close(10);
+ _vm->bankMan()->close(12);
+
+ _vm->display()->palFadeOut(_currentRoom);
+
+ // invalidates all persons animations
+ _vm->graphics()->clearPersonFrames();
+ _vm->graphics()->eraseAllAnims();
+
+ uint16 cur = _roomData[_oldRoom] + 1;
+ uint16 last = _roomData[_oldRoom + 1];
+ for (; cur <= last; ++cur) {
+ ObjectData *pod = &_objectData[cur];
+ if (pod->name == 0) {
+ // object has been deleted, invalidate image
+ pod->image = 0;
+ } else if (pod->image > -4000 && pod->image <= -10) {
+ if (_graphicData[ABS(pod->image + 10)].lastFrame == 0) {
+ // static Bob
+ pod->image = -1;
+ } else {
+ // animated Bob
+ pod->image = -2;
+ }
+ }
+ }
+}
+
+void Logic::setupRoom(const char *room, int comPanel, bool inCutaway) {
+ // load backdrop image, init dynalum, setup colors
+ _vm->display()->setupNewRoom(room, _currentRoom);
+
+ // setup graphics to enter fullscreen/panel mode
+ _vm->display()->screenMode(comPanel, inCutaway);
+
+ _vm->grid()->setupNewRoom(_currentRoom, _roomData[_currentRoom]);
+
+ int16 furn[9];
+ uint16 furnTot = 0;
+ for (uint16 i = 1; i <= _numFurniture; ++i) {
+ if (_furnitureData[i].room == _currentRoom) {
+ ++furnTot;
+ furn[furnTot] = _furnitureData[i].objNum;
+ }
+ }
+ _vm->graphics()->setupNewRoom(room, _currentRoom, furn, furnTot);
+
+ _vm->display()->forceFullRefresh();
+}
+
+void Logic::displayRoom(uint16 room, RoomDisplayMode mode, uint16 scale, int comPanel, bool inCutaway) {
+ debug(6, "Logic::displayRoom(%d, %d, %d, %d, %d)", room, mode, scale, comPanel, inCutaway);
+
+ eraseRoom();
+
+ if (_credits)
+ _credits->nextRoom();
+
+ setupRoom(roomName(room), comPanel, inCutaway);
+ if (mode != RDM_FADE_NOJOE) {
+ setupJoeInRoom(mode != RDM_FADE_JOE_XY, scale);
+ }
+ if (mode != RDM_NOFADE_JOE) {
+ _vm->update();
+ BobSlot *joe = _vm->graphics()->bob(0);
+ _vm->display()->palFadeIn(_currentRoom, joe->active, joe->x, joe->y);
+ }
+ if (mode != RDM_FADE_NOJOE && joeX() != 0 && joeY() != 0) {
+ int16 jx = joeX();
+ int16 jy = joeY();
+ joePos(0, 0);
+ _vm->walk()->moveJoe(0, jx, jy, inCutaway);
+ }
+}
+
+ActorData *Logic::findActor(uint16 noun, const char *name) const {
+ uint16 obj = currentRoomData() + noun;
+ int16 img = objectData(obj)->image;
+ if (img != -3 && img != -4) {
+ warning("Logic::findActor() - Object %d is not a person", obj);
+ return NULL;
+ }
+
+ // search Bob number for the person
+ uint16 bobNum = findPersonNumber(obj, _currentRoom);
+
+ // search for a matching actor
+ if (bobNum > 0) {
+ for (uint16 i = 1; i <= _numActors; ++i) {
+ ActorData *pad = &_actorData[i];
+ if (pad->room == _currentRoom && gameState(pad->gsSlot) == pad->gsValue) {
+ if (bobNum == pad->bobNum || (name && _aName[pad->name] == name)) {
+ return pad;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+bool Logic::initPerson(uint16 noun, const char *actorName, bool loadBank, Person *pp) {
+ const ActorData *pad = findActor(noun, actorName);
+ if (pad != NULL) {
+ pp->actor = pad;
+ pp->name = _aName[pad->name].c_str();
+ if (pad->anim != 0) {
+ pp->anim = _aAnim[pad->anim].c_str();
+ } else {
+ pp->anim = NULL;
+ }
+ if (loadBank && pad->file != 0) {
+ _vm->bankMan()->load(_aFile[pad->file].c_str(), pad->bankNum);
+ // if there is no valid actor file (ie pad->file is 0), the person
+ // data is already loaded as it is included in objects room bank (.bbk)
+ }
+ pp->bobFrame = 31 + pp->actor->bobNum;
+ }
+ return pad != NULL;
+}
+
+uint16 Logic::findPersonNumber(uint16 obj, uint16 room) const {
+ uint16 num = 0;
+ for (uint16 i = _roomData[room] + 1; i <= obj; ++i) {
+ int16 img = _objectData[i].image;
+ if (img == -3 || img == -4) {
+ ++num;
+ }
+ }
+ return num;
+}
+
+void Logic::loadJoeBanks(const char *animBank, const char *standBank) {
+ _vm->bankMan()->load(animBank, 13);
+ for (int i = 11; i < 31; ++i) {
+ _vm->bankMan()->unpack(i - 10, i, 13);
+ }
+ _vm->bankMan()->close(13);
+
+ _vm->bankMan()->load(standBank, 7);
+ _vm->bankMan()->unpack(1, 35, 7);
+ _vm->bankMan()->unpack(3, 36, 7);
+ _vm->bankMan()->unpack(5, 37, 7);
+}
+
+void Logic::setupJoe() {
+ loadJoeBanks("joe_a.BBK", "joe_b.BBK");
+ joePrevFacing(DIR_FRONT);
+ joeFacing(DIR_FRONT);
+}
+
+void Logic::setupJoeInRoom(bool autoPosition, uint16 scale) {
+ debug(9, "Logic::setupJoeInRoom(%d, %d) joe.x=%d joe.y=%d", autoPosition, scale, _joe.x, _joe.y);
+
+ int16 oldx, oldy;
+ if (!autoPosition || joeX() != 0 || joeY() != 0) {
+ oldx = joeX();
+ oldy = joeY();
+ joePos(0, 0);
+ } else {
+ const ObjectData *pod = objectData(_entryObj);
+ // find the walk off point for the entry object and make
+ // Joe walking to that point
+ const WalkOffData *pwo = walkOffPointForObject(_entryObj);
+ if (pwo != NULL) {
+ oldx = pwo->x;
+ oldy = pwo->y;
+ // entryObj has a walk off point, then walk from there to object x,y
+ joePos(pod->x, pod->y);
+ } else {
+ // no walk off point, use object position
+ oldx = pod->x;
+ oldy = pod->y;
+ joePos(0, 0);
+ }
+ }
+
+ debug(6, "Logic::setupJoeInRoom() - oldx=%d, oldy=%d scale=%d", oldx, oldy, scale);
+
+ if (scale > 0 && scale < 100) {
+ joeScale(scale);
+ } else {
+ uint16 a = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
+ if (a > 0) {
+ joeScale(_vm->grid()->area(_currentRoom, a)->calcScale(oldy));
+ } else {
+ joeScale(100);
+ }
+ }
+
+ if (joeCutFacing() > 0) {
+ joeFacing(joeCutFacing());
+ joeCutFacing(0);
+ } else {
+ // check to see which way Joe entered room
+ const ObjectData *pod = objectData(_entryObj);
+ switch (State::findDirection(pod->state)) {
+ case DIR_BACK:
+ joeFacing(DIR_FRONT);
+ break;
+ case DIR_FRONT:
+ joeFacing(DIR_BACK);
+ break;
+ case DIR_LEFT:
+ joeFacing(DIR_RIGHT);
+ break;
+ case DIR_RIGHT:
+ joeFacing(DIR_LEFT);
+ break;
+ }
+ }
+ joePrevFacing(joeFacing());
+
+ BobSlot *pbs = _vm->graphics()->bob(0);
+ pbs->scale = joeScale();
+
+ if (_currentRoom == 108) {
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->bankMan()->load("joe_e.act", 7);
+ _vm->bankMan()->unpack(2, 31, 7);
+
+ _vm->display()->horizontalScroll(320);
+
+ joeFacing(DIR_RIGHT);
+ joeCutFacing(DIR_RIGHT);
+ joePrevFacing(DIR_RIGHT);
+ }
+
+ joeFace();
+ pbs->curPos(oldx, oldy);
+ pbs->frameNum = 31;
+}
+
+uint16 Logic::joeFace() {
+ debug(9, "Logic::joeFace() - curFace = %d, prevFace = %d", _joe.facing, _joe.prevFacing);
+ BobSlot *pbs = _vm->graphics()->bob(0);
+ uint16 frame;
+ if (_currentRoom == 108) {
+ frame = 1;
+ } else {
+ frame = 35;
+ if (joeFacing() == DIR_FRONT) {
+ if (joePrevFacing() == DIR_BACK) {
+ pbs->frameNum = 35;
+ _vm->update();
+ }
+ frame = 36;
+ } else if (joeFacing() == DIR_BACK) {
+ if (joePrevFacing() == DIR_FRONT) {
+ pbs->frameNum = 35;
+ _vm->update();
+ }
+ frame = 37;
+ } else if ((joeFacing() == DIR_LEFT && joePrevFacing() == DIR_RIGHT)
+ || (joeFacing() == DIR_RIGHT && joePrevFacing() == DIR_LEFT)) {
+ pbs->frameNum = 36;
+ _vm->update();
+ }
+ pbs->frameNum = frame;
+ pbs->scale = joeScale();
+ pbs->xflip = (joeFacing() == DIR_LEFT);
+ _vm->update();
+ joePrevFacing(joeFacing());
+ switch (frame) {
+ case 35:
+ frame = 1;
+ break;
+ case 36:
+ frame = 3;
+ break;
+ case 37:
+ frame = 5;
+ break;
+ }
+ }
+ pbs->frameNum = 31;
+ _vm->bankMan()->unpack(frame, pbs->frameNum, 7);
+ return frame;
+}
+
+void Logic::joeGrab(int16 grabState) {
+ uint16 frame = 0;
+ BobSlot *bobJoe = _vm->graphics()->bob(0);
+
+ switch (grabState) {
+ case STATE_GRAB_NONE:
+ break;
+ case STATE_GRAB_MID:
+ if (joeFacing() == DIR_BACK) {
+ frame = 6;
+ } else if (joeFacing() == DIR_FRONT) {
+ frame = 4;
+ } else {
+ frame = 2;
+ }
+ break;
+ case STATE_GRAB_DOWN:
+ if (joeFacing() == DIR_BACK) {
+ frame = 9;
+ } else {
+ frame = 8;
+ }
+ break;
+ case STATE_GRAB_UP:
+ // turn back
+ _vm->bankMan()->unpack(5, 31, 7);
+ bobJoe->xflip = (joeFacing() == DIR_LEFT);
+ bobJoe->scale = joeScale();
+ _vm->update();
+ // grab up
+ _vm->bankMan()->unpack(7, 31, 7);
+ bobJoe->xflip = (joeFacing() == DIR_LEFT);
+ bobJoe->scale = joeScale();
+ _vm->update();
+ // turn back
+ frame = 7;
+ break;
+ }
+
+ if (frame != 0) {
+ _vm->bankMan()->unpack(frame, 31, 7);
+ bobJoe->xflip = (joeFacing() == DIR_LEFT);
+ bobJoe->scale = joeScale();
+ _vm->update();
+
+ // extra delay for grab down
+ if (grabState == STATE_GRAB_DOWN) {
+ _vm->update();
+ _vm->update();
+ }
+ }
+}
+
+void Logic::joeUseDress(bool showCut) {
+ if (showCut) {
+ joeFacing(DIR_FRONT);
+ joeFace();
+ if (gameState(VAR_JOE_DRESSING_MODE) == 0) {
+ playCutaway("cdres.CUT");
+ inventoryInsertItem(ITEM_CLOTHES);
+ } else {
+ playCutaway("cudrs.CUT");
+ }
+ }
+ _vm->display()->palSetJoeDress();
+ loadJoeBanks("JoeD_A.BBK", "JoeD_B.BBK");
+ inventoryDeleteItem(ITEM_DRESS);
+ gameState(VAR_JOE_DRESSING_MODE, 2);
+}
+
+void Logic::joeUseClothes(bool showCut) {
+ if (showCut) {
+ joeFacing(DIR_FRONT);
+ joeFace();
+ playCutaway("cdclo.CUT");
+ inventoryInsertItem(ITEM_DRESS);
+ }
+ _vm->display()->palSetJoeNormal();
+ loadJoeBanks("Joe_A.BBK", "Joe_B.BBK");
+ inventoryDeleteItem(ITEM_CLOTHES);
+ gameState(VAR_JOE_DRESSING_MODE, 0);
+}
+
+void Logic::joeUseUnderwear() {
+ _vm->display()->palSetJoeNormal();
+ loadJoeBanks("JoeU_A.BBK", "JoeU_B.BBK");
+ gameState(VAR_JOE_DRESSING_MODE, 1);
+}
+
+void Logic::makePersonSpeak(const char *sentence, Person *person, const char *voiceFilePrefix) {
+ _vm->command()->clear(false);
+ Talk::speak(sentence, person, voiceFilePrefix, _vm);
+}
+
+void Logic::startDialogue(const char *dlgFile, int personInRoom, char *cutaway) {
+ ObjectData *data = objectData(_roomData[_currentRoom] + personInRoom);
+ if (data->name > 0 && data->entryObj <= 0) {
+ if (State::findTalk(data->state) == STATE_TALK_MUTE) {
+ // 'I can't talk to that'
+ makeJoeSpeak(24 + _vm->randomizer.getRandomNumber(2));
+ } else {
+ char cutawayFile[20];
+ if (cutaway == NULL) {
+ cutaway = cutawayFile;
+ }
+ _vm->display()->fullscreen(true);
+ Talk::talk(dlgFile, personInRoom, cutaway, _vm);
+ if (!cutaway[0]) {
+ _vm->display()->fullscreen(false);
+ }
+ }
+ }
+}
+
+void Logic::playCutaway(const char *cutFile, char *next) {
+ char nextFile[20];
+ if (next == NULL) {
+ next = nextFile;
+ }
+ _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
+ Cutaway::run(cutFile, next, _vm);
+}
+
+void Logic::makeJoeSpeak(uint16 descNum, bool objectType) {
+ const char *text = objectType ? _objDescription[descNum].c_str() : _joeResponse[descNum].c_str();
+ if (objectType) {
+ descNum += JOE_RESPONSE_MAX;
+ }
+ char descFilePrefix[10];
+ sprintf(descFilePrefix, "JOE%04i", descNum);
+ makePersonSpeak(text, NULL, descFilePrefix);
+}
+
+uint16 Logic::findInventoryItem(int invSlot) const {
+ // queen.c l.3894-3898
+ if (invSlot >= 0 && invSlot < 4) {
+ return _inventoryItem[invSlot];
+ }
+ return 0;
+}
+
+void Logic::inventorySetup() {
+ _vm->bankMan()->load("objects.BBK", 14);
+ if (_vm->resource()->isInterview()) {
+ _inventoryItem[0] = 1;
+ _inventoryItem[1] = 2;
+ _inventoryItem[2] = 3;
+ _inventoryItem[3] = 4;
+ } else {
+ _inventoryItem[0] = ITEM_BAT;
+ _inventoryItem[1] = ITEM_JOURNAL;
+ _inventoryItem[2] = ITEM_NONE;
+ _inventoryItem[3] = ITEM_NONE;
+ }
+}
+
+void Logic::inventoryRefresh() {
+ uint16 x = 182;
+ for (int i = 0; i < 4; ++i) {
+ uint16 itemNum = _inventoryItem[i];
+ if (itemNum != 0) {
+ // 1st object in inventory uses frame 9,
+ // whereas 2nd, 3rd and 4th uses frame 8
+ uint16 dstFrame = (itemNum != 0) ? 8 : 9;
+ // unpack frame for object and draw it
+ _vm->bankMan()->unpack(_itemData[itemNum].frame, dstFrame, 14);
+ _vm->graphics()->drawInventoryItem(dstFrame, x, 14);
+ } else {
+ // no object, clear the panel
+ _vm->graphics()->drawInventoryItem(0, x, 14);
+ }
+ x += 35;
+ }
+}
+
+int16 Logic::previousInventoryItem(int16 first) const {
+ int i;
+ for (i = first - 1; i >= 1; i--)
+ if (_itemData[i].name > 0)
+ return i;
+ for (i = _numItems; i > first; i--)
+ if (_itemData[i].name > 0)
+ return i;
+
+ return 0; //nothing found
+}
+
+int16 Logic::nextInventoryItem(int16 first) const {
+ int i;
+ for (i = first + 1; i < _numItems; i++)
+ if (_itemData[i].name > 0)
+ return i;
+ for (i = 1; i < first; i++)
+ if (_itemData[i].name > 0)
+ return i;
+
+ return 0; //nothing found
+}
+
+void Logic::removeDuplicateItems() {
+ for (int i = 0; i < 4; i++)
+ for (int j = i + 1; j < 4; j++)
+ if (_inventoryItem[i] == _inventoryItem[j])
+ _inventoryItem[j] = ITEM_NONE;
+}
+
+uint16 Logic::numItemsInventory() const {
+ uint16 count = 0;
+ for (int i = 1; i < _numItems; i++)
+ if (_itemData[i].name > 0)
+ count++;
+
+ return count;
+}
+
+void Logic::inventoryInsertItem(uint16 itemNum, bool refresh) {
+ int16 item = _inventoryItem[0] = (int16)itemNum;
+ _itemData[itemNum].name = ABS(_itemData[itemNum].name); //set visible
+ for (int i = 1; i < 4; i++) {
+ item = nextInventoryItem(item);
+ _inventoryItem[i] = item;
+ removeDuplicateItems();
+ }
+
+ if (refresh)
+ inventoryRefresh();
+}
+
+void Logic::inventoryDeleteItem(uint16 itemNum, bool refresh) {
+ int16 item = (int16)itemNum;
+ _itemData[itemNum].name = -ABS(_itemData[itemNum].name); //set invisible
+ for (int i = 0; i < 4; i++) {
+ item = nextInventoryItem(item);
+ _inventoryItem[i] = item;
+ removeDuplicateItems();
+ }
+
+ if (refresh)
+ inventoryRefresh();
+}
+
+void Logic::inventoryScroll(uint16 count, bool up) {
+ if (!(numItemsInventory() > 4))
+ return;
+ while (count--) {
+ if (up) {
+ for (int i = 3; i > 0; i--)
+ _inventoryItem[i] = _inventoryItem[i - 1];
+ _inventoryItem[0] = previousInventoryItem(_inventoryItem[0]);
+ } else {
+ for (int i = 0; i < 3; i++)
+ _inventoryItem[i] = _inventoryItem[i + 1];
+ _inventoryItem[3] = nextInventoryItem(_inventoryItem[3]);
+ }
+ }
+
+ inventoryRefresh();
+}
+
+void Logic::removeHotelItemsFromInventory() {
+ if (currentRoom() == 1 && gameState(VAR_HOTEL_ITEMS_REMOVED) == 0) {
+ inventoryDeleteItem(ITEM_CROWBAR, false);
+ inventoryDeleteItem(ITEM_DRESS, false);
+ inventoryDeleteItem(ITEM_CLOTHES, false);
+ inventoryDeleteItem(ITEM_HAY, false);
+ inventoryDeleteItem(ITEM_OIL, false);
+ inventoryDeleteItem(ITEM_CHICKEN, false);
+ gameState(VAR_HOTEL_ITEMS_REMOVED, 1);
+ inventoryRefresh();
+ }
+}
+
+void Logic::objectCopy(int dummyObjectIndex, int realObjectIndex) {
+ // copy data from dummy object to real object, if COPY_FROM object
+ // images are greater than COPY_TO Object images then swap the objects around.
+
+ ObjectData *dummyObject = objectData(dummyObjectIndex);
+ ObjectData *realObject = objectData(realObjectIndex);
+
+ int fromState = (dummyObject->name < 0) ? -1 : 0;
+
+ int frameCountReal = 1;
+ int frameCountDummy = 1;
+
+ int graphic = realObject->image;
+ if (graphic > 0) {
+ if (graphic > 5000)
+ graphic -= 5000;
+
+ GraphicData *data = graphicData(graphic);
+
+ if (data->lastFrame > 0)
+ frameCountReal = data->lastFrame - data->firstFrame + 1;
+
+ graphic = dummyObject->image;
+ if (graphic > 0) {
+ if (graphic > 5000)
+ graphic -= 5000;
+
+ data = graphicData(graphic);
+
+ if (data->lastFrame > 0)
+ frameCountDummy = data->lastFrame - data->firstFrame + 1;
+ }
+ }
+
+ ObjectData temp = *realObject;
+ *realObject = *dummyObject;
+
+ if (frameCountDummy > frameCountReal)
+ *dummyObject = temp;
+
+ realObject->name = ABS(realObject->name);
+
+ if (fromState == -1)
+ dummyObject->name = -ABS(dummyObject->name);
+
+ for (int i = 1; i <= _numWalkOffs; i++) {
+ WalkOffData *walkOff = &_walkOffData[i];
+ if (walkOff->entryObj == (int16)dummyObjectIndex) {
+ walkOff->entryObj = (int16)realObjectIndex;
+ break;
+ }
+ }
+}
+
+void Logic::handleSpecialArea(Direction facing, uint16 areaNum, uint16 walkDataNum) {
+ // queen.c l.2838-2911
+ debug(9, "handleSpecialArea(%d, %d, %d)\n", facing, areaNum, walkDataNum);
+
+ // Stop animating Joe
+ _vm->graphics()->bob(0)->animating = false;
+
+ // Make Joe face the right direction
+ joeFacing(facing);
+ joeFace();
+
+ _newRoom = 0;
+ _entryObj = 0;
+
+ char nextCut[20];
+ memset(nextCut, 0, sizeof(nextCut));
+
+ switch (_currentRoom) {
+ case ROOM_JUNGLE_BRIDGE:
+ makeJoeSpeak(16);
+ break;
+ case ROOM_JUNGLE_GORILLA_1:
+ playCutaway("c6c.CUT", nextCut);
+ break;
+ case ROOM_JUNGLE_GORILLA_2:
+ playCutaway("c14b.CUT", nextCut);
+ break;
+ case ROOM_AMAZON_ENTRANCE:
+ if (areaNum == 3) {
+ playCutaway("c16a.CUT", nextCut);
+ }
+ break;
+ case ROOM_AMAZON_HIDEOUT:
+ if (walkDataNum == 4) {
+ playCutaway("c17a.CUT", nextCut);
+ } else if (walkDataNum == 2) {
+ playCutaway("c17b.CUT", nextCut);
+ }
+ break;
+ case ROOM_FLODA_OUTSIDE:
+ playCutaway("c22a.CUT", nextCut);
+ break;
+ case ROOM_FLODA_KITCHEN:
+ playCutaway("c26b.CUT", nextCut);
+ break;
+ case ROOM_FLODA_KLUNK:
+ playCutaway("c30a.CUT", nextCut);
+ break;
+ case ROOM_FLODA_HENRY:
+ playCutaway("c32c.CUT", nextCut);
+ break;
+ case ROOM_TEMPLE_ZOMBIES:
+ if (areaNum == 6) {
+ switch (gameState(VAR_BYPASS_ZOMBIES)) {
+ case 0:
+ playCutaway("c50d.CUT", nextCut);
+ while (nextCut[0] != '\0') {
+ playCutaway(nextCut, nextCut);
+ }
+ gameState(VAR_BYPASS_ZOMBIES, 1);
+ break;
+ case 1:
+ playCutaway("c50h.CUT", nextCut);
+ break;
+ }
+ }
+ break;
+ case ROOM_TEMPLE_SNAKE:
+ playCutaway("c53b.CUT", nextCut);
+ break;
+ case ROOM_TEMPLE_LIZARD_LASER:
+ makeJoeSpeak(19);
+ break;
+ case ROOM_HOTEL_DOWNSTAIRS:
+ makeJoeSpeak(21);
+ break;
+ case ROOM_HOTEL_LOBBY:
+ switch (gameState(VAR_HOTEL_ESCAPE_STATE)) {
+ case 0:
+ playCutaway("c73a.CUT");
+ joeUseUnderwear();
+ joeFace();
+ gameState(VAR_HOTEL_ESCAPE_STATE, 1);
+ break;
+ case 1:
+ playCutaway("c73b.CUT");
+ gameState(VAR_HOTEL_ESCAPE_STATE, 2);
+ break;
+ case 2:
+ playCutaway("c73c.CUT");
+ break;
+ }
+ break;
+ case ROOM_TEMPLE_MAZE_5:
+ if (areaNum == 7) {
+ makeJoeSpeak(17);
+ }
+ break;
+ case ROOM_TEMPLE_MAZE_6:
+ if (areaNum == 5 && gameState(187) == 0) {
+ playCutaway("c101b.CUT", nextCut);
+ }
+ break;
+ case ROOM_FLODA_FRONTDESK:
+ if (areaNum == 3) {
+ switch (gameState(VAR_BYPASS_FLODA_RECEPTIONIST)) {
+ case 0:
+ playCutaway("c103b.CUT", nextCut);
+ gameState(VAR_BYPASS_FLODA_RECEPTIONIST, 1);
+ break;
+ case 1:
+ playCutaway("c103e.CUT", nextCut);
+ break;
+ }
+ }
+ break;
+ }
+
+ while (strlen(nextCut) > 4 &&
+ scumm_stricmp(nextCut + strlen(nextCut) - 4, ".cut") == 0) {
+ playCutaway(nextCut, nextCut);
+ }
+}
+
+void Logic::handlePinnacleRoom() {
+ // camera does not follow Joe anymore
+ _vm->graphics()->putCameraOnBob(-1);
+ displayRoom(ROOM_JUNGLE_PINNACLE, RDM_NOFADE_JOE, 100, 2, true);
+
+ BobSlot *joe = _vm->graphics()->bob(6);
+ BobSlot *piton = _vm->graphics()->bob(7);
+
+ // set scrolling value to mouse position to avoid glitch
+ _vm->display()->horizontalScroll(_vm->input()->mousePosX());
+
+ joe->x = piton->x = 3 * _vm->input()->mousePosX() / 4 + 200;
+ joe->frameNum = _vm->input()->mousePosX() / 36 + 45;
+
+ // bobs have been unpacked from animating objects, we don't need them
+ // to animate anymore ; so turn animation off
+ joe->animating = piton->animating = false;
+
+ _vm->update();
+ _vm->display()->palFadeIn(ROOM_JUNGLE_PINNACLE, joe->active, joe->x, joe->y);
+
+ _entryObj = 0;
+ uint16 prevObj = 0;
+ CmdText cmdText((_vm->resource()->getLanguage() == HEBREW), 5, _vm);
+ cmdText.setVerb(VERB_WALK_TO);
+ while (_vm->input()->mouseButton() == 0 || _entryObj == 0) {
+
+ _vm->update();
+ int mx = _vm->input()->mousePosX();
+ int my = _vm->input()->mousePosY();
+
+ // update screen scrolling
+ _vm->display()->horizontalScroll(mx);
+
+ // update bobs position / frame
+ joe->x = piton->x = 3 * mx / 4 + 200;
+ joe->frameNum = mx / 36 + 45;
+
+ _vm->display()->clearTexts(5, 5);
+
+ uint16 curObj = _vm->grid()->findObjectUnderCursor(mx, my);
+ if (curObj != 0 && curObj != prevObj) {
+ _entryObj = 0;
+ curObj += currentRoomData(); // global object number
+ ObjectData *objData = objectData(curObj);
+ if (objData->name > 0) {
+ _entryObj = objData->entryObj;
+ cmdText.displayTemp(INK_PINNACLE_ROOM, objectName(objData->name), true);
+ }
+ prevObj = curObj;
+ }
+ }
+ _vm->input()->clearMouseButton();
+
+ _newRoom = objectData(_entryObj)->room;
+
+ // FIXME - only a few commands can be triggered from this room :
+ // piton -> crash : 0x216 (obj1=0x2a, song=3)
+ // piton -> floda : 0x217 (obj1=0x29, song=16)
+ // piton -> bob : 0x219 (obj1=0x2f, song=6)
+ // piton -> embark : 0x218 (obj1=0x2c, song=7)
+ // piton -> jungle : 0x20B (obj1=0x2b, song=3)
+ // piton -> amazon : 0x21A (obj1=0x30, song=3)
+ //
+ // Because none of these update objects/areas/gamestate, the EXECUTE_ACTION()
+ // call, as the original does, is useless. All we have to do is the playsong
+ // call (all songs have the PLAY_BEFORE type). This way we could get rid of
+ // the hack described in execute.c l.334-339.
+ struct {
+ uint16 obj;
+ int16 song;
+ } cmds[] = {
+ { 0x2A, 3 },
+ { 0x29, 16 },
+ { 0x2F, 6 },
+ { 0x2C, 7 },
+ { 0x2B, 3 },
+ { 0x30, 3 }
+ };
+ for (int i = 0; i < ARRAYSIZE(cmds); ++i) {
+ if (cmds[i].obj == prevObj) {
+ _vm->sound()->playSong(cmds[i].song);
+ break;
+ }
+ }
+
+ joe->active = piton->active = false;
+ _vm->display()->clearTexts(5, 5);
+
+ // camera follows Joe again
+ _vm->graphics()->putCameraOnBob(0);
+
+ _vm->display()->palFadeOut(ROOM_JUNGLE_PINNACLE);
+}
+
+void Logic::update() {
+ if (_credits)
+ _credits->update();
+
+ if (_vm->debugger()->flags() & Debugger::DF_DRAW_AREAS) {
+ _vm->grid()->drawZones();
+ }
+}
+
+void Logic::saveState(byte *&ptr) {
+ uint16 i;
+ for (i = 0; i < 4; i++) {
+ WRITE_BE_UINT16(ptr, _inventoryItem[i]); ptr += 2;
+ }
+
+ WRITE_BE_UINT16(ptr, _vm->graphics()->bob(0)->x); ptr += 2;
+ WRITE_BE_UINT16(ptr, _vm->graphics()->bob(0)->y); ptr += 2;
+
+ WRITE_BE_UINT16(ptr, _currentRoom); ptr += 2;
+
+ for (i = 1; i <= _numObjects; i++)
+ _objectData[i].writeToBE(ptr);
+
+ for (i = 1; i <= _numItems; i++)
+ _itemData[i].writeToBE(ptr);
+
+ for (i = 0; i < GAME_STATE_COUNT; i++) {
+ WRITE_BE_UINT16(ptr, _gameState[i]); ptr += 2;
+ }
+
+ for (i = 0; i < TALK_SELECTED_COUNT; i++)
+ _talkSelected[i].writeToBE(ptr);
+
+ for (i = 1; i <= _numWalkOffs; i++)
+ _walkOffData[i].writeToBE(ptr);
+
+ WRITE_BE_UINT16(ptr, _joe.facing); ptr += 2;
+
+ // V1
+ WRITE_BE_UINT16(ptr, _puzzleAttemptCount); ptr += 2;
+ for (i = 1; i <= _numObjDesc; i++)
+ _objectDescription[i].writeToBE(ptr);
+}
+
+void Logic::loadState(uint32 ver, byte *&ptr) {
+ uint16 i;
+ for (i = 0; i < 4; i++) {
+ _inventoryItem[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ }
+
+ _joe.x = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _joe.y = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ _currentRoom = READ_BE_UINT16(ptr); ptr += 2;
+
+ for (i = 1; i <= _numObjects; i++)
+ _objectData[i].readFromBE(ptr);
+
+ for (i = 1; i <= _numItems; i++)
+ _itemData[i].readFromBE(ptr);
+
+ for (i = 0; i < GAME_STATE_COUNT; i++) {
+ _gameState[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ }
+
+ for (i = 0; i < TALK_SELECTED_COUNT; i++)
+ _talkSelected[i].readFromBE(ptr);
+
+ for (i = 1; i <= _numWalkOffs; i++)
+ _walkOffData[i].readFromBE(ptr);
+
+ _joe.facing = READ_BE_UINT16(ptr); ptr += 2;
+
+ if (ver >= 1) {
+ _puzzleAttemptCount = READ_BE_UINT16(ptr); ptr += 2;
+
+ for (i = 1; i <= _numObjDesc; i++)
+ _objectDescription[i].readFromBE(ptr);
+ }
+}
+
+void Logic::setupRestoredGame() {
+ _vm->sound()->playLastSong();
+
+ switch (gameState(VAR_JOE_DRESSING_MODE)) {
+ case 0:
+ _vm->display()->palSetJoeNormal();
+ loadJoeBanks("Joe_A.BBK", "Joe_B.BBK");
+ break;
+ case 1:
+ _vm->display()->palSetJoeNormal();
+ loadJoeBanks("JoeU_A.BBK", "JoeU_B.BBK");
+ break;
+ case 2:
+ _vm->display()->palSetJoeDress();
+ loadJoeBanks("JoeD_A.BBK", "JoeD_B.BBK");
+ break;
+ }
+
+ BobSlot *pbs = _vm->graphics()->bob(0);
+ pbs->xflip = (joeFacing() == DIR_LEFT);
+ joePrevFacing(joeFacing());
+ joeCutFacing(joeFacing());
+ switch (joeFacing()) {
+ case DIR_FRONT:
+ pbs->frameNum = 36;
+ _vm->bankMan()->unpack(3, 31, 7);
+ break;
+ case DIR_BACK:
+ pbs->frameNum = 37;
+ _vm->bankMan()->unpack(5, 31, 7);
+ break;
+ default:
+ pbs->frameNum = 35;
+ _vm->bankMan()->unpack(1, 31, 7);
+ break;
+ }
+
+ _oldRoom = 0;
+ _newRoom = _currentRoom;
+ _entryObj = 0;
+
+ if (_vm->bam()->_flag != BamScene::F_STOP) {
+ _vm->bam()->prepareAnimation();
+ }
+
+ inventoryRefresh();
+}
+
+void Logic::sceneStart() {
+ debug(6, "[Logic::sceneStart] _scene = %i", _scene);
+ _scene++;
+
+ _vm->display()->showMouseCursor(false);
+
+ if (1 == _scene) {
+ _vm->display()->palGreyPanel();
+ }
+
+ _vm->update();
+}
+
+void Logic::sceneStop() {
+ debug(6, "[Logic::sceneStop] _scene = %i", _scene);
+ _scene--;
+
+ if (_scene > 0)
+ return;
+
+ _vm->display()->palSetAllDirty();
+ _vm->display()->showMouseCursor(true);
+ _vm->grid()->setupPanel();
+}
+
+void Logic::changeRoom() {
+ if (!preChangeRoom())
+ displayRoom(currentRoom(), RDM_FADE_JOE, 100, 1, false);
+ _vm->display()->showMouseCursor(true);
+}
+
+void Logic::executeSpecialMove(uint16 sm) {
+ debug(6, "Special move: %d", sm);
+ if (!handleSpecialMove(sm))
+ warning("unhandled / invalid special move : %d", sm);
+}
+
+void Logic::asmMakeJoeUseDress() {
+ joeUseDress(false);
+}
+
+void Logic::asmMakeJoeUseNormalClothes() {
+ joeUseClothes(false);
+}
+
+void Logic::asmMakeJoeUseUnderwear() {
+ joeUseUnderwear();
+}
+
+void Logic::asmSwitchToDressPalette() {
+ _vm->display()->palSetJoeDress();
+}
+
+void Logic::asmSwitchToNormalPalette() {
+ _vm->display()->palSetJoeNormal();
+}
+
+void Logic::asmStartCarAnimation() {
+ _vm->bam()->_flag = BamScene::F_PLAY;
+ _vm->bam()->prepareAnimation();
+}
+
+void Logic::asmStopCarAnimation() {
+ _vm->bam()->_flag = BamScene::F_STOP;
+ _vm->graphics()->bob(findBob(594))->active = false; // oil object
+ _vm->graphics()->bob(7)->active = false; // gun shots
+}
+
+void Logic::asmStartFightAnimation() {
+ _vm->bam()->_flag = BamScene::F_PLAY;
+ _vm->bam()->prepareAnimation();
+ gameState(148, 1);
+}
+
+void Logic::asmWaitForFrankPosition() {
+ _vm->bam()->_flag = BamScene::F_REQ_STOP;
+ while (_vm->bam()->_flag != BamScene::F_STOP) {
+ _vm->update();
+ }
+}
+
+void Logic::asmMakeFrankGrowing() {
+ _vm->bankMan()->unpack(1, 38, 15);
+ BobSlot *bobFrank = _vm->graphics()->bob(5);
+ bobFrank->frameNum = 38;
+ bobFrank->curPos(160, 200);
+
+ int i;
+ for (i = 10; i <= 100; i += 4) {
+ bobFrank->scale = i;
+ _vm->update();
+ }
+ for (i = 0; i <= 20; ++i) {
+ _vm->update();
+ }
+
+ objectData(521)->name = ABS(objectData(521)->name); // Dinoray
+ objectData(526)->name = ABS(objectData(526)->name); // Frank obj
+ objectData(522)->name = -ABS(objectData(522)->name); // TMPD object off
+ objectData(525)->name = -ABS(objectData(525)->name); // Floda guards off
+ objectData(523)->name = -ABS(objectData(523)->name); // Sparky object off
+ gameState(157, 1); // No more Ironstein
+}
+
+void Logic::asmMakeRobotGrowing() {
+ _vm->bankMan()->unpack(1, 38, 15);
+ BobSlot *bobRobot = _vm->graphics()->bob(5);
+ bobRobot->frameNum = 38;
+ bobRobot->curPos(160, 200);
+
+ int i;
+ for (i = 10; i <= 100; i += 4) {
+ bobRobot->scale = i;
+ _vm->update();
+ }
+ for (i = 0; i <= 20; ++i) {
+ _vm->update();
+ }
+
+ objectData(524)->name = -ABS(objectData(524)->name); // Azura object off
+ objectData(526)->name = -ABS(objectData(526)->name); // Frank object off
+}
+
+void Logic::asmShrinkRobot() {
+ int i;
+ BobSlot *robot = _vm->graphics()->bob(6);
+ for (i = 100; i >= 35; i -= 5) {
+ robot->scale = i;
+ _vm->update();
+ }
+}
+
+void Logic::asmEndGame() {
+ int n = 40;
+ while (n--) {
+ _vm->update();
+ }
+ debug(0, "Game completed.");
+ _vm->quitGame();
+}
+
+void Logic::asmPutCameraOnDino() {
+ _vm->graphics()->putCameraOnBob(-1);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx < 320) {
+ scrollx += 16;
+ if (scrollx > 320) {
+ scrollx = 320;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+ _vm->graphics()->putCameraOnBob(1);
+}
+
+void Logic::asmPutCameraOnJoe() {
+ _vm->graphics()->putCameraOnBob(0);
+}
+
+void Logic::asmAltIntroPanRight() {
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->input()->fastMode(true);
+ _vm->update();
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx < 285 && !_vm->input()->cutawayQuit()) {
+ ++scrollx;
+ if (scrollx > 285) {
+ scrollx = 285;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+ _vm->input()->fastMode(false);
+}
+
+void Logic::asmAltIntroPanLeft() {
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->input()->fastMode(true);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx > 0 && !_vm->input()->cutawayQuit()) {
+ scrollx -= 4;
+ if (scrollx < 0) {
+ scrollx = 0;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+ _vm->input()->fastMode(false);
+}
+
+void Logic::asmSetAzuraInLove() {
+ gameState(VAR_AZURA_IN_LOVE, 1);
+}
+
+void Logic::asmPanRightFromJoe() {
+ _vm->graphics()->putCameraOnBob(-1);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx < 320) {
+ scrollx += 16;
+ if (scrollx > 320) {
+ scrollx = 320;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+}
+
+void Logic::asmSetLightsOff() {
+ _vm->display()->palCustomLightsOff(currentRoom());
+}
+
+void Logic::asmSetLightsOn() {
+ _vm->display()->palCustomLightsOn(currentRoom());
+}
+
+void Logic::asmSetManequinAreaOn() {
+ Area *a = _vm->grid()->area(ROOM_FLODA_FRONTDESK, 7);
+ a->mapNeighbours = ABS(a->mapNeighbours);
+}
+
+void Logic::asmPanToJoe() {
+ int i = _vm->graphics()->bob(0)->x - 160;
+ if (i < 0) {
+ i = 0;
+ } else if (i > 320) {
+ i = 320;
+ }
+ _vm->graphics()->putCameraOnBob(-1);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ if (i < scrollx) {
+ while (scrollx > i) {
+ scrollx -= 16;
+ if (scrollx < i) {
+ scrollx = i;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+ } else {
+ while (scrollx < i) {
+ scrollx += 16;
+ if (scrollx > i) {
+ scrollx = i;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+ _vm->update();
+ }
+ _vm->graphics()->putCameraOnBob(0);
+}
+
+void Logic::asmTurnGuardOn() {
+ gameState(VAR_GUARDS_TURNED_ON, 1);
+}
+
+void Logic::asmPanLeft320To144() {
+ _vm->graphics()->putCameraOnBob(-1);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx > 144) {
+ scrollx -= 8;
+ if (scrollx < 144) {
+ scrollx = 144;
+ }
+ _vm->display()->horizontalScroll(scrollx);
+ _vm->update();
+ }
+}
+
+void Logic::asmSmooch() {
+ _vm->graphics()->putCameraOnBob(-1);
+ BobSlot *bobAzura = _vm->graphics()->bob(5);
+ BobSlot *bobJoe = _vm->graphics()->bob(6);
+ int16 scrollx = _vm->display()->horizontalScroll();
+ while (scrollx < 320) {
+ scrollx += 8;
+ _vm->display()->horizontalScroll(scrollx);
+ if (bobJoe->x - bobAzura->x > 128) {
+ bobAzura->x += 10;
+ bobJoe->x += 6;
+ } else {
+ bobAzura->x += 8;
+ bobJoe->x += 8;
+ }
+ _vm->update();
+ }
+}
+
+void Logic::asmMakeLightningHitPlane() {
+ _vm->graphics()->putCameraOnBob(-1);
+ short iy = 0, x, ydir = -1, j, k;
+
+ BobSlot *planeBob = _vm->graphics()->bob(5);
+ BobSlot *lightningBob = _vm->graphics()->bob(20);
+
+ planeBob->y = 135;
+
+ planeBob->scale = 20;
+
+ for (x = 660; x > 163; x -= 6) {
+ planeBob->x = x;
+ planeBob->y = 135 + iy;
+
+ iy -= ydir;
+ if (iy < -9 || iy > 9)
+ ydir = -ydir;
+
+ planeBob->scale++;
+ if (planeBob->scale > 100)
+ planeBob->scale = 100;
+
+ int scrollX = x - 163;
+ if (scrollX > 320)
+ scrollX = 320;
+ _vm->display()->horizontalScroll(scrollX);
+ _vm->update();
+ }
+
+ planeBob->scale = 100;
+ _vm->display()->horizontalScroll(0);
+
+ planeBob->x += 8;
+ planeBob->y += 6;
+
+ lightningBob->x = 160;
+ lightningBob->y = 0;
+
+ _vm->sound()->playSfx(currentRoomSfx(), false);
+
+ _vm->bankMan()->unpack(18, lightningBob->frameNum, 15);
+ _vm->bankMan()->unpack(4, planeBob ->frameNum, 15);
+
+ // Plane plunges into the jungle!
+ BobSlot *fireBob = _vm->graphics()->bob(6);
+
+ fireBob->animating = true;
+ fireBob->x = planeBob->x;
+ fireBob->y = planeBob->y + 10;
+
+ _vm->bankMan()->unpack(19, fireBob->frameNum, 15);
+ _vm->update();
+
+ k = 20;
+ j = 1;
+
+ for (x = 163; x > -30; x -= 10) {
+ planeBob->y += 4;
+ fireBob->y += 4;
+ planeBob->x = fireBob->x = x;
+
+ if (k < 40) {
+ _vm->bankMan()->unpack(j, planeBob->frameNum, 15);
+ _vm->bankMan()->unpack(k, fireBob ->frameNum, 15);
+ k++;
+ j++;
+
+ if (j == 4)
+ j = 1;
+ }
+
+ _vm->update();
+ }
+
+ _vm->graphics()->putCameraOnBob(0);
+}
+
+void Logic::asmScaleBlimp() {
+ int16 z = 256;
+ BobSlot *bob = _vm->graphics()->bob(7);
+ int16 x = bob->x;
+ int16 y = bob->y;
+ while (bob->x > 150) {
+ bob->x = x * 256 / z + 150;
+ bob->y = y * 256 / z + 112;
+ bob->scale = 100 * 256 / z;
+
+ ++z;
+ if (z % 6 == 0) {
+ --x;
+ }
+
+ _vm->update();
+ }
+}
+
+void Logic::asmScaleEnding() {
+ _vm->graphics()->bob(7)->active = false; // Turn off blimp
+ BobSlot *b = _vm->graphics()->bob(20);
+ b->x = 160;
+ b->y = 100;
+ int i;
+ for (i = 5; i <= 100; i += 5) {
+ b->scale = i;
+ _vm->update();
+ }
+ for (i = 0; i < 50; ++i) {
+ _vm->update();
+ }
+ _vm->display()->palFadeOut(_currentRoom);
+}
+
+void Logic::asmWaitForCarPosition() {
+ // Wait for car to reach correct position before pouring oil
+ while (_vm->bam()->_index != 60) {
+ _vm->update();
+ }
+}
+
+void Logic::asmShakeScreen() {
+ _vm->display()->shake(false);
+ _vm->update();
+ _vm->display()->shake(true);
+ _vm->update();
+}
+
+void Logic::asmAttemptPuzzle() {
+ ++_puzzleAttemptCount;
+ if (_puzzleAttemptCount == 4) {
+ makeJoeSpeak(226, true);
+ _puzzleAttemptCount = 0;
+ }
+}
+
+void Logic::asmScaleTitle() {
+ BobSlot *bob = _vm->graphics()->bob(5);
+ bob->animating = false;
+ bob->x = 161;
+ bob->y = 200;
+ bob->scale = 100;
+
+ int i;
+ for (i = 5; i <= 100; i +=5) {
+ bob->scale = i;
+ bob->y -= 4;
+ _vm->update();
+ }
+}
+
+void Logic::asmPanRightToHugh() {
+ BobSlot *bob_thugA1 = _vm->graphics()->bob(20);
+ BobSlot *bob_thugA2 = _vm->graphics()->bob(21);
+ BobSlot *bob_thugA3 = _vm->graphics()->bob(22);
+ BobSlot *bob_hugh1 = _vm->graphics()->bob(1);
+ BobSlot *bob_hugh2 = _vm->graphics()->bob(23);
+ BobSlot *bob_hugh3 = _vm->graphics()->bob(24);
+ BobSlot *bob_thugB1 = _vm->graphics()->bob(25);
+ BobSlot *bob_thugB2 = _vm->graphics()->bob(26);
+
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->input()->fastMode(true);
+ _vm->update();
+
+ // Adjust thug1 gun so it matches rest of body
+ bob_thugA1->x += 160 - 45;
+ bob_thugA2->x += 160;
+ bob_thugA3->x += 160;
+
+ bob_hugh1->x += 160 * 2;
+ bob_hugh2->x += 160 * 2;
+ bob_hugh3->x += 160 * 2;
+
+ bob_thugB1->x += 160 * 3;
+ bob_thugB2->x += 160 * 3;
+
+ int horizontalScroll = 0;
+ while (horizontalScroll < 160 && !_vm->input()->cutawayQuit()) {
+
+ horizontalScroll += 8;
+ if (horizontalScroll > 160)
+ horizontalScroll = 160;
+
+ _vm->display()->horizontalScroll(horizontalScroll);
+
+ bob_thugA1->x -= 16;
+ bob_thugA2->x -= 16;
+ bob_thugA3->x -= 16;
+
+ bob_hugh1->x -= 24;
+ bob_hugh2->x -= 24;
+ bob_hugh3->x -= 24;
+
+ bob_thugB1->x -= 32;
+ bob_thugB2->x -= 32;
+
+ _vm->update();
+ }
+
+ _vm->input()->fastMode(false);
+}
+
+void Logic::asmMakeWhiteFlash() {
+ _vm->display()->palCustomFlash();
+}
+
+void Logic::asmPanRightToJoeAndRita() { // cdint.cut
+ BobSlot *bob_box = _vm->graphics()->bob(20);
+ BobSlot *bob_beam = _vm->graphics()->bob(21);
+ BobSlot *bob_crate = _vm->graphics()->bob(22);
+ BobSlot *bob_clock = _vm->graphics()->bob(23);
+ BobSlot *bob_hands = _vm->graphics()->bob(24);
+
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->input()->fastMode(true);
+
+ _vm->update();
+
+ bob_box ->x += 280 * 2;
+ bob_beam ->x += 30;
+ bob_crate->x += 180 * 3;
+
+ int horizontalScroll = _vm->display()->horizontalScroll();
+
+ while (horizontalScroll < 290 && !_vm->input()->cutawayQuit()) {
+
+ ++horizontalScroll;
+ if (horizontalScroll > 290)
+ horizontalScroll = 290;
+
+ _vm->display()->horizontalScroll(horizontalScroll);
+
+ bob_box ->x -= 2;
+ bob_beam ->x -= 1;
+ bob_crate->x -= 3;
+ bob_clock->x -= 2;
+ bob_hands->x -= 2;
+
+ _vm->update();
+ }
+ _vm->input()->fastMode(false);
+}
+
+void Logic::asmPanLeftToBomb() {
+ BobSlot *bob21 = _vm->graphics()->bob(21);
+ BobSlot *bob22 = _vm->graphics()->bob(22);
+
+ _vm->graphics()->putCameraOnBob(-1);
+ _vm->input()->fastMode(true);
+
+ int horizontalScroll = _vm->display()->horizontalScroll();
+
+ while ((horizontalScroll > 0 || bob21->x < 136) && !_vm->input()->cutawayQuit()) {
+
+ horizontalScroll -= 5;
+ if (horizontalScroll < 0)
+ horizontalScroll = 0;
+
+ _vm->display()->horizontalScroll(horizontalScroll);
+
+ if (horizontalScroll < 272 && bob21->x < 136)
+ bob21->x += 2;
+
+ bob22->x += 5;
+
+ _vm->update();
+ }
+
+ _vm->input()->fastMode(false);
+}
+
+void Logic::asmEndDemo() {
+ debug(0, "Flight of the Amazon Queen, released January 95.");
+ _vm->quitGame();
+}
+
+void Logic::asmInterviewIntro() {
+ // put camera on airship
+ _vm->graphics()->putCameraOnBob(5);
+ BobSlot *bas = _vm->graphics()->bob(5);
+
+ bas->curPos(-30, 40);
+
+ bas->move(700, 10, 3);
+ int scale = 450;
+ while (bas->moving && !_vm->input()->cutawayQuit()) {
+ bas->scale = 256 * 100 / scale;
+ --scale;
+ if (scale < 256) {
+ scale = 256;
+ }
+ _vm->update();
+ }
+
+ bas->scale = 90;
+ bas->xflip = true;
+
+ bas->move(560, 25, 4);
+ while (bas->moving && !_vm->input()->cutawayQuit()) {
+ _vm->update();
+ }
+
+ bas->move(545, 65, 2);
+ while (bas->moving && !_vm->input()->cutawayQuit()) {
+ _vm->update();
+ }
+
+ bas->move(540, 75, 2);
+ while (bas->moving && !_vm->input()->cutawayQuit()) {
+ _vm->update();
+ }
+
+ // put camera on Joe
+ _vm->graphics()->putCameraOnBob(0);
+}
+
+void Logic::asmEndInterview() {
+ debug(0, "Interactive Interview copyright (c) 1995, IBI.");
+ _vm->quitGame();
+}
+
+void Logic::startCredits(const char *filename) {
+ stopCredits();
+ _credits = new Credits(_vm, filename);
+}
+
+void Logic::stopCredits() {
+ if (_credits) {
+ _vm->display()->clearTexts(0, 199);
+ delete _credits;
+ _credits = NULL;
+ }
+}
+
+void LogicDemo::useJournal() {
+ makePersonSpeak("This is a demo, so I can't load or save games*14", NULL, "");
+}
+
+bool LogicDemo::preChangeRoom() {
+ if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) {
+ currentRoom(79);
+ displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
+ playCutaway("clogo.cut");
+ sceneReset();
+ currentRoom(ROOM_HOTEL_LOBBY);
+ entryObj(584);
+ displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true);
+ playCutaway("c70d.cut");
+ gameState(VAR_INTRO_PLAYED, 1);
+ inventoryRefresh();
+ return true;
+ }
+ return false;
+}
+
+bool LogicDemo::handleSpecialMove(uint16 sm) {
+ switch (sm) {
+ case 4:
+ asmMakeJoeUseUnderwear();
+ break;
+ case 5:
+ asmSwitchToDressPalette();
+ break;
+ case 14:
+ asmEndDemo();
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void LogicInterview::useJournal() {
+ // no-op
+}
+
+bool LogicInterview::preChangeRoom() {
+ if (currentRoom() == 2 && gameState(2) == 0) {
+ currentRoom(6);
+ displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
+ playCutaway("start.cut");
+ gameState(2, 1);
+ inventoryRefresh();
+ return true;
+ }
+ return false;
+}
+
+bool LogicInterview::handleSpecialMove(uint16 sm) {
+ switch (sm) {
+ case 1:
+ asmInterviewIntro();
+ break;
+ case 2:
+ asmEndInterview();
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void LogicGame::useJournal() {
+ _vm->command()->clear(false);
+ _journal->use();
+ _vm->walk()->stopJoe();
+}
+
+bool LogicGame::preChangeRoom() {
+ if (currentRoom() == ROOM_JUNGLE_PINNACLE) {
+ handlePinnacleRoom();
+ return true;
+ } else if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) {
+ displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
+ playCutaway("copy.cut");
+ playCutaway("clogo.cut");
+
+ if (ConfMan.getBool("alt_intro") && _vm->resource()->isCD()) {
+ playCutaway("cintr.cut");
+ } else {
+ playCutaway("cdint.cut");
+ }
+
+ playCutaway("cred.cut");
+ _vm->display()->palSetPanel();
+ sceneReset();
+ currentRoom(ROOM_HOTEL_LOBBY);
+ entryObj(584);
+ displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true);
+ playCutaway("c70d.cut");
+ gameState(VAR_INTRO_PLAYED, 1);
+ inventoryRefresh();
+ return true;
+ }
+ return false;
+}
+
+bool LogicGame::handleSpecialMove(uint16 sm) {
+ typedef void (LogicGame::*SpecialMoveProc)();
+ static const SpecialMoveProc asmTable[] = {
+ /* 00 */
+ 0,
+ 0,
+ &LogicGame::asmMakeJoeUseDress,
+ &LogicGame::asmMakeJoeUseNormalClothes,
+ /* 04 */
+ &LogicGame::asmMakeJoeUseUnderwear,
+ &LogicGame::asmSwitchToDressPalette,
+ &LogicGame::asmSwitchToNormalPalette,
+ &LogicGame::asmStartCarAnimation, // room 74
+ /* 08 */
+ &LogicGame::asmStopCarAnimation, // room 74
+ &LogicGame::asmStartFightAnimation, // room 69
+ &LogicGame::asmWaitForFrankPosition, // c69e.cut
+ &LogicGame::asmMakeFrankGrowing, // c69z.cut
+ /* 12 */
+ &LogicGame::asmMakeRobotGrowing, // c69z.cut
+ &LogicGame::asmShrinkRobot,
+ &LogicGame::asmEndGame,
+ &LogicGame::asmPutCameraOnDino,
+ /* 16 */
+ &LogicGame::asmPutCameraOnJoe,
+ &LogicGame::asmAltIntroPanRight, // cintr.cut
+ &LogicGame::asmAltIntroPanLeft, // cintr.cut
+ &LogicGame::asmSetAzuraInLove,
+ /* 20 */
+ &LogicGame::asmPanRightFromJoe,
+ &LogicGame::asmSetLightsOff,
+ &LogicGame::asmSetLightsOn,
+ &LogicGame::asmSetManequinAreaOn,
+ /* 24 */
+ &LogicGame::asmPanToJoe,
+ &LogicGame::asmTurnGuardOn,
+ &LogicGame::asmPanLeft320To144,
+ &LogicGame::asmSmooch,
+ /* 28 */
+ &LogicGame::asmMakeLightningHitPlane,
+ &LogicGame::asmScaleBlimp,
+ &LogicGame::asmScaleEnding,
+ &LogicGame::asmWaitForCarPosition,
+ /* 32 */
+ &LogicGame::asmShakeScreen,
+ &LogicGame::asmAttemptPuzzle,
+ &LogicGame::asmScaleTitle,
+ 0,
+ /* 36 */
+ &LogicGame::asmPanRightToHugh,
+ &LogicGame::asmMakeWhiteFlash,
+ &LogicGame::asmPanRightToJoeAndRita,
+ &LogicGame::asmPanLeftToBomb // cdint.cut
+ };
+ if (sm >= ARRAYSIZE(asmTable) || asmTable[sm] == 0)
+ return false;
+ (this->*asmTable[sm])();
+ return true;
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/logic.h b/engines/queen/logic.h
new file mode 100644
index 0000000000..f1f93de17e
--- /dev/null
+++ b/engines/queen/logic.h
@@ -0,0 +1,410 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENLOGIC_H
+#define QUEENLOGIC_H
+
+#include "common/str.h"
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+enum RoomDisplayMode {
+ RDM_FADE_NOJOE = 0, // fade in, hide Joe
+ RDM_FADE_JOE = 1, // fade in, display Joe
+ RDM_NOFADE_JOE = 2, // screen does not dissolve into view
+ RDM_FADE_JOE_XY = 3 // display Joe at the current X, Y coords
+};
+
+enum JoeWalkMode {
+ JWM_NORMAL = 0,
+ JWM_MOVE = 1,
+ JWM_EXECUTE = 2,
+ JWM_SPEAK = 3
+};
+
+class Credits;
+class Journal;
+class LineReader;
+class QueenEngine;
+
+class Logic {
+
+public:
+ Logic(QueenEngine *vm);
+ virtual ~Logic();
+
+ uint16 currentRoom() const { return _currentRoom; }
+ void currentRoom(uint16 room) {
+ assert(room >= 1 && room <= _numRooms);
+ _currentRoom = room;
+ }
+
+ uint16 oldRoom() const { return _oldRoom; }
+ void oldRoom(uint16 room) {
+ assert(room <= _numRooms);
+ _oldRoom = room;
+ }
+
+ uint16 newRoom() const { return _newRoom; }
+ void newRoom(uint16 room) {
+ assert(room <= _numRooms);
+ _newRoom = room;
+ }
+
+ ObjectData *objectData(int index) const;
+ uint16 roomData(int room) const { return _roomData[room]; }
+ GraphicData *graphicData(int index) const { return &_graphicData[index]; }
+ ItemData *itemData(int index) const { return &_itemData[index]; }
+ uint16 itemDataCount() const { return _numItems; }
+
+ uint16 findBob(uint16 obj) const;
+ uint16 findFrame(uint16 obj) const;
+ uint16 objectForPerson(uint16 bobnum) const;
+ WalkOffData *walkOffPointForObject(int16 obj) const;
+
+ uint16 walkOffCount() const { return _numWalkOffs; }
+ WalkOffData *walkOffData(int index) const { return &_walkOffData[index]; }
+ uint16 currentRoomData() const { return _roomData[_currentRoom]; }
+ GraphicAnim *graphicAnim(int index) const { return &_graphicAnim[index]; }
+ uint16 graphicAnimCount() const { return _numGraphicAnim; }
+ ObjectDescription *objectDescription(uint16 objNum) const { return &_objectDescription[objNum]; }
+ uint16 objectDescriptionCount() const { return _numObjDesc; }
+ uint16 currentRoomSfx() const { return _sfxName[_currentRoom]; }
+
+ uint16 joeFacing() const { return _joe.facing; }
+ uint16 joeX() const { return _joe.x; }
+ uint16 joeY() const { return _joe.y; }
+ JoeWalkMode joeWalk() const { return _joe.walk; }
+ uint16 joeScale() const { return _joe.scale; }
+ uint16 joeCutFacing() const { return _joe.cutFacing; }
+ uint16 joePrevFacing() const { return _joe.prevFacing; }
+
+ void joeFacing(uint16 dir) { _joe.facing = dir; }
+ void joePos(uint16 x, uint16 y) { _joe.x = x; _joe.y = y; }
+ void joeWalk(JoeWalkMode walking);
+ void joeScale(uint16 scale) { _joe.scale = scale; }
+ void joeCutFacing(uint16 dir) { _joe.cutFacing = dir; }
+ void joePrevFacing(uint16 dir) { _joe.prevFacing = dir; }
+
+ int16 gameState(int index) const;
+ void gameState(int index, int16 newValue);
+
+ TalkSelected *talkSelected(int index) { return &_talkSelected[index]; }
+
+ const char *roomName(uint16 roomNum) const;
+ const char *objectName(uint16 objNum) const;
+ const char *objectTextualDescription(uint16 objNum) const;
+ const char *joeResponse(int i) const;
+ const char *verbName(Verb v) const;
+
+ void eraseRoom();
+ void setupRoom(const char *room, int comPanel, bool inCutaway);
+ void displayRoom(uint16 room, RoomDisplayMode mode, uint16 joeScale, int comPanel, bool inCutaway);
+
+ int16 entryObj() const { return _entryObj; }
+ void entryObj(int16 obj) { _entryObj = obj; }
+
+ ActorData *findActor(uint16 noun, const char *name = NULL) const;
+ bool initPerson(uint16 noun, const char *actorName, bool loadBank, Person *pp);
+ uint16 findPersonNumber(uint16 obj, uint16 room) const;
+
+ //! load banks used for Joe animation
+ void loadJoeBanks(const char *animBank, const char *standBank);
+
+ //! load the various bobs needed to animate Joe
+ void setupJoe();
+
+ //! setup Joe at the right place when entering a room
+ void setupJoeInRoom(bool autoPosition, uint16 scale);
+
+ uint16 joeFace();
+ void joeGrab(int16 grabState);
+
+ //! change Joe clothes to dress
+ void joeUseDress(bool showCut);
+
+ //! restore Joe clothes
+ void joeUseClothes(bool showCut);
+
+ //! change Joe clothes to underwear
+ void joeUseUnderwear();
+
+ void makeJoeSpeak(uint16 descNum, bool objectType = false);
+ void makePersonSpeak(const char *sentence, Person *person, const char *voiceFilePrefix);
+
+ //! start the specified dialogue
+ void startDialogue(const char *dlgFile, int personInRoom, char *cutaway);
+
+ //! play the specified cutaway
+ void playCutaway(const char *cutFile, char *next = NULL);
+
+ //! initialize the inventory
+ void inventorySetup();
+
+ //! get the inventory item for the specified inventory slot
+ uint16 findInventoryItem(int invSlot) const;
+
+ //! refresh inventory contents
+ void inventoryRefresh();
+ int16 previousInventoryItem(int16 first) const;
+ int16 nextInventoryItem(int16 first) const;
+ void removeDuplicateItems();
+ uint16 numItemsInventory() const;
+ void inventoryInsertItem(uint16 itemNum, bool refresh = true);
+ void inventoryDeleteItem(uint16 itemNum, bool refresh = true);
+ void inventoryScroll(uint16 count, bool up);
+ void removeHotelItemsFromInventory();
+
+ //! copy data from dummy object to object
+ void objectCopy(int dummyObjectIndex, int objectIndex);
+
+ //! handle a particular event when Joe walks on this area
+ void handleSpecialArea(Direction facing, uint16 areaNum, uint16 walkDataNum);
+
+ //! handle the pinnacle room (== room chooser in the jungle)
+ void handlePinnacleRoom();
+
+ void update();
+
+ void saveState(byte *&ptr);
+ void loadState(uint32 ver, byte *&ptr);
+
+ //! called after a save state has been loaded
+ void setupRestoredGame();
+
+ //! ugly hack from original code
+ void sceneReset() { _scene = 0; }
+
+ //! make a scene
+ void sceneStart();
+
+ //! stop making a scene
+ void sceneStop();
+
+ void changeRoom();
+
+ //! enter the Journal (save/load, configuration)
+ virtual void useJournal() = 0;
+
+ //! execute a special move
+ void executeSpecialMove(uint16 sm);
+
+ void startCredits(const char *filename);
+ void stopCredits();
+
+ void start();
+
+ enum {
+ JOE_RESPONSE_MAX = 40,
+ DEFAULT_TALK_SPEED = 7 * 3,
+ GAME_STATE_COUNT = 211,
+ TALK_SELECTED_COUNT = 86
+ };
+
+protected:
+
+ void initialise();
+
+ void asmMakeJoeUseDress();
+ void asmMakeJoeUseNormalClothes();
+ void asmMakeJoeUseUnderwear();
+ void asmSwitchToDressPalette();
+ void asmSwitchToNormalPalette();
+ void asmStartCarAnimation();
+ void asmStopCarAnimation();
+ void asmStartFightAnimation();
+ void asmWaitForFrankPosition();
+ void asmMakeFrankGrowing();
+ void asmMakeRobotGrowing();
+ void asmShrinkRobot();
+ void asmEndGame();
+ void asmPutCameraOnDino();
+ void asmPutCameraOnJoe();
+ void asmAltIntroPanRight();
+ void asmAltIntroPanLeft();
+ void asmSetAzuraInLove();
+ void asmPanRightFromJoe();
+ void asmSetLightsOff();
+ void asmSetLightsOn();
+ void asmSetManequinAreaOn();
+ void asmPanToJoe();
+ void asmTurnGuardOn();
+ void asmPanLeft320To144();
+ void asmSmooch();
+ void asmMakeLightningHitPlane();
+ void asmScaleBlimp();
+ void asmScaleEnding();
+ void asmWaitForCarPosition();
+ void asmShakeScreen();
+ void asmAttemptPuzzle();
+ void asmScaleTitle();
+ void asmPanRightToHugh();
+ void asmMakeWhiteFlash();
+ void asmPanRightToJoeAndRita();
+ void asmPanLeftToBomb();
+ void asmEndDemo();
+ void asmInterviewIntro();
+ void asmEndInterview();
+
+ virtual bool preChangeRoom() = 0;
+ virtual bool handleSpecialMove(uint16 sm) = 0;
+
+
+ uint16 _currentRoom;
+ uint16 _oldRoom;
+ uint16 _newRoom;
+
+ //! total number of room in game
+ uint16 _numRooms;
+
+ //! first object number in room
+ uint16 *_roomData;
+
+ //! background music to play in room
+ uint16 *_sfxName;
+
+ //! bounding box of object
+ Box *_objectBox;
+
+ //! inventory items
+ ItemData *_itemData;
+ uint16 _numItems;
+
+ GraphicData *_graphicData;
+ uint16 _numGraphics;
+
+ ObjectData *_objectData;
+ uint16 _numObjects;
+
+ ObjectDescription *_objectDescription;
+ uint16 _numObjDesc;
+
+ ActorData *_actorData;
+ uint16 _numActors;
+
+ //! walk off point for an object
+ WalkOffData *_walkOffData;
+ uint16 _numWalkOffs;
+
+ FurnitureData *_furnitureData;
+ uint16 _numFurniture;
+
+ GraphicAnim *_graphicAnim;
+ uint16 _numGraphicAnim;
+
+ //! actor initial position in room is _walkOffData[_entryObj]
+ int16 _entryObj;
+
+ //! object description (Look At)
+ Common::StringList _objDescription;
+ uint16 _numDescriptions;
+
+ Common::StringList _objName;
+ uint16 _numNames;
+
+ //! room name, prefix for data files (PCX, LUM...)
+ Common::StringList _roomName;
+
+ Common::StringList _verbName;
+
+ Common::StringList _joeResponse;
+
+ //! actor animation strings
+ Common::StringList _aAnim;
+ uint16 _numAAnim;
+
+ //! actor names
+ Common::StringList _aName;
+ uint16 _numAName;
+
+ //! actor filenames
+ Common::StringList _aFile;
+ uint16 _numAFile;
+
+ struct {
+ uint16 x, y;
+ uint16 facing, cutFacing, prevFacing;
+ JoeWalkMode walk;
+ uint16 scale;
+ } _joe;
+
+ int16 _gameState[GAME_STATE_COUNT];
+
+ TalkSelected _talkSelected[TALK_SELECTED_COUNT];
+
+ //! inventory items
+ int16 _inventoryItem[4];
+
+ //! puzzle counter for room T7
+ uint8 _puzzleAttemptCount;
+
+ //! cutscene counter
+ int _scene;
+
+ Credits *_credits;
+ Journal *_journal;
+
+ QueenEngine *_vm;
+};
+
+class LogicDemo : public Logic {
+public:
+
+ LogicDemo(QueenEngine *vm) : Logic(vm) {}
+ void useJournal();
+
+protected:
+
+ bool preChangeRoom();
+ bool handleSpecialMove(uint16 sm);
+};
+
+class LogicInterview : public Logic {
+public:
+
+ LogicInterview(QueenEngine *vm) : Logic(vm) {}
+ void useJournal();
+
+protected:
+
+ bool preChangeRoom();
+ bool handleSpecialMove(uint16 sm);
+};
+
+class LogicGame : public Logic {
+public:
+
+ LogicGame(QueenEngine *vm) : Logic(vm) {}
+ void useJournal();
+
+protected:
+
+ bool preChangeRoom();
+ bool handleSpecialMove(uint16 sm);
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/module.mk b/engines/queen/module.mk
new file mode 100644
index 0000000000..be3c5707e6
--- /dev/null
+++ b/engines/queen/module.mk
@@ -0,0 +1,34 @@
+MODULE := engines/queen
+
+MODULE_OBJS := \
+ engines/queen/bankman.o \
+ engines/queen/command.o \
+ engines/queen/credits.o \
+ engines/queen/cutaway.o \
+ engines/queen/debug.o \
+ engines/queen/display.o \
+ engines/queen/graphics.o \
+ engines/queen/grid.o \
+ engines/queen/input.o \
+ engines/queen/journal.o \
+ engines/queen/logic.o \
+ engines/queen/music.o \
+ engines/queen/musicdata.o \
+ engines/queen/queen.o \
+ engines/queen/resource.o \
+ engines/queen/restables.o \
+ engines/queen/sound.o \
+ engines/queen/state.o \
+ engines/queen/talk.o \
+ engines/queen/walk.o
+
+MODULE_DIRS += \
+ engines/queen
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/common.rules
diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp
new file mode 100644
index 0000000000..c4a7a24503
--- /dev/null
+++ b/engines/queen/music.cpp
@@ -0,0 +1,344 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/music.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+
+#include "sound/midiparser.h"
+
+namespace Queen {
+
+MusicPlayer::MusicPlayer(MidiDriver *driver, byte *data, uint32 size) : _driver(driver), _isPlaying(false), _looping(false), _randomLoop(false), _masterVolume(192), _queuePos(0), _musicData(data), _musicDataSize(size), _passThrough(false), _buf(0) {
+ memset(_channel, 0, sizeof(_channel));
+ queueClear();
+ _lastSong = _currentSong = 0;
+ _parser = MidiParser::createParser_SMF();
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
+
+ _numSongs = READ_LE_UINT16(_musicData);
+ this->open();
+}
+
+MusicPlayer::~MusicPlayer() {
+ _parser->unloadMusic();
+ delete _parser;
+ this->close();
+ delete[] _buf;
+}
+
+void MusicPlayer::setVolume(int volume) {
+ if (volume < 0)
+ volume = 0;
+ else if (volume > 255)
+ volume = 255;
+
+ if (_masterVolume == volume)
+ return;
+
+ _masterVolume = volume;
+
+ for (int i = 0; i < 16; ++i) {
+ if (_channel[i])
+ _channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
+ }
+}
+
+bool MusicPlayer::queueSong(uint16 songNum) {
+ if (songNum >= _numSongs && songNum < 1000) {
+ // this happens at the end of the car chase, where we try to play song 176,
+ // see Sound::_tune[], entry 39
+ debug(3, "Trying to queue an invalid song number %d, max %d", songNum, _numSongs);
+ return false;
+ }
+ uint8 emptySlots = 0;
+ for (int i = 0; i < MUSIC_QUEUE_SIZE; i++)
+ if (!_songQueue[i])
+ emptySlots++;
+
+ if (!emptySlots)
+ return false;
+
+ // Work around bug in Roland music, note that these numbers are 'one-off'
+ // from the original code
+ if (/*isRoland && */ songNum == 88 || songNum == 89)
+ songNum = 62;
+
+ _songQueue[MUSIC_QUEUE_SIZE - emptySlots] = songNum;
+ return true;
+}
+
+void MusicPlayer::queueClear() {
+ _lastSong = _songQueue[0];
+ _queuePos = 0;
+ _looping = _randomLoop = false;
+ memset(_songQueue, 0, sizeof(_songQueue));
+}
+
+int MusicPlayer::open() {
+ // Don't ever call open without first setting the output driver!
+ if (!_driver)
+ return 255;
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+ _driver->setTimerCallback(this, &onTimer);
+ return 0;
+}
+
+void MusicPlayer::close() {
+ _driver->setTimerCallback(NULL, NULL);
+ if (_driver)
+ _driver->close();
+ _driver = 0;
+}
+
+void MusicPlayer::send(uint32 b) {
+ if (_passThrough) {
+ _driver->send(b);
+ return;
+ }
+
+ byte channel = (byte)(b & 0x0F);
+ if ((b & 0xFFF0) == 0x07B0) {
+ // Adjust volume changes by master volume
+ byte volume = (byte)((b >> 16) & 0x7F);
+ _channelVolume[channel] = volume;
+ volume = volume * _masterVolume / 255;
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ } else if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+ else if ((b & 0xFFF0) == 0x007BB0) {
+ //Only respond to All Notes Off if this channel
+ //has currently been allocated
+ if (_channel[b & 0x0F])
+ return;
+ }
+
+ //Work around annoying loud notes in certain Roland Floda tunes
+ if (channel == 3 && _currentSong == 90)
+ return;
+ if (channel == 4 && _currentSong == 27)
+ return;
+ if (channel == 5 && _currentSong == 38)
+ return;
+
+ if (!_channel[channel])
+ _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+
+ if (_channel[channel])
+ _channel[channel]->send(b);
+}
+
+void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
+ //Only thing we care about is End of Track.
+ if (type != 0x2F)
+ return;
+
+ if (_looping || _songQueue[1])
+ playMusic();
+ else
+ stopMusic();
+}
+
+void MusicPlayer::onTimer(void *refCon) {
+ MusicPlayer *music = (MusicPlayer *)refCon;
+ if (music->_isPlaying)
+ music->_parser->onTimer();
+}
+
+void MusicPlayer::queueTuneList(int16 tuneList) {
+ queueClear();
+
+ //Jungle is the only part of the game that uses multiple tunelists.
+ //For the sake of code simplification we just hardcode the extended list ourselves
+ if ((tuneList + 1) == 3) {
+ _randomLoop = true;
+ int i = 0;
+ while (Sound::_jungleList[i])
+ queueSong(Sound::_jungleList[i++] - 1);
+ return;
+ }
+
+ int mode = (_numSongs == 40) ? Sound::_tuneDemo[tuneList].mode : Sound::_tune[tuneList].mode;
+ switch (mode) {
+ case 0: // random loop
+ _randomLoop = true;
+ setLoop(false);
+ break;
+ case 1: // sequential loop
+ setLoop(_songQueue[1] == 0);
+ break;
+ case 2: // play once
+ default:
+ setLoop(false);
+ break;
+ }
+
+ int i = 0;
+ if (_numSongs == 40) {
+ while (Sound::_tuneDemo[tuneList].tuneNum[i])
+ queueSong(Sound::_tuneDemo[tuneList].tuneNum[i++] - 1);
+ } else {
+ while (Sound::_tune[tuneList].tuneNum[i])
+ queueSong(Sound::_tune[tuneList].tuneNum[i++] - 1);
+ }
+
+ if (_randomLoop)
+ _queuePos = randomQueuePos();
+}
+
+void MusicPlayer::playMusic() {
+ if (!_songQueue[0]) {
+ debug(5, "MusicPlayer::playMusic - Music queue is empty!");
+ return;
+ }
+
+ uint16 songNum = _songQueue[_queuePos];
+
+ //Special type
+ // > 1000 && < 2000 -> queue different tunelist
+ // 2000 -> repeat music from previous queue
+ if (songNum > 999) {
+ if ((songNum + 1) == 2000) {
+ songNum = _lastSong;
+ queueClear();
+ queueSong(songNum);
+ } else {
+ queueTuneList(songNum - 1000);
+ _queuePos = _randomLoop ? randomQueuePos() : 0;
+ songNum = _songQueue[_queuePos];
+ }
+ }
+
+ byte *prevSong = _musicData + songOffset(_currentSong);
+ if (*prevSong == 0x43 || *prevSong == 0x63) {
+ if (_buf) {
+ delete[] _buf;
+ _buf = 0;
+ }
+ }
+
+ _currentSong = songNum;
+ if (!songNum) {
+ stopMusic();
+ return;
+ }
+
+ byte *musicPtr = _musicData + songOffset(songNum);
+ uint32 size = songLength(songNum);
+ if (*musicPtr == 0x43 || *musicPtr == 0x63) {
+ uint32 packedSize = songLength(songNum) - 0x200;
+ _buf = new uint16[packedSize];
+
+ uint16 *data = (uint16 *)(musicPtr + 1);
+ byte *idx = ((byte *)data) + 0x200;
+
+ for (uint i = 0; i < packedSize; i++)
+#if defined(SCUMM_NEED_ALIGNMENT)
+ memcpy(&_buf[i], (byte*)((byte*)data + *(idx + i) * sizeof(uint16)), sizeof(uint16));
+#else
+ _buf[i] = data[*(idx + i)];
+#endif
+
+ musicPtr = ((byte *)_buf) + ((*musicPtr == 0x63) ? 1 : 0);
+ size = packedSize * 2;
+ }
+
+ _parser->loadMusic(musicPtr, size);
+ _parser->setTrack(0);
+ debug(8, "Playing song %d [queue position: %d]", songNum, _queuePos);
+ _isPlaying = true;
+ queueUpdatePos();
+}
+
+void MusicPlayer::queueUpdatePos() {
+ if (_randomLoop) {
+ _queuePos = randomQueuePos();
+ } else {
+ if (_queuePos < (MUSIC_QUEUE_SIZE - 1) && _songQueue[_queuePos + 1])
+ _queuePos++;
+ else if (_looping)
+ _queuePos = 0;
+ }
+}
+
+uint8 MusicPlayer::randomQueuePos() {
+ int queueSize = 0;
+ for (int i = 0; i < MUSIC_QUEUE_SIZE; i++)
+ if (_songQueue[i])
+ queueSize++;
+
+ if (!queueSize)
+ return 0;
+
+ return (uint8) _rnd.getRandomNumber(queueSize - 1) & 0xFF;
+}
+
+void MusicPlayer::stopMusic() {
+ _isPlaying = false;
+ _parser->unloadMusic();
+}
+
+uint32 MusicPlayer::songOffset(uint16 songNum) const {
+ uint16 offsLo = READ_LE_UINT16(_musicData + (songNum * 4) + 2);
+ uint16 offsHi = READ_LE_UINT16(_musicData + (songNum * 4) + 4);
+ return (offsHi << 4) | offsLo;
+}
+
+uint32 MusicPlayer::songLength(uint16 songNum) const {
+ if (songNum < _numSongs)
+ return (songOffset(songNum + 1) - songOffset(songNum));
+ return (_musicDataSize - songOffset(songNum));
+}
+
+Music::Music(MidiDriver *driver, QueenEngine *vm) : _vToggle(false) {
+ if (vm->resource()->isDemo()) {
+ _musicData = vm->resource()->loadFile("AQ8.RL", 0, &_musicDataSize);
+ } else {
+ _musicData = vm->resource()->loadFile("AQ.RL", 0, &_musicDataSize);
+ }
+ _player = new MusicPlayer(driver, _musicData, _musicDataSize);
+}
+
+Music::~Music() {
+ delete _player;
+ delete[] _musicData;
+}
+
+void Music::playSong(uint16 songNum) {
+ _player->queueClear();
+ _player->queueSong(songNum);
+ _player->playMusic();
+}
+
+void Music::toggleVChange() {
+ setVolume(_vToggle ? (volume() * 2) : (volume() / 2));
+ _vToggle ^= true;
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/music.h b/engines/queen/music.h
new file mode 100644
index 0000000000..1051b8b988
--- /dev/null
+++ b/engines/queen/music.h
@@ -0,0 +1,125 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENMUSIC_H
+#define QUEENMUSIC_H
+
+#include "common/util.h"
+#include "sound/mididrv.h"
+
+class MidiParser;
+
+namespace Queen {
+
+class QueenEngine;
+
+class MusicPlayer : public MidiDriver {
+public:
+ MusicPlayer(MidiDriver *driver, byte *data, uint32 size);
+ ~MusicPlayer();
+ void setVolume(int volume);
+ int getVolume() { return _masterVolume; }
+
+ void hasNativeMT32(bool b) { _nativeMT32 = b; }
+ void playMusic();
+ void stopMusic();
+ void setLoop(bool loop) { _looping = loop; }
+ void queueTuneList(int16 tuneList);
+ bool queueSong(uint16 songNum);
+ void queueClear();
+ void setPassThrough(bool b) { _passThrough = b; }
+
+ //MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+
+ void metaEvent(byte type, byte *data, uint16 length);
+
+ void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
+ uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
+
+ //Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+protected:
+
+ enum {
+ MUSIC_QUEUE_SIZE = 14
+ };
+
+ void queueUpdatePos();
+ uint8 randomQueuePos();
+ static void onTimer(void *data);
+ uint32 songOffset(uint16 songNum) const;
+ uint32 songLength(uint16 songNum) const;
+
+ MidiDriver *_driver;
+ MidiParser *_parser;
+ MidiChannel *_channel[16];
+ byte _channelVolume[16];
+ bool _nativeMT32;
+ bool _passThrough;
+
+ Common::RandomSource _rnd;
+
+ bool _isPlaying;
+ bool _looping;
+ bool _randomLoop;
+ byte _masterVolume;
+ uint8 _queuePos;
+ int16 _currentSong;
+ int16 _lastSong; //first song from previous queue
+ int16 _songQueue[MUSIC_QUEUE_SIZE];
+
+ uint16 _numSongs;
+ byte *_musicData;
+ uint16 *_buf;
+ uint32 _musicDataSize;
+};
+
+class Music {
+public:
+ Music(MidiDriver *_driver, QueenEngine *vm);
+ ~Music();
+ void hasNativeMT32(bool b) { _player->hasNativeMT32(b); }
+ void playSong(uint16 songNum);
+ void queueTuneList(int16 tuneList) { _player->queueTuneList(tuneList); }
+ void playMusic() { _player->playMusic(); }
+ void stopSong() { _player->stopMusic(); }
+ void setPassThrough(bool b) { _player->setPassThrough(b); }
+
+ void toggleVChange();
+ void setVolume(int vol) { _player->setVolume(vol); }
+ int volume() { return _player->getVolume(); }
+
+protected:
+ bool _vToggle;
+ byte *_musicData;
+ uint32 _musicDataSize;
+ MusicPlayer *_player;
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/musicdata.cpp b/engines/queen/musicdata.cpp
new file mode 100644
index 0000000000..39acdf8ab4
--- /dev/null
+++ b/engines/queen/musicdata.cpp
@@ -0,0 +1,1944 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/sound.h"
+
+namespace Queen {
+
+#ifdef PALMOS_68K
+
+const songData *Sound::_songDemo;
+const songData *Sound::_song;
+const tuneData *Sound::_tuneDemo;
+const tuneData *Sound::_tune;
+const char *Sound::_sfxName;
+const int16 *Sound::_jungleList;
+
+#else
+const songData Sound::_songDemo[] = {
+ /* 1 - Hotel Gangsters */
+ { { 1, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 2 - Hotel General */
+ { { 2, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 3 - Jungle */
+ { { 3, 4, 5, 6, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 4 - Waterfall On */
+ { { 7, 0 }, 128, 128, 128, 0, 0 },
+
+ /* 5 - Vnormal */
+ { { 8, 0 }, 128, 128, 128, 2, 0 },
+
+ /* 6 - Trader Bob */
+ { { 9, 0 }, 120, 128, 128, 1, 0 },
+
+ /* 7 - Jetty Music */
+ { { 10, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 8 - Ferry Music */
+ { { 11, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 9 - Temple Upstairs */
+ { { 12, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 10 - Temple Downstairs */
+ { { 13, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 11 - Temple Maze */
+ { { 14, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 12 - Temple Skull */
+ { { 15, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 13 - Johns Theme (Love Story) */
+ { { 16, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 14 - Vmedium */
+ { { 17, 0 }, 128, 128, 0, 2, 0 },
+
+ /* 15 - Vsoft */
+ { { 18, 0 }, 128, 128, 0, 2, 0 },
+
+ /* 16 - Floda Upstairs */
+ { { 19, 0 }, 128, 128, 0, 1, 0 },
+
+ /* 17 - Floda General */
+ { { 20, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 18 - Klunks Room */
+ { { 21, 0 }, 110, 128, 128, 1, 0 },
+
+ /* 19 - Hotel Lola */
+ { { 22, 0 }, 120, 18128, 128, 1, 0 },
+
+ /* 20 - Hotel Escape 1 */
+ { { 23, 0 }, 128, 18128, 128, 1, 0 },
+
+ /* 21 - Amazon Fortress */
+ { { 24, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 22 - Waterfall Off */
+ { { 25, 0 }, 128, 128, 128, 0, 0 },
+
+ /* 23 - Wave Torch */
+ { { 26, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 24 - Zombies Rez Out */
+ { { 27, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 25 - Open Door (standard) */
+ { { 28, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 26 - Close Door (standard) */
+ { { 29, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 27 - Cloth Unrolls */
+ { { 30, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 28 - Snake Slithers Off */
+ { { 31, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 29 - Hotel Fanfare 2 */
+ { { 32, 0 }, 128, 128, 128, 1, 1 },
+
+ /* 30 - Floda Secret */
+ { { 33, 0 }, 120, 128, 128, 1, 0 },
+
+ /* 31 - Temple Fanfare 1 */
+ { { 34, 0 }, 128, 128, 128, 1, 1 },
+};
+
+const songData Sound::_song[] = {
+ /* 1 - Hotel Gangsters */
+ { { 1, 0 }, 128, 180, 0, 1, 0 },
+
+ /* 2 - Hotel General */
+ { { 2, 0 }, 128, 180, 0, 1, 0 },
+
+ /* 3 - Jungle */
+ { { 3, 4, 5, 6, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 4 - Waterfall On */
+ { { 7, 0 }, 128, 0, 0, 0, 0 },
+
+ /* 5 - Vnormal */
+ { { 8, 0 }, 128, 0, 0, 2, 0 },
+
+ /* 6 - Trader Bob */
+ { { 9, 0 }, 120, 0, 0, 1, 0 },
+
+ /* 7 - Jetty Music */
+ { { 10, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 8 - Ferry Music */
+ { { 11, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 9 - Temple Upstairs */
+ { { 12, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 10 - Temple Downstairs */
+ { { 13, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 11 - Temple Maze */
+ { { 14, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 12 - Temple Skull */
+ { { 15, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 13 - Johns Theme (Love Story) */
+ { { 16, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 14 - Vmedium */
+ { { 17, 0 }, 120, 0, 0, 2, 0 },
+
+ /* 15 - Vsoft */
+ { { 18, 0 }, 110, 0, 0, 2, 0 },
+
+ /* 16 - Floda Upstairs */
+ { { 19, 0 }, 110, 0, 0, 1, 0 },
+
+ /* 17 - Floda General */
+ { { 20, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 18 - Klunks Room */
+ { { 21, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 19 - Hotel Lola */
+ { { 22, 0 }, 120, 180, 0, 1, 0 },
+
+ /* 20 - Hotel Escape 1 */
+ { { 23, 0 }, 128, 180, 0, 1, 0 },
+
+ /* 21 - Amazon Fortress */
+ { { 24, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 22 - Waterfall Off */
+ { { 25, 0 }, 128, 0, 0, 0, 0 },
+
+ /* 23 - Wave Torch */
+ { { 26, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 24 - Zombies Rez Out */
+ { { 27, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 25 - Open Door (standard) */
+ { { 28, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 26 - Close Door (standard) */
+ { { 29, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 27 - Cloth Unrolls */
+ { { 30, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 28 - Snake Slithers Off */
+ { { 31, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 29 - Hotel Fanfare 2 */
+ { { 32, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 30 - Floda Secret */
+ { { 33, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 31 - Temple Fanfare 1 */
+ { { 34, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 32 - Commander Rocket 1 */
+ { { 35, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 33 - Hotel Escape 2 */
+ { { 36, 0 }, 128, 180, 0, 1, 0 },
+
+ /* 34 - Back of Truck */
+ { { 37, 0 }, 128, 180, 0, 1, 0 },
+
+ /* 35 - Hotel Fanfare 1 */
+ { { 38, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 36 - Truck Fanfare */
+ { { 39, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 37 - Airport */
+ { { 40, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 38 - Plane Leaves */
+ { { 41, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 39 - Arrive Hotel */
+ { { 42, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 40 - Jungle Fanfare */
+ { { 43, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 41 - General Fanfare */
+ { { 44, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 42 - Johns Room */
+ { { 45, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 43 - Floda Lab */
+ { { 46, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 44 - Azura's Theme */
+ { { 47, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 45 - Use Record */
+ { { 48, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 46 - Franks Theme */
+ { { 49, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 47 - Anderson Doubts */
+ { { 50, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 48 - Bud and Lou Theme */
+ { { 51, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 49 - Gorilla Theme */
+ { { 52, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 50 - Missionaries Theme */
+ { { 53, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 51 - Sloth Theme */
+ { { 54, 0 }, 128, 0, 0, 1, 1 },
+
+ /* 52 - Amazon Dungeon */
+ { { 55, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 53 - Throne Room */
+ { { 56, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 54 - Temple Puzzle */
+ { { 57, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 55 - Temple Fountain Room */
+ { { 58, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 56 - Light Switch */
+ { { 59, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 57 - Hydraulic Open */
+ { { 60, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 58 - Hydraulic Close */
+ { { 61, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 59 - Close Door (metal) */
+ { { 62, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 60 - Small Hatch Close */
+ { { 63, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 61 - Scissors Snip */
+ { { 64, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 62 - Pick up Sticky */
+ { { 65, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 63 - Oracle Rezzes In */
+ { { 66, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 64 - Sparkle SFX */
+ { { 67, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 65 - Splorch! */
+ { { 68, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 66 - Pour Liquid */
+ { { 69, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 67 - End Credit Medley */
+ { { 70, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 68 - Dino Ray */
+ { { 71, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 69 - Squish! */
+ { { 72, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 70 - Robot Laser */
+ { { 73, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 71 - Thud wood light */
+ { { 74, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 72 - Thud wood deep */
+ { { 75, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 73 - Thud metallic */
+ { { 76, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 74 - Cut Coconut */
+ { { 77, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 75 - Thud Stone */
+ { { 78, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 76 - Cloth Slide 1 */
+ { { 79, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 77 - Open Chest */
+ { { 80, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 78 - Close Chest */
+ { { 81, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 79 - Open Drawer */
+ { { 82, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 80 - Truck door closes */
+ { { 83, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 81 - Truck Starts */
+ { { 84, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 82 - Truck Drives Off */
+ { { 85, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 83 - Fish Splash */
+ { { 86, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 84 - Close Drawer/Push Ladder */
+ { { 87, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 85 - Agression Enhancer */
+ { { 88, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 86 - Stone Door Grind 1 */
+ { { 89, 0 }, 128, 0, 0, 0, 1 },
+
+ /* 87 - Prequel 1 */
+ { { 90, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 88 - Intro Credits */
+ { { 91, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 89 - Valley 1 */
+ { { 92, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 90 - Valley 3 */
+ { { 93, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 91 - Fight Music */
+ { { 94, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 92 - Confrontation 1 */
+ { { 95, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 93 - Confrontation 2 */
+ { { 96, 0 }, 128, 0, 0, 1, 0 },
+
+ /* 94 - Plane Hatch Open */
+ { { 97, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 95 - Plane Hatch Close */
+ { { 98, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 96 - Tie Vines */
+ { { 99, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 97 - Pterodactyl */
+ { { 100, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 98 - Beef Jerky Splash */
+ { { 101, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 99 - Piranha Burp */
+ { { 102, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 100 - Falling Vine */
+ { { 103, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 101 - Stone Door Grind 2 */
+ { { 104, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 102 - Stone Grind (light) */
+ { { 105, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 103 - Ape Takes Off Mask */
+ { { 106, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 104 - Bark Breaks */
+ { { 107, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 105 - Stone Click */
+ { { 108, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 106 - Sproing! */
+ { { 109, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 107 - Cash Register */
+ { { 110, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 108 - Squeaky Toy */
+ { { 111, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 109 - Falling Chains */
+ { { 112, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 110 - Open Locker Door */
+ { { 113, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 111 - Close Locker Door */
+ { { 114, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 112 - Rub Pencil */
+ { { 115, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 113 - Open Safe */
+ { { 116, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 114 - Close Safe */
+ { { 117, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 115 - Push Chair */
+ { { 118, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 116 - Snake Hiss */
+ { { 119, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 117 - Oracle Rezzes Out */
+ { { 120, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 118 - Wall Crumbles */
+ { { 121, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 119 - Crypt Crumbles */
+ { { 122, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 120 - Joe Sucked Up */
+ { { 123, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 121 - Rocket Pack Zoom */
+ { { 124, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 122 - Piranha Splash */
+ { { 125, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 123 - Snap Branch */
+ { { 126, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 124 - Dino Horn */
+ { { 127, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 125 - Tyre Screech */
+ { { 128, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 126 - Oil Splat */
+ { { 129, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 127 - Punch */
+ { { 130, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 128 - Body Hits Ground */
+ { { 131, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 129 - Chicken */
+ { { 132, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 130 - Open Sarcophagus */
+ { { 133, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 131 - Close Sarcophagus */
+ { { 134, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 132 - Creaking Stick */
+ { { 135, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 133 - Pick Hits Stone */
+ { { 136, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 134 - Stalactite Crumbles */
+ { { 137, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 135 - Tic-Toc */
+ { { 138, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 136 - Stone Grind (heavy) */
+ { { 139, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 137 - Explosion */
+ { { 140, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 138 - Cloth Slide 2 */
+ { { 141, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 139 - Temple Laser */
+ { { 142, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 140 - Dino Transformation */
+ { { 143, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 141 - Experimental Laser */
+ { { 144, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 142 - Stone Grind (medium) */
+ { { 145, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 143 - Weeping God Grind */
+ { { 146, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 144 - Alien Hum */
+ { { 147, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 145 - Alien Puzzle */
+ { { 148, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 146 - Vacuum On */
+ { { 149, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 147 - Vacuum Off */
+ { { 150, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 148 - Elevator Starts */
+ { { 151, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 149 - Mummy Crumbles */
+ { { 152, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 150 - Temple Green Circle */
+ { { 153, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 151 - Rattle Bars */
+ { { 154, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 152 - Door Dissolves */
+ { { 155, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 153 - Altar Slides */
+ { { 156, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 154 - Light Torch */
+ { { 157, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 155 - Stamp Sound */
+ { { 158, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 156 - Plaster Loud */
+ { { 159, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 157 - Sparky Bathtub */
+ { { 160, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 158 - Ape Rezzes Out */
+ { { 161, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 159 - Song 159 */
+ { { 162, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 160 - Song 160 */
+ { { 163, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 161 - Song 161 */
+ { { 164, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 162 - Piranhas Swim */
+ { { 165, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 163 - Prison/Dungeon Door */
+ { { 166, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 164 - Fight Explosion */
+ { { 167, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 165 - Press Button */
+ { { 168, 0 }, 128, 128, 128, 2, 1 },
+
+ /* 166 - Pull Lever */
+ { { 169, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 167 - Wrong Code */
+ { { 170, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 168 - Correct Code */
+ { { 171, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 169 - Sizzle */
+ { { 172, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 170 - Money In Slot */
+ { { 173, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 171 - Lightning Crack */
+ { { 174, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 172 - Machine Gun Fire */
+ { { 175, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 173 - Cage Descends */
+ { { 176, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 174 - Chair Activates */
+ { { 177, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 175 - Robot Powers On */
+ { { 178, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 176 - Grow Big */
+ { { 179, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 177 - Eat Food */
+ { { 180, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 178 - Head Shrink */
+ { { 181, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 179 - Grinding Gears */
+ { { 182, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 180 - Chair Splash */
+ { { 183, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 181 - Deflect Laser */
+ { { 184, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 182 - Zap Frank */
+ { { 185, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 183 - Frank Transforms */
+ { { 186, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 184 - Alarm Clock */
+ { { 187, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 185 - Slide Chute */
+ { { 188, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 186 - Puff */
+ { { 189, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 187 - Bite */
+ { { 190, 0 }, 128, 128, 128, 0, 0 },
+
+ /* 188 - Stone Door Grind 2 */
+ { { 191, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 189 - Prequel 2 */
+ { { 192, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 190 - Prequel 3 */
+ { { 193, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 191 - Prequel 4 */
+ { { 194, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 192 - Stop Music */
+ { { 195, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 193 - Plane Flyby */
+ { { 196, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 194 - Commander Rocket 2 */
+ { { 197, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 195 - Commander Rocket 3 */
+ { { 198, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 196 - Rescue */
+ { { 199, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 197 - Slow Fanfare */
+ { { 200, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 198 - Plane Crash */
+ { { 201, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 199 - Plane Engine 1 */
+ { { 202, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 200 - Plane Engine 2 */
+ { { 203, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 201 - Boat In */
+ { { 204, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 202 - Boat Out */
+ { { 205, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 203 - Final Fanfare! */
+ { { 206, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 204 - Frank Destroyed */
+ { { 207, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 205 - Jaspar Eats */
+ { { 208, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 206 - Compy Scream 1 */
+ { { 209, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 207 - Compy Scream 2 */
+ { { 210, 0 }, 128, 128, 128, 0, 1 },
+
+ /* 208 - Punch Klunk Fanfare */
+ { { 211, 0 }, 128, 128, 128, 1, 0 },
+
+ /* 209 - Talk Frank */
+ { { 212, 0 }, 128, 128, 128, 1, 0 }
+};
+
+const tuneData Sound::_tuneDemo[] = {
+ /* 1 - Hotel Gangsters */
+ { { 32, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 2 - Hotel General */
+ { { 26, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 3 - Jungle */
+ { { 15, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 4 - Jungle */
+ { { 17, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 5 - Jungle */
+ { { 18, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 6 - Jungle */
+ { { 7, 8, 9, 10, 11, 12, 13, 14, 0 }, { 0, 0 }, 0, 0 },
+
+ /* 7 - Waterfall On */
+ { { 3, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 8 - Vnormal */
+ { { 1, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 9 - Trader Bob */
+ { { 1, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 10 - Jetty Music */
+ { { 37, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 11 - Ferry Music */
+ { { 38, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 12 - Temple Upstairs */
+ { { 30, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 13 - Temple Downstairs */
+ { { 34, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 14 - Temple Maze */
+ { { 35, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 15 - Temple Skull */
+ { { 36, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 16 - Johns Theme (Love Story) */
+ { { 43, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 17 - Vmedium */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 18 - Vsoft */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 19 - Floda Upstairs */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 20 - Floda General */
+ { { 29, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 21 - Klunks Room */
+ { { 39, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 22 - Hotel Lola */
+ { { 31, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 23 - Hotel Escape 1 */
+ { { 33, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 24 - Amazon Fortress */
+ { { 40, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 25 - Waterfall Off */
+ { { -3, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 26 - Wave Torch */
+ { { 22, 0 }, { 121, 0 }, 2, 0 },
+
+ /* 27 - Zombies Rez Out */
+ { { 25, 0 }, { 20, 0 }, 2, 0 },
+
+ /* 28 - Open Door (standard) */
+ { { 20, 0 }, { 1, 0 }, 2, 0 },
+
+ /* 29 - Close Door (standard) */
+ { { 21, 0 }, { 2, 0 }, 2, 0 },
+
+ /* 30 - Cloth Unrolls */
+ { { 23, 0 }, { 51, 0 }, 2, 0 },
+
+ /* 31 - Snake Slithers Off */
+ { { 24, 0 }, { 122, 0 }, 2, 0 },
+
+ /* 32 - Hotel Fanfare 2 */
+ { { 69, 1003, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 33 - Floda Secret */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 34 - Temple Fanfare 1 */
+ { { 60, 162, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 35 - Commander Rocket 1 */
+ { { 46, 0 }, { 0, 0 }, 1, 0 },
+};
+
+const tuneData Sound::_tune[] = {
+ /* 1 - Hotel Gangsters */
+ { { 32, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 2 - Hotel General */
+ { { 41, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 3 - Jungle */
+ { { 15, 16, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 4 - Jungle */
+ { { 17, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 5 - Jungle */
+ { { 18, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 6 - Jungle */
+ { { 7, 8, 9, 10, 11, 12, 13, 14, 0 }, { 0, 0 }, 0, -10 },
+
+ /* 7 - Waterfall On */
+ { { 3, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 8 - Vnormal */
+ { { 23, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 9 - Trader Bob */
+ { { 23, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 10 - Jetty Music */
+ { { 37, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 11 - Ferry Music */
+ { { 38, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 12 - Temple Upstairs */
+ { { 30, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 13 - Temple Downstairs */
+ { { 34, 36, 56, 0 }, { 0, 0 }, 0, 0 },
+
+ /* 14 - Temple Maze */
+ { { 87, 35, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 15 - Temple Skull */
+ { { 76, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 16 - Johns Theme (Love Story) */
+ { { 44, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 17 - Vmedium */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 18 - Vsoft */
+ { { 28, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 19 - Floda Upstairs */
+ { { 28, 39, 0 }, { 0, 0 }, 0, 0 },
+
+ /* 20 - Floda General */
+ { { 89, 63, 64, 65, 0 }, { 0, 0 }, 0, 0 },
+
+ /* 21 - Klunks Room */
+ { { 43, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 22 - Hotel Lola */
+ { { 31, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 23 - Hotel Escape 1 */
+ { { 52, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 24 - Amazon Fortress */
+ { { 40, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 25 - Waterfall Off */
+ { {-3, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 26 - Wave Torch */
+ { { 0, 0 }, { 121, 0 }, 2, 0 },
+
+ /* 27 - Zombies Rez Out */
+ { { 0, 0 }, { 20, 0 }, 2, 0 },
+
+ /* 28 - Open Door (standard) */
+ { { 0, 0 }, { 1, 0 }, 2, 0 },
+
+ /* 29 - Close Door (standard) */
+ { { 0, 0 }, { 2, 0 }, 2, 0 },
+
+ /* 30 - Cloth Unrolls */
+ { { 0, 0 }, { 51, 0 }, 2, 0 },
+
+ /* 31 - Snake Slithers Off */
+ { { 0, 0 }, { 122, 0 }, 2, 0 },
+
+ /* 32 - Hotel Fanfare 2 */
+ { { 69, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 33 - Floda Secret */
+ { { 29, 42, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 34 - Temple Fanfare 1 */
+ { { 70, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 35 - Commander Rocket 1 */
+ { { 45, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 36 - Hotel Escape 2 */
+ { { 52, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 37 - Back of Truck */
+ { { 51, 48, 33, 54, 52, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 38 - Hotel Fanfare 1 */
+ { { 67, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 39 - Truck Fanfare */
+ { { 67, 177, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 40 - Airport */
+ { { 81, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 41 - Plane Leaves */
+ { { 68, 1198, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 42 - Arrive Hotel */
+ { { 26, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 43 - Jungle Fanfare */
+ { { 68, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 44 - General Fanfare */
+ { { 57, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 45 - Johns Room */
+ { { 90, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 46 - Floda Lab */
+ { { 92, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 47 - Azura's Theme */
+ { { 80, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 48 - Use Record */
+ { { 91, 2000, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 49 - Franks Theme */
+ { { 77, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 50 - Anderson Doubts */
+ { { 75, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 51 - Bud and Lou Theme */
+ { { 94, 1003, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 52 - Gorilla Theme */
+ { { 97, 1003, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 53 - Missionaries Theme */
+ { { 98, 1003, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 54 - Sloth Theme */
+ { { 100, 1003, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 55 - Amazon Dungeon */
+ { { 96, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 56 - Throne Room */
+ { { 78, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 57 - Temple Puzzle */
+ { { 88, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 58 - Temple Fountain Room */
+ { { 55, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 59 - Light Switch */
+ { { 0, 0 }, { 4, 0 }, 2, 0 },
+
+ /* 60 - Hydraulic Open */
+ { { 0, 0 }, { 7, 0 }, 2, 0 },
+
+ /* 61 - Hydraulic Close */
+ { { 0, 0 }, { 8, 0 }, 2, 0 },
+
+ /* 62 - Close Door (metal) */
+ { { 0, 0 }, { 9, 0 }, 2, 0 },
+
+ /* 63 - Small Hatch Close */
+ { { 0, 0 }, { 10, 0 }, 2, 0 },
+
+ /* 64 - Scissors Snip */
+ { { 0, 0 }, { 5, 0 }, 2, 0 },
+
+ /* 65 - Pick up Sticky */
+ { { 0, 0 }, { 6, 0 }, 2, 0 },
+
+ /* 66 - Oracle Rezzes In */
+ { { 0, 0 }, { 11, 0 }, 2, 0 },
+
+ /* 67 - Sparkle SFX */
+ { { 0, 0 }, { 12, 0 }, 2, 0 },
+
+ /* 68 - Splorch! */
+ { { 0, 0 }, { 13, 0 }, 2, 0 },
+
+ /* 69 - Pour Liquid */
+ { { 0, 0 }, { 3, 0 }, 2, 0 },
+
+ /* 70 - End Credit Medley */
+ { { 95, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 71 - Dino Ray */
+ { { 0, 0 }, { 14, 0 }, 2, 0 },
+
+ /* 72 - Squish! */
+ { { 0, 0 }, { 15, 0 }, 2, 0 },
+
+ /* 73 - Robot Laser */
+ { { 0, 0 }, { 16, 0 }, 2, 0 },
+
+ /* 74 - Thud wood light */
+ { { 0, 0 }, { 17, 0 }, 2, 0 },
+
+ /* 75 - Thud wood deep */
+ { { 0, 0 }, { 18, 0 }, 2, 0 },
+
+ /* 76 - Thud metallic */
+ { { 0, 0 }, { 19, 0 }, 2, 0 },
+
+ /* 77 - Cut Coconut */
+ { { 0, 0 }, { 22, 0 }, 2, 0 },
+
+ /* 78 - Thud Stone */
+ { { 0, 0 }, { 23, 0 }, 2, 0 },
+
+ /* 79 - Cloth Slide 1 */
+ { { 0, 0 }, { 24, 0 }, 2, 0 },
+
+ /* 80 - Open Chest */
+ { { 0, 0 }, { 25, 0 }, 2, 0 },
+
+ /* 81 - Close Chest */
+ { { 0, 0 }, { 26, 0 }, 2, 0 },
+
+ /* 82 - Open Drawer */
+ { { 0, 0 }, { 27, 0 }, 2, 0 },
+
+ /* 83 - Truck door closes */
+ { { 0, 0 }, { 28, 0 }, 2, 0 },
+
+ /* 84 - Truck Starts */
+ { { 0, 0 }, { 29, 0 }, 2, 0 },
+
+ /* 85 - Truck Drives Off */
+ { { 0, 0 }, { 30, 0 }, 2, 0 },
+
+ /* 86 - Fish Splash */
+ { { 0, 0 }, { 31, 0 }, 2, 0 },
+
+ /* 87 - Close Drawer/Push Ladder */
+ { { 0, 0 }, { 33, 0 }, 2, 0 },
+
+ /* 88 - Agression Enhancer */
+ { { 0, 0 }, { 32, 0 }, 2, 0 },
+
+ /* 89 - Stone Door Grind 1 */
+ { { 0, 0 }, { 78, 0 }, 2, 0 },
+
+ /* 90 - Prequel 1 */
+ { { 20, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 91 - Intro Credits */
+ { { 21, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 92 - Valley 1 */
+ { { 71, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 93 - Valley 3 */
+ { { 73, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 94 - Fight Music */
+ { { 72, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 95 - Confrontation 1 */
+ { { 93, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 96 - Confrontation 2 */
+ { { 74, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 97 - Plane Hatch Open */
+ { { 0, 0 }, { 35, 0 }, 2, 0 },
+
+ /* 98 - Plane Hatch Close */
+ { { 0, 0 }, { 36, 0 }, 2, 0 },
+
+ /* 99 - Tie Vines */
+ { { 0, 0 }, { 37, 0 }, 2, 0 },
+
+ /* 100 - Pterodactyl */
+ { { 0, 0 }, { 38, 0 }, 2, 0 },
+
+ /* 101 - Beef Jerky Splash */
+ { { 0, 0 }, { 39, 0 }, 2, 0 },
+
+ /* 102 - Piranha Burp */
+ { { 0, 0 }, { 40, 0 }, 2, 0 },
+
+ /* 103 - Falling Vine */
+ { { 0, 0 }, { 41, 0 }, 2, 0 },
+
+ /* 104 - Stone Door Grind 2 */
+ { { 0, 0 }, { 79, 0 }, 2, 0 },
+
+ /* 105 - Stone Grind (light) */
+ { { 0, 0 }, { 82, 0 }, 2, 0 },
+
+ /* 106 - Ape Takes Off Mask */
+ { { 0, 0 }, { 44, 0 }, 2, 0 },
+
+ /* 107 - Bark Breaks */
+ { { 0, 0 }, { 45, 0 }, 2, 0 },
+
+ /* 108 - Stone Click */
+ { { 0, 0 }, { 46, 0 }, 2, 0 },
+
+ /* 109 - Sproing! */
+ { { 0, 0 }, { 42, 0 }, 2, 0 },
+
+ /* 110 - Cash Register */
+ { { 0, 0 }, { 48, 0 }, 2, 0 },
+
+ /* 111 - Squeaky Toy */
+ { { 0, 0 }, { 49, 0 }, 2, 0 },
+
+ /* 112 - Falling Chains */
+ { { 0, 0 }, { 50, 0 }, 2, 0 },
+
+ /* 113 - Open Locker Door */
+ { { 0, 0 }, { 52, 0 }, 2, 0 },
+
+ /* 114 - Close Locker Door */
+ { { 0, 0 }, { 53, 0 }, 2, 0 },
+
+ /* 115 - Rub Pencil */
+ { { 0, 0 }, { 54, 0 }, 2, 0 },
+
+ /* 116 - Open Safe */
+ { { 0, 0 }, { 55, 0 }, 2, 0 },
+
+ /* 117 - Close Safe */
+ { { 0, 0 }, { 56, 0 }, 2, 0 },
+
+ /* 118 - Push Chair */
+ { { 0, 0 }, { 57, 0 }, 2, 0 },
+
+ /* 119 - Snake Hiss */
+ { { 0, 0 }, { 58, 0 }, 2, 0 },
+
+ /* 120 - Oracle Rezzes Out */
+ { { 0, 0 }, { 59, 0 }, 2, 0 },
+
+ /* 121 - Wall Crumbles */
+ { { 0, 0 }, { 60, 0 }, 2, 0 },
+
+ /* 122 - Crypt Crumbles */
+ { { 0, 0 }, { 61, 0 }, 2, 0 },
+
+ /* 123 - Joe Sucked Up */
+ { { 0, 0 }, { 63, 0 }, 2, 0 },
+
+ /* 124 - Rocket Pack Zoom */
+ { { 0, 0 }, { 47, 0 }, 2, 0 },
+
+ /* 125 - Piranha Splash */
+ { { 0, 0 }, { 83, 0 }, 2, 0 },
+
+ /* 126 - Snap Branch */
+ { { 0, 0 }, { 66, 0 }, 2, 0 },
+
+ /* 127 - Dino Horn */
+ { { 0, 0 }, { 67, 0 }, 2, 0 },
+
+ /* 128 - Tyre Screech */
+ { { 0, 0 }, { 68, 0 }, 2, 0 },
+
+ /* 129 - Oil Splat */
+ { { 0, 0 }, { 70, 0 }, 2, 0 },
+
+ /* 130 - Punch */
+ { { 0, 0 }, { 71, 0 }, 2, 0 },
+
+ /* 131 - Body Hits Ground */
+ { { 0, 0 }, { 72, 0 }, 2, 0 },
+
+ /* 132 - Chicken */
+ { { 0, 0 }, { 69, 0 }, 2, 0 },
+
+ /* 133 - Open Sarcophagus */
+ { { 0, 0 }, { 21, 0 }, 2, 0 },
+
+ /* 134 - Close Sarcophagus */
+ { { 0, 0 }, { 21, 0 }, 2, 0 },
+
+ /* 135 - Creaking Stick */
+ { { 0, 0 }, { 62, 0 }, 2, 0 },
+
+ /* 136 - Pick Hits Stone */
+ { { 0, 0 }, { 73, 0 }, 2, 0 },
+
+ /* 137 - Stalactite Crumbles */
+ { { 0, 0 }, { 74, 0 }, 2, 0 },
+
+ /* 138 - Tic-Toc */
+ { { 0, 0 }, { 76, 0 }, 2, 0 },
+
+ /* 139 - Stone Grind (heavy) */
+ { { 0, 0 }, { 81, 0 }, 2, 0 },
+
+ /* 140 - Explosion */
+ { { 0, 0 }, { 77, 0 }, 2, 0 },
+
+ /* 141 - Cloth Slide 2 */
+ { { 0, 0 }, { 84, 0 }, 2, 0 },
+
+ /* 142 - Temple Laser */
+ { { 0, 0 }, { 85, 0 }, 2, 0 },
+
+ /* 143 - Dino Transformation */
+ { { 0, 0 }, { 86, 0 }, 2, 0 },
+
+ /* 144 - Experimental Laser */
+ { { 0, 0 }, { 87, 0 }, 2, 0 },
+
+ /* 145 - Stone Grind (medium) */
+ { { 0, 0 }, { 88, 0 }, 2, 0 },
+
+ /* 146 - Weeping God Grind */
+ { { 0, 0 }, { 89, 0 }, 2, 0 },
+
+ /* 147 - Alien Hum */
+ { { 0, 0 }, { 90, 0 }, 2, 0 },
+
+ /* 148 - Alien Puzzle */
+ { { 0, 0 }, { 91, 0 }, 2, 0 },
+
+ /* 149 - Vacuum On */
+ { { 0, 0 }, { 92, 0 }, 2, 0 },
+
+ /* 150 - Vacuum Off */
+ { { 0, 0 }, { 93, 0 }, 2, 0 },
+
+ /* 151 - Elevator Starts */
+ { { 0, 0 }, { 94, 0 }, 2, 0 },
+
+ /* 152 - Mummy Crumbles */
+ { { 0, 0 }, { 95, 0 }, 2, 0 },
+
+ /* 153 - Temple Green Circle */
+ { { 0, 0 }, { 96, 0 }, 2, 0 },
+
+ /* 154 - Rattle Bars */
+ { { 0, 0 }, { 97, 0 }, 2, 0 },
+
+ /* 155 - Door Dissolves */
+ { { 0, 0 }, { 98, 0 }, 2, 0 },
+
+ /* 156 - Altar Slides */
+ { { 0, 0 }, { 99, 0 }, 2, 0 },
+
+ /* 157 - Light Torch */
+ { { 0, 0 }, { 100, 0 }, 2, 0 },
+
+ /* 158 - Stamp Sound */
+ { { 0, 0 }, { 34, 0 }, 2, 0 },
+
+ /* 159 - Plaster Loud */
+ { { 0, 0 }, { 102, 0 }, 2, 0 },
+
+ /* 160 - Sparky Bathtub */
+ { { 0, 0 }, { 103, 0 }, 2, 0 },
+
+ /* 161 - Ape Rezzes Out */
+ { { 0, 0 }, { 104, 0 }, 2, 0 },
+
+ /* 162 - Song 159 */
+ { { 0, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 163 - Song 160 */
+ { { 0, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 164 - Song 161 */
+ { { 0, 0 }, { 0, 0 }, 2, 0 },
+
+ /* 165 - Piranhas Swim */
+ { { 0, 0 }, { 105, 0 }, 2, 0 },
+
+ /* 166 - Prison/Dungeon Door */
+ { { 0, 0 }, { 43, 0 }, 2, 0 },
+
+ /* 167 - Fight Explosion */
+ { { 0, 0 }, { 80, 0 }, 2, 0 },
+
+ /* 168 - Press Button */
+ { { 0, 0 }, { 65, 0 }, 2, 0 },
+
+ /* 169 - Pull Lever */
+ { { 0, 0 }, { 107, 0 }, 2, 0 },
+
+ /* 170 - Wrong Code */
+ { { 0, 0 }, { 108, 0 }, 2, 0 },
+
+ /* 171 - Correct Code */
+ { { 0, 0 }, { 109, 0 }, 2, 0 },
+
+ /* 172 - Sizzle */
+ { { 0, 0 }, { 110, 0 }, 2, 0 },
+
+ /* 173 - Money In Slot */
+ { { 0, 0 }, { 111, 0 }, 2, 0 },
+
+ /* 174 - Lightning Crack */
+ { { 0, 0 }, { 112, 0 }, 2, 0 },
+
+ /* 175 - Machine Gun Fire */
+ { { 0, 0 }, { 113, 0 }, 2, 0 },
+
+ /* 176 - Cage Descends */
+ { { 0, 0 }, { 114, 0 }, 2, 0 },
+
+ /* 177 - Chair Activates */
+ { { 0, 0 }, { 115, 0 }, 2, 0 },
+
+ /* 178 - Robot Powers On */
+ { { 0, 0 }, { 116, 0 }, 2, 0 },
+
+ /* 179 - Grow Big */
+ { { 0, 0 }, { 117, 0 }, 2, 0 },
+
+ /* 180 - Eat Food */
+ { { 0, 0 }, { 118, 0 }, 2, 0 },
+
+ /* 181 - Head Shrink */
+ { { 0, 0 }, { 119, 0 }, 2, 0 },
+
+ /* 182 - Grinding Gears */
+ { { 0, 0 }, { 120, 0 }, 2, 0 },
+
+ /* 183 - Chair Splash */
+ { { 0, 0 }, { 123, 0 }, 2, 0 },
+
+ /* 184 - Deflect Laser */
+ { { 0, 0 }, { 124, 0 }, 2, 0 },
+
+ /* 185 - Zap Frank */
+ { { 0, 0 }, { 125, 0 }, 2, 0 },
+
+ /* 186 - Frank Transforms */
+ { { 0, 0 }, { 126, 0 }, 2, 0 },
+
+ /* 187 - Alarm Clock */
+ { { 0, 0 }, { 127, 0 }, 2, 0 },
+
+ /* 188 - Slide Chute */
+ { { 0, 0 }, { 64, 0 }, 2, 0 },
+
+ /* 189 - Puff */
+ { { 0, 0 }, { 128, 0 }, 2, 0 },
+
+ /* 190 - Bite */
+ { { 0, 0 }, { 129, 0 }, 2, 0 },
+
+ /* 191 - Stone Door Grind 2 */
+ { { 0, 0 }, { 79, 0 }, 2, 0 },
+
+ /* 192 - Prequel 2 */
+ { { 22, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 193 - Prequel 3 */
+ { { 24, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 194 - Prequel 4 */
+ { { 25, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 195 - Stop Music */
+ { { 1, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 196 - Plane Flyby */
+ { { 0, 0 }, { 101, 0 }, 2, 0 },
+
+ /* 197 - Commander Rocket 2 */
+ { { 46, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 198 - Commander Rocket 3 */
+ { { 47, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 199 - Rescue */
+ { { 99, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 200 - Slow Fanfare */
+ { { 0, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 201 - Plane Crash */
+ { { 93, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 202 - Plane Engine 1 */
+ { { 0, 0 }, { 130, 0 }, 2, 0 },
+
+ /* 203 - Plane Engine 2 */
+ { { 0, 0 }, { 131, 0 }, 2, 0 },
+
+ /* 204 - Boat In */
+ { { 0, 0 }, { 132, 0 }, 2, 0 },
+
+ /* 205 - Boat Out */
+ { { 0, 0 }, { 133, 0 }, 2, 0 },
+
+ /* 206 - Final Fanfare! */
+ { { 21, 95, 21, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 207 - Frank Destroyed */
+ { { 25, 1044, 0 }, { 0, 0 }, 1, 0 },
+
+
+ /* 208 - Jaspar Eats */
+ { { 0, 0 }, { 134, 0 }, 2, 0 },
+
+ /* 209 - Compy Scream 1 */
+ { { 0, 0 }, { 135, 0 }, 2, 0 },
+
+ /* 210 - Compy Scream 2 */
+ { { 0, 0 }, { 136, 0 }, 2, 0 },
+
+ /* 211 - Punch Klunk Fanfare */
+ { { 69, 1017, 0 }, { 0, 0 }, 1, 0 },
+
+ /* 212 - Talk Frank */
+ { { 77, 1017, 0 }, { 0, 0 }, 1, 0 }
+};
+
+const char *Sound::_sfxName[] = {
+ /* 1 - Door Open (standard) */
+ "116Bssss",
+
+ /* 2 - Door Close (standard) */
+ "105assss",
+
+ /* 3 - Pour Liquid */
+ "133sssss",
+
+ /* 4 - Light Switch */
+ "27ssssss",
+
+ /* 5 - Scissor Snip */
+ "15ssssss",
+
+ /* 6 - Pick up Sticky */
+ "79ssssss",
+
+ /* 7 - Hydraulic Doors Open */
+ "96ssssss",
+
+ /* 8 - Hydraulic Doors Close */
+ "97ssssss",
+
+ /* 9 - Metallic Door Slams */
+ "105sssss",
+
+ /* 10 - Small Hatch Close */
+ "106sssss",
+
+ /* 11 - Oracle Rezzes In */
+ "132sssss",
+
+ /* 12 - Polish Sparkle */
+ "132Cssss",
+
+ /* 13 - Splorch! */
+ "137Bssss",
+
+ /* 14 - Dino Ray Gun */
+ "138sssss",
+
+ /* 15 - Squish! */
+ "137Assss",
+
+ /* 16 - Robot Laser */
+ "61ssssss",
+
+ /* 17 - Thud wood light */
+ "109sssss",
+
+ /* 18 - Thud wood deep */
+ "110sssss",
+
+ /* 19 - Thud metallic */
+ "111sssss",
+
+ /* 20 - Zombies Rez Out */
+ "77ssssss",
+
+ /* 21 - Sarc Door Closes */
+ "58ssssss",
+
+ /* 22 - Thud breadboard fruit/Coconut */
+ "131Assss",
+
+ /* 23 - Thud stone */
+ "75ssssss",
+
+ /* 24 - Cloth Slide 1 */
+ "135sssss",
+
+ /* 25 - Open Chest */
+ "112sssss",
+
+ /* 26 - Close Chest */
+ "121sssss",
+
+ /* 27 - Open Drawer */
+ "120sssss",
+
+ /* 28 - Truck door closes */
+ "122sssss",
+
+ /* 29 - Truck Starts */
+ "123Assss",
+
+ /* 30 - Truck Drives Off */
+ "123Bssss",
+
+ /* 31 - Fish Splash */
+ "18ssssss",
+
+ /* 32 - Agression Enhancer */
+ "138Bssss",
+
+ /* 33 - Close Drawer/Push Ladder */
+ "113sssss",
+
+ /* 34 - *Stamp Sound */
+ "40ssssss",
+
+ /* 35 - plane hatch open */
+ "3sssssss",
+
+ /* 36 - plane hatch close */
+ "4sssssss",
+
+ /* 37 - tie vines */
+ "11ssssss",
+
+ /* 38 - Pterodactyl */
+ "10ssssss",
+
+ /* 39 - Beef Jerky Splash */
+ "6sssssss",
+
+ /* 40 - Piranha Burp */
+ "7sssssss",
+
+ /* 41 - Falling Vine */
+ "13ssssss",
+
+ /* 42 - Sproing! */
+ "29ssssss",
+
+ /* 43 - Prison/Dungeon Door */
+ "33ssssss",
+
+ /* 44 - Ape takes off mask */
+ "24ssssss",
+
+ /* 45 - Bark breaks */
+ "25ssssss",
+
+ /* 46 - Stone Click */
+ "136sssss",
+
+ /* 47 - Rocket Pack Zoom */
+ "1006ssss",
+
+ /* 48 - Cash Register */
+ "36ssssss",
+
+ /* 49 - Squeaky Toy */
+ "37ssssss",
+
+ /* 50 - Falling Chains */
+ "38ssssss",
+
+ /* 51 - Cloth Unravels */
+ "64ssssss",
+
+ /* 52 - Open Locker Door */
+ "48ssssss",
+
+ /* 53 - Close Locker Door */
+ "49ssssss",
+
+ /* 54 - Rub Pencil on Pad */
+ "50ssssss",
+
+ /* 55 - Open Safe */
+ "51ssssss",
+
+ /* 56 - Close Safe */
+ "52ssssss",
+
+ /* 57 - Push Chair */
+ "59ssssss",
+
+ /* 58 - Snake Hiss */
+ "83ssssss",
+
+ /* 59 - Oracle Rezzes Out */
+ "70ssssss",
+
+ /* 60 - Wall Crumbles */
+ "73Asssss",
+
+ /* 61 - Crypt Crumbles */
+ "76ssssss",
+
+ /* 62 - Creaking Stick */
+ "74Asssss",
+
+ /* 63 - Joe Sucked Up */
+ "80ssssss",
+
+ /* 64 - Slide Chute */
+ "114assss",
+
+ /* 65 - Press Button */
+ "1007ssss",
+
+ /* 66 - Snap Branch */
+ "101sssss",
+
+ /* 67 - Dino Horn */
+ "103sssss",
+
+ /* 68 - Tyre Screech */
+ "125sssss",
+
+ /* 69 - Chicken */
+ "126sssss",
+
+ /* 70 - Oil Splat */
+ "127sssss",
+
+ /* 71 - Punch */
+ "128sssss",
+
+ /* 72 - Body Hits Ground */
+ "129sssss",
+
+ /* 73 - Pick Hits Stone */
+ "71ssssss",
+
+ /* 74 - Stalactite Crumbles */
+ "119sssss",
+
+ /* 75 - *Drip */
+ "93ssssss",
+
+ /* 76 - Tic-Toc */
+ "42Bsssss",
+
+ /* 77 - Explosion */
+ "88ssssss",
+
+ /* 78 - Stone Door Grind 1 */
+ "1001ssss",
+
+ /* 79 - Stone Door Grind 2 */
+ "1002ssss",
+
+ /* 80 - *Fight Explosion */
+ "1000ssss",
+
+ /* 81 - Stone Grind (heavy) */
+ "1003ssss",
+
+ /* 82 - Stone Grind (light) */
+ "89ssssss",
+
+ /* 83 - Piranha Splash */
+ "5sssssss",
+
+ /* 84 - Cloth Slide 2 */
+ "1005ssss",
+
+ /* 85 - Temple Laser */
+ "87ssssss",
+
+ /* 86 - Dino Transformation */
+ "55Bsssss",
+
+ /* 87 - Experimental Laser */
+ "55ssssss",
+
+ /* 88 - Stone Grind (medium) */
+ "134sssss",
+
+ /* 89 - Weeping God Grind */
+ "94ssssss",
+
+ /* 90 - Alien Hum */
+ "95ssssss",
+
+ /* 91 - Alien Puzzle */
+ "103Assss",
+
+ /* 92 - Vacuum On */
+ "21ssssss",
+
+ /* 93 - Vacuum Off */
+ "21Csssss",
+
+ /* 94 - Elevator Starts */
+ "44ssssss",
+
+ /* 95 - Mummy Crumbles */
+ "68ssssss",
+
+ /* 96 - Temple Green Circle */
+ "60Bsssss",
+
+ /* 97 - Rattle Bars */
+ "115sssss",
+
+ /* 98 - Door Dissolves */
+ "56ssssss",
+
+ /* 99 - Altar Slides */
+ "85ssssss",
+
+ /* 100 - Light Torch */
+ "81ssssss",
+
+ /* 101 - Plane Flyby */
+ "1027ssss",
+
+ /* 102 - Plaster Loud */
+ "41Bsssss",
+
+ /* 103 - Sparky Bathtub */
+ "73ssssss",
+
+ /* 104 - Ape Rezzes Out */
+ "14ssssss",
+
+ /* 105 - Piranhas Swim */
+ "17ssssss",
+
+ /* 106 - *Gun Shot */
+ "1004ssss",
+
+ /* 107 - Pull Lever */
+ "1008ssss",
+
+ /* 108 - Wrong Code */
+ "1009ssss",
+
+ /* 109 - Correct Code */
+ "1010ssss",
+
+ /* 110 - Sizzle */
+ "1011ssss",
+
+ /* 111 - Money In Slot */
+ "1012ssss",
+
+ /* 112 - Lightning */
+ "1013ssss",
+
+ /* 113 - Machine Gun Fire */
+ "1014ssss",
+
+ /* 114 - Cage Descends */
+ "1015ssss",
+
+ /* 115 - Temple Chair Activates */
+ "1016ssss",
+
+ /* 116 - Robot Powers On */
+ "1017ssss",
+
+ /* 117 - Grow Big */
+ "1018ssss",
+
+ /* 118 - Eat Food */
+ "1019ssss",
+
+ /* 119 - Head Shrink */
+ "1020ssss",
+
+ /* 120 - Grinding Gears */
+ "84ssssss",
+
+ /* 121 - Wave Torch */
+ "1021ssss",
+
+ /* 122 - Snake Slithers Off */
+ "1022ssss",
+
+ /* 123 - Chair Splash */
+ "26ssssss",
+
+ /* 124 - Deflect Laser */
+ "60ssssss",
+
+ /* 125 - Zap Frank */
+ "1023ssss",
+
+ /* 126 - Frank Transforms */
+ "1024ssss",
+
+ /* 127 - Alarm Clock */
+ "1025ssss",
+
+ /* 128 - Puff */
+ "35ssssss",
+
+ /* 129 - Bite */
+ "1026ssss",
+
+ /* 130 - Plane Engine 1 */
+ "1028ssss",
+
+ /* 131 - Plane Engine 2 */
+ "1029ssss",
+
+ /* 132 - Boat In */
+ "1030ssss",
+
+ /* 133 - Boat Out */
+ "1031ssss",
+
+ /* 134 - Jaspar Eats */
+ "1032ssss",
+
+ /* 135 - Compy Scream 1 */
+ "1033ssss",
+
+ /* 136 - Compy Scream 2 */
+ "1034ssss"
+};
+
+const int16 Sound::_jungleList[] = { 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
+#endif
+
+} // End of namespace Queen
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Queen_Musicdata)
+_GSETPTR(Queen::Sound::_songDemo, GBVARS_MUSICDATASONGDEMO_INDEX, Queen::songData, GBVARS_QUEEN)
+_GSETPTR(Queen::Sound::_song, GBVARS_MUSICDATASONG_INDEX, Queen::songData, GBVARS_QUEEN)
+_GSETPTR(Queen::Sound::_tuneDemo, GBVARS_MUSICDATATUNEDEMO_INDEX, Queen::tuneData, GBVARS_QUEEN)
+_GSETPTR(Queen::Sound::_tune, GBVARS_MUSICDATATUNE_INDEX, Queen::tuneData, GBVARS_QUEEN)
+_GSETPTR(Queen::Sound::_sfxName, GBVARS_MUSICDATASFXNAME_INDEX, char, GBVARS_QUEEN)
+_GSETPTR(Queen::Sound::_jungleList, GBVARS_MUSICDATAJUNGLELIST_INDEX, int16, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Queen_Musicdata)
+_GRELEASEPTR(GBVARS_MUSICDATASONGDEMO_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_MUSICDATASONG_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_MUSICDATATUNEDEMO_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_MUSICDATATUNE_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_MUSICDATASFXNAME_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_MUSICDATAJUNGLELIST_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp
new file mode 100644
index 0000000000..e6c6f39269
--- /dev/null
+++ b/engines/queen/queen.cpp
@@ -0,0 +1,454 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "backends/fs/fs.h"
+
+#include "base/gameDetector.h"
+#include "base/plugins.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+
+#include "queen/queen.h"
+#include "queen/bankman.h"
+#include "queen/command.h"
+#include "queen/cutaway.h"
+#include "queen/debug.h"
+#include "queen/display.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/input.h"
+#include "queen/logic.h"
+#include "queen/music.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+#include "queen/talk.h"
+#include "queen/walk.h"
+
+#include "sound/mididrv.h"
+
+#ifdef _WIN32_WCE
+bool isSmartphone();
+#endif
+
+/* Flight of the Amazon Queen */
+static const GameSettings queen_setting[] = {
+ { "queen", "Flight of the Amazon Queen", 0 },
+ { "queen", "Flight of the Amazon Queen (Demo)", 0 },
+ { "queen", "Flight of the Amazon Queen (Interview)", 0 },
+ { 0, 0, 0 }
+};
+
+GameList Engine_QUEEN_gameList() {
+ GameList games;
+ const GameSettings *g = queen_setting;
+
+ while (g->gameid) {
+ games.push_back(*g);
+ g++;
+ }
+ return games;
+}
+
+GameSettings determineTarget(uint32 size) {
+ switch (size) {
+ case 3724538: //regular demo
+ case 3732177:
+ return queen_setting[1];
+ break;
+ case 1915913: //interview demo
+ return queen_setting[2];
+ break;
+ default: //non-demo
+ return queen_setting[0];
+ break;
+ }
+ return queen_setting[0];
+}
+
+DetectedGameList Engine_QUEEN_detectGames(const FSList &fslist) {
+ DetectedGameList detectedGames;
+
+ // Iterate over all files in the given directory
+ for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (!file->isDirectory()) {
+ const char *gameName = file->displayName().c_str();
+
+ if (0 == scumm_stricmp("queen.1", gameName) || 0 == scumm_stricmp("queen.1c", gameName)) {
+ Common::File dataFile;
+ dataFile.open(file->path().c_str());
+ assert(dataFile.isOpen());
+
+ if (0 == scumm_stricmp("queen.1", gameName)) { //an unmodified file
+ detectedGames.push_back(determineTarget(dataFile.size()));
+ } else if (0 == scumm_stricmp("queen.1c", gameName)) { //oh joy, it's a rebuilt file
+ char header[9];
+ dataFile.read(header, 9);
+ if (0 == scumm_strnicmp("QTBL", header, 4)) { //check validity
+ uint8 version = 0; //default to full/normal version
+
+ if (0 == scumm_strnicmp("PE100", header + 4, 5)) //One of the 2 regular demos
+ version = 1;
+ if (0 == scumm_strnicmp("PEint", header + 4, 5)) //Interview demo
+ version = 2;
+
+ detectedGames.push_back(queen_setting[version]);
+ }
+ }
+
+ dataFile.close();
+ break;
+ }
+ }
+ }
+ return detectedGames;
+}
+
+Engine *Engine_QUEEN_create(GameDetector *detector, OSystem *syst) {
+ return new Queen::QueenEngine(detector, syst);
+}
+
+REGISTER_PLUGIN(QUEEN, "Flight of the Amazon Queen")
+
+namespace Queen {
+
+QueenEngine::QueenEngine(GameDetector *detector, OSystem *syst)
+ : Engine(syst), _debugger(0) {
+}
+
+QueenEngine::~QueenEngine() {
+ delete _bam;
+ delete _resource;
+ delete _bankMan;
+ delete _command;
+ delete _debugger;
+ delete _display;
+ delete _graphics;
+ delete _grid;
+ delete _input;
+ delete _logic;
+ delete _music;
+ delete _sound;
+ delete _walk;
+}
+
+void QueenEngine::registerDefaultSettings() {
+ ConfMan.registerDefault("music_mute", false);
+ ConfMan.registerDefault("sfx_mute", false);
+ ConfMan.registerDefault("talkspeed", Logic::DEFAULT_TALK_SPEED);
+ ConfMan.registerDefault("speech_mute", _resource->isDemo() || _resource->isInterview());
+ ConfMan.registerDefault("subtitles", true);
+}
+
+void QueenEngine::checkOptionSettings() {
+ // check talkspeed value
+ if (_talkSpeed < MIN_TEXT_SPEED) {
+ _talkSpeed = MIN_TEXT_SPEED;
+ } else if (_talkSpeed > MAX_TEXT_SPEED) {
+ _talkSpeed = MAX_TEXT_SPEED;
+ }
+
+ // ensure text is always on when voice is off
+ if (!_sound->speechOn()) {
+ _subtitles = true;
+ }
+
+ // demo and interview versions don't have speech at all
+ if (_sound->speechOn() && (_resource->isDemo() || _resource->isInterview())) {
+ _sound->speechToggle(false);
+ }
+}
+
+void QueenEngine::readOptionSettings() {
+ _music->setVolume(ConfMan.getInt("music_volume"));
+ _sound->musicToggle(!ConfMan.getBool("music_mute"));
+ _sound->sfxToggle(!ConfMan.getBool("sfx_mute"));
+ _talkSpeed = ConfMan.getInt("talkspeed");
+ _sound->speechToggle(!ConfMan.getBool("speech_mute"));
+ _subtitles = ConfMan.getBool("subtitles");
+ checkOptionSettings();
+}
+
+void QueenEngine::writeOptionSettings() {
+ ConfMan.set("music_volume", _music->volume());
+ ConfMan.set("music_mute", !_sound->musicOn());
+ ConfMan.set("sfx_mute", !_sound->sfxOn());
+ ConfMan.set("talkspeed", _talkSpeed);
+ ConfMan.set("speech_mute", !_sound->speechOn());
+ ConfMan.set("subtitles", _subtitles);
+ ConfMan.flushToDisk();
+}
+
+void QueenEngine::update(bool checkPlayerInput) {
+ if (_debugger->isAttached()) {
+ _debugger->onFrame();
+ }
+
+ _graphics->update(_logic->currentRoom());
+ _logic->update();
+
+ _input->delay();
+
+ if (!_resource->isInterview()) {
+ _display->palCustomScroll(_logic->currentRoom());
+ }
+ BobSlot *joe = _graphics->bob(0);
+ _display->update(joe->active, joe->x, joe->y);
+
+ _input->checkKeys();
+ if (_input->debugger()) {
+ _input->debuggerReset();
+ _debugger->attach();
+ }
+ if (canLoadOrSave()) {
+ if (_input->quickSave()) {
+ _input->quickSaveReset();
+ saveGameState(0, "Quicksave");
+ }
+ if (_input->quickLoad()) {
+ _input->quickLoadReset();
+ loadGameState(0);
+ }
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ saveGameState(AUTOSAVE_SLOT, "Autosave");
+ _lastSaveTime = _system->getMillis();
+ }
+ }
+ if (!_input->cutawayRunning()) {
+ if (checkPlayerInput) {
+ _command->updatePlayer();
+ }
+ if (_input->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
+ _display->blankScreen();
+ }
+ }
+}
+
+bool QueenEngine::canLoadOrSave() const {
+ return !_input->cutawayRunning() && !(_resource->isDemo() || _resource->isInterview());
+}
+
+void QueenEngine::saveGameState(uint16 slot, const char *desc) {
+ debug(3, "Saving game to slot %d", slot);
+ char name[20];
+ makeGameStateName(slot, name);
+ Common::OutSaveFile *file = _saveFileMan->openForSaving(name);
+ if (file) {
+ // save data
+ byte *saveData = new byte[SAVESTATE_MAX_SIZE];
+ byte *p = saveData;
+ _bam->saveState(p);
+ _grid->saveState(p);
+ _logic->saveState(p);
+ _sound->saveState(p);
+ uint32 dataSize = p - saveData;
+ assert(dataSize < SAVESTATE_MAX_SIZE);
+
+ // write header
+ GameStateHeader header;
+ memset(&header, 0, sizeof(header));
+ file->writeUint32BE('SCVM');
+ header.version = TO_BE_32(SAVESTATE_CUR_VER);
+ header.flags = TO_BE_32(0);
+ header.dataSize = TO_BE_32(dataSize);
+ strncpy(header.description, desc, sizeof(header.description) - 1);
+ file->write(&header, sizeof(header));
+
+ // write save data
+ file->write(saveData, dataSize);
+ file->flush();
+
+ // check for errors
+ if (file->ioFailed()) {
+ warning("Can't write file '%s'. (Disk full?)", name);
+ }
+ delete[] saveData;
+ delete file;
+ } else {
+ warning("Can't create file '%s', game not saved", name);
+ }
+}
+
+void QueenEngine::loadGameState(uint16 slot) {
+ debug(3, "Loading game from slot %d", slot);
+ GameStateHeader header;
+ Common::InSaveFile *file = readGameStateHeader(slot, &header);
+ if (file && header.dataSize != 0) {
+ byte *saveData = new byte[header.dataSize];
+ byte *p = saveData;
+ if (file->read(saveData, header.dataSize) != header.dataSize) {
+ warning("Error reading savegame file");
+ } else {
+ _bam->loadState(header.version, p);
+ _grid->loadState(header.version, p);
+ _logic->loadState(header.version, p);
+ _sound->loadState(header.version, p);
+ if (header.dataSize != (uint32)(p - saveData)) {
+ warning("Corrupted savegame file");
+ } else {
+ _logic->setupRestoredGame();
+ }
+ }
+ delete[] saveData;
+ delete file;
+ }
+}
+
+Common::InSaveFile *QueenEngine::readGameStateHeader(uint16 slot, GameStateHeader *gsh) {
+ char name[20];
+ makeGameStateName(slot, name);
+ Common::InSaveFile *file = _saveFileMan->openForLoading(name);
+ if (file && file->readUint32BE() == 'SCVM') {
+ gsh->version = file->readUint32BE();
+ gsh->flags = file->readUint32BE();
+ gsh->dataSize = file->readUint32BE();
+ file->read(gsh->description, sizeof(gsh->description));
+ } else {
+ memset(gsh, 0, sizeof(GameStateHeader));
+ }
+ return file;
+}
+
+void QueenEngine::makeGameStateName(uint16 slot, char *buf) {
+ if (slot == AUTOSAVE_SLOT) {
+ strcpy(buf, "queen.asd");
+ } else {
+ sprintf(buf, "queen.s%02d", slot);
+ }
+}
+
+void QueenEngine::findGameStateDescriptions(char descriptions[100][32]) {
+ char filename[20];
+ makeGameStateName(0, filename);
+ filename[strlen(filename) - 2] = 0;
+ bool marks[SAVESTATE_MAX_NUM];
+ _saveFileMan->listSavefiles(filename, marks, SAVESTATE_MAX_NUM);
+ for (int i = 0; i < SAVESTATE_MAX_NUM; ++i) {
+ if (marks[i]) {
+ GameStateHeader header;
+ Common::InSaveFile *f = readGameStateHeader(i, &header);
+ strcpy(descriptions[i], header.description);
+ delete f;
+ }
+ }
+}
+
+void QueenEngine::errorString(const char *buf1, char *buf2) {
+ strcpy(buf2, buf1);
+
+#ifdef _WIN32_WCE
+ if (isSmartphone())
+ return;
+#endif
+
+ // Unless an error -originated- within the debugger, spawn the
+ // debugger. Otherwise exit out normally.
+ if (_debugger && !_debugger->isAttached()) {
+ // (Print it again in case debugger segfaults)
+ printf("%s\n", buf2);
+ _debugger->attach(buf2);
+ _debugger->onFrame();
+ }
+}
+
+int QueenEngine::go() {
+ _logic->start();
+ if (ConfMan.hasKey("save_slot") && canLoadOrSave()) {
+ loadGameState(ConfMan.getInt("save_slot"));
+ }
+ _lastSaveTime = _system->getMillis();
+ _quit = false;
+ while (!_quit) {
+ if (_logic->newRoom() > 0) {
+ _logic->update();
+ _logic->oldRoom(_logic->currentRoom());
+ _logic->currentRoom(_logic->newRoom());
+ _logic->changeRoom();
+ _display->fullscreen(false);
+ if (_logic->currentRoom() == _logic->newRoom()) {
+ _logic->newRoom(0);
+ }
+ } else if (_logic->joeWalk() == JWM_EXECUTE) {
+ _logic->joeWalk(JWM_NORMAL);
+ _command->executeCurrentAction();
+ } else {
+ _logic->joeWalk(JWM_NORMAL);
+ update(true);
+ }
+ }
+ return 0;
+}
+
+int QueenEngine::init(GameDetector &detector) {
+ _system->beginGFXTransaction();
+ initCommonGFX(detector);
+ _system->initSize(GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
+ _system->endGFXTransaction();
+
+ _bam = new BamScene(this);
+ _resource = new Resource();
+ _bankMan = new BankManager(_resource);
+ _command = new Command(this);
+ _debugger = new Debugger(this);
+ _display = new Display(this, _system);
+ _graphics = new Graphics(this);
+ _grid = new Grid(this);
+ _input = new Input(_resource->getLanguage(), _system);
+
+ if (_resource->isDemo()) {
+ _logic = new LogicDemo(this);
+ } else if (_resource->isInterview()) {
+ _logic = new LogicInterview(this);
+ } else {
+ _logic = new LogicGame(this);
+ }
+
+ if (!_mixer->isReady())
+ warning("Sound initialisation failed");
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ // Set mixer music volume to maximum, since music volume is regulated by MusicPlayer's MIDI messages
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
+
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+ bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+
+ MidiDriver *driver = MidiDriver::createMidi(midiDriver);
+ if (native_mt32)
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ _music = new Music(driver, this);
+ _music->hasNativeMT32(native_mt32);
+
+ _sound = Sound::giveSound(_mixer, this, _resource->compression());
+ _walk = new Walk(this);
+
+ registerDefaultSettings();
+ readOptionSettings();
+
+ return 0;
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/queen.h b/engines/queen/queen.h
new file mode 100644
index 0000000000..91c657cf14
--- /dev/null
+++ b/engines/queen/queen.h
@@ -0,0 +1,164 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEEN_H
+#define QUEEN_H
+
+#include "base/engine.h"
+
+class GameDetector;
+namespace Common {
+ class InSaveFile;
+}
+
+#if defined(_WIN32_WCE) && (_WIN32_WCE <= 300)
+
+FORCEINLINE int16 READ_BE_INT16(const void *ptr) {
+ uint16 result;
+ char dummy[2];
+ result = READ_BE_UINT16(ptr);
+ strcpy(dummy, "x"); // Hello, I'm a drunk optimizer. Thanks for helping me.
+ return result;
+}
+
+#else
+
+#define READ_BE_INT16 READ_BE_UINT16
+
+#endif
+
+namespace Queen {
+
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+struct GameStateHeader {
+ uint32 version;
+ uint32 flags;
+ uint32 dataSize;
+ char description[32];
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
+class BamScene;
+class BankManager;
+class Command;
+class Debugger;
+class Display;
+class Graphics;
+class Grid;
+class Input;
+class Logic;
+class Music;
+class Resource;
+class Sound;
+class Walk;
+
+class QueenEngine : public Engine {
+public:
+
+ QueenEngine(GameDetector *detector, OSystem *syst);
+ virtual ~QueenEngine();
+
+ BamScene *bam() const { return _bam; }
+ BankManager *bankMan() const { return _bankMan; }
+ Command *command() const { return _command; }
+ Debugger *debugger() const { return _debugger; }
+ Display *display() const { return _display; }
+ Graphics *graphics() const { return _graphics; }
+ Grid *grid() const { return _grid; }
+ Input *input() const { return _input; }
+ Logic *logic() const { return _logic; }
+ Music *music() const { return _music; }
+ Resource *resource() const { return _resource; }
+ Sound *sound() const { return _sound; }
+ Walk *walk() const { return _walk; }
+
+ Common::RandomSource randomizer;
+
+ void registerDefaultSettings();
+ void checkOptionSettings();
+ void readOptionSettings();
+ void writeOptionSettings();
+
+ int talkSpeed() const { return _talkSpeed; }
+ void talkSpeed(int speed) { _talkSpeed = speed; }
+ bool subtitles() const { return _subtitles; }
+ void subtitles(bool enable) { _subtitles = enable; }
+ void quitGame() { _quit = true; }
+
+ void update(bool checkPlayerInput = false);
+
+ bool canLoadOrSave() const;
+ void saveGameState(uint16 slot, const char *desc);
+ void loadGameState(uint16 slot);
+ void makeGameStateName(uint16 slot, char *buf);
+ void findGameStateDescriptions(char descriptions[100][32]);
+ Common::InSaveFile *readGameStateHeader(uint16 slot, GameStateHeader *gsh);
+
+ enum {
+ SAVESTATE_CUR_VER = 1,
+ SAVESTATE_MAX_NUM = 100,
+ SAVESTATE_MAX_SIZE = 30000,
+
+ AUTOSAVE_SLOT = 0xFF,
+
+ MIN_TEXT_SPEED = 4,
+ MAX_TEXT_SPEED = 100,
+ MAX_MUSIC_VOLUME = 255
+ };
+
+protected:
+
+ void errorString(const char *buf_input, char *buf_output);
+
+ int go();
+ int init(GameDetector &detector);
+
+
+ int _talkSpeed;
+ bool _subtitles;
+ bool _quit;
+ uint32 _lastSaveTime;
+
+ BamScene *_bam;
+ BankManager *_bankMan;
+ Command *_command;
+ Debugger *_debugger;
+ Display *_display;
+ Graphics *_graphics;
+ Grid *_grid;
+ Input *_input;
+ Logic *_logic;
+ Music *_music;
+ Resource *_resource;
+ Sound *_sound;
+ Walk *_walk;
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp
new file mode 100644
index 0000000000..51fa47b687
--- /dev/null
+++ b/engines/queen/resource.cpp
@@ -0,0 +1,287 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/resource.h"
+
+namespace Queen {
+
+#ifdef PALMOS_68K
+static ResourceEntry *_resourceTablePEM10;
+#endif
+
+const char *Resource::_tableFilename = "queen.tbl";
+
+const GameVersion Resource::_gameVersions[] = {
+ { "PEM10", 0x00000008, 22677657 },
+ { "CEM10", 0x0000584E, 190787021 },
+ { "PFM10", 0x0002CD93, 22157304 },
+ { "CFM10", 0x00032585, 186689095 },
+ { "PGM10", 0x00059ACA, 22240013 },
+ { "CGM10", 0x0005F2A7, 217648975 },
+ { "PIM10", 0x000866B1, 22461366 },
+ { "CIM10", 0x0008BEE2, 190795582 },
+ { "CSM10", 0x000B343C, 190730602 },
+ { "CHM10", 0x000DA981, 190705558 },
+ { "PE100", 0x00101EC6, 3724538 },
+ { "PE100", 0x00102B7F, 3732177 },
+ { "PEint", 0x00103838, 1915913 }
+};
+
+static int compareResourceEntry(const void *a, const void *b) {
+ const char *filename = (const char *)a;
+ const ResourceEntry *entry = (const ResourceEntry *)b;
+ return strcmp(filename, entry->filename);
+}
+
+Resource::Resource()
+ : _resourceEntries(0), _resourceTable(NULL) {
+ _resourceFile = new Common::File();
+ if (!findCompressedVersion() && !findNormalVersion())
+ error("Could not open resource file '%s'", "queen.1");
+ checkJASVersion();
+ debug(5, "Detected game version: %s, which has %d resource entries", _versionString, _resourceEntries);
+}
+
+Resource::~Resource() {
+ _resourceFile->close();
+ delete _resourceFile;
+
+ if (_resourceTable != _resourceTablePEM10)
+ delete[] _resourceTable;
+}
+
+ResourceEntry *Resource::resourceEntry(const char *filename) const {
+ assert(filename[0] && strlen(filename) < 14);
+
+ char entryName[14];
+ char *ptr = entryName;
+
+ strcpy(entryName, filename);
+ do
+ *ptr = toupper(*ptr);
+ while (*ptr++);
+
+ ResourceEntry *re = NULL;
+#ifndef PALMOS_MODE
+ re = (ResourceEntry *)bsearch(entryName, _resourceTable, _resourceEntries, sizeof(ResourceEntry), compareResourceEntry);
+#else
+ // PALMOS FIXME (?) : still doesn't work for me (????) use this instead
+ uint32 cur = 0;
+ do {
+ if (!strcmp(entryName, _resourceTable[cur].filename)) {
+ re = &_resourceTable[cur];
+ break;
+ }
+ } while (cur++ < _resourceEntries);
+#endif
+ return re;
+}
+
+uint8 *Resource::loadFile(const char *filename, uint32 skipBytes, uint32 *size, bool useMalloc) {
+ ResourceEntry *re = resourceEntry(filename);
+ assert(re != NULL);
+ uint32 sz = re->size - skipBytes;
+ if (size != NULL) {
+ *size = sz;
+ }
+
+ byte *dstBuf;
+ if (useMalloc) {
+ dstBuf = (byte *)malloc(sz);
+ } else {
+ dstBuf = new byte[sz];
+ }
+
+ _resourceFile->seek(re->offset + skipBytes);
+ _resourceFile->read(dstBuf, sz);
+ return dstBuf;
+}
+
+bool Resource::findNormalVersion() {
+ _resourceFile->open("queen.1");
+ if (!_resourceFile->isOpen()) {
+ return false;
+ }
+
+ _compression = COMPRESSION_NONE;
+
+ // detect game version based on resource file size ; we try to
+ // verify that it is indeed the version we think it is later on
+ const GameVersion *gameVersion = detectGameVersion(_resourceFile->size());
+ if (gameVersion == NULL)
+ error("Unknown/unsupported FOTAQ version");
+
+ strcpy(_versionString, gameVersion->versionString);
+ if (!readTableFile(gameVersion)) {
+ // check if it is the english floppy version, for which we have a hardcoded version of the table
+ if (!strcmp(gameVersion->versionString, _gameVersions[VER_ENG_FLOPPY].versionString)) {
+ _resourceEntries = 1076;
+ _resourceTable = _resourceTablePEM10;
+ } else {
+ error("Could not find tablefile '%s'", _tableFilename);
+ }
+ }
+ return true;
+}
+
+bool Resource::findCompressedVersion() {
+ _resourceFile->open("queen.1c");
+ if (!_resourceFile->isOpen()) {
+ return false;
+ }
+ readTableCompResource();
+ return true;
+}
+
+void Resource::checkJASVersion() {
+ ResourceEntry *re = resourceEntry("QUEEN.JAS");
+ assert(re != NULL);
+ uint32 offset = re->offset;
+ if (isDemo())
+ offset += JAS_VERSION_OFFSET_DEMO;
+ else if (isInterview())
+ offset += JAS_VERSION_OFFSET_INTV;
+ else
+ offset += JAS_VERSION_OFFSET_PC;
+ _resourceFile->seek(offset);
+
+ char versionStr[6];
+ _resourceFile->read(versionStr, 6);
+ if (strcmp(_versionString, versionStr))
+ error("Verifying game version failed! (expected: '%s', found: '%s')", _versionString, versionStr);
+}
+
+Language Resource::getLanguage() const {
+ switch (_versionString[1]) {
+ case 'E':
+ return ENGLISH;
+ case 'G':
+ return GERMAN;
+ case 'F':
+ return FRENCH;
+ case 'I':
+ return ITALIAN;
+ case 'S':
+ return SPANISH;
+ case 'H':
+ return HEBREW;
+ default:
+ return ENGLISH;
+ }
+}
+
+bool Resource::readTableFile(const GameVersion *gameVersion) {
+ Common::File tableFile;
+ tableFile.open(_tableFilename);
+ if (tableFile.isOpen() && tableFile.readUint32BE() == 'QTBL') {
+ if (tableFile.readUint32BE() != CURRENT_TBL_VERSION)
+ warning("Incorrect version of queen.tbl, please update it");
+ tableFile.seek(gameVersion->tableOffset);
+ readTableEntries(&tableFile);
+ return true;
+ }
+ return false;
+}
+
+void Resource::readTableCompResource() {
+ if (_resourceFile->readUint32BE() != 'QTBL')
+ error("Invalid table header");
+
+ _resourceFile->read(_versionString, 6);
+ _resourceFile->readByte(); // obsolete
+ _resourceFile->readByte(); // obsolete
+ _compression = _resourceFile->readByte();
+
+ readTableEntries(_resourceFile);
+}
+
+void Resource::readTableEntries(Common::File *file) {
+ _resourceEntries = file->readUint16BE();
+ _resourceTable = new ResourceEntry[_resourceEntries];
+ for (uint16 i = 0; i < _resourceEntries; ++i) {
+ ResourceEntry *re = &_resourceTable[i];
+ file->read(re->filename, 12);
+ re->filename[12] = '\0';
+ re->bundle = file->readByte();
+ re->offset = file->readUint32BE();
+ re->size = file->readUint32BE();
+ }
+}
+
+const GameVersion *Resource::detectGameVersion(uint32 size) const {
+ const GameVersion *pgv = _gameVersions;
+ for (int i = 0; i < VER_COUNT; ++i, ++pgv) {
+ if (pgv->dataFileSize == size) {
+ return pgv;
+ }
+ }
+ return NULL;
+}
+
+Common::File *Resource::giveCompressedSound(const char *filename, uint32 *size) {
+ assert(strstr(filename, ".SB"));
+ Common::File *f = NULL;
+ ResourceEntry *re = resourceEntry(filename);
+ if (re) {
+ if (size != NULL) {
+ *size = re->size;
+ }
+ _resourceFile->seek(re->offset);
+ f = _resourceFile;
+ }
+ return f;
+}
+
+LineReader::LineReader(char *buffer, uint32 bufsize) : _buffer(buffer), _bufSize(bufsize), _current(0) {
+}
+
+LineReader::~LineReader() {
+ delete[] _buffer;
+}
+
+char *LineReader::nextLine() {
+ char *startOfLine = _buffer + _current;
+ char *curPos = startOfLine;
+ while (curPos < _buffer + _bufSize && *curPos++ != 0xd) ;
+ *(curPos - 1) = '\0'; // '\r'
+ if (curPos < _buffer + _bufSize) {
+ *curPos = '\0'; // '\n'
+ _current = (curPos - _buffer) + 1;
+ }
+ return startOfLine;
+}
+
+} // End of namespace Queen
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Queen_Restables)
+_GSETPTR(Queen::_resourceTablePEM10, GBVARS_RESOURCETABLEPM10_INDEX, Queen::ResourceEntry, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Queen_Restables)
+_GRELEASEPTR(GBVARS_RESOURCETABLEPM10_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/queen/resource.h b/engines/queen/resource.h
new file mode 100644
index 0000000000..e205490eca
--- /dev/null
+++ b/engines/queen/resource.h
@@ -0,0 +1,169 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENRESOURCE_H
+#define QUEENRESOURCE_H
+
+#include "common/file.h"
+#include "common/util.h"
+#include "queen/defs.h"
+
+namespace Queen {
+
+struct ResourceEntry {
+ char filename[13];
+ uint8 bundle;
+ uint32 offset;
+ uint32 size;
+};
+
+struct GameVersion {
+ char versionString[6];
+ uint32 tableOffset;
+ uint32 dataFileSize;
+};
+
+class LineReader {
+public:
+
+ LineReader(char *buffer, uint32 bufsize);
+ ~LineReader();
+ char *nextLine();
+
+private:
+
+ char *_buffer;
+ uint32 _bufSize;
+ int _current;
+};
+
+class Resource {
+public:
+
+ Resource();
+ ~Resource();
+
+ //! loads the specified from the resource file
+ uint8 *loadFile(const char *filename, uint32 skipBytes = 0, uint32 *size = NULL, bool useMalloc = false);
+
+ //! returns true if the file is present in the resource
+ bool fileExists(const char *filename) const { return resourceEntry(filename) != NULL; }
+
+ //! returns a reference to a sound file
+ Common::File *giveCompressedSound(const char *filename, uint32 *size);
+
+ bool isDemo() const { return !strcmp(_versionString, "PE100"); }
+ bool isInterview() const { return !strcmp(_versionString, "PEint"); }
+ bool isFloppy() const { return _versionString[0] == 'P'; }
+ bool isCD() const { return _versionString[0] == 'C'; }
+
+ //! returns compression type for audio files
+ uint8 compression() const { return _compression; }
+
+ //! returns JAS version string (contains language, platform and version information)
+ const char *JASVersion() const { return _versionString; }
+
+ //! returns language of the game
+ Language getLanguage() const;
+
+ enum Version {
+ VER_ENG_FLOPPY = 0,
+ VER_ENG_TALKIE = 1,
+ VER_FRE_FLOPPY = 2,
+ VER_FRE_TALKIE = 3,
+ VER_GER_FLOPPY = 4,
+ VER_GER_TALKIE = 5,
+ VER_ITA_FLOPPY = 6,
+ VER_ITA_TALKIE = 7,
+ VER_SPA_TALKIE = 8,
+ VER_HEB_TALKIE = 9,
+ VER_DEMO_PCGAMES = 10,
+ VER_DEMO = 11,
+ VER_INTERVIEW = 12,
+
+ VER_COUNT = 13
+ };
+
+ enum {
+ CURRENT_TBL_VERSION = 1
+ };
+
+ enum {
+ JAS_VERSION_OFFSET_DEMO = 0x119A8,
+ JAS_VERSION_OFFSET_INTV = 0xCF8,
+ JAS_VERSION_OFFSET_PC = 0x12484
+ };
+
+protected:
+
+ Common::File *_resourceFile;
+
+ //! compression type for audio files
+ uint8 _compression;
+
+ //! JAS version string of the game
+ char _versionString[6];
+
+ //! number of entries in resource table
+ uint32 _resourceEntries;
+
+ ResourceEntry *_resourceTable;
+
+ //! look for a normal queen version (ie. queen.1)
+ bool findNormalVersion();
+
+ //! look for a compressed/rebuilt queen version (ie. queen.1c)
+ bool findCompressedVersion();
+
+ //! verify the version of the selected game
+ void checkJASVersion();
+
+ //! returns a reference to the ReseourceEntry for the specified filename
+ ResourceEntry *resourceEntry(const char *filename) const;
+
+ //! extarct the resource table for the specified game version
+ bool readTableFile(const GameVersion *gameVersion);
+
+ //! reads the resource table from a rebuilt datafile (ie. queen.1c)
+ void readTableCompResource();
+
+ //! read the resource table from the specified file
+ void readTableEntries(Common::File *file);
+
+ //! detect game version based on queen.1 datafile size
+ const GameVersion *detectGameVersion(uint32 size) const;
+
+ //! resource table filename (queen.tbl)
+ static const char *_tableFilename;
+
+ //! known FOTAQ versions
+ static const GameVersion _gameVersions[];
+
+#ifndef PALMOS_68K
+ //! resource table for english floppy version
+ static ResourceEntry _resourceTablePEM10[];
+#endif
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/restables.cpp b/engines/queen/restables.cpp
new file mode 100644
index 0000000000..8cebaccf49
--- /dev/null
+++ b/engines/queen/restables.cpp
@@ -0,0 +1,1108 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "queen/resource.h"
+
+namespace Queen {
+
+#ifndef PALMOS_68K
+//English Floppy Version
+ResourceEntry Resource::_resourceTablePEM10[] = {
+ { "1000SSSS.SB", 1, 0x00000000, 0x000027fe },
+ { "1001SSSS.SB", 1, 0x000027fe, 0x00007af8 },
+ { "1002SSSS.SB", 1, 0x0000a2f6, 0x000049e2 },
+ { "1003SSSS.SB", 1, 0x0000ecd8, 0x00001d42 },
+ { "1004SSSS.SB", 1, 0x00010a1a, 0x00001a1c },
+ { "1005SSSS.SB", 1, 0x00012436, 0x00001a8a },
+ { "1006SSSS.SB", 1, 0x00013ec0, 0x00009d41 },
+ { "1007SSSS.SB", 1, 0x0001dc01, 0x00001372 },
+ { "1008SSSS.SB", 1, 0x0001ef73, 0x00002e4a },
+ { "1009SSSS.SB", 1, 0x00021dbd, 0x0000220c },
+ { "1010SSSS.SB", 1, 0x00023fc9, 0x00003b1e },
+ { "1011SSSS.SB", 1, 0x00027ae7, 0x00000dd8 },
+ { "1012SSSS.SB", 1, 0x000288bf, 0x0000444c },
+ { "1013SSSS.SB", 1, 0x0002cd0b, 0x00007e66 },
+ { "1014SSSS.SB", 1, 0x00034b71, 0x00006e14 },
+ { "1015SSSS.SB", 1, 0x0003b985, 0x0000760c },
+ { "1016SSSS.SB", 1, 0x00042f91, 0x00004f8b },
+ { "1017SSSS.SB", 1, 0x00047f1c, 0x00004848 },
+ { "1018SSSS.SB", 1, 0x0004c764, 0x00007e94 },
+ { "1019SSSS.SB", 1, 0x000545f8, 0x00003a70 },
+ { "101SSSSS.SB", 1, 0x00058068, 0x0000191a },
+ { "1020SSSS.SB", 1, 0x00059982, 0x00004d90 },
+ { "1021SSSS.SB", 1, 0x0005e712, 0x00003dcc },
+ { "1023SSSS.SB", 1, 0x000624de, 0x00003d7f },
+ { "1024SSSS.SB", 1, 0x0006625d, 0x00004f8a },
+ { "1025SSSS.SB", 1, 0x0006b1e7, 0x00006488 },
+ { "1026SSSS.SB", 1, 0x0007166f, 0x00002022 },
+ { "1027SSSS.SB", 1, 0x00073691, 0x00009e76 },
+ { "1028SSSS.SB", 1, 0x0007d507, 0x0001b37c },
+ { "1029SSSS.SB", 1, 0x00098883, 0x0000ce2c },
+ { "1030SSSS.SB", 1, 0x000a56af, 0x0001e6e4 },
+ { "1031SSSS.SB", 1, 0x000c3d93, 0x00011532 },
+ { "1032SSSS.SB", 1, 0x000d52c5, 0x000034d4 },
+ { "1033SSSS.SB", 1, 0x000d8799, 0x00002de6 },
+ { "1034SSSS.SB", 1, 0x000db57f, 0x000099a1 },
+ { "103ASSSS.SB", 1, 0x000e4f20, 0x00005040 },
+ { "103SSSSS.SB", 1, 0x000e9f60, 0x00006a94 },
+ { "105ASSSS.SB", 1, 0x000f09f4, 0x00001d04 },
+ { "105SSSSS.SB", 1, 0x000f26f8, 0x000024de },
+ { "106SSSSS.SB", 1, 0x000f4bd6, 0x00000ac4 },
+ { "109SSSSS.SB", 1, 0x000f569a, 0x00000d96 },
+ { "10SSSSSS.SB", 1, 0x000f6430, 0x000013f6 },
+ { "110SSSSS.SB", 1, 0x000f7826, 0x00000c96 },
+ { "111SSSSS.SB", 1, 0x000f84bc, 0x00000f72 },
+ { "112SSSSS.SB", 1, 0x000f942e, 0x00000f1a },
+ { "113SSSSS.SB", 1, 0x000fa348, 0x00003f5e },
+ { "114ASSSS.SB", 1, 0x000fe2a6, 0x00001e54 },
+ { "115SSSSS.SB", 1, 0x001000fa, 0x00002580 },
+ { "116BSSSS.SB", 1, 0x0010267a, 0x00002350 },
+ { "119SSSSS.SB", 1, 0x001049ca, 0x00003808 },
+ { "11SSSSSS.SB", 1, 0x001081d2, 0x0000157e },
+ { "120SSSSS.SB", 1, 0x00109750, 0x00002be4 },
+ { "121SSSSS.SB", 1, 0x0010c334, 0x00001340 },
+ { "122SSSSS.SB", 1, 0x0010d674, 0x0000173e },
+ { "123ASSSS.SB", 1, 0x0010edb2, 0x00009e9d },
+ { "123BSSSS.SB", 1, 0x00118c4f, 0x0000f613 },
+ { "125SSSSS.SB", 1, 0x00128262, 0x0000e628 },
+ { "126SSSSS.SB", 1, 0x0013688a, 0x0000372e },
+ { "127SSSSS.SB", 1, 0x00139fb8, 0x0000ff1e },
+ { "128SSSSS.SB", 1, 0x00149ed6, 0x00000e34 },
+ { "129SSSSS.SB", 1, 0x0014ad0a, 0x00000b02 },
+ { "130SSSSS.SB", 1, 0x0014b80c, 0x00000a10 },
+ { "131ASSSS.SB", 1, 0x0014c21c, 0x000022d4 },
+ { "132CSSSS.SB", 1, 0x0014e4f0, 0x000094c3 },
+ { "132SSSSS.SB", 1, 0x001579b3, 0x00006183 },
+ { "133SSSSS.SB", 1, 0x0015db36, 0x00006a13 },
+ { "134SSSSS.SB", 1, 0x00164549, 0x00004ea3 },
+ { "135SSSSS.SB", 1, 0x001693ec, 0x000017c8 },
+ { "136SSSSS.SB", 1, 0x0016abb4, 0x000004a0 },
+ { "137ASSSS.SB", 1, 0x0016b054, 0x00001826 },
+ { "137BSSSS.SB", 1, 0x0016c87a, 0x00001d46 },
+ { "138BSSSS.SB", 1, 0x0016e5c0, 0x000065f9 },
+ { "138SSSSS.SB", 1, 0x00174bb9, 0x000053c3 },
+ { "13SSSSSS.SB", 1, 0x00179f7c, 0x00001f32 },
+ { "14SSSSSS.SB", 1, 0x0017beae, 0x00004921 },
+ { "15SSSSSS.SB", 1, 0x001807cf, 0x000007aa },
+ { "17SSSSSS.SB", 1, 0x00180f79, 0x00005080 },
+ { "18SSSSSS.SB", 1, 0x00185ff9, 0x000015e2 },
+ { "21CSSSSS.SB", 1, 0x001875db, 0x000048ec },
+ { "21SSSSSS.SB", 1, 0x0018bec7, 0x0000bb40 },
+ { "24SSSSSS.SB", 1, 0x00197a07, 0x000023fc },
+ { "25SSSSSS.SB", 1, 0x00199e03, 0x000016d8 },
+ { "26SSSSSS.SB", 1, 0x0019b4db, 0x000049dd },
+ { "27SSSSSS.SB", 1, 0x0019feb8, 0x000010a0 },
+ { "29SSSSSS.SB", 1, 0x001a0f58, 0x00004e50 },
+ { "33SSSSSS.SB", 1, 0x001a5da8, 0x00005218 },
+ { "35SSSSSS.SB", 1, 0x001aafc0, 0x00002c6c },
+ { "36SSSSSS.SB", 1, 0x001adc2c, 0x000031d2 },
+ { "37SSSSSS.SB", 1, 0x001b0dfe, 0x0000197a },
+ { "38SSSSSS.SB", 1, 0x001b2778, 0x00002162 },
+ { "3SSSSSSS.SB", 1, 0x001b48da, 0x00000d04 },
+ { "40SSSSSS.SB", 1, 0x001b55de, 0x00000268 },
+ { "41BSSSSS.SB", 1, 0x001b5846, 0x000005fe },
+ { "42BSSSSS.SB", 1, 0x001b5e44, 0x00000308 },
+ { "44SSSSSS.SB", 1, 0x001b614c, 0x000052c0 },
+ { "48SSSSSS.SB", 1, 0x001bb40c, 0x000010a8 },
+ { "49SSSSSS.SB", 1, 0x001bc4b4, 0x00001dd4 },
+ { "4SSSSSSS.SB", 1, 0x001be288, 0x000009d2 },
+ { "50SSSSSS.SB", 1, 0x001bec5a, 0x00003f8a },
+ { "51SSSSSS.SB", 1, 0x001c2be4, 0x000015da },
+ { "52SSSSSS.SB", 1, 0x001c41be, 0x0000125a },
+ { "55BSSSSS.SB", 1, 0x001c5418, 0x00003d7f },
+ { "55SSSSSS.SB", 1, 0x001c9197, 0x00004508 },
+ { "56SSSSSS.SB", 1, 0x001cd69f, 0x0000520b },
+ { "58SSSSSS.SB", 1, 0x001d28aa, 0x00003399 },
+ { "59SSSSSS.SB", 1, 0x001d5c43, 0x000032b8 },
+ { "5SSSSSSS.SB", 1, 0x001d8efb, 0x00004ae9 },
+ { "60BSSSSS.SB", 1, 0x001dd9e4, 0x000050f2 },
+ { "60SSSSSS.SB", 1, 0x001e2ad6, 0x00003c57 },
+ { "61SSSSSS.SB", 1, 0x001e672d, 0x0000513d },
+ { "64SSSSSS.SB", 1, 0x001eb86a, 0x00005a98 },
+ { "68SSSSSS.SB", 1, 0x001f1302, 0x00003e85 },
+ { "6SSSSSSS.SB", 1, 0x001f5187, 0x00001650 },
+ { "70SSSSSS.SB", 1, 0x001f67d7, 0x00009645 },
+ { "71SSSSSS.SB", 1, 0x001ffe1c, 0x00000fa3 },
+ { "73ASSSSS.SB", 1, 0x00200dbf, 0x00008812 },
+ { "73SSSSSS.SB", 1, 0x002095d1, 0x00006706 },
+ { "74ASSSSS.SB", 1, 0x0020fcd7, 0x000029b2 },
+ { "75SSSSSS.SB", 1, 0x00212689, 0x00000920 },
+ { "76SSSSSS.SB", 1, 0x00212fa9, 0x00004ef8 },
+ { "77SSSSSS.SB", 1, 0x00217ea1, 0x00003358 },
+ { "79SSSSSS.SB", 1, 0x0021b1f9, 0x000016a8 },
+ { "7SSSSSSS.SB", 1, 0x0021c8a1, 0x000010d4 },
+ { "80SSSSSS.SB", 1, 0x0021d975, 0x0000441e },
+ { "81SSSSSS.SB", 1, 0x00221d93, 0x0000517f },
+ { "83SSSSSS.SB", 1, 0x00226f12, 0x000043e3 },
+ { "84SSSSSS.SB", 1, 0x0022b2f5, 0x00003baa },
+ { "85SSSSSS.SB", 1, 0x0022ee9f, 0x00004470 },
+ { "87SSSSSS.SB", 1, 0x0023330f, 0x00005113 },
+ { "88SSSSSS.SB", 1, 0x00238422, 0x00005275 },
+ { "89SSSSSS.SB", 1, 0x0023d697, 0x00001a69 },
+ { "93SSSSSS.SB", 1, 0x0023f100, 0x00000470 },
+ { "94SSSSSS.SB", 1, 0x0023f570, 0x000051e4 },
+ { "95SSSSSS.SB", 1, 0x00244754, 0x0000343b },
+ { "96SSSSSS.SB", 1, 0x00247b8f, 0x00005110 },
+ { "97SSSSSS.SB", 1, 0x0024cc9f, 0x00004972 },
+ { "AMAZON.ACT", 1, 0x00251611, 0x0000a97a },
+ { "AND1.DOG", 1, 0x0025bf8b, 0x000009ca },
+ { "ANDERSON.ACT", 1, 0x0025c955, 0x00007c0a },
+ { "ANDSON2.ACT", 1, 0x0026455f, 0x00007c0a },
+ { "ANDSON_E.ACT", 1, 0x0026c169, 0x00003c42 },
+ { "APE.ACT", 1, 0x0026fdab, 0x000084cd },
+ { "APE.DOG", 1, 0x00278278, 0x000011d4 },
+ { "APE2.DOG", 1, 0x0027944c, 0x000008da },
+ { "APE3.DOG", 1, 0x00279d26, 0x00000788 },
+ { "AQ.RL", 1, 0x0027a4ae, 0x00063f3a },
+ { "AQ8.RL", 1, 0x002de3e8, 0x000167f8 },
+ { "AQB2.MUS", 1, 0x002f4be0, 0x00039972 },
+ { "AQBANK.MUS", 1, 0x0032e552, 0x0004fe89 },
+ { "AQBANK.RL", 1, 0x0037e3db, 0x000059e9 },
+ { "AZURA_E.ACT", 1, 0x00383dc4, 0x0000425a },
+ { "AZURA_H.ACT", 1, 0x0038801e, 0x00008a7a },
+ { "AZURA_H.BBK", 1, 0x00390a98, 0x0001a712 },
+ { "AZURA_H.PCX", 1, 0x003ab1aa, 0x0000accb },
+ { "B1.BBK", 1, 0x003b5e75, 0x000051fb },
+ { "B1.LUM", 1, 0x003bb070, 0x00000018 },
+ { "B1.MSK", 1, 0x003bb088, 0x00001f40 },
+ { "B1.PCX", 1, 0x003bcfc8, 0x000162a8 },
+ { "B2.BBK", 1, 0x003d3270, 0x000034b1 },
+ { "B2.LUM", 1, 0x003d6721, 0x00000018 },
+ { "B2.MSK", 1, 0x003d6739, 0x00001f40 },
+ { "B2.PCX", 1, 0x003d8679, 0x0000a521 },
+ { "BAT.SAM", 1, 0x003e2b9a, 0x00009d9a },
+ { "BEETLE.ACT", 1, 0x003ec934, 0x00001e42 },
+ { "BIGAM.ACT", 1, 0x003ee776, 0x00002d12 },
+ { "BLANK000.SB", 1, 0x003f1488, 0x00000076 },
+ { "BLUEP.CUT", 1, 0x003f14fe, 0x00000148 },
+ { "BOB1.DOG", 1, 0x003f1646, 0x000010bc },
+ { "BOB2.DOG", 1, 0x003f2702, 0x00000e5a },
+ { "BOB3.DOG", 1, 0x003f355c, 0x00000df8 },
+ { "BOB4.DOG", 1, 0x003f4354, 0x00000dea },
+ { "BOB5.DOG", 1, 0x003f513e, 0x00000bf0 },
+ { "BUD.ACT", 1, 0x003f5d2e, 0x00006582 },
+ { "BUD1.DOG", 1, 0x003fc2b0, 0x0000129c },
+ { "BUD2.DOG", 1, 0x003fd54c, 0x00000c0e },
+ { "C1.BBK", 1, 0x003fe15a, 0x000026fd },
+ { "C1.LUM", 1, 0x00400857, 0x00000018 },
+ { "C1.MSK", 1, 0x0040086f, 0x00001f40 },
+ { "C1.PCX", 1, 0x004027af, 0x00004888 },
+ { "C10.BBK", 1, 0x00407037, 0x0003949f },
+ { "C10.PCX", 1, 0x004404d6, 0x0000e6fd },
+ { "C100A.CUT", 1, 0x0044ebd3, 0x000003be },
+ { "C100B.CUT", 1, 0x0044ef91, 0x00000346 },
+ { "C100C.CUT", 1, 0x0044f2d7, 0x0000019a },
+ { "C100D.CUT", 1, 0x0044f471, 0x00000774 },
+ { "C101A.CUT", 1, 0x0044fbe5, 0x0000021a },
+ { "C101B.CUT", 1, 0x0044fdff, 0x000000e6 },
+ { "C101C.CUT", 1, 0x0044fee5, 0x00000200 },
+ { "C101D.CUT", 1, 0x004500e5, 0x00000144 },
+ { "C101E.CUT", 1, 0x00450229, 0x00000144 },
+ { "C102A.CUT", 1, 0x0045036d, 0x0000040e },
+ { "C102B.CUT", 1, 0x0045077b, 0x0000040e },
+ { "C102C.CUT", 1, 0x00450b89, 0x0000047e },
+ { "C102D.CUT", 1, 0x00451007, 0x000003b8 },
+ { "C102E.CUT", 1, 0x004513bf, 0x0000037e },
+ { "C103A.CUT", 1, 0x0045173d, 0x000000b4 },
+ { "C103B.CUT", 1, 0x004517f1, 0x00000104 },
+ { "C103C.CUT", 1, 0x004518f5, 0x00000090 },
+ { "C103D.CUT", 1, 0x00451985, 0x00000070 },
+ { "C103E.CUT", 1, 0x004519f5, 0x000000da },
+ { "C103F.CUT", 1, 0x00451acf, 0x0000084a },
+ { "C103G.CUT", 1, 0x00452319, 0x0000068e },
+ { "C103H.CUT", 1, 0x004529a7, 0x000003be },
+ { "C103I.CUT", 1, 0x00452d65, 0x000001f2 },
+ { "C103J.CUT", 1, 0x00452f57, 0x0000041c },
+ { "C103K.CUT", 1, 0x00453373, 0x0000016a },
+ { "C103L.CUT", 1, 0x004534dd, 0x00000458 },
+ { "C11.BBK", 1, 0x00453935, 0x0000bf94 },
+ { "C11.PCX", 1, 0x0045f8c9, 0x0000c01a },
+ { "C11A.CUT", 1, 0x0046b8e3, 0x00000346 },
+ { "C12A.CUT", 1, 0x0046bc29, 0x000004d0 },
+ { "C13A.CUT", 1, 0x0046c0f9, 0x00000164 },
+ { "C13B.CUT", 1, 0x0046c25d, 0x0000016c },
+ { "C13C.CUT", 1, 0x0046c3c9, 0x000001fa },
+ { "C13D.CUT", 1, 0x0046c5c3, 0x00000174 },
+ { "C13E.CUT", 1, 0x0046c737, 0x000001d0 },
+ { "C13F.CUT", 1, 0x0046c907, 0x000002d6 },
+ { "C13G.CUT", 1, 0x0046cbdd, 0x00000152 },
+ { "C13H.CUT", 1, 0x0046cd2f, 0x00000116 },
+ { "C13I.CUT", 1, 0x0046ce45, 0x00000080 },
+ { "C13J.CUT", 1, 0x0046cec5, 0x00000272 },
+ { "C13K.CUT", 1, 0x0046d137, 0x00000192 },
+ { "C13L.CUT", 1, 0x0046d2c9, 0x000001dc },
+ { "C13M.CUT", 1, 0x0046d4a5, 0x00000468 },
+ { "C13N.CUT", 1, 0x0046d90d, 0x0000015e },
+ { "C14A.CUT", 1, 0x0046da6b, 0x000002fe },
+ { "C14B.CUT", 1, 0x0046dd69, 0x00000126 },
+ { "C14C.CUT", 1, 0x0046de8f, 0x00000150 },
+ { "C14D.CUT", 1, 0x0046dfdf, 0x00000108 },
+ { "C15A.CUT", 1, 0x0046e0e7, 0x00000264 },
+ { "C15B.CUT", 1, 0x0046e34b, 0x00000136 },
+ { "C15C.CUT", 1, 0x0046e481, 0x00000380 },
+ { "C15D.CUT", 1, 0x0046e801, 0x000002d2 },
+ { "C15E.CUT", 1, 0x0046ead3, 0x000000f4 },
+ { "C16A.CUT", 1, 0x0046ebc7, 0x000005d6 },
+ { "C16B.CUT", 1, 0x0046f19d, 0x0000057e },
+ { "C17A.CUT", 1, 0x0046f71b, 0x00000156 },
+ { "C18A.CUT", 1, 0x0046f871, 0x00000a60 },
+ { "C18B.CUT", 1, 0x004702d1, 0x000012b8 },
+ { "C18C.CUT", 1, 0x00471589, 0x00001202 },
+ { "C18D.CUT", 1, 0x0047278b, 0x000009fa },
+ { "C18E.CUT", 1, 0x00473185, 0x000009e4 },
+ { "C19A.CUT", 1, 0x00473b69, 0x00001076 },
+ { "C19B.CUT", 1, 0x00474bdf, 0x0000015c },
+ { "C1A.CUT", 1, 0x00474d3b, 0x0000034e },
+ { "C2.BBK", 1, 0x00475089, 0x00005908 },
+ { "C2.LUM", 1, 0x0047a991, 0x00000018 },
+ { "C2.MSK", 1, 0x0047a9a9, 0x00001f40 },
+ { "C2.PCX", 1, 0x0047c8e9, 0x00007f3a },
+ { "C2.SAM", 1, 0x00484823, 0x000147ac },
+ { "C20A.CUT", 1, 0x00498fcf, 0x00000500 },
+ { "C20B.CUT", 1, 0x004994cf, 0x00000168 },
+ { "C20C.CUT", 1, 0x00499637, 0x00000170 },
+ { "C20D.CUT", 1, 0x004997a7, 0x00000388 },
+ { "C20E.CUT", 1, 0x00499b2f, 0x00000394 },
+ { "C20F.CUT", 1, 0x00499ec3, 0x0000073a },
+ { "C20G.CUT", 1, 0x0049a5fd, 0x0000029c },
+ { "C21A.CUT", 1, 0x0049a899, 0x000000da },
+ { "C21B.CUT", 1, 0x0049a973, 0x000000ee },
+ { "C21C.CUT", 1, 0x0049aa61, 0x0000025e },
+ { "C21D.CUT", 1, 0x0049acbf, 0x000002ec },
+ { "C21E.CUT", 1, 0x0049afab, 0x00000602 },
+ { "C21F.CUT", 1, 0x0049b5ad, 0x000003e2 },
+ { "C21G.CUT", 1, 0x0049b98f, 0x00000136 },
+ { "C21H.CUT", 1, 0x0049bac5, 0x00000172 },
+ { "C21I.CUT", 1, 0x0049bc37, 0x0000024c },
+ { "C21J.CUT", 1, 0x0049be83, 0x00000122 },
+ { "C21K.CUT", 1, 0x0049bfa5, 0x00000584 },
+ { "C21L.CUT", 1, 0x0049c529, 0x00000522 },
+ { "C21M.CUT", 1, 0x0049ca4b, 0x000001ea },
+ { "C21N.CUT", 1, 0x0049cc35, 0x00000610 },
+ { "C21O.CUT", 1, 0x0049d245, 0x000000f4 },
+ { "C21P.CUT", 1, 0x0049d339, 0x00000150 },
+ { "C21Q.CUT", 1, 0x0049d489, 0x000002ec },
+ { "C21R.CUT", 1, 0x0049d775, 0x00000106 },
+ { "C21S.CUT", 1, 0x0049d87b, 0x0000012a },
+ { "C21T.CUT", 1, 0x0049d9a5, 0x0000015e },
+ { "C21U.CUT", 1, 0x0049db03, 0x000000c6 },
+ { "C22A.CUT", 1, 0x0049dbc9, 0x00000156 },
+ { "C22B.CUT", 1, 0x0049dd1f, 0x000000fc },
+ { "C22C.CUT", 1, 0x0049de1b, 0x00000166 },
+ { "C24A.CUT", 1, 0x0049df81, 0x000000ec },
+ { "C24B.CUT", 1, 0x0049e06d, 0x000005ca },
+ { "C25A.CUT", 1, 0x0049e637, 0x000002d0 },
+ { "C25B.CUT", 1, 0x0049e907, 0x000002e4 },
+ { "C25C.CUT", 1, 0x0049ebeb, 0x0000023e },
+ { "C25D.CUT", 1, 0x0049ee29, 0x00000182 },
+ { "C25E.CUT", 1, 0x0049efab, 0x00000126 },
+ { "C25F.CUT", 1, 0x0049f0d1, 0x0000017c },
+ { "C25G.CUT", 1, 0x0049f24d, 0x000001e2 },
+ { "C25H.CUT", 1, 0x0049f42f, 0x00000218 },
+ { "C25I.CUT", 1, 0x0049f647, 0x000001da },
+ { "C26A.CUT", 1, 0x0049f821, 0x0000030e },
+ { "C26B.CUT", 1, 0x0049fb2f, 0x000000be },
+ { "C26C.CUT", 1, 0x0049fbed, 0x000001a4 },
+ { "C2A.CUT", 1, 0x0049fd91, 0x000008d0 },
+ { "C2B.CUT", 1, 0x004a0661, 0x000004b8 },
+ { "C2C.CUT", 1, 0x004a0b19, 0x0000023e },
+ { "C3.BBK", 1, 0x004a0d57, 0x00006875 },
+ { "C3.LUM", 1, 0x004a75cc, 0x00000018 },
+ { "C3.MSK", 1, 0x004a75e4, 0x00001f40 },
+ { "C3.PCX", 1, 0x004a9524, 0x0000c40c },
+ { "C3.SAM", 1, 0x004b5930, 0x00011c72 },
+ { "C30A.CUT", 1, 0x004c75a2, 0x00000254 },
+ { "C30B.CUT", 1, 0x004c77f6, 0x000003c4 },
+ { "C30C.CUT", 1, 0x004c7bba, 0x00000722 },
+ { "C30D.CUT", 1, 0x004c82dc, 0x00000206 },
+ { "C30E.CUT", 1, 0x004c84e2, 0x00000976 },
+ { "C30F.CUT", 1, 0x004c8e58, 0x0000010e },
+ { "C30G.CUT", 1, 0x004c8f66, 0x000001e6 },
+ { "C30H.CUT", 1, 0x004c914c, 0x0000014c },
+ { "C31A.CUT", 1, 0x004c9298, 0x0000020c },
+ { "C31B.CUT", 1, 0x004c94a4, 0x00000596 },
+ { "C31C.CUT", 1, 0x004c9a3a, 0x000000e2 },
+ { "C31D.CUT", 1, 0x004c9b1c, 0x000004e4 },
+ { "C31E.CUT", 1, 0x004ca000, 0x000000ee },
+ { "C31F.CUT", 1, 0x004ca0ee, 0x0000010e },
+ { "C32A.CUT", 1, 0x004ca1fc, 0x000000ac },
+ { "C32B.CUT", 1, 0x004ca2a8, 0x0000010c },
+ { "C32C.CUT", 1, 0x004ca3b4, 0x000000e8 },
+ { "C35A.CUT", 1, 0x004ca49c, 0x0000042a },
+ { "C35B.CUT", 1, 0x004ca8c6, 0x000001c0 },
+ { "C36A.CUT", 1, 0x004caa86, 0x0000078c },
+ { "C39A.CUT", 1, 0x004cb212, 0x00000ed4 },
+ { "C3A.CUT", 1, 0x004cc0e6, 0x00000610 },
+ { "C3B.CUT", 1, 0x004cc6f6, 0x000000a0 },
+ { "C3C.CUT", 1, 0x004cc796, 0x000005d8 },
+ { "C3D.CUT", 1, 0x004ccd6e, 0x00000344 },
+ { "C3E.CUT", 1, 0x004cd0b2, 0x0000013a },
+ { "C3F.CUT", 1, 0x004cd1ec, 0x000000e0 },
+ { "C3G.CUT", 1, 0x004cd2cc, 0x00000102 },
+ { "C3H.CUT", 1, 0x004cd3ce, 0x00000120 },
+ { "C4.BBK", 1, 0x004cd4ee, 0x00009420 },
+ { "C4.LUM", 1, 0x004d690e, 0x00000018 },
+ { "C4.MSK", 1, 0x004d6926, 0x00001f40 },
+ { "C4.PCX", 1, 0x004d8866, 0x00009487 },
+ { "C4.SAM", 1, 0x004e1ced, 0x00002754 },
+ { "C40A.CUT", 1, 0x004e4441, 0x0000094a },
+ { "C40B.CUT", 1, 0x004e4d8b, 0x000002c2 },
+ { "C41A.CUT", 1, 0x004e504d, 0x00000b84 },
+ { "C41B.CUT", 1, 0x004e5bd1, 0x00001ba0 },
+ { "C41C.CUT", 1, 0x004e7771, 0x00000170 },
+ { "C41D.CUT", 1, 0x004e78e1, 0x0000025c },
+ { "C41E.CUT", 1, 0x004e7b3d, 0x000001b8 },
+ { "C41F.CUT", 1, 0x004e7cf5, 0x0000009c },
+ { "C41G.CUT", 1, 0x004e7d91, 0x000000fe },
+ { "C41H.CUT", 1, 0x004e7e8f, 0x000000ba },
+ { "C42A.CUT", 1, 0x004e7f49, 0x000003ce },
+ { "C42B.CUT", 1, 0x004e8317, 0x00000802 },
+ { "C42C.CUT", 1, 0x004e8b19, 0x000001ae },
+ { "C42D.CUT", 1, 0x004e8cc7, 0x0000010e },
+ { "C42E.CUT", 1, 0x004e8dd5, 0x00000106 },
+ { "C42F.CUT", 1, 0x004e8edb, 0x00000166 },
+ { "C44A.CUT", 1, 0x004e9041, 0x000004f8 },
+ { "C44B.CUT", 1, 0x004e9539, 0x0000079e },
+ { "C44C.CUT", 1, 0x004e9cd7, 0x0000030a },
+ { "C45A.CUT", 1, 0x004e9fe1, 0x000000f8 },
+ { "C45B.CUT", 1, 0x004ea0d9, 0x000000f8 },
+ { "C45C.CUT", 1, 0x004ea1d1, 0x000000f8 },
+ { "C45D.CUT", 1, 0x004ea2c9, 0x000000f8 },
+ { "C45E.CUT", 1, 0x004ea3c1, 0x00000186 },
+ { "C46A.CUT", 1, 0x004ea547, 0x000000f8 },
+ { "C46B.CUT", 1, 0x004ea63f, 0x000000f8 },
+ { "C46C.CUT", 1, 0x004ea737, 0x000000f8 },
+ { "C46D.CUT", 1, 0x004ea82f, 0x000000f8 },
+ { "C47A.CUT", 1, 0x004ea927, 0x00000640 },
+ { "C48A.CUT", 1, 0x004eaf67, 0x00000656 },
+ { "C48C.CUT", 1, 0x004eb5bd, 0x00000516 },
+ { "C49B.CUT", 1, 0x004ebad3, 0x00000398 },
+ { "C49C.CUT", 1, 0x004ebe6b, 0x00000132 },
+ { "C49D.CUT", 1, 0x004ebf9d, 0x000004e4 },
+ { "C4A.CUT", 1, 0x004ec481, 0x00000094 },
+ { "C4B.CUT", 1, 0x004ec515, 0x000003f4 },
+ { "C5.BBK", 1, 0x004ec909, 0x00004171 },
+ { "C5.LUM", 1, 0x004f0a7a, 0x00000018 },
+ { "C5.MSK", 1, 0x004f0a92, 0x00001f40 },
+ { "C5.PCX", 1, 0x004f29d2, 0x000099f2 },
+ { "C5.SAM", 1, 0x004fc3c4, 0x00003016 },
+ { "C50A.CUT", 1, 0x004ff3da, 0x000004f2 },
+ { "C50B.CUT", 1, 0x004ff8cc, 0x000001f8 },
+ { "C50C.CUT", 1, 0x004ffac4, 0x0000086e },
+ { "C50D.CUT", 1, 0x00500332, 0x000000e2 },
+ { "C50E.CUT", 1, 0x00500414, 0x00000618 },
+ { "C50F.CUT", 1, 0x00500a2c, 0x000003b8 },
+ { "C50G.CUT", 1, 0x00500de4, 0x000008da },
+ { "C50H.CUT", 1, 0x005016be, 0x000000ba },
+ { "C50I.CUT", 1, 0x00501778, 0x000009d4 },
+ { "C50J.CUT", 1, 0x0050214c, 0x000000f2 },
+ { "C51A.CUT", 1, 0x0050223e, 0x0000080e },
+ { "C51B.CUT", 1, 0x00502a4c, 0x000001d8 },
+ { "C51C.CUT", 1, 0x00502c24, 0x000001d8 },
+ { "C51D.CUT", 1, 0x00502dfc, 0x000000ec },
+ { "C53A.CUT", 1, 0x00502ee8, 0x00000566 },
+ { "C53B.CUT", 1, 0x0050344e, 0x0000018a },
+ { "C54A.CUT", 1, 0x005035d8, 0x0000028c },
+ { "C55A.CUT", 1, 0x00503864, 0x000006c8 },
+ { "C56A.CUT", 1, 0x00503f2c, 0x000003ba },
+ { "C56B.CUT", 1, 0x005042e6, 0x00000678 },
+ { "C58A.CUT", 1, 0x0050495e, 0x000001cc },
+ { "C59A.CUT", 1, 0x00504b2a, 0x0000014a },
+ { "C5A.CUT", 1, 0x00504c74, 0x0000040c },
+ { "C5C.CUT", 1, 0x00505080, 0x0000050c },
+ { "C6.BBK", 1, 0x0050558c, 0x0000711b },
+ { "C6.LUM", 1, 0x0050c6a7, 0x00000018 },
+ { "C6.MSK", 1, 0x0050c6bf, 0x00001f40 },
+ { "C6.PCX", 1, 0x0050e5ff, 0x0000c6c0 },
+ { "C6.SAM", 1, 0x0051acbf, 0x00004a87 },
+ { "C60A.CUT", 1, 0x0051f746, 0x00000170 },
+ { "C61A.CUT", 1, 0x0051f8b6, 0x00000170 },
+ { "C62A.CUT", 1, 0x0051fa26, 0x00000dde },
+ { "C62B.CUT", 1, 0x00520804, 0x00000268 },
+ { "C62C.CUT", 1, 0x00520a6c, 0x00000164 },
+ { "C62D.CUT", 1, 0x00520bd0, 0x000002a2 },
+ { "C63A.CUT", 1, 0x00520e72, 0x000002d0 },
+ { "C63B.CUT", 1, 0x00521142, 0x0000098e },
+ { "C63C.CUT", 1, 0x00521ad0, 0x000005d8 },
+ { "C63D.CUT", 1, 0x005220a8, 0x00000194 },
+ { "C63E.CUT", 1, 0x0052223c, 0x00000336 },
+ { "C63F.CUT", 1, 0x00522572, 0x0000041a },
+ { "C63G.CUT", 1, 0x0052298c, 0x00000170 },
+ { "C63H.CUT", 1, 0x00522afc, 0x0000039a },
+ { "C63I.CUT", 1, 0x00522e96, 0x000003ac },
+ { "C63J.CUT", 1, 0x00523242, 0x000002f0 },
+ { "C63K.CUT", 1, 0x00523532, 0x00000634 },
+ { "C64A.CUT", 1, 0x00523b66, 0x00000128 },
+ { "C66A.CUT", 1, 0x00523c8e, 0x000002e8 },
+ { "C67A.CUT", 1, 0x00523f76, 0x000005b6 },
+ { "C67B.CUT", 1, 0x0052452c, 0x0000054c },
+ { "C69A.CUT", 1, 0x00524a78, 0x00000700 },
+ { "C69B.CUT", 1, 0x00525178, 0x00000670 },
+ { "C69C.CUT", 1, 0x005257e8, 0x00000688 },
+ { "C69D.CUT", 1, 0x00525e70, 0x000006ac },
+ { "C69E.CUT", 1, 0x0052651c, 0x000009cc },
+ { "C69F.CUT", 1, 0x00526ee8, 0x00000aa2 },
+ { "C69G.CUT", 1, 0x0052798a, 0x000019ac },
+ { "C69H.CUT", 1, 0x00529336, 0x0000075a },
+ { "C69I.CUT", 1, 0x00529a90, 0x000003f0 },
+ { "C69J.CUT", 1, 0x00529e80, 0x0000008a },
+ { "C69K.CUT", 1, 0x00529f0a, 0x000005c8 },
+ { "C69L.CUT", 1, 0x0052a4d2, 0x0000062a },
+ { "C69M.CUT", 1, 0x0052aafc, 0x000005ba },
+ { "C69N.CUT", 1, 0x0052b0b6, 0x0000012c },
+ { "C69O.CUT", 1, 0x0052b1e2, 0x000001e4 },
+ { "C69Z.CUT", 1, 0x0052b3c6, 0x000017a4 },
+ { "C6A.CUT", 1, 0x0052cb6a, 0x00000220 },
+ { "C6B.CUT", 1, 0x0052cd8a, 0x000000da },
+ { "C6C.CUT", 1, 0x0052ce64, 0x00000138 },
+ { "C7.BBK", 1, 0x0052cf9c, 0x00013c13 },
+ { "C7.PCX", 1, 0x00540baf, 0x0000a75d },
+ { "C70A.CUT", 1, 0x0054b30c, 0x000002b8 },
+ { "C70B.CUT", 1, 0x0054b5c4, 0x00000384 },
+ { "C70B.SAM", 1, 0x0054b948, 0x00009a4e },
+ { "C70C.CUT", 1, 0x00555396, 0x00000292 },
+ { "C70D.CUT", 1, 0x00555628, 0x00000952 },
+ { "C70E.CUT", 1, 0x00555f7a, 0x0000038c },
+ { "C70F.CUT", 1, 0x00556306, 0x0000034c },
+ { "C70F.SAM", 1, 0x00556652, 0x000076bf },
+ { "C70G.CUT", 1, 0x0055dd11, 0x00000348 },
+ { "C70G.SAM", 1, 0x0055e059, 0x00008d7d },
+ { "C70H.CUT", 1, 0x00566dd6, 0x00000322 },
+ { "C70I.CUT", 1, 0x005670f8, 0x000003d8 },
+ { "C70J.CUT", 1, 0x005674d0, 0x00000184 },
+ { "C70K.CUT", 1, 0x00567654, 0x000002c0 },
+ { "C70L.CUT", 1, 0x00567914, 0x000002c0 },
+ { "C70M.CUT", 1, 0x00567bd4, 0x000002ba },
+ { "C70N.CUT", 1, 0x00567e8e, 0x000002ba },
+ { "C71A.CUT", 1, 0x00568148, 0x00000094 },
+ { "C71B.CUT", 1, 0x005681dc, 0x00000094 },
+ { "C71C.CUT", 1, 0x00568270, 0x000000b2 },
+ { "C72A.CUT", 1, 0x00568322, 0x00000730 },
+ { "C72B.CUT", 1, 0x00568a52, 0x00000632 },
+ { "C72C.CUT", 1, 0x00569084, 0x0000007c },
+ { "C73A.CUT", 1, 0x00569100, 0x0000038a },
+ { "C73B.CUT", 1, 0x0056948a, 0x000002b8 },
+ { "C73C.CUT", 1, 0x00569742, 0x00000192 },
+ { "C73D.CUT", 1, 0x005698d4, 0x000000c8 },
+ { "C73E.CUT", 1, 0x0056999c, 0x00000330 },
+ { "C73F.CUT", 1, 0x00569ccc, 0x00000344 },
+ { "C73G.CUT", 1, 0x0056a010, 0x00000210 },
+ { "C74A.CUT", 1, 0x0056a220, 0x0000075e },
+ { "C74B.CUT", 1, 0x0056a97e, 0x0000018c },
+ { "C74C.CUT", 1, 0x0056ab0a, 0x000001dc },
+ { "C74D.CUT", 1, 0x0056ace6, 0x0000018c },
+ { "C74F.CUT", 1, 0x0056ae72, 0x000000e0 },
+ { "C75B.CUT", 1, 0x0056af52, 0x00000d00 },
+ { "C76A.CUT", 1, 0x0056bc52, 0x00000072 },
+ { "C76B.CUT", 1, 0x0056bcc4, 0x00000f28 },
+ { "C8.BBK", 1, 0x0056cbec, 0x0000b5ce },
+ { "C8.PCX", 1, 0x005781ba, 0x0000c31f },
+ { "C8A.CUT", 1, 0x005844d9, 0x000007e4 },
+ { "C8B.CUT", 1, 0x00584cbd, 0x000002a8 },
+ { "C9.BBK", 1, 0x00584f65, 0x0000f68b },
+ { "C9.PCX", 1, 0x005945f0, 0x0000a787 },
+ { "C97A.CUT", 1, 0x0059ed77, 0x0000017e },
+ { "C97B.CUT", 1, 0x0059eef5, 0x0000013c },
+ { "C99D.CUT", 1, 0x0059f031, 0x00000094 },
+ { "C99E.CUT", 1, 0x0059f0c5, 0x000002e6 },
+ { "C99F.CUT", 1, 0x0059f3ab, 0x000002e6 },
+ { "C9A.CUT", 1, 0x0059f691, 0x000001fa },
+ { "C9B.CUT", 1, 0x0059f88b, 0x000000f8 },
+ { "C9C.CUT", 1, 0x0059f983, 0x00000136 },
+ { "C9D.CUT", 1, 0x0059fab9, 0x000000a0 },
+ { "CDCLO.CUT", 1, 0x0059fb59, 0x000001f6 },
+ { "CDINT.CUT", 1, 0x0059fd4f, 0x000017fe },
+ { "CDINT061.SB", 1, 0x005a154d, 0x0000334c },
+ { "CDINT063.SB", 1, 0x005a4899, 0x0000798b },
+ { "CDINT072.SB", 1, 0x005ac224, 0x00005f03 },
+ { "CDINT081.SB", 1, 0x005b2127, 0x000062b3 },
+ { "CDINT091.SB", 1, 0x005b83da, 0x00008a0e },
+ { "CDINT102.SB", 1, 0x005c0de8, 0x0000673a },
+ { "CDINT111.SB", 1, 0x005c7522, 0x00008453 },
+ { "CDINT141.SB", 1, 0x005cf975, 0x000031be },
+ { "CDINT151.SB", 1, 0x005d2b33, 0x00002a7c },
+ { "CDINT191.SB", 1, 0x005d55af, 0x00001fc8 },
+ { "CDINT201.SB", 1, 0x005d7577, 0x00002cd8 },
+ { "CDINT212.SB", 1, 0x005da24f, 0x00004b03 },
+ { "CDINT231.SB", 1, 0x005ded52, 0x00008dc0 },
+ { "CDINT241.SB", 1, 0x005e7b12, 0x000032cf },
+ { "CDINT281.SB", 1, 0x005eade1, 0x000053a6 },
+ { "CDINT291.SB", 1, 0x005f0187, 0x00002138 },
+ { "CDINT301.SB", 1, 0x005f22bf, 0x00003dae },
+ { "CDINT321.SB", 1, 0x005f606d, 0x00007e92 },
+ { "CDINT351.SB", 1, 0x005fdeff, 0x00002000 },
+ { "CDINT361.SB", 1, 0x005ffeff, 0x00005a8b },
+ { "CDINT381.SB", 1, 0x0060598a, 0x00003882 },
+ { "CDINT442.SB", 1, 0x0060920c, 0x0000471b },
+ { "CDINT451.SB", 1, 0x0060d927, 0x00005929 },
+ { "CDINT452.SB", 1, 0x00613250, 0x00007915 },
+ { "CDINT461.SB", 1, 0x0061ab65, 0x00001c6a },
+ { "CDINT463.SB", 1, 0x0061c7cf, 0x000030ae },
+ { "CDINT464.SB", 1, 0x0061f87d, 0x0000c980 },
+ { "CDINT471.SB", 1, 0x0062c1fd, 0x00003593 },
+ { "CDINT481.SB", 1, 0x0062f790, 0x00004e60 },
+ { "CDINT492.SB", 1, 0x006345f0, 0x00004594 },
+ { "CDRES.CUT", 1, 0x00638b84, 0x000001f6 },
+ { "CHANGE.SAM", 1, 0x00638d7a, 0x00005ef2 },
+ { "CHEF.ACT", 1, 0x0063ec6c, 0x00005362 },
+ { "CHEF.DOG", 1, 0x00643fce, 0x00000af0 },
+ { "CHIEF1.DOG", 1, 0x00644abe, 0x000009ca },
+ { "CHIEF2.DOG", 1, 0x00645488, 0x0000121e },
+ { "CHIEF3.DOG", 1, 0x006466a6, 0x00000be4 },
+ { "CHIEF4.DOG", 1, 0x0064728a, 0x000002c4 },
+ { "CHORN.CUT", 1, 0x0064754e, 0x0000034a },
+ { "CINTR.CUT", 1, 0x00647898, 0x00001768 },
+ { "CLOGO.CUT", 1, 0x00649000, 0x000000aa },
+ { "CMASK.CUT", 1, 0x006490aa, 0x00000386 },
+ { "COCON.CUT", 1, 0x00649430, 0x000003d8 },
+ { "COCONUT.SAM", 1, 0x00649808, 0x0000a047 },
+ { "COMIC.CUT", 1, 0x0065384f, 0x0000094e },
+ { "COMPY.ACT", 1, 0x0065419d, 0x00005533 },
+ { "CONTROL.BBK", 1, 0x006596d0, 0x00000e0e },
+ { "COPY.BBK", 1, 0x0065a4de, 0x00000002 },
+ { "COPY.CUT", 1, 0x0065a4e0, 0x00000086 },
+ { "COPY.LBM", 1, 0x0065a566, 0x000053ca },
+ { "COPY.PCX", 1, 0x0065f930, 0x0000646f },
+ { "CRAP.PCX", 1, 0x00665d9f, 0x0000724c },
+ { "CRED.CUT", 1, 0x0066cfeb, 0x000003ae },
+ { "CREDIT1.CRD", 1, 0x0066d399, 0x00000604 },
+ { "CREDIT2.CRD", 1, 0x0066d99d, 0x000010d3 },
+ { "CROWBAR.SAM", 1, 0x0066ea70, 0x00009aca },
+ { "CUDRS.CUT", 1, 0x0067853a, 0x000001f6 },
+ { "D1.BBK", 1, 0x00678730, 0x000061b7 },
+ { "D1.LUM", 1, 0x0067e8e7, 0x00000018 },
+ { "D1.MSK", 1, 0x0067e8ff, 0x00001f40 },
+ { "D1.PCX", 1, 0x0068083f, 0x0000a331 },
+ { "D1C.SAM", 1, 0x0068ab70, 0x0000ddd7 },
+ { "D2.BBK", 1, 0x00698947, 0x00004630 },
+ { "D2.LUM", 1, 0x0069cf77, 0x00000018 },
+ { "D2.MSK", 1, 0x0069cf8f, 0x00001f40 },
+ { "D2.PCX", 1, 0x0069eecf, 0x00008dc3 },
+ { "D3.BBK", 1, 0x006a7c92, 0x00004b34 },
+ { "D3.LUM", 1, 0x006ac7c6, 0x00000018 },
+ { "D3.MSK", 1, 0x006ac7de, 0x00001f40 },
+ { "D3.PCX", 1, 0x006ae71e, 0x0000a662 },
+ { "D3.SAM", 1, 0x006b8d80, 0x0000c55a },
+ { "D4.BBK", 1, 0x006c52da, 0x00013e0d },
+ { "D4.LUM", 1, 0x006d90e7, 0x00000018 },
+ { "D4.MSK", 1, 0x006d90ff, 0x00001f40 },
+ { "D4.PCX", 1, 0x006db03f, 0x0000a69b },
+ { "D5.BBK", 1, 0x006e56da, 0x000088a1 },
+ { "D5.PCX", 1, 0x006edf7b, 0x00007bc5 },
+ { "D5.SAM", 1, 0x006f5b40, 0x00002ee7 },
+ { "D5B.SAM", 1, 0x006f8a27, 0x0001128e },
+ { "D6.BBK", 1, 0x00709cb5, 0x0000a480 },
+ { "D6.LUM", 1, 0x00714135, 0x00000018 },
+ { "D6.MSK", 1, 0x0071414d, 0x00001f40 },
+ { "D6.PCX", 1, 0x0071608d, 0x000099a6 },
+ { "D9.BBK", 1, 0x0071fa33, 0x00008461 },
+ { "D9.PCX", 1, 0x00727e94, 0x0000b551 },
+ { "DATA", 1, 0x007333e5, 0x00001434 },
+ { "DEATH.ACT", 1, 0x00734819, 0x0000d83a },
+ { "DEATH1.DOG", 1, 0x00742053, 0x000017ca },
+ { "DEATH2.DOG", 1, 0x0074381d, 0x0000081e },
+ { "DEINO.ACT", 1, 0x0074403b, 0x0000e199 },
+ { "DFRANK.ACT", 1, 0x007521d4, 0x000052e2 },
+ { "DISK1.SAM", 1, 0x007574b6, 0x000033da },
+ { "DOG.ACT", 1, 0x0075a890, 0x00002a62 },
+ { "DOG.DOG", 1, 0x0075d2f2, 0x0000023a },
+ { "E1.BBK", 1, 0x0075d52c, 0x0001765b },
+ { "E1.PCX", 1, 0x00774b87, 0x0000dcc7 },
+ { "E2.BBK", 1, 0x0078284e, 0x0000cefc },
+ { "E2.PCX", 1, 0x0078f74a, 0x0000f5f2 },
+ { "E3.BBK", 1, 0x0079ed3c, 0x00011042 },
+ { "E3.PCX", 1, 0x007afd7e, 0x0000a4d0 },
+ { "EQDATA.LHA", 1, 0x007ba24e, 0x00031a7a },
+ { "F1.BBK", 1, 0x007ebcc8, 0x00004716 },
+ { "F1.LUM", 1, 0x007f03de, 0x00000018 },
+ { "F1.MSK", 1, 0x007f03f6, 0x00001f40 },
+ { "F1.PCX", 1, 0x007f2336, 0x0000991d },
+ { "F1.SAM", 1, 0x007fbc53, 0x0000fd04 },
+ { "F1B.PCX", 1, 0x0080b957, 0x00005739 },
+ { "F2.BBK", 1, 0x00811090, 0x00006a18 },
+ { "F2.LUM", 1, 0x00817aa8, 0x00000018 },
+ { "F2.MSK", 1, 0x00817ac0, 0x00001f40 },
+ { "F2.PCX", 1, 0x00819a00, 0x00009f28 },
+ { "F2B.PCX", 1, 0x00823928, 0x00004abb },
+ { "F3.BBK", 1, 0x008283e3, 0x00002c59 },
+ { "F3.LUM", 1, 0x0082b03c, 0x00000018 },
+ { "F3.MSK", 1, 0x0082b054, 0x00001f40 },
+ { "F3.PCX", 1, 0x0082cf94, 0x0000aa0c },
+ { "F3.SAM", 1, 0x008379a0, 0x0000a940 },
+ { "F4.BBK", 1, 0x008422e0, 0x0000b561 },
+ { "F4.LUM", 1, 0x0084d841, 0x00000018 },
+ { "F4.MSK", 1, 0x0084d859, 0x00001f40 },
+ { "F4.PCX", 1, 0x0084f799, 0x00014df0 },
+ { "F4B.PCX", 1, 0x00864589, 0x000117d8 },
+ { "F4S.PCX", 1, 0x00875d61, 0x0000833e },
+ { "FALL.SAM", 1, 0x0087e09f, 0x0000cbda },
+ { "FAYE.ACT", 1, 0x0088ac79, 0x00013fda },
+ { "FAYE2.DOG", 1, 0x0089ec53, 0x0000098e },
+ { "FAYE3.DOG", 1, 0x0089f5e1, 0x000005d8 },
+ { "FAYE4.DOG", 1, 0x0089fbb9, 0x00000c40 },
+ { "FAYE5.CUT", 1, 0x008a07f9, 0x0000007a },
+ { "FAYE5.DOG", 1, 0x008a0873, 0x000009ce },
+ { "FAYE6.DOG", 1, 0x008a1241, 0x00000466 },
+ { "FAYE_E.ACT", 1, 0x008a16a7, 0x00002d4a },
+ { "FAYE_H.ACT", 1, 0x008a43f1, 0x0000807a },
+ { "FAYE_H.BBK", 1, 0x008ac46b, 0x0000e9fb },
+ { "FAYE_H.PCX", 1, 0x008bae66, 0x000096b5 },
+ { "FRANK.ACT", 1, 0x008c451b, 0x00008342 },
+ { "FRANK.DOG", 1, 0x008cc85d, 0x00000e48 },
+ { "FRANK_H.ACT", 1, 0x008cd6a5, 0x0000ad60 },
+ { "FRANK_H.BBK", 1, 0x008d8405, 0x00016369 },
+ { "FRANK_H.PCX", 1, 0x008ee76e, 0x00008dd6 },
+ { "GET_GEM.SAM", 1, 0x008f7544, 0x000099d2 },
+ { "GET_HORN.BBK", 1, 0x00900f16, 0x000045d8 },
+ { "GET_HORN.SAM", 1, 0x009054ee, 0x00005dde },
+ { "GM.CUT", 1, 0x0090b2cc, 0x0000009c },
+ { "GOONS.ACT", 1, 0x0090b368, 0x0000728a },
+ { "GUARDS.ACT", 1, 0x009125f2, 0x0000504a },
+ { "HENRY.ACT", 1, 0x0091763c, 0x0000b102 },
+ { "HENRY.DOG", 1, 0x0092273e, 0x00001280 },
+ { "HENRY2.DOG", 1, 0x009239be, 0x00000b24 },
+ { "HORN.SAM", 1, 0x009244e2, 0x000067b2 },
+ { "HUGH.ACT", 1, 0x0092ac94, 0x0000e8da },
+ { "I1.SAM", 1, 0x0093956e, 0x0000cbf2 },
+ { "IAN.ACT", 1, 0x00946160, 0x0000a542 },
+ { "IAN1.DOG", 1, 0x009506a2, 0x00000518 },
+ { "IAN2.DOG", 1, 0x00950bba, 0x00000a9a },
+ { "J1.BBK", 1, 0x00951654, 0x000025fc },
+ { "J1.LUM", 1, 0x00953c50, 0x00000018 },
+ { "J1.MSK", 1, 0x00953c68, 0x00001f40 },
+ { "J1.PCX", 1, 0x00955ba8, 0x00008d84 },
+ { "J1.SAM", 1, 0x0095e92c, 0x00008442 },
+ { "J2.BBK", 1, 0x00966d6e, 0x00000e97 },
+ { "J2.LUM", 1, 0x00967c05, 0x00000018 },
+ { "J2.MSK", 1, 0x00967c1d, 0x00001f40 },
+ { "J2.PCX", 1, 0x00969b5d, 0x0000c33c },
+ { "J2.SAM", 1, 0x00975e99, 0x0000a1e3 },
+ { "J3.BBK", 1, 0x0098007c, 0x00003289 },
+ { "J3.LUM", 1, 0x00983305, 0x00000018 },
+ { "J3.MSK", 1, 0x0098331d, 0x00001f40 },
+ { "J3.PCX", 1, 0x0098525d, 0x000094b4 },
+ { "J4.BBK", 1, 0x0098e711, 0x00006e28 },
+ { "J4.LUM", 1, 0x00995539, 0x00000018 },
+ { "J4.MSK", 1, 0x00995551, 0x00001f40 },
+ { "J4.PCX", 1, 0x00997491, 0x00008e90 },
+ { "J5.BBK", 1, 0x009a0321, 0x00004521 },
+ { "J5.LUM", 1, 0x009a4842, 0x00000018 },
+ { "J5.MSK", 1, 0x009a485a, 0x00001f40 },
+ { "J5.PCX", 1, 0x009a679a, 0x00009b37 },
+ { "J5.SAM", 1, 0x009b02d1, 0x000042f2 },
+ { "J6.BBK", 1, 0x009b45c3, 0x000043d7 },
+ { "J6.LUM", 1, 0x009b899a, 0x00000018 },
+ { "J6.MSK", 1, 0x009b89b2, 0x00001f40 },
+ { "J6.PCX", 1, 0x009ba8f2, 0x0000a5c5 },
+ { "J7.BBK", 1, 0x009c4eb7, 0x00003234 },
+ { "J7.LUM", 1, 0x009c80eb, 0x00000018 },
+ { "J7.MSK", 1, 0x009c8103, 0x00001f40 },
+ { "J7.PCX", 1, 0x009ca043, 0x0000cd63 },
+ { "J7.SAM", 1, 0x009d6da6, 0x000083aa },
+ { "J8.BBK", 1, 0x009df150, 0x0000320d },
+ { "J8.LUM", 1, 0x009e235d, 0x00000018 },
+ { "J8.MSK", 1, 0x009e2375, 0x00001f40 },
+ { "J8.PCX", 1, 0x009e42b5, 0x0000c0e2 },
+ { "J8.SAM", 1, 0x009f0397, 0x0000024e },
+ { "JASPAR.ACT", 1, 0x009f05e5, 0x00004fb2 },
+ { "JIM1.DOG", 1, 0x009f5597, 0x00001276 },
+ { "JIM2.DOG", 1, 0x009f680d, 0x00001282 },
+ { "JIM3.DOG", 1, 0x009f7a8f, 0x00000df6 },
+ { "JIMTAM.ACT", 1, 0x009f8885, 0x0000a08a },
+ { "JOE.BBK", 1, 0x00a0290f, 0x00014b8a },
+ { "JOE1.BBK", 1, 0x00a17499, 0x00012a5a },
+ { "JOED_A.BBK", 1, 0x00a29ef3, 0x00009b8a },
+ { "JOED_B.BBK", 1, 0x00a33a7d, 0x0000a50a },
+ { "JOEU_A.BBK", 1, 0x00a3df87, 0x00009b8a },
+ { "JOEU_B.BBK", 1, 0x00a47b11, 0x0000a50a },
+ { "JOE_A.BBK", 1, 0x00a5201b, 0x00009b8a },
+ { "JOE_B.BBK", 1, 0x00a5bba5, 0x0000dc5a },
+ { "JOE_E.ACT", 1, 0x00a697ff, 0x0000388a },
+ { "JOE_H.ACT", 1, 0x00a6d089, 0x0000dace },
+ { "JOHN.ACT", 1, 0x00a7ab57, 0x00006312 },
+ { "JOHN1.DOG", 1, 0x00a80e69, 0x0000067c },
+ { "JOURNAL.BBK", 1, 0x00a814e5, 0x0000a318 },
+ { "JOURNAL.PCX", 1, 0x00a8b7fd, 0x00009c70 },
+ { "KISS1.SAM", 1, 0x00a9546d, 0x0000f722 },
+ { "KLUNK.ACT", 1, 0x00aa4b8f, 0x00007c30 },
+ { "KLUNK1.DOG", 1, 0x00aac7bf, 0x00000e6a },
+ { "KLUNK2.DOG", 1, 0x00aad629, 0x00000ed0 },
+ { "KLUNK2.SAM", 1, 0x00aae4f9, 0x0001737c },
+ { "L1.BBK", 1, 0x00ac5875, 0x00000002 },
+ { "L1.PCX", 1, 0x00ac5877, 0x000043f7 },
+ { "L2.BBK", 1, 0x00ac9c6e, 0x00000002 },
+ { "L2.PCX", 1, 0x00ac9c70, 0x0000ba60 },
+ { "LARIS.ACT", 1, 0x00ad56d0, 0x0000355a },
+ { "LARIS.DOG", 1, 0x00ad8c2a, 0x00000f32 },
+ { "LARIS3.DOG", 1, 0x00ad9b5c, 0x0000079a },
+ { "LITTLEP.ACT", 1, 0x00ada2f6, 0x000002e2 },
+ { "LOLA.ACT", 1, 0x00ada5d8, 0x0001342d },
+ { "LOLA1.DOG", 1, 0x00aeda05, 0x00000ad6 },
+ { "LOU.ACT", 1, 0x00aee4db, 0x00005552 },
+ { "LOU1.DOG", 1, 0x00af3a2d, 0x000010ac },
+ { "LOU2.DOG", 1, 0x00af4ad9, 0x00000bae },
+ { "M1.BBK", 1, 0x00af5687, 0x00006d5c },
+ { "M1.PCX", 1, 0x00afc3e3, 0x000193ce },
+ { "M2.BBK", 1, 0x00b157b1, 0x00001a4a },
+ { "M2.PCX", 1, 0x00b171fb, 0x0000a9d3 },
+ { "M2.SAM", 1, 0x00b21bce, 0x0001433c },
+ { "MAN1.DOG", 1, 0x00b35f0a, 0x0000101e },
+ { "MAN2.DOG", 1, 0x00b36f28, 0x000007a4 },
+ { "MASK.SAM", 1, 0x00b376cc, 0x000081ea },
+ { "N1.BBK", 1, 0x00b3f8b6, 0x00002d74 },
+ { "N1.LUM", 1, 0x00b4262a, 0x00000018 },
+ { "N1.MSK", 1, 0x00b42642, 0x00001f40 },
+ { "N1.PCX", 1, 0x00b44582, 0x0000cbe7 },
+ { "N10.BBK", 1, 0x00b51169, 0x00000002 },
+ { "N10.PCX", 1, 0x00b5116b, 0x0000a28d },
+ { "N10.SAM", 1, 0x00b5b3f8, 0x000147f8 },
+ { "N11.BBK", 1, 0x00b6fbf0, 0x00000d48 },
+ { "N11.PCX", 1, 0x00b70938, 0x00008e85 },
+ { "N12.BBK", 1, 0x00b797bd, 0x000049aa },
+ { "N12.LUM", 1, 0x00b7e167, 0x00000018 },
+ { "N12.MSK", 1, 0x00b7e17f, 0x00001f40 },
+ { "N12.PCX", 1, 0x00b800bf, 0x000074ea },
+ { "N13.BBK", 1, 0x00b875a9, 0x000046b7 },
+ { "N13.LUM", 1, 0x00b8bc60, 0x00000018 },
+ { "N13.MSK", 1, 0x00b8bc78, 0x00001f40 },
+ { "N13.PCX", 1, 0x00b8dbb8, 0x00008640 },
+ { "N13.SAM", 1, 0x00b961f8, 0x00025a26 },
+ { "N13B.SAM", 1, 0x00bbbc1e, 0x0000250a },
+ { "N14.BBK", 1, 0x00bbe128, 0x000073ec },
+ { "N14.PCX", 1, 0x00bc5514, 0x0000b3f3 },
+ { "N14.SAM", 1, 0x00bd0907, 0x0002550a },
+ { "N14B.PCX", 1, 0x00bf5e11, 0x0000b933 },
+ { "N15.BBK", 1, 0x00c01744, 0x00000002 },
+ { "N15.PCX", 1, 0x00c01746, 0x0000ae43 },
+ { "N16.BBK", 1, 0x00c0c589, 0x000014c0 },
+ { "N16.LUM", 1, 0x00c0da49, 0x00000018 },
+ { "N16.MSK", 1, 0x00c0da61, 0x00001f40 },
+ { "N16.PCX", 1, 0x00c0f9a1, 0x0000e038 },
+ { "N2.BBK", 1, 0x00c1d9d9, 0x00007377 },
+ { "N2.LUM", 1, 0x00c24d50, 0x00000018 },
+ { "N2.MSK", 1, 0x00c24d68, 0x00001f40 },
+ { "N2.PCX", 1, 0x00c26ca8, 0x00007d65 },
+ { "N3.BBK", 1, 0x00c2ea0d, 0x00004fe2 },
+ { "N3.LUM", 1, 0x00c339ef, 0x00000018 },
+ { "N3.MSK", 1, 0x00c33a07, 0x00001f40 },
+ { "N3.PCX", 1, 0x00c35947, 0x0000a6de },
+ { "N4.BBK", 1, 0x00c40025, 0x0000acc0 },
+ { "N4.LUM", 1, 0x00c4ace5, 0x00000018 },
+ { "N4.MSK", 1, 0x00c4acfd, 0x00001f40 },
+ { "N4.PCX", 1, 0x00c4cc3d, 0x00006e0b },
+ { "N5.BBK", 1, 0x00c53a48, 0x0000202a },
+ { "N5.LUM", 1, 0x00c55a72, 0x00000018 },
+ { "N5.MSK", 1, 0x00c55a8a, 0x00001f40 },
+ { "N5.PCX", 1, 0x00c579ca, 0x000092f0 },
+ { "N6.BBK", 1, 0x00c60cba, 0x00001d97 },
+ { "N6.LUM", 1, 0x00c62a51, 0x00000018 },
+ { "N6.MSK", 1, 0x00c62a69, 0x00001f40 },
+ { "N6.PCX", 1, 0x00c649a9, 0x000086e2 },
+ { "N7.BBK", 1, 0x00c6d08b, 0x000025f8 },
+ { "N7.LUM", 1, 0x00c6f683, 0x00000018 },
+ { "N7.MSK", 1, 0x00c6f69b, 0x00001f40 },
+ { "N7.PCX", 1, 0x00c715db, 0x00008e79 },
+ { "N8.BBK", 1, 0x00c7a454, 0x00007bb7 },
+ { "N8.LUM", 1, 0x00c8200b, 0x00000018 },
+ { "N8.MSK", 1, 0x00c82023, 0x00001f40 },
+ { "N8.PCX", 1, 0x00c83f63, 0x0000be5f },
+ { "N9.BBK", 1, 0x00c8fdc2, 0x0000c9bf },
+ { "N9.LUM", 1, 0x00c9c781, 0x00000018 },
+ { "N9.MSK", 1, 0x00c9c799, 0x00001f40 },
+ { "N9.PCX", 1, 0x00c9e6d9, 0x0000aa4b },
+ { "N9.SAM", 1, 0x00ca9124, 0x0000e902 },
+ { "NAOMI.DOG", 1, 0x00cb7a26, 0x000013b6 },
+ { "NAOMI2.DOG", 1, 0x00cb8ddc, 0x00000a40 },
+ { "OBJECTS.BBK", 1, 0x00cb981c, 0x00019322 },
+ { "ORACLE.ACT", 1, 0x00cd2b3e, 0x00004042 },
+ { "ORACLE1.DOG", 1, 0x00cd6b80, 0x00001088 },
+ { "ORACLE2.DOG", 1, 0x00cd7c08, 0x000003c0 },
+ { "ORACLE3.DOG", 1, 0x00cd7fc8, 0x00000806 },
+ { "PANEL.PCX", 1, 0x00cd87ce, 0x00002279 },
+ { "PRIN1.CUT", 1, 0x00cdaa47, 0x0000007a },
+ { "PRIN1.DOG", 1, 0x00cdaac1, 0x00000aea },
+ { "PRIN2.DOG", 1, 0x00cdb5ab, 0x0000055a },
+ { "PRIN4.DOG", 1, 0x00cdbb05, 0x00000720 },
+ { "PRINCESS.ACT", 1, 0x00cdc225, 0x0000d732 },
+ { "PRISON.ACT", 1, 0x00ce9957, 0x00006f22 },
+ { "PUNCH.SAM", 1, 0x00cf0879, 0x00007e9a },
+ { "PUSH.SAM", 1, 0x00cf8713, 0x00009308 },
+ { "PYGMY.ACT", 1, 0x00d01a1b, 0x00010a63 },
+ { "QUEEN.JAS", 1, 0x00d1247e, 0x0001371a },
+ { "QUEEN2.JAS", 1, 0x00d25b98, 0x00008c00 },
+ { "R1.BBK", 1, 0x00d2e798, 0x00001a4a },
+ { "R1.PCX", 1, 0x00d301e2, 0x000065c0 },
+ { "R2.BBK", 1, 0x00d367a2, 0x00001a4a },
+ { "R2.PCX", 1, 0x00d381ec, 0x00005f32 },
+ { "R3.BBK", 1, 0x00d3e11e, 0x00001a4a },
+ { "R3.PCX", 1, 0x00d3fb68, 0x000061a1 },
+ { "R4.BBK", 1, 0x00d45d09, 0x00001a4a },
+ { "R4.PCX", 1, 0x00d47753, 0x00009ec3 },
+ { "RASH.SAM", 1, 0x00d51616, 0x0000431a },
+ { "RENEGADE.BBK", 1, 0x00d55930, 0x0000117a },
+ { "RENEGADE.PCX", 1, 0x00d56aaa, 0x0000296d },
+ { "RITA.ACT", 1, 0x00d59417, 0x000020ea },
+ { "RITA_H.ACT", 1, 0x00d5b501, 0x00015cdb },
+ { "ROCKET.SAM", 1, 0x00d711dc, 0x00027e20 },
+ { "SEC.ACT", 1, 0x00d98ffc, 0x00006e6a },
+ { "SEC1.DOG", 1, 0x00d9fe66, 0x00001672 },
+ { "SEC2.DOG", 1, 0x00da14d8, 0x00000944 },
+ { "SHEET.SAM", 1, 0x00da1e1c, 0x0000ad00 },
+ { "SHIELD.SAM", 1, 0x00dacb1c, 0x00002afb },
+ { "SHOWER.ACT", 1, 0x00daf617, 0x0000762a },
+ { "SHOWERAM.DOG", 1, 0x00db6c41, 0x000005fc },
+ { "SKULL.ACT", 1, 0x00db723d, 0x00001973 },
+ { "SPARKY.ACT", 1, 0x00db8bb0, 0x0000f912 },
+ { "SPARKY1.DOG", 1, 0x00dc84c2, 0x00000986 },
+ { "SPARKY2.DOG", 1, 0x00dc8e48, 0x00000402 },
+ { "SPARKY3.DOG", 1, 0x00dc924a, 0x0000126e },
+ { "SPARKY4.DOG", 1, 0x00dca4b8, 0x0000043a },
+ { "SPARKY5.DOG", 1, 0x00dca8f2, 0x0000091c },
+ { "SPARKY6.DOG", 1, 0x00dcb20e, 0x000007b6 },
+ { "SPARKY7.DOG", 1, 0x00dcb9c4, 0x0000095e },
+ { "SPARKY8.DOG", 1, 0x00dcc322, 0x0000072a },
+ { "SPARKY_H.ACT", 1, 0x00dcca4c, 0x0000280a },
+ { "T1.BBK", 1, 0x00dcf256, 0x0000f492 },
+ { "T1.LUM", 1, 0x00dde6e8, 0x00000018 },
+ { "T1.MSK", 1, 0x00dde700, 0x00001f40 },
+ { "T1.PCX", 1, 0x00de0640, 0x0000aa3d },
+ { "T1.SAM", 1, 0x00deb07d, 0x0000711a },
+ { "T10.BBK", 1, 0x00df2197, 0x0000a957 },
+ { "T10.LUM", 1, 0x00dfcaee, 0x00000018 },
+ { "T10.MSK", 1, 0x00dfcb06, 0x00001f40 },
+ { "T10.PCX", 1, 0x00dfea46, 0x0001198a },
+ { "T10.SAM", 1, 0x00e103d0, 0x0000bc49 },
+ { "T11.BBK", 1, 0x00e1c019, 0x00001e84 },
+ { "T11.LUM", 1, 0x00e1de9d, 0x00000018 },
+ { "T11.MSK", 1, 0x00e1deb5, 0x00001f40 },
+ { "T11.PCX", 1, 0x00e1fdf5, 0x00008e7e },
+ { "T12.BBK", 1, 0x00e28c73, 0x000059b5 },
+ { "T12.LUM", 1, 0x00e2e628, 0x00000018 },
+ { "T12.MSK", 1, 0x00e2e640, 0x00001f40 },
+ { "T12.PCX", 1, 0x00e30580, 0x00007b3c },
+ { "T12.SAM", 1, 0x00e380bc, 0x0000fe4b },
+ { "T13.BBK", 1, 0x00e47f07, 0x000043b4 },
+ { "T13.LUM", 1, 0x00e4c2bb, 0x00000018 },
+ { "T13.MSK", 1, 0x00e4c2d3, 0x00001f40 },
+ { "T13.PCX", 1, 0x00e4e213, 0x00007591 },
+ { "T14.BBK", 1, 0x00e557a4, 0x0000468b },
+ { "T14.LUM", 1, 0x00e59e2f, 0x00000018 },
+ { "T14.MSK", 1, 0x00e59e47, 0x00001f40 },
+ { "T14.PCX", 1, 0x00e5bd87, 0x00007df5 },
+ { "T14.SAM", 1, 0x00e63b7c, 0x00016db3 },
+ { "T15.BBK", 1, 0x00e7a92f, 0x000096e6 },
+ { "T15.LUM", 1, 0x00e84015, 0x00000018 },
+ { "T15.MSK", 1, 0x00e8402d, 0x00001f40 },
+ { "T15.PCX", 1, 0x00e85f6d, 0x00008b28 },
+ { "T15.SAM", 1, 0x00e8ea95, 0x0000a7d0 },
+ { "T15B.SAM", 1, 0x00e99265, 0x000164d7 },
+ { "T16.BBK", 1, 0x00eaf73c, 0x000027ff },
+ { "T16.LUM", 1, 0x00eb1f3b, 0x00000018 },
+ { "T16.MSK", 1, 0x00eb1f53, 0x00001f40 },
+ { "T16.PCX", 1, 0x00eb3e93, 0x00009110 },
+ { "T17.BBK", 1, 0x00ebcfa3, 0x000056df },
+ { "T17.LUM", 1, 0x00ec2682, 0x00000018 },
+ { "T17.MSK", 1, 0x00ec269a, 0x00001f40 },
+ { "T17.PCX", 1, 0x00ec45da, 0x00007db6 },
+ { "T18.BBK", 1, 0x00ecc390, 0x00006174 },
+ { "T18.LUM", 1, 0x00ed2504, 0x00000018 },
+ { "T18.MSK", 1, 0x00ed251c, 0x00001f40 },
+ { "T18.PCX", 1, 0x00ed445c, 0x000087d6 },
+ { "T19.BBK", 1, 0x00edcc32, 0x0000aec8 },
+ { "T19.LUM", 1, 0x00ee7afa, 0x00000018 },
+ { "T19.MSK", 1, 0x00ee7b12, 0x00001f40 },
+ { "T19.PCX", 1, 0x00ee9a52, 0x0000768e },
+ { "T19.SAM", 1, 0x00ef10e0, 0x000167ea },
+ { "T1B.SAM", 1, 0x00f078ca, 0x0002fa9f },
+ { "T2.BBK", 1, 0x00f37369, 0x00004dea },
+ { "T2.LUM", 1, 0x00f3c153, 0x00000018 },
+ { "T2.MSK", 1, 0x00f3c16b, 0x00001f40 },
+ { "T2.PCX", 1, 0x00f3e0ab, 0x00011404 },
+ { "T2.SAM", 1, 0x00f4f4af, 0x0000aa32 },
+ { "T20.BBK", 1, 0x00f59ee1, 0x0000611c },
+ { "T20.LUM", 1, 0x00f5fffd, 0x00000018 },
+ { "T20.MSK", 1, 0x00f60015, 0x00001f40 },
+ { "T20.PCX", 1, 0x00f61f55, 0x0000852a },
+ { "T20.SAM", 1, 0x00f6a47f, 0x00007f9c },
+ { "T20B.SAM", 1, 0x00f7241b, 0x0000a2bc },
+ { "T21.BBK", 1, 0x00f7c6d7, 0x00000002 },
+ { "T21.PCX", 1, 0x00f7c6d9, 0x0000b7b0 },
+ { "T22.BBK", 1, 0x00f87e89, 0x00000002 },
+ { "T22.PCX", 1, 0x00f87e8b, 0x0000a982 },
+ { "T23.BBK", 1, 0x00f9280d, 0x00005bca },
+ { "T23.LUM", 1, 0x00f983d7, 0x00000018 },
+ { "T23.MSK", 1, 0x00f983ef, 0x00001f40 },
+ { "T23.PCX", 1, 0x00f9a32f, 0x00008200 },
+ { "T24.BBK", 1, 0x00fa252f, 0x0000aaf1 },
+ { "T24.LUM", 1, 0x00fad020, 0x00000018 },
+ { "T24.MSK", 1, 0x00fad038, 0x00001f40 },
+ { "T24.PCX", 1, 0x00faef78, 0x00006f7e },
+ { "T25.BBK", 1, 0x00fb5ef6, 0x0000a631 },
+ { "T25.LUM", 1, 0x00fc0527, 0x00000018 },
+ { "T25.MSK", 1, 0x00fc053f, 0x00001f40 },
+ { "T25.PCX", 1, 0x00fc247f, 0x00008881 },
+ { "T25.SAM", 1, 0x00fcad00, 0x000091ac },
+ { "T26.BBK", 1, 0x00fd3eac, 0x00014578 },
+ { "T26.LUM", 1, 0x00fe8424, 0x00000018 },
+ { "T26.MSK", 1, 0x00fe843c, 0x00001f40 },
+ { "T26.PCX", 1, 0x00fea37c, 0x00012570 },
+ { "T26A.SAM", 1, 0x00ffc8ec, 0x000126a6 },
+ { "T27.BBK", 1, 0x0100ef92, 0x0000a73e },
+ { "T27.LUM", 1, 0x010196d0, 0x00000018 },
+ { "T27.MSK", 1, 0x010196e8, 0x00001f40 },
+ { "T27.PCX", 1, 0x0101b628, 0x000085fa },
+ { "T28.BBK", 1, 0x01023c22, 0x00000002 },
+ { "T28.PCX", 1, 0x01023c24, 0x000017d2 },
+ { "T2B.SAM", 1, 0x010253f6, 0x00021df6 },
+ { "T3.BBK", 1, 0x010471ec, 0x00004b24 },
+ { "T3.LUM", 1, 0x0104bd10, 0x00000018 },
+ { "T3.MSK", 1, 0x0104bd28, 0x00001f40 },
+ { "T3.PCX", 1, 0x0104dc68, 0x0000724c },
+ { "T3.SAM", 1, 0x01054eb4, 0x00006042 },
+ { "T4.BBK", 1, 0x0105aef6, 0x00002dca },
+ { "T4.MSK", 1, 0x0105dcc0, 0x00001f40 },
+ { "T4.PCX", 1, 0x0105fc00, 0x00007566 },
+ { "T5.BBK", 1, 0x01067166, 0x00001ac0 },
+ { "T5.LUM", 1, 0x01068c26, 0x00000018 },
+ { "T5.MSK", 1, 0x01068c3e, 0x00001f40 },
+ { "T5.PCX", 1, 0x0106ab7e, 0x00009509 },
+ { "T5.SAM", 1, 0x01074087, 0x000049aa },
+ { "T5B.SAM", 1, 0x01078a31, 0x00022018 },
+ { "T5C.SAM", 1, 0x0109aa49, 0x00011612 },
+ { "T6.BBK", 1, 0x010ac05b, 0x00007db0 },
+ { "T6.LUM", 1, 0x010b3e0b, 0x00000018 },
+ { "T6.MSK", 1, 0x010b3e23, 0x00001f40 },
+ { "T6.PCX", 1, 0x010b5d63, 0x000096b4 },
+ { "T6.SAM", 1, 0x010bf417, 0x0000f04d },
+ { "T6A.SAM", 1, 0x010ce464, 0x000199ee },
+ { "T6B.PCX", 1, 0x010e7e52, 0x0000ad10 },
+ { "T6B.SAM", 1, 0x010f2b62, 0x00010cba },
+ { "T6C.SAM", 1, 0x0110381c, 0x00015041 },
+ { "T7.BBK", 1, 0x0111885d, 0x0000c781 },
+ { "T7.PCX", 1, 0x01124fde, 0x00006da0 },
+ { "T7.SAM", 1, 0x0112bd7e, 0x000172ea },
+ { "T8.BBK", 1, 0x01143068, 0x00002762 },
+ { "T8.LUM", 1, 0x011457ca, 0x00000018 },
+ { "T8.MSK", 1, 0x011457e2, 0x00001f40 },
+ { "T8.PCX", 1, 0x01147722, 0x0000831b },
+ { "T8.SAM", 1, 0x0114fa3d, 0x00012c01 },
+ { "T9.BBK", 1, 0x0116263e, 0x000029f3 },
+ { "T9.LUM", 1, 0x01165031, 0x00000018 },
+ { "T9.MSK", 1, 0x01165049, 0x00001f40 },
+ { "T9.PCX", 1, 0x01166f89, 0x0000735b },
+ { "T9.SAM", 1, 0x0116e2e4, 0x0000d9e6 },
+ { "TABLET.BBK", 1, 0x0117bcca, 0x00013902 },
+ { "TABLET.PCX", 1, 0x0118f5cc, 0x0000af16 },
+ { "TALLPYG.DOG", 1, 0x0119a4e2, 0x0000034a },
+ { "TAM1.DOG", 1, 0x0119a82c, 0x00001e8a },
+ { "TAM2.DOG", 1, 0x0119c6b6, 0x0000076c },
+ { "TAM3.DOG", 1, 0x0119ce22, 0x000007c2 },
+ { "TAM4.DOG", 1, 0x0119d5e4, 0x0000083c },
+ { "TEMPLE.ACT", 1, 0x0119de20, 0x00005052 },
+ { "TMPD.ACT", 1, 0x011a2e72, 0x0000b00c },
+ { "TRADER.ACT", 1, 0x011ade7e, 0x0001424a },
+ { "V1.BBK", 1, 0x011c20c8, 0x00006724 },
+ { "V1.PCX", 1, 0x011c87ec, 0x000091ea },
+ { "V1.SAM", 1, 0x011d19d6, 0x000061e5 },
+ { "V10.BBK", 1, 0x011d7bbb, 0x000094e8 },
+ { "V10.PCX", 1, 0x011e10a3, 0x0000946c },
+ { "V11.BBK", 1, 0x011ea50f, 0x0000e122 },
+ { "V11.PCX", 1, 0x011f8631, 0x0000946c },
+ { "V2.BBK", 1, 0x01201a9d, 0x00007dfb },
+ { "V2.LUM", 1, 0x01209898, 0x00000018 },
+ { "V2.MSK", 1, 0x012098b0, 0x00001f40 },
+ { "V2.PCX", 1, 0x0120b7f0, 0x0000876c },
+ { "V3.BBK", 1, 0x01213f5c, 0x0000d716 },
+ { "V3.LUM", 1, 0x01221672, 0x00000018 },
+ { "V3.MSK", 1, 0x0122168a, 0x00001f40 },
+ { "V3.PCX", 1, 0x012235ca, 0x00005efa },
+ { "V4.BBK", 1, 0x012294c4, 0x0000571a },
+ { "V4.PCX", 1, 0x0122ebde, 0x00010cd4 },
+ { "V5.BBK", 1, 0x0123f8b2, 0x0001c43f },
+ { "V5.MSK", 1, 0x0125bcf1, 0x00001f40 },
+ { "V5.PCX", 1, 0x0125dc31, 0x00009148 },
+ { "V5.SAM", 1, 0x01266d79, 0x0003953d },
+ { "V5B.SAM", 1, 0x012a02b6, 0x0000ce6f },
+ { "V5C.SAM", 1, 0x012ad125, 0x0000f142 },
+ { "V5D.SAM", 1, 0x012bc267, 0x00000f50 },
+ { "V5E.SAM", 1, 0x012bd1b7, 0x00009352 },
+ { "V5X.SAM", 1, 0x012c6509, 0x0001d7c2 },
+ { "V6.BBK", 1, 0x012e3ccb, 0x0000d716 },
+ { "V6.LUM", 1, 0x012f13e1, 0x00000018 },
+ { "V6.MSK", 1, 0x012f13f9, 0x00001f40 },
+ { "V6.PCX", 1, 0x012f3339, 0x000074ce },
+ { "V7.BBK", 1, 0x012fa807, 0x000177cd },
+ { "V7.PCX", 1, 0x01311fd4, 0x0000a3b4 },
+ { "V8.BBK", 1, 0x0131c388, 0x00006724 },
+ { "V8.PCX", 1, 0x01322aac, 0x0000a8d0 },
+ { "VACUUM.SAM", 1, 0x0132d37c, 0x00009516 },
+ { "WATER.ACT", 1, 0x01336892, 0x00001c02 },
+ { "WEDGE.ACT", 1, 0x01338494, 0x0000390e },
+ { "WEDGE.DOG", 1, 0x0133bda2, 0x000002c4 },
+ { "WEENIE.SAM", 1, 0x0133c066, 0x0000b4d2 },
+ { "WITCH1.DOG", 1, 0x01347538, 0x000012e4 },
+ { "WITCH2.DOG", 1, 0x0134881c, 0x0000088e },
+ { "WITCH3.DOG", 1, 0x013490aa, 0x00000df8 },
+ { "WITCH4.DOG", 1, 0x01349ea2, 0x000002b2 },
+ { "X1.BBK", 1, 0x0134a154, 0x00010e5d },
+ { "X1.PCX", 1, 0x0135afb1, 0x0000cc4b },
+ { "X10.BBK", 1, 0x01367bfc, 0x00009907 },
+ { "X10.PCX", 1, 0x01371503, 0x0000a1b3 },
+ { "X10_JOE.ACT", 1, 0x0137b6b6, 0x0000943a },
+ { "X10_RITA.ACT", 1, 0x01384af0, 0x000076d9 },
+ { "X11.BBK", 1, 0x0138c1c9, 0x00016966 },
+ { "X11.PCX", 1, 0x013a2b2f, 0x0000c160 },
+ { "X11_JOE.ACT", 1, 0x013aec8f, 0x0000872e },
+ { "X11_RITA.ACT", 1, 0x013b73bd, 0x0000a6f2 },
+ { "X2.BBK", 1, 0x013c1aaf, 0x0000df2b },
+ { "X2.PCX", 1, 0x013cf9da, 0x00013ed5 },
+ { "X2_JOE.ACT", 1, 0x013e38af, 0x00008042 },
+ { "X2_RITA.ACT", 1, 0x013eb8f1, 0x0000df02 },
+ { "X3.BBK", 1, 0x013f97f3, 0x00000002 },
+ { "X3.PCX", 1, 0x013f97f5, 0x0000d165 },
+ { "X3_RITA.ACT", 1, 0x0140695a, 0x0000a0fa },
+ { "X4.BBK", 1, 0x01410a54, 0x00004b53 },
+ { "X4.PCX", 1, 0x014155a7, 0x0000b51b },
+ { "X4A.SAM", 1, 0x01420ac2, 0x0001b456 },
+ { "X4B.SAM", 1, 0x0143bf18, 0x0002a1b4 },
+ { "X4_JOE.ACT", 1, 0x014660cc, 0x000088a5 },
+ { "X4_RITA.ACT", 1, 0x0146e971, 0x0000398a },
+ { "X5.BBK", 1, 0x014722fb, 0x000075a0 },
+ { "X5.PCX", 1, 0x0147989b, 0x0000adeb },
+ { "X5_SPARK.ACT", 1, 0x01484686, 0x00006e5a },
+ { "X6.BBK", 1, 0x0148b4e0, 0x0001889e },
+ { "X6.PCX", 1, 0x014a3d7e, 0x0000be75 },
+ { "X6_HUGH.ACT", 1, 0x014afbf3, 0x0000c25a },
+ { "X7.BBK", 1, 0x014bbe4d, 0x00002ada },
+ { "X7.PCX", 1, 0x014be927, 0x00009456 },
+ { "X7A.SAM", 1, 0x014c7d7d, 0x0001b7cb },
+ { "X7B.SAM", 1, 0x014e3548, 0x0003b107 },
+ { "X8.BBK", 1, 0x0151e64f, 0x00032a14 },
+ { "X8.PCX", 1, 0x01551063, 0x00013d4f },
+ { "X9.BBK", 1, 0x01564db2, 0x00028337 },
+ { "X9.PCX", 1, 0x0158d0e9, 0x0000a31c },
+ { "ZOMBIE.ACT", 1, 0x01597405, 0x000078ea },
+ { "ZOMBIE1.DOG", 1, 0x0159ecef, 0x00000f6a },
+ { "ZOMBIE2.DOG", 1, 0x0159fc59, 0x00000c40 }
+};
+#endif
+} // End of namespace Queen
diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp
new file mode 100644
index 0000000000..a5c756e366
--- /dev/null
+++ b/engines/queen/sound.cpp
@@ -0,0 +1,239 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/sound.h"
+
+#include "queen/input.h"
+#include "queen/music.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+
+#include "sound/flac.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+
+#define SB_HEADER_SIZE 110
+#define STOP_MUSIC -1
+
+namespace Queen {
+
+Sound::Sound(Audio::Mixer *mixer, QueenEngine *vm) :
+ _mixer(mixer), _vm(vm), _sfxToggle(true), _speechToggle(true), _musicToggle(true), _lastOverride(0) {
+}
+
+Sound::~Sound() {
+}
+
+Sound *Sound::giveSound(Audio::Mixer *mixer, QueenEngine *vm, uint8 compression) {
+ if (!mixer->isReady())
+ return new SilentSound(mixer, vm);
+
+ switch (compression) {
+ case COMPRESSION_NONE:
+ return new SBSound(mixer, vm);
+ break;
+ case COMPRESSION_MP3:
+#ifndef USE_MAD
+ warning("Using MP3 compressed datafile, but MP3 support not compiled in");
+ return new SilentSound(mixer, vm);
+#else
+ return new MP3Sound(mixer, vm);
+#endif
+ break;
+ case COMPRESSION_OGG:
+#ifndef USE_VORBIS
+ warning("Using OGG compressed datafile, but OGG support not compiled in");
+ return new SilentSound(mixer, vm);
+#else
+ return new OGGSound(mixer, vm);
+#endif
+ break;
+ case COMPRESSION_FLAC:
+#ifndef USE_FLAC
+ warning("Using FLAC compressed datafile, but FLAC support not compiled in");
+ return new SilentSound(mixer, vm);
+#else
+ return new FLACSound(mixer, vm);
+#endif
+ break;
+ default:
+ warning("Unknown compression type");
+ return new SilentSound(mixer, vm);
+ }
+}
+
+void Sound::waitFinished(bool isSpeech) {
+ if (isSpeech)
+ while (_mixer->isSoundHandleActive(_speechHandle))
+ _vm->input()->delay(10);
+ else
+ while (_mixer->isSoundHandleActive(_sfxHandle))
+ _vm->input()->delay(10);
+}
+
+void Sound::playSfx(uint16 sfx, bool isSpeech) {
+ if (isSpeech && !speechOn()) return;
+ else if (!sfxOn()) return;
+
+ if (sfx != 0) {
+ char name[13];
+#ifndef PALMOS_68K
+ strcpy(name, _sfxName[sfx - 1]);
+#else
+ strncpy(name, _sfxName + 10 * (sfx - 1), 10); // saved as 8char + /0/0
+#endif
+ strcat(name, ".SB");
+ waitFinished(isSpeech);
+ if (sfxPlay(name, isSpeech ? &_speechHandle : &_sfxHandle)) {
+ _speechSfxExists = isSpeech;
+ } else {
+ _speechSfxExists = false;
+ }
+ }
+}
+
+void Sound::playSfx(const char *base, bool isSpeech) {
+ if (isSpeech && !speechOn()) return;
+ else if (!sfxOn()) return;
+
+ char name[13];
+ strcpy(name, base);
+ // alter filename to add zeros and append ".SB"
+ for (int i = 0; i < 8; i++) {
+ if (name[i] == ' ')
+ name[i] = '0';
+ }
+ strcat(name, ".SB");
+ waitFinished(isSpeech);
+ if (sfxPlay(name, isSpeech ? &_speechHandle : &_sfxHandle)) {
+ _speechSfxExists = isSpeech;
+ } else {
+ _speechSfxExists = false;
+ }
+}
+
+void Sound::playSong(int16 songNum) {
+ if (songNum <= 0) {
+ _vm->music()->stopSong();
+ return;
+ }
+
+ int16 newTune;
+ if (_vm->resource()->isDemo()) {
+ if (songNum == 17) {
+ _vm->music()->stopSong();
+ return;
+ }
+ newTune = _songDemo[songNum - 1].tuneList[0] - 1;
+ } else {
+ newTune = _song[songNum - 1].tuneList[0] - 1;
+ }
+
+ if (_tune[newTune].sfx[0]) {
+ if (sfxOn())
+ playSfx(_tune[newTune].sfx[0], false);
+ return;
+ }
+
+ if (!musicOn())
+ return;
+
+ int override = (_vm->resource()->isDemo()) ? _songDemo[songNum - 1].override : _song[songNum - 1].override;
+ switch (override) {
+ // Override all songs
+ case 1:
+ break;
+ // Alter song settings (such as volume) and exit
+ case 2:
+ _vm->music()->toggleVChange();
+ default:
+ return;
+ break;
+ }
+
+ _lastOverride = songNum;
+
+ _vm->music()->queueTuneList(newTune);
+ _vm->music()->playMusic();
+}
+
+void Sound::saveState(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, _lastOverride); ptr += 2;
+}
+
+void Sound::loadState(uint32 ver, byte *&ptr) {
+ _lastOverride = (int16)READ_BE_INT16(ptr); ptr += 2;
+}
+
+bool SilentSound::sfxPlay(const char *name, Audio::SoundHandle *soundHandle) {
+ return false;
+}
+
+bool SBSound::sfxPlay(const char *name, Audio::SoundHandle *soundHandle) {
+ if (_vm->resource()->fileExists(name)) {
+ uint32 size;
+ uint8 *sound = _vm->resource()->loadFile(name, SB_HEADER_SIZE, &size, true);
+ byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE;
+ _mixer->playRaw(soundHandle, sound, size, 11025, flags);
+ return true;
+ }
+ return false;
+}
+
+#ifdef USE_MAD
+bool MP3Sound::sfxPlay(const char *name, Audio::SoundHandle *soundHandle) {
+ uint32 size;
+ Common::File *f = _vm->resource()->giveCompressedSound(name, &size);
+ if (f) {
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, makeMP3Stream(f, size));
+ return true;
+ }
+ return false;
+}
+#endif
+
+#ifdef USE_VORBIS
+bool OGGSound::sfxPlay(const char *name, Audio::SoundHandle *soundHandle) {
+ uint32 size;
+ Common::File *f = _vm->resource()->giveCompressedSound(name, &size);
+ if (f) {
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, makeVorbisStream(f, size));
+ return true;
+ }
+ return false;
+}
+#endif
+
+#ifdef USE_FLAC
+bool FLACSound::sfxPlay(const char *name, Audio::SoundHandle *soundHandle) {
+ uint32 size;
+ Common::File *f = _vm->resource()->giveCompressedSound(name, &size);
+ if (f) {
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, makeFlacStream(f, size));
+ return true;
+ }
+ return false;
+}
+#endif
+
+} //End of namespace Queen
diff --git a/engines/queen/sound.h b/engines/queen/sound.h
new file mode 100644
index 0000000000..d12032e994
--- /dev/null
+++ b/engines/queen/sound.h
@@ -0,0 +1,158 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENSOUND_H
+#define QUEENSOUND_H
+
+#include "common/util.h"
+#include "sound/mixer.h"
+#include "queen/defs.h"
+
+namespace Queen {
+
+class Input;
+class Resource;
+
+struct songData {
+ int16 tuneList[5];
+ int16 volume;
+ int16 tempo;
+ int16 reverb;
+ int16 override;
+ int16 ignore;
+};
+
+struct tuneData {
+ int16 tuneNum[9];
+ int16 sfx[2];
+ int16 mode;
+ int16 delay;
+};
+
+class QueenEngine;
+
+class Sound {
+public:
+ Sound(Audio::Mixer *mixer, QueenEngine *vm);
+ virtual ~Sound();
+ virtual bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle) = 0;
+ static Sound *giveSound(Audio::Mixer *mixer, QueenEngine *vm, uint8 compression);
+ void playSfx(uint16 sfx, bool isSpeech);
+ void playSfx(const char *base, bool isSpeech);
+ void playSong(int16 songNum);
+ void playLastSong() { playSong(_lastOverride); }
+ void stopSpeech() { _mixer->stopHandle(_speechHandle); }
+ void stopSfx() { _mixer->stopHandle(_sfxHandle); }
+
+ bool sfxOn() const { return _sfxToggle; }
+ void sfxToggle(bool val) { _sfxToggle = val; }
+ void toggleSfx() { _sfxToggle ^= true; }
+
+ bool speechOn() const { return _speechToggle; }
+ void speechToggle(bool val) { _speechToggle = val; }
+ void toggleSpeech() { _speechToggle ^= true; }
+
+ bool musicOn() const { return _musicToggle; }
+ void musicToggle(bool val) { _musicToggle = val; }
+ void toggleMusic() { _musicToggle ^= true; }
+
+ bool isSpeechActive() const { return _mixer->isSoundHandleActive(_speechHandle); }
+ bool isSfxActive() const { return _mixer->isSoundHandleActive(_sfxHandle); }
+
+ bool speechSfxExists() const { return _speechSfxExists; }
+
+ int16 lastOverride() const { return _lastOverride; }
+
+ void saveState(byte *&ptr);
+ void loadState(uint32 ver, byte *&ptr);
+
+#ifndef PALMOS_68K
+ static const songData _songDemo[];
+ static const songData _song[];
+ static const tuneData _tuneDemo[];
+ static const tuneData _tune[];
+ static const char *_sfxName[];
+ static const int16 _jungleList[];
+#else
+ static const songData *_songDemo;
+ static const songData *_song;
+ static const tuneData *_tuneDemo;
+ static const tuneData *_tune;
+ static const char *_sfxName;
+ static const int16 *_jungleList;
+#endif
+
+protected:
+ void waitFinished(bool isSpeech);
+
+ Audio::Mixer *_mixer;
+ QueenEngine *_vm;
+
+ bool _sfxToggle;
+ bool _speechToggle;
+ bool _musicToggle;
+ bool _speechSfxExists;
+
+ int16 _lastOverride;
+ Audio::SoundHandle _sfxHandle;
+ Audio::SoundHandle _speechHandle;
+};
+
+class SilentSound : public Sound {
+public:
+ SilentSound(Audio::Mixer *mixer, QueenEngine *vm) : Sound(mixer, vm) {};
+ bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle);
+};
+
+class SBSound : public Sound {
+public:
+ SBSound(Audio::Mixer *mixer, QueenEngine *vm) : Sound(mixer, vm) {};
+ bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle);
+};
+
+#ifdef USE_MAD
+class MP3Sound : public Sound {
+public:
+ MP3Sound(Audio::Mixer *mixer, QueenEngine *vm) : Sound(mixer, vm) {};
+ bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle);
+};
+#endif
+
+#ifdef USE_VORBIS
+class OGGSound : public Sound {
+public:
+ OGGSound(Audio::Mixer *mixer, QueenEngine *vm) : Sound(mixer, vm) {};
+ bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle);
+};
+#endif
+
+#ifdef USE_FLAC
+class FLACSound : public Sound {
+public:
+ FLACSound(Audio::Mixer *mixer, QueenEngine *vm) : Sound(mixer, vm) {};
+ bool sfxPlay(const char *name, Audio::SoundHandle *soundHandle);
+};
+#endif // #ifdef USE_FLAC
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/state.cpp b/engines/queen/state.cpp
new file mode 100644
index 0000000000..5709bb07c6
--- /dev/null
+++ b/engines/queen/state.cpp
@@ -0,0 +1,130 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/state.h"
+
+namespace Queen {
+
+Direction State::findDirection(uint16 state) {
+ static const Direction sd[] = {
+ DIR_BACK,
+ DIR_RIGHT,
+ DIR_LEFT,
+ DIR_FRONT
+ };
+ return sd[(state >> 2) & 3];
+}
+
+StateTalk State::findTalk(uint16 state) {
+ return (state & (1 << 9)) ? STATE_TALK_TALK : STATE_TALK_MUTE;
+}
+
+StateGrab State::findGrab(uint16 state) {
+ static const StateGrab sg[] = {
+ STATE_GRAB_NONE,
+ STATE_GRAB_DOWN,
+ STATE_GRAB_UP,
+ STATE_GRAB_MID
+ };
+ return sg[state & 3];
+}
+
+StateOn State::findOn(uint16 state) {
+ return (state & (1 << 8)) ? STATE_ON_ON : STATE_ON_OFF;
+}
+
+Verb State::findDefaultVerb(uint16 state) {
+ static const Verb sdv[] = {
+ VERB_NONE,
+ VERB_OPEN,
+ VERB_NONE,
+ VERB_CLOSE,
+
+ VERB_NONE,
+ VERB_NONE,
+ VERB_LOOK_AT,
+ VERB_MOVE,
+
+ VERB_GIVE,
+ VERB_TALK_TO,
+ VERB_NONE,
+ VERB_NONE,
+
+ VERB_USE,
+ VERB_NONE,
+ VERB_PICK_UP,
+ VERB_NONE
+ };
+ return sdv[(state >> 4) & 0xF];
+}
+
+StateUse State::findUse(uint16 state) {
+ return (state & (1 << 10)) ? STATE_USE : STATE_USE_ON;
+}
+
+void State::alterOn(uint16 *objState, StateOn state) {
+ switch (state) {
+ case STATE_ON_ON:
+ *objState |= (1 << 8);
+ break;
+ case STATE_ON_OFF:
+ *objState &= ~(1 << 8);
+ break;
+ }
+}
+
+void State::alterDefaultVerb(uint16 *objState, Verb v) {
+ uint16 val;
+ switch (v) {
+ case VERB_OPEN:
+ val = 1;
+ break;
+ case VERB_CLOSE:
+ val = 3;
+ break;
+ case VERB_MOVE:
+ val = 7;
+ break;
+ case VERB_GIVE:
+ val = 8;
+ break;
+ case VERB_USE:
+ val = 12;
+ break;
+ case VERB_PICK_UP:
+ val = 14;
+ break;
+ case VERB_TALK_TO:
+ val = 9;
+ break;
+ case VERB_LOOK_AT:
+ val = 6;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+ *objState = (*objState & ~0xF0) | (val << 4);
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/state.h b/engines/queen/state.h
new file mode 100644
index 0000000000..d7be47fbc8
--- /dev/null
+++ b/engines/queen/state.h
@@ -0,0 +1,113 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENSTATE_H
+#define QUEENSTATE_H
+
+#include "common/util.h"
+#include "queen/defs.h"
+
+namespace Queen {
+
+
+enum StateTalk {
+ STATE_TALK_TALK,
+ STATE_TALK_MUTE
+};
+
+enum StateGrab {
+ STATE_GRAB_NONE,
+ STATE_GRAB_DOWN,
+ STATE_GRAB_UP,
+ STATE_GRAB_MID
+};
+
+enum StateOn {
+ STATE_ON_ON,
+ STATE_ON_OFF
+};
+
+enum StateUse {
+ STATE_USE,
+ STATE_USE_ON
+};
+
+
+/*!
+ Each object/item in game has a state field.
+ (refer to ObjectData and ItemData).
+
+ <table>
+ <tr>
+ <td>Name</td>
+ <td>Bits</td>
+ <td>Description</td>
+ </tr>
+ <tr>
+ <td>USE</td>
+ <td>10</td>
+ <td>Use</td>
+ </tr>
+ <tr>
+ <td>TALK</td>
+ <td>9</td>
+ <td>Talk</td>
+ </tr>
+ <tr>
+ <td>ON</td>
+ <td>8</td>
+ <td>On/Off</td>
+ </tr>
+ <tr>
+ <td>DEF</td>
+ <td>7,6,5,4</td>
+ <td>Default verb command</td>
+ </tr>
+ <tr>
+ <td>DIR</td>
+ <td>3,2</td>
+ <td>Direction to face for the object</td>
+ </tr>
+ <tr>
+ <td>GRAB</td>
+ <td>1,0</td>
+ <td>Grab Direction</td>
+ </tr>
+ </table>
+*/
+struct State {
+
+ static Direction findDirection(uint16 state);
+ static StateTalk findTalk(uint16 state);
+ static StateGrab findGrab(uint16 state);
+ static StateOn findOn(uint16 state);
+ static Verb findDefaultVerb(uint16 state);
+ static StateUse findUse(uint16 state);
+
+ static void alterOn(uint16 *objState, StateOn state);
+ static void alterDefaultVerb(uint16 *objState, Verb v);
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/structs.h b/engines/queen/structs.h
new file mode 100644
index 0000000000..4f43950fa4
--- /dev/null
+++ b/engines/queen/structs.h
@@ -0,0 +1,580 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENSTRUCTS_H
+#define QUEENSTRUCTS_H
+
+#include "queen/defs.h"
+
+namespace Queen {
+
+struct Box {
+ int16 x1, y1, x2, y2;
+
+ Box()
+ : x1(0), y1(0), x2(0), y2(0) {
+ }
+
+ Box(int16 xx1, int16 yy1, int16 xx2, int16 yy2)
+ : x1(xx1), y1(yy1), x2(xx2), y2(yy2) {
+ }
+
+ void readFromBE(byte *&ptr) {
+ x1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ y1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ x2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ y2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, x1); ptr += 2;
+ WRITE_BE_UINT16(ptr, y1); ptr += 2;
+ WRITE_BE_UINT16(ptr, x2); ptr += 2;
+ WRITE_BE_UINT16(ptr, y2); ptr += 2;
+ }
+
+ int16 xDiff() const {
+ return x2 - x1;
+ }
+
+ int16 yDiff() const {
+ return y2 - y1;
+ }
+
+ bool intersects(int16 x, int16 y, uint16 w, uint16 h) const {
+ return (x + w > x1) && (y + h > y1) && (x <= x2) && (y <= y2);
+ }
+
+ bool contains(int16 x, int16 y) const {
+ return (x >= x1) && (x <= x2) && (y >= y1) && (y <= y2);
+ }
+
+ bool operator==(const Box &b) const {
+ return (x1 == b.x1) && (x2 == b.x2) && (y1 == b.y1) && (y2 == b.y2);
+ }
+};
+
+
+struct Area {
+ //! bitmask of connected areas
+ int16 mapNeighbours;
+ //! coordinates defining area limits
+ Box box;
+ //! scaling factors for bobs actors
+ uint16 bottomScaleFactor, topScaleFactor;
+ //! entry in ObjectData, object lying in this area
+ uint16 object;
+
+ void readFromBE(byte *&ptr) {
+ mapNeighbours = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ box.readFromBE(ptr);
+ bottomScaleFactor = READ_BE_UINT16(ptr); ptr += 2;
+ topScaleFactor = READ_BE_UINT16(ptr); ptr += 2;
+ object = READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, mapNeighbours); ptr += 2;
+ box.writeToBE(ptr);
+ WRITE_BE_UINT16(ptr, bottomScaleFactor); ptr += 2;
+ WRITE_BE_UINT16(ptr, topScaleFactor); ptr += 2;
+ WRITE_BE_UINT16(ptr, object); ptr += 2;
+ }
+
+ uint16 calcScale(int16 y) const {
+ uint16 dy = box.yDiff();
+ int16 ds = scaleDiff();
+ uint16 scale = 0;
+
+ if (dy) // Prevent division-by-zero
+ scale = ((((y - box.y1) * 100) / dy) * ds) / 100 + bottomScaleFactor;
+
+ if (scale == 0)
+ scale = 100;
+
+ return scale;
+ }
+
+ int16 scaleDiff() const {
+ return (int16)(topScaleFactor - bottomScaleFactor);
+ }
+};
+
+
+struct WalkOffData {
+ //! entry in ObjectData
+ int16 entryObj;
+ //! coordinates to reach
+ uint16 x, y;
+
+ void readFromBE(byte *&ptr) {
+ entryObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ x = READ_BE_UINT16(ptr); ptr += 2;
+ y = READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, entryObj); ptr += 2;
+ WRITE_BE_UINT16(ptr, x); ptr += 2;
+ WRITE_BE_UINT16(ptr, y); ptr += 2;
+ }
+};
+
+
+struct GraphicData {
+ //! coordinates of object
+ uint16 x, y;
+ //! bank bobframes
+ /*!
+ <table>
+ <tr>
+ <td>lastFrame == 0</td>
+ <td>non-animated bob (one frame)</td>
+ </tr>
+ <tr>
+ <td>lastFrame < 0</td>
+ <td>rebound animation</td>
+ </tr>
+ <tr>
+ <td>firstFrame < 0</td>
+ <td>BobSlot::animString (animation is described by a string)</td>
+ </tr>
+ <tr>
+ <td>firstFrame > 0</td>
+ <td>BobSlot::animNormal (animation is a sequence of frames)</td>
+ </tr>
+ </table>
+ */
+ int16 firstFrame, lastFrame;
+ //! moving speed of object
+ uint16 speed;
+
+ void readFromBE(byte *&ptr) {
+ x = READ_BE_UINT16(ptr); ptr += 2;
+ y = READ_BE_UINT16(ptr); ptr += 2;
+ firstFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ lastFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ speed = READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct ObjectData {
+ //! entry in OBJECT_NAME (<0: object is hidden, 0: object has been deleted)
+ int16 name;
+ //! coordinates of object
+ uint16 x, y;
+ //! entry in OBJECT_DESCR
+ uint16 description;
+ //! associated object
+ int16 entryObj;
+ //! room in which this object is available
+ uint16 room;
+ //! state of the object (grab direction, on/off, default command...)
+ uint16 state;
+ //! entry in GraphicData
+ /*!
+ <table>
+ <tr>
+ <td>value</td>
+ <td>description</td>
+ </tr>
+ <tr>
+ <td>]-4000..-10]</td>
+ <td>graphic image turned off</td>
+ </tr>
+ <tr>
+ <td>-4</td>
+ <td>person object (right facing)</td>
+ </tr>
+ <tr>
+ <td>-3</td>
+ <td>person object (left facing)</td>
+ </tr>
+ <tr>
+ <td>-2</td>
+ <td>animated bob (off)</td>
+ </tr>
+ <tr>
+ <td>-1</td>
+ <td>static bob (off)</td>
+ </tr>
+ <tr>
+ <td>0</td>
+ <td>object deleted</td>
+ </tr>
+ <tr>
+ <td>]0..5000]</td>
+ <td>static or animated bob (on)</td>
+ </tr>
+ <tr>
+ <td>]5000.. [</td>
+ <td>'paste down' bob</td>
+ </tr>
+ </table>
+ */
+ int16 image;
+
+ void readFromBE(byte *&ptr) {
+ name = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ x = READ_BE_UINT16(ptr); ptr += 2;
+ y = READ_BE_UINT16(ptr); ptr += 2;
+ description = READ_BE_UINT16(ptr); ptr += 2;
+ entryObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ room = READ_BE_UINT16(ptr); ptr += 2;
+ state = READ_BE_UINT16(ptr); ptr += 2;
+ image = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, name); ptr += 2;
+ WRITE_BE_UINT16(ptr, x); ptr += 2;
+ WRITE_BE_UINT16(ptr, y); ptr += 2;
+ WRITE_BE_UINT16(ptr, description); ptr += 2;
+ WRITE_BE_UINT16(ptr, entryObj); ptr += 2;
+ WRITE_BE_UINT16(ptr, room); ptr += 2;
+ WRITE_BE_UINT16(ptr, state); ptr += 2;
+ WRITE_BE_UINT16(ptr, image); ptr += 2;
+ }
+};
+
+
+struct ObjectDescription {
+ //! entry in ObjectData or ItemData
+ uint16 object;
+ //! type of the description
+ /*!
+ refer to select.c l.75-101
+ <table>
+ <tr>
+ <td>value</td>
+ <td>description</td>
+ </tr>
+ <tr>
+ <td>0</td>
+ <td>random but starts at first description</td>
+ <tr>
+ <td>1</td>
+ <td>random</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>sequential with loop</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>sequential and set description to last</td>
+ </tr>
+ </table>
+ */
+ uint16 type;
+ //! last entry possible in OBJECT_DESCR for this object
+ uint16 lastDescription;
+ //! last description number used (in order to avoid re-using it)
+ uint16 lastSeenNumber;
+
+ void readFromBE(byte *&ptr) {
+ object = READ_BE_UINT16(ptr); ptr += 2;
+ type = READ_BE_UINT16(ptr); ptr += 2;
+ lastDescription = READ_BE_UINT16(ptr); ptr += 2;
+ lastSeenNumber = READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, object); ptr += 2;
+ WRITE_BE_UINT16(ptr, type); ptr += 2;
+ WRITE_BE_UINT16(ptr, lastDescription); ptr += 2;
+ WRITE_BE_UINT16(ptr, lastSeenNumber); ptr += 2;
+ }
+};
+
+
+struct ItemData {
+ //! entry in OBJECT_NAME
+ int16 name;
+ //! entry in OBJECT_DESCR
+ uint16 description;
+ //! state of the object
+ uint16 state;
+ //! bank bobframe
+ uint16 frame;
+ //! entry in OBJECT_DESCR (>0 if available)
+ int16 sfxDescription;
+
+ void readFromBE(byte *&ptr) {
+ name = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ description = READ_BE_UINT16(ptr); ptr += 2;
+ state = READ_BE_UINT16(ptr); ptr += 2;
+ frame = READ_BE_UINT16(ptr); ptr += 2;
+ sfxDescription = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, name); ptr += 2;
+ WRITE_BE_UINT16(ptr, description); ptr += 2;
+ WRITE_BE_UINT16(ptr, state); ptr += 2;
+ WRITE_BE_UINT16(ptr, frame); ptr += 2;
+ WRITE_BE_UINT16(ptr, sfxDescription); ptr += 2;
+ }
+};
+
+
+struct ActorData {
+ //! room in which the actor is
+ int16 room;
+ //! bob number associated to this actor
+ int16 bobNum;
+ //! entry in ACTOR_NAME
+ uint16 name;
+ //! gamestate entry/value, actor is valid if GAMESTATE[slot] == value
+ int16 gsSlot, gsValue;
+ //! spoken text color
+ uint16 color;
+ //! bank bobframe for standing position of the actor
+ uint16 bobFrameStanding;
+ //! initial coordinates in the room
+ uint16 x, y;
+ //! entry in ACTOR_ANIM
+ uint16 anim;
+ //! bank to use to load the actor file
+ uint16 bankNum;
+ //! entry in ACTOR_FILE
+ uint16 file;
+
+ void readFromBE(byte *&ptr) {
+ room = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ bobNum = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ name = READ_BE_UINT16(ptr); ptr += 2;
+ gsSlot = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ gsValue = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ color = READ_BE_UINT16(ptr); ptr += 2;
+ bobFrameStanding = READ_BE_UINT16(ptr); ptr += 2;
+ x = READ_BE_UINT16(ptr); ptr += 2;
+ y = READ_BE_UINT16(ptr); ptr += 2;
+ anim = READ_BE_UINT16(ptr); ptr += 2;
+ bankNum = READ_BE_UINT16(ptr); ptr += 2;
+ file = READ_BE_UINT16(ptr); ptr += 2;
+ // Fix the actor data (see queen.c - l.1518-1519). When there is no
+ // valid actor file, we must load the data from the objects room bank.
+ // This bank has number 15 (not 10 as in the data files).
+ if (file == 0) {
+ bankNum = 15;
+ }
+ }
+};
+
+
+struct CmdListData {
+ //! action to perform
+ Verb verb;
+ //! first object used in the action
+ int16 nounObj1;
+ //! second object used in the action
+ int16 nounObj2;
+ //! song to play (>0: playbefore, <0: playafter)
+ int16 song;
+ //! if set, P2_SET_AREAS must be called (using CmdArea)
+ bool setAreas;
+ //! if set, P3_SET_OBJECTS must be called (using CmdObject)
+ bool setObjects;
+ //! if set, P4_SET_ITEMS must be called (using CmdInventory)
+ bool setItems;
+ //! if set, P1_SET_CONDITIONS must be called (using CmdGameState)
+ bool setConditions;
+ //! graphic image order
+ int16 imageOrder;
+ //! special section to execute (refer to execute.c l.423-451)
+ int16 specialSection;
+
+ void readFromBE(byte *&ptr) {
+ verb = (Verb)READ_BE_UINT16(ptr); ptr += 2;
+ nounObj1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ nounObj2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ song = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ setAreas = READ_BE_UINT16(ptr) != 0; ptr += 2;
+ setObjects = READ_BE_UINT16(ptr) != 0; ptr += 2;
+ setItems = READ_BE_UINT16(ptr) != 0; ptr += 2;
+ setConditions = READ_BE_UINT16(ptr) != 0; ptr += 2;
+ imageOrder = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ specialSection = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+
+ bool match(const Verb& v, int16 obj1, int16 obj2) const {
+ return verb == v && nounObj1 == obj1 && nounObj2 == obj2;
+ }
+};
+
+
+struct CmdArea {
+ //! CmdListData number
+ int16 id;
+ //! area to turn off/on (<0: off, >0: on)
+ int16 area;
+ //! room in which the area must be changed
+ uint16 room;
+
+ void readFromBE(byte *&ptr) {
+ id = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ area = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ room = READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct CmdObject {
+ //! CmdListData number
+ int16 id;
+ //! >0: show, <0: hide
+ int16 dstObj;
+ //! >0: copy from srcObj, 0: nothing, -1: delete dstObj
+ int16 srcObj;
+
+ void readFromBE(byte *&ptr) {
+ id = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ dstObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ srcObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct CmdInventory {
+ //! CmdListData number
+ int16 id;
+ //! <0: delete, >0: add
+ int16 dstItem;
+ //! >0: valid
+ int16 srcItem;
+
+ void readFromBE(byte *&ptr) {
+ id = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ dstItem = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ srcItem = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct CmdGameState {
+ //! CmdListData number
+ int16 id;
+ int16 gameStateSlot;
+ int16 gameStateValue;
+ uint16 speakValue;
+
+ void readFromBE(byte *&ptr) {
+ id = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ gameStateSlot = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ gameStateValue = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ speakValue = READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct FurnitureData {
+ //! room in which the furniture are
+ int16 room;
+ //! furniture object number
+ /*!
+ <table>
+ <tr>
+ <td>range</td>
+ <td>type</td>
+ </tr>
+ <tr>
+ <td>]0..5000]</td>
+ <td>static or animated</td>
+ </tr>
+ <tr>
+ <td>]5000..[</td>
+ <td>paste down</td>
+ </tr>
+ </table>
+ */
+ int16 objNum;
+
+ void readFromBE(byte *&ptr) {
+ room = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ objNum = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct GraphicAnim {
+ int16 keyFrame;
+ int16 frame;
+ uint16 speed;
+
+ void readFromBE(byte *&ptr) {
+ keyFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ frame = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ speed = READ_BE_UINT16(ptr); ptr += 2;
+ }
+};
+
+
+struct AnimFrame {
+ uint16 frame;
+ uint16 speed;
+};
+
+
+struct Person {
+ //! actor settings to use
+ const ActorData *actor;
+ //! actor name
+ const char *name;
+ //! animation string
+ const char *anim;
+ //! current frame
+ uint16 bobFrame;
+};
+
+
+struct TalkSelected {
+ bool hasTalkedTo;
+ int16 values[4];
+
+ void readFromBE(byte *&ptr) {
+ hasTalkedTo = READ_BE_UINT16(ptr) != 0; ptr += 2;
+ for (int i = 0; i < 4; i++) {
+ values[i] = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ }
+ }
+
+ void writeToBE(byte *&ptr) {
+ WRITE_BE_UINT16(ptr, (uint16)hasTalkedTo); ptr += 2;
+ for (int i = 0; i < 4; i++) {
+ WRITE_BE_UINT16(ptr, values[i]); ptr += 2;
+ }
+ }
+};
+
+
+struct BobFrame {
+ uint16 width, height;
+ uint16 xhotspot, yhotspot;
+ uint8 *data;
+};
+
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp
new file mode 100644
index 0000000000..27399ab0cf
--- /dev/null
+++ b/engines/queen/talk.cpp
@@ -0,0 +1,1812 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/talk.h"
+
+#include "queen/bankman.h"
+#include "queen/display.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/input.h"
+#include "queen/logic.h"
+#include "queen/queen.h"
+#include "queen/resource.h"
+#include "queen/sound.h"
+#include "queen/state.h"
+#include "queen/walk.h"
+
+#include "common/file.h"
+
+namespace Queen {
+
+#ifdef PALMOS_68K
+static const Talk::SpeechParameters *_speechParameters;
+#endif
+
+void Talk::talk(
+ const char *filename,
+ int personInRoom,
+ char *cutawayFilename,
+ QueenEngine *vm) {
+ Talk *talk = new Talk(vm);
+ talk->talk(filename, personInRoom, cutawayFilename);
+ delete talk;
+}
+
+bool Talk::speak(
+ const char *sentence,
+ Person *person,
+ const char *voiceFilePrefix,
+ QueenEngine *vm) {
+ Talk *talk = new Talk(vm);
+ bool result;
+ if (sentence)
+ result = talk->speak(sentence, person, voiceFilePrefix);
+ else
+ result = false;
+ delete talk;
+ return result;
+}
+
+Talk::Talk(QueenEngine *vm)
+ : _vm(vm), _fileData(NULL) {
+ _vm->input()->talkQuitReset();
+}
+
+Talk::~Talk() {
+ delete[] _fileData;
+}
+
+void Talk::talk(const char *filename, int personInRoom, char *cutawayFilename) {
+ int i;
+ _oldSelectedSentenceIndex = 0;
+ _oldSelectedSentenceValue = 0;
+
+ debug(6, "----- talk(\"%s\") -----", filename);
+
+ cutawayFilename[0] = '\0';
+
+ load(filename);
+
+ Person person;
+ memset(&person, 0, sizeof(Person));
+ _vm->logic()->initPerson(personInRoom, "", false, &person);
+
+ if (NULL == person.name) {
+ error("Invalid person object");
+ }
+
+ int16 oldLevel = 0;
+ bool personWalking = false;
+
+ // Lines 828-846 in talk.c
+ for (i = 1; i <= 4; i++) {
+ if (selectedValue(i) > 0) {
+ // This option has been redefined so display new dialogue option
+ _dialogueTree[1][i].head = selectedValue(i);
+ } else if (selectedValue(i) == -1) {
+ // Already selected so don't redisplay
+ if (_dialogueTree[1][i].gameStateIndex >= 0) {
+ _dialogueTree[1][i].head = -1;
+ _dialogueTree[1][i].dialogueNodeValue1 = -1;
+ _dialogueTree[1][i].gameStateIndex = -1;
+ _dialogueTree[1][i].gameStateValue = -1;
+ }
+ }
+ }
+
+ initialTalk();
+
+ // Lines 906-? in talk.c
+ _vm->display()->showMouseCursor(true);
+
+ int16 level=1, retval=0;
+ int16 head = _dialogueTree[level][0].head;
+
+ // TODO: split this loop in several functions
+ while (retval != -1) {
+ char otherVoiceFilePrefix[MAX_STRING_SIZE];
+
+ _talkString[0][0] = '\0';
+
+ if (hasTalkedTo() && head == 1)
+ strcpy(_talkString[0], _person2String);
+ else
+ findDialogueString(_person1PtrOff, head, _pMax, _talkString[0]);
+
+ if (hasTalkedTo() && head == 1)
+ sprintf(otherVoiceFilePrefix, "%2dXXXXP", _talkKey);
+ else
+ sprintf(otherVoiceFilePrefix, "%2d%4xP", _talkKey, head);
+
+ if (_talkString[0][0] == '\0' && retval > 1) {
+ findDialogueString(_person1PtrOff, retval, _pMax, _talkString[0]);
+ sprintf(otherVoiceFilePrefix,"%2d%4xP", _talkKey, retval);
+ }
+
+ // Joe dialogue
+
+ for (i = 1; i <= 4; i++) {
+ findDialogueString(_joePtrOff, _dialogueTree[level][i].head, _jMax, _talkString[i]);
+
+ int16 index = _dialogueTree[level][i].gameStateIndex;
+
+ if (index < 0 && _vm->logic()->gameState(ABS(index)) != _dialogueTree[level][i].gameStateValue)
+ _talkString[i][0] = '\0';
+
+ sprintf(_joeVoiceFilePrefix[i], "%2d%4xJ", _talkKey, _dialogueTree[level][i].head);
+ }
+
+ // Check to see if (all the dialogue options have been selected.
+ // if this is the case, and the last one left is the exit option,
+ // then automatically set S to that and exit.
+
+ int choicesLeft = 0;
+ int selectedSentence = 0;
+
+ for (i = 1; i <= 4; i++) {
+ if (_talkString[i][0] != '\0') {
+ choicesLeft++;
+ selectedSentence = i;
+ }
+ }
+
+ debug(6, "choicesLeft = %i", choicesLeft);
+
+ if (1 == choicesLeft) {
+ // Automatically run the final dialogue option
+ if (speak(_talkString[0], &person, otherVoiceFilePrefix))
+ personWalking = true;
+
+ if (_vm->input()->talkQuit())
+ break;
+
+ speak(_talkString[selectedSentence], NULL, _joeVoiceFilePrefix[selectedSentence]);
+ } else {
+ if (person.actor->bobNum > 0) {
+ speak(_talkString[0], &person, otherVoiceFilePrefix);
+ selectedSentence = selectSentence();
+ } else {
+ warning("bobBum is %i", person.actor->bobNum);
+ selectedSentence = 0;
+ }
+ }
+
+ if (_vm->input()->talkQuit())
+ break;
+
+ retval = _dialogueTree[level][selectedSentence].dialogueNodeValue1;
+ head = _dialogueTree[level][selectedSentence].head;
+ oldLevel = level;
+ level = 0;
+
+ // Set LEVEL to the selected child in dialogue tree
+
+ for (i = 1; i <= _levelMax; i++)
+ if (_dialogueTree[i][0].head == head)
+ level = i;
+
+ if (0 == level) {
+ // No new level has been selected, so lets set LEVEL to the
+ // tree path pointed to by the RETVAL
+
+ for (i = 1; i <= _levelMax; i++)
+ for (int j = 0; j <= 5; j++)
+ if (_dialogueTree[i][j].head == retval)
+ level = i;
+
+ disableSentence(oldLevel, selectedSentence);
+ } else { // 0 != level
+ // Check to see if Person Return value is positive, if it is, then
+ // change the selected dialogue option to the Return value
+
+ if (_dialogueTree[level][0].dialogueNodeValue1 > 0) {
+ if (1 == oldLevel) {
+ _oldSelectedSentenceIndex = selectedSentence;
+ _oldSelectedSentenceValue = selectedValue(selectedSentence);
+ selectedValue(selectedSentence, _dialogueTree[level][0].dialogueNodeValue1);
+ }
+
+ _dialogueTree[oldLevel][selectedSentence].head = _dialogueTree[level][0].dialogueNodeValue1;
+ _dialogueTree[level][0].dialogueNodeValue1 = -1;
+ } else {
+ disableSentence(oldLevel, selectedSentence);
+ }
+ }
+
+ // Check selected person to see if any Gamestates need setting
+
+ int16 index = _dialogueTree[level][0].gameStateIndex;
+ if (index > 0)
+ _vm->logic()->gameState(index, _dialogueTree[level][0].gameStateValue);
+
+ // if the selected dialogue line has a POSITIVE game state value
+ // then set gamestate to Value = TALK(OLDLEVEL,S,3)
+
+ index = _dialogueTree[oldLevel][selectedSentence].gameStateIndex;
+ if (index > 0)
+ _vm->logic()->gameState(index, _dialogueTree[oldLevel][selectedSentence].gameStateValue);
+
+ // check to see if person has something final to say
+ if (-1 == retval) {
+ findDialogueString(_person1PtrOff, head, _pMax, _talkString[0]);
+ if (_talkString[0][0] != '\0') {
+ sprintf(otherVoiceFilePrefix, "%2d%4xP", _talkKey, head);
+ if (speak(_talkString[0], &person, otherVoiceFilePrefix))
+ personWalking = true;
+ }
+ }
+ }
+
+ cutawayFilename[0] = '\0';
+
+ for (i = 0; i < 2; i++) {
+ if (_gameState[i] > 0) {
+ if (_vm->logic()->gameState(_gameState[i]) == _testValue[i]) {
+ if (_itemNumber[i] > 0)
+ _vm->logic()->inventoryInsertItem(_itemNumber[i]);
+ else
+ _vm->logic()->inventoryDeleteItem(ABS(_itemNumber[i]));
+ }
+ }
+ }
+
+ _vm->grid()->setupPanel();
+
+ uint16 offset = _cutawayPtrOff;
+
+ int16 cutawayGameState = (int16)READ_BE_INT16(_fileData + offset); offset += 2;
+ int16 cutawayTestValue = (int16)READ_BE_INT16(_fileData + offset); offset += 2;
+
+ if (_vm->logic()->gameState(cutawayGameState) == cutawayTestValue) {
+ getString(_fileData, offset, cutawayFilename, 20);
+ if (cutawayFilename[0]) {
+ //CR 2 - 7/3/95, If we're executing a cutaway scene, then make sure
+ // Joe can talk, so set TALKQUIT to 0 just in case we exit on the
+ // line that set's the cutaway game states.
+ _vm->input()->talkQuitReset();
+ }
+ }
+ if (_vm->input()->talkQuit()) {
+ if (_oldSelectedSentenceIndex > 0)
+ selectedValue(_oldSelectedSentenceIndex, _oldSelectedSentenceValue);
+ _vm->input()->talkQuitReset();
+ _vm->display()->clearTexts(0, 198);
+ _vm->logic()->makeJoeSpeak(15, false);
+ } else {
+ setHasTalkedTo();
+ }
+
+ _vm->logic()->joeFace();
+
+ if (cutawayFilename[0] == '\0') {
+ BobSlot *pbs = _vm->graphics()->bob(person.actor->bobNum);
+
+ pbs->x = person.actor->x;
+ pbs->y = person.actor->y;
+
+ // Better kick start the persons anim sequence
+ _vm->graphics()->resetPersonAnim(person.actor->bobNum);
+ }
+
+ _vm->logic()->joeWalk(JWM_NORMAL);
+}
+
+void Talk::disableSentence(int oldLevel, int selectedSentence) {
+ // Mark off selected option
+
+ if (1 == oldLevel) {
+ if (_dialogueTree[oldLevel][selectedSentence].dialogueNodeValue1 != -1) {
+ // Make sure choice is not exit option
+ _oldSelectedSentenceIndex = selectedSentence;
+ _oldSelectedSentenceValue = selectedValue(selectedSentence);
+ selectedValue(selectedSentence, -1);
+ }
+ }
+
+ // Cancel selected dialogue line, so that its no longer displayed
+ _dialogueTree[oldLevel][selectedSentence].head = -1;
+ _dialogueTree[oldLevel][selectedSentence].dialogueNodeValue1 = -1;
+}
+
+void Talk::findDialogueString(uint16 offset, int16 id, int16 max, char *str) {
+ str[0] = '\0';
+ for (int i = 1; i <= max; i++) {
+ offset += 2;
+ int16 currentId = (int16)READ_BE_INT16(_fileData + offset);
+ offset += 2;
+ if (id == currentId) {
+ getString(_fileData, offset, str, MAX_STRING_LENGTH, 4);
+ break;
+ } else {
+ getString(_fileData, offset, NULL, MAX_STRING_LENGTH, 4);
+ }
+ }
+}
+
+byte *Talk::loadDialogFile(const char *filename) {
+ static const struct {
+ const char *filename;
+ Language lang;
+ } dogFiles[] = {
+ { "chief1.dog", FRENCH },
+ { "chief2.dog", FRENCH },
+ { "bud1.dog", ITALIAN }
+ };
+ for (int i = 0; i < ARRAYSIZE(dogFiles); ++i) {
+ if (!scumm_stricmp(filename, dogFiles[i].filename) &&
+ _vm->resource()->getLanguage() == dogFiles[i].lang) {
+ Common::File fdog;
+ fdog.open(filename);
+ if (fdog.isOpen()) {
+ debug(6, "Loading dog file '%s' from game data path", filename);
+ uint32 size = fdog.size() - DOG_HEADER_SIZE;
+ byte *buf = new byte[size];
+ fdog.seek(DOG_HEADER_SIZE);
+ fdog.read(buf, size);
+ return buf;
+ }
+ }
+ }
+ return _vm->resource()->loadFile(filename, DOG_HEADER_SIZE);
+}
+
+void Talk::load(const char *filename) {
+ int i;
+ byte *ptr = _fileData = loadDialogFile(filename);
+ bool canQuit;
+
+ // Load talk header
+
+ _levelMax = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ if (_levelMax < 0) {
+ _levelMax = -_levelMax;
+ canQuit = false;
+ } else {
+ canQuit = true;
+ }
+
+ _uniqueKey = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _talkKey = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _jMax = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _pMax = (int16)READ_BE_INT16(ptr); ptr += 2;
+
+ for (i = 0; i < 2; i++) {
+ _gameState [i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _testValue [i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ _itemNumber[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
+ }
+
+ _person1PtrOff = READ_BE_UINT16(ptr); ptr += 2;
+ _cutawayPtrOff = READ_BE_UINT16(ptr); ptr += 2;
+ _person2PtrOff = READ_BE_UINT16(ptr); ptr += 2;
+ _joePtrOff = 32 + _levelMax * 96;
+
+ // Load dialogue tree
+ ptr = _fileData + 32;
+ memset(&_dialogueTree[0], 0, sizeof(_dialogueTree[0]));
+ for (i = 1; i <= _levelMax; i++)
+ for (int j = 0; j <= 5; j++) {
+ ptr += 2;
+ _dialogueTree[i][j].head = (int16)READ_BE_INT16(ptr); ptr += 2;
+ ptr += 2;
+ _dialogueTree[i][j].dialogueNodeValue1 = (int16)READ_BE_INT16(ptr); ptr += 2;
+ ptr += 2;
+ _dialogueTree[i][j].gameStateIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
+ ptr += 2;
+ _dialogueTree[i][j].gameStateValue = (int16)READ_BE_INT16(ptr); ptr += 2;
+ }
+}
+
+void Talk::initialTalk() {
+ // Lines 848-903 in talk.c
+
+ uint16 offset = _joePtrOff + 2;
+ uint16 hasNotString = READ_BE_UINT16(_fileData + offset); offset += 2;
+
+ char joeString[MAX_STRING_SIZE];
+ if (!hasNotString) {
+ getString(_fileData, offset, joeString, MAX_STRING_LENGTH);
+ } else {
+ joeString[0] = '\0';
+ }
+
+ offset = _person2PtrOff;
+ char joe2String[MAX_STRING_SIZE];
+ getString(_fileData, offset, _person2String, MAX_STRING_LENGTH);
+ getString(_fileData, offset, joe2String, MAX_STRING_LENGTH);
+
+ if (!hasTalkedTo()) {
+ // Not yet talked to this person
+ if (joeString[0] != '0') {
+ char voiceFilePrefix[MAX_STRING_SIZE];
+ sprintf(voiceFilePrefix, "%2dSSSSJ", _talkKey);
+ speak(joeString, NULL, voiceFilePrefix);
+ }
+ } else {
+ // Already spoken to them, choose second response
+ if (joe2String[0] != '0') {
+ char voiceFilePrefix[MAX_STRING_SIZE];
+ sprintf(voiceFilePrefix, "%2dXXXXJ", _talkKey);
+ speak(joe2String, NULL, voiceFilePrefix);
+ }
+ }
+}
+
+int Talk::getSpeakCommand(const Person *person, const char *sentence, unsigned &index) {
+ // Lines 1299-1362 in talk.c
+ int commandCode = SPEAK_DEFAULT;
+ uint16 id = (sentence[index] << 8) | sentence[index + 1];
+ switch (id) {
+ case 'AO':
+ commandCode = SPEAK_AMAL_ON;
+ break;
+ case 'FL':
+ commandCode = SPEAK_FACE_LEFT;
+ break;
+ case 'FF':
+ commandCode = SPEAK_FACE_FRONT;
+ break;
+ case 'FB':
+ commandCode = SPEAK_FACE_BACK;
+ break;
+ case 'FR':
+ commandCode = SPEAK_FACE_RIGHT;
+ break;
+ case 'GD':
+ _vm->logic()->joeGrab(STATE_GRAB_DOWN);
+ commandCode = SPEAK_NONE;
+ break;
+ case 'GM':
+ _vm->logic()->joeGrab(STATE_GRAB_MID);
+ commandCode = SPEAK_NONE;
+ break;
+ case 'WT':
+ commandCode = SPEAK_PAUSE;
+ break;
+ case 'XY':
+ // For example *XY00(237,112)
+ {
+ commandCode = atoi(sentence + index + 2);
+ int x = atoi(sentence + index + 5);
+ int y = atoi(sentence + index + 9);
+ if (0 == strcmp(person->name, "JOE"))
+ _vm->walk()->moveJoe(0, x, y, _vm->input()->cutawayRunning());
+ else
+ _vm->walk()->movePerson(person, x, y, _vm->graphics()->numFrames(), 0);
+ index += 11;
+ // if (JOEWALK==3) CUTQUIT=0;
+ // XXX personWalking = true;
+ }
+ break;
+ default:
+ if (sentence[index + 0] >= '0' && sentence[index + 0] <= '9' &&
+ sentence[index + 1] >= '0' && sentence[index + 1] <= '9') {
+ commandCode = (sentence[index] - '0') * 10 + (sentence[index + 1] - '0');
+ } else
+ warning("Unknown command string: '%2s'", sentence + index);
+ }
+
+ index += 2;
+
+ return commandCode;
+}
+
+
+bool Talk::speak(const char *sentence, Person *person, const char *voiceFilePrefix) {
+ // Function SPEAK, lines 1266-1384 in talk.c
+ bool personWalking = false;
+ unsigned segmentIndex = 0;
+ unsigned segmentStart = 0;
+ unsigned i;
+
+ Person joe_person;
+ ActorData joe_actor;
+
+ _vm->logic()->joeWalk(JWM_SPEAK);
+
+ if (!person) {
+ // Fill in values for use by speakSegment() etc.
+ memset(&joe_person, 0, sizeof(Person));
+ memset(&joe_actor, 0, sizeof(ActorData));
+
+ joe_actor.bobNum = 0;
+ joe_actor.color = 14;
+ joe_actor.bankNum = 7;
+
+ joe_person.actor = &joe_actor;
+ joe_person.name = "JOE";
+
+ person = &joe_person;
+ }
+
+ debug(6, "Sentence '%s' is said by person '%s' and voice files with prefix '%s' played",
+ sentence, person->name, voiceFilePrefix);
+
+ if (sentence[0] == '\0') {
+ return personWalking;
+ }
+
+ if (0 == strcmp(person->name, "FAYE-H" ) ||
+ 0 == strcmp(person->name, "FRANK-H") ||
+ 0 == strcmp(person->name, "AZURA-H") ||
+ 0 == strcmp(person->name, "X3_RITA") ||
+ (0 == strcmp(person->name, "JOE") && _vm->logic()->currentRoom() == FAYE_HEAD ) ||
+ (0 == strcmp(person->name, "JOE") && _vm->logic()->currentRoom() == AZURA_HEAD) ||
+ (0 == strcmp(person->name, "JOE") && _vm->logic()->currentRoom() == FRANK_HEAD))
+ _talkHead = true;
+ else
+ _talkHead = false;
+
+ for (i = 0; i < strlen(sentence); ) {
+ if (sentence[i] == '*') {
+ int segmentLength = i - segmentStart;
+
+ i++;
+ int command = getSpeakCommand(person, sentence, i);
+
+ if (SPEAK_NONE != command) {
+ speakSegment(
+ sentence + segmentStart,
+ segmentLength,
+ person,
+ command,
+ voiceFilePrefix,
+ segmentIndex);
+ // XXX if (JOEWALK == 2) break
+ }
+
+ segmentIndex++;
+ segmentStart = i;
+ } else
+ i++;
+
+ if (_vm->input()->cutawayQuit() || _vm->input()->talkQuit())
+ return personWalking;
+ }
+
+ if (segmentStart != i) {
+ speakSegment(
+ sentence + segmentStart,
+ i - segmentStart,
+ person,
+ 0,
+ voiceFilePrefix,
+ segmentIndex);
+ }
+
+ return personWalking;
+}
+
+int Talk::countSpaces(const char *segment) {
+ int tmp = 0;
+
+ while (*segment++)
+ tmp++;
+
+ if (tmp < 10)
+ tmp = 10;
+
+ return (tmp * 2) / (_vm->talkSpeed() / 3);
+}
+
+void Talk::headStringAnimation(const SpeechParameters *parameters, int bobNum, int bankNum) {
+ // talk.c lines 1612-1635
+ BobSlot *bob2 = _vm->graphics()->bob(2);
+
+ if (parameters->animation[0] == 'E') {
+ int offset = 1;
+
+ BobSlot *bob = _vm->graphics()->bob(bobNum);
+ int16 x = bob->x;
+ int16 y = bob->y;
+
+ for (;;) {
+ uint16 frame;
+
+ frame = atoi(parameters->animation + offset);
+ if (!frame)
+ break;
+
+ offset += 4;
+
+ _vm->bankMan()->unpack(frame, _vm->graphics()->numFrames(), bankNum);
+
+ bob2->frameNum = _vm->graphics()->numFrames();
+ bob2->scale = 100;
+ bob2->active = true;
+ bob2->x = x;
+ bob2->y = y;
+
+ _vm->update();
+ }
+ } else
+ bob2->active = false;
+}
+
+void Talk::stringAnimation(const SpeechParameters *parameters, int startFrame, int bankNum) {
+ // lines 1639-1690 in talk.c
+
+ int offset = 0;
+ bool torso;
+
+ if (parameters->animation[0] == 'T') {
+ // Torso animation
+ torso = true;
+ _vm->bankMan()->overpack(parameters->body, startFrame, bankNum);
+ offset++;
+ } else if (parameters->animation[0] == 'E') {
+ // Talking head animation
+ return;
+ } else if (!isdigit(parameters->animation[0])) {
+ debug(6, "Error in speak string animation: '%s'", parameters->animation);
+ return;
+ } else
+ torso = false;
+
+ for (;;) {
+ uint16 frame;
+
+ frame = atoi(parameters->animation + offset);
+ if (!frame)
+ break;
+
+ offset += 4;
+
+ if (frame > 500) {
+ frame -= 500;
+ _vm->sound()->playSfx(_vm->logic()->currentRoomSfx(), false);
+ }
+
+ if (torso) {
+ _vm->bankMan()->overpack(frame, startFrame, bankNum);
+ } else {
+ _vm->bankMan()->unpack(frame, startFrame, bankNum);
+ // XXX bobs[BNUM].scale=SF;
+ }
+
+ _vm->update();
+ }
+}
+
+void Talk::defaultAnimation(
+ const char *segment,
+ bool isJoe,
+ const SpeechParameters *parameters,
+ int startFrame,
+ int bankNum) {
+ // lines 1730-1823 in talk.c
+
+ if (segment[0] != 0) {
+
+ // Why on earth would someone name a variable qzx?
+ short qzx = 0;
+
+ int len = countSpaces(segment);
+ while (1) {
+ if (parameters != NULL) {
+
+ int bf;
+ if (segment[0] == ' ')
+ bf = 0;
+ else
+ bf = parameters->bf;
+
+ int head;
+ if (parameters->rf > 0)
+ head = bf + _vm->randomizer.getRandomNumber(parameters->rf);
+ else
+ head = bf;
+
+ if (bf > 0) {
+ // Make the head move
+ qzx ^= 1;
+ if (parameters->af && qzx)
+ _vm->bankMan()->overpack(parameters->af + head, startFrame, bankNum);
+ else {
+ _vm->bankMan()->overpack(head, startFrame, bankNum);
+ }
+ } else {
+ debug(6, "[Talk::defaultAnimation] Body action!");
+ // Just do a body action
+ _vm->bankMan()->overpack(parameters->body, startFrame, bankNum);
+ }
+
+ if (!_talkHead)
+ _vm->update();
+ } else { // (_talkHead && isJoe)
+ _vm->update();
+ }
+
+ if (_vm->input()->talkQuit())
+ break;
+
+ if (_vm->logic()->joeWalk() == JWM_SPEAK) {
+ _vm->update();
+ } else {
+ _vm->update(true);
+ if (_vm->logic()->joeWalk() == JWM_EXECUTE)
+ // Selected a command, so exit
+ break;
+ }
+
+ // Skip through text more quickly
+ if (_vm->input()->keyVerb() == VERB_SKIP_TEXT) {
+ _vm->input()->clearKeyVerb();
+ _vm->sound()->stopSpeech();
+ break;
+ }
+
+ if (_vm->sound()->speechOn() && _vm->sound()->speechSfxExists()) {
+ // sfx is finished, stop the speak animation
+ if (!_vm->sound()->isSpeechActive()) {
+ break;
+ }
+ } else {
+ // no sfx, stop the animation when speak segment 'length' is 0
+ --len;
+ if (len <= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Make sure that Person closes their mouth
+ if (!isJoe && parameters->ff > 0)
+ _vm->bankMan()->overpack(parameters->ff, startFrame, bankNum);
+}
+
+
+void Talk::speakSegment(
+ const char *segmentStart,
+ int length,
+ Person *person,
+ int command,
+ const char *voiceFilePrefix,
+ int index)
+{
+ int i;
+ char segment[MAX_STRING_SIZE];
+ memcpy(segment, segmentStart, length);
+ segment[length] = '\0';
+
+ char voiceFileName[MAX_STRING_SIZE];
+ sprintf(voiceFileName, "%s%1x", voiceFilePrefix, index + 1);
+
+ // FIXME - it seems the french talkie version has a useless voice file ;
+ // the c30e_102 file is very similar to c30e_101, so there is no need to
+ // play it. This voice was used in room 30 (N8) when talking to Klunk.
+ if (!(_vm->resource()->getLanguage() == FRENCH && !strcmp(voiceFileName, "c30e_102"))
+ && _vm->sound()->speechOn())
+ _vm->sound()->playSfx(voiceFileName, true);
+
+ int faceDirectionCommand = 0;
+
+ switch (command) {
+ case SPEAK_PAUSE:
+ for (i = 0; i < 10 && !_vm->input()->talkQuit(); i++) {
+ _vm->update();
+ }
+ return;
+
+ case SPEAK_FACE_LEFT:
+ case SPEAK_FACE_RIGHT:
+ case SPEAK_FACE_FRONT:
+ case SPEAK_FACE_BACK:
+ faceDirectionCommand = command;
+ command = 0;
+ break;
+ }
+
+ bool isJoe = (0 == person->actor->bobNum);
+
+ int16 bobNum = person->actor->bobNum;
+ uint16 color = person->actor->color;
+ uint16 bankNum = person->actor->bankNum;
+
+ BobSlot *bob = _vm->graphics()->bob(bobNum);
+
+ bool oracle = false;
+ int textX = 0;
+ int textY = 0;
+
+ if (!isJoe) {
+ if (SPEAK_AMAL_ON == command) {
+ // It's the oracle!
+ // Don't turn AMAL animation off, and don't manually anim person
+ command = SPEAK_ORACLE;
+ oracle = true;
+ uint16 frameNum = _vm->graphics()->personFrames(bobNum);
+ for (i = 5; i <= 8; ++i) {
+ _vm->bankMan()->unpack(i, frameNum, bankNum);
+ ++frameNum;
+ }
+ } else {
+ bob->animating = false;
+ bob->frameNum = 31 + bobNum;
+ }
+ }
+
+ if (_talkHead) {
+ // talk.c lines 1491-1533
+ switch (_vm->logic()->currentRoom()) {
+ case FAYE_HEAD:
+ case AZURA_HEAD:
+ textX = 15;
+ break;
+ default: // FRANK_HEAD
+ textX = 150;
+ break;
+ }
+ textY = isJoe ? 30 : 60;
+ } else {
+ textX = bob->x;
+ textY = bob->y;
+ }
+
+ //int SF = _vm->grid()->findScale(textX, textY);
+
+ const SpeechParameters *parameters = NULL;
+ int startFrame = 0;
+
+ if (_talkHead && isJoe) {
+ if (_vm->subtitles())
+ _vm->graphics()->setBobText(bob, segment, textX, textY, color, true);
+ defaultAnimation(segment, isJoe, parameters, startFrame, bankNum);
+ } else {
+ if (SPEAK_UNKNOWN_6 == command)
+ return;
+
+ if (isJoe) {
+ if (_vm->logic()->currentRoom() == 108)
+ parameters = findSpeechParameters("JOE-E", command, 0);
+ else
+ parameters = findSpeechParameters("JOE", command, _vm->logic()->joeFacing());
+ }
+ else
+ parameters = findSpeechParameters(person->name, command, 0);
+
+ startFrame = 31 + bobNum;
+ int faceDirection = 0;
+
+ if (isJoe && _vm->logic()->joeFacing() == DIR_LEFT)
+ faceDirection = DIR_LEFT;
+ else if (!isJoe) {
+ ObjectData *data = _vm->logic()->objectData(_vm->logic()->objectForPerson(bobNum));
+
+ if (data->image == -3)
+ faceDirection = DIR_LEFT;
+
+ if (faceDirectionCommand == SPEAK_FACE_LEFT)
+ data->image = -3;
+ else if (faceDirectionCommand == SPEAK_FACE_RIGHT)
+ data->image = -4;
+ }
+
+ if (faceDirectionCommand) {
+ switch (faceDirectionCommand) {
+ case SPEAK_FACE_LEFT:
+ faceDirection = DIR_LEFT;
+ break;
+ case SPEAK_FACE_RIGHT:
+ faceDirection = DIR_RIGHT;
+ break;
+ case SPEAK_FACE_FRONT:
+ faceDirection = DIR_FRONT;
+ break;
+ case SPEAK_FACE_BACK:
+ faceDirection = DIR_BACK;
+ break;
+ }
+ if (isJoe)
+ _vm->logic()->joeFacing(faceDirection);
+ }
+
+ if (!isJoe) {
+ bob->xflip = (faceDirection == DIR_LEFT);
+ }
+
+ // Run animated sequence if SANIMstr is primed
+
+ if (_talkHead) {
+ // talk.c lines 1612-1635
+ headStringAnimation(parameters, bobNum, bankNum);
+ }
+
+ if (_vm->subtitles())
+ _vm->graphics()->setBobText(bob, segment, textX, textY, color, _talkHead);
+
+ if (parameters->animation[0] != '\0' && parameters->animation[0] != 'E') {
+ stringAnimation(parameters, startFrame, bankNum);
+ } else {
+ _vm->bankMan()->unpack(parameters->body, startFrame, bankNum);
+
+ if (length == 0 && !isJoe && parameters->bf > 0) {
+ _vm->bankMan()->overpack(parameters->bf, startFrame, bankNum);
+ _vm->update();
+ }
+
+ if (-1 == parameters->rf) {
+ // Setup the Torso frames
+ _vm->bankMan()->overpack(parameters->bf, startFrame, bankNum);
+ if (isJoe)
+ parameters = findSpeechParameters(person->name, 0, _vm->logic()->joeFacing());
+ else
+ parameters = findSpeechParameters(person->name, 0, 0);
+ }
+
+ if (-2 == parameters->rf) {
+ // Setup the Torso frames
+ _vm->bankMan()->overpack(parameters->bf, startFrame, bankNum);
+ if (isJoe)
+ parameters = findSpeechParameters(person->name, 14, _vm->logic()->joeFacing());
+ else
+ parameters = findSpeechParameters(person->name, 14, 0);
+ }
+
+ defaultAnimation(segment, isJoe, parameters, startFrame, bankNum);
+ }
+ }
+
+ // Moved here so that Text is cleared when a Torso command done!
+ _vm->display()->clearTexts(0,198);
+
+ if (oracle) {
+ uint16 frameNum = _vm->graphics()->personFrames(bobNum);
+ for (i = 1; i <= 4; ++i) {
+ _vm->bankMan()->unpack(i, frameNum, bankNum);
+ ++frameNum;
+ }
+ }
+
+ // Ensure that the correct buffer frame is selected
+
+ if (isJoe && !_talkHead) {
+ if (_vm->logic()->joeFacing() == DIR_FRONT ||
+ _vm->logic()->joeFacing() == DIR_BACK) {
+ // Joe is facing either Front or Back!
+ // - Don't FACE_JOE in room 69, because Joe is probably
+ // holding the Dino Ray gun.
+ if (_vm->logic()->currentRoom() != 69)
+ _vm->logic()->joeFace();
+ } else {
+ if (command == SPEAK_DEFAULT ||
+ command == 6 ||
+ command == 7) {
+ _vm->logic()->joeFace();
+ } else if (command != 5) {
+ // 7/11/94, Ensure that correct mouth closed frame is used!
+ if (parameters->rf != -1)
+ // XXX should really be just "bf", but it is not always calculated... :-(
+ _vm->bankMan()->overpack(parameters->bf, startFrame, bankNum);
+
+ if (parameters->ff == 0)
+ _vm->bankMan()->overpack(10, startFrame, bankNum);
+ else
+ _vm->bankMan()->overpack(parameters->ff, startFrame, bankNum);
+ }
+ }
+ }
+
+ _vm->update();
+}
+
+const Talk::SpeechParameters *Talk::findSpeechParameters(
+ const char *name,
+ int state,
+ int faceDirection) {
+ const SpeechParameters *iterator = _speechParameters;
+ if (faceDirection == DIR_RIGHT)
+ faceDirection = DIR_LEFT;
+
+ while (iterator->name[0] != '*') {
+ if (0 == scumm_stricmp(iterator->name, name) &&
+ iterator->state == state &&
+ iterator->faceDirection == faceDirection)
+ break;
+ iterator++;
+ }
+
+ return iterator;
+}
+
+void Talk::getString(const byte *ptr, uint16 &offset, char *str, int maxLength, int align) {
+ assert((align & 1) == 0);
+ int length = *(ptr + offset);
+ ++offset;
+
+ if (length > maxLength) {
+ error("String too long. Length = %i, maxLength = %i", length, maxLength);
+ } else if (length) {
+ if (str) {
+ memcpy(str, ptr + offset, length);
+ str[length] = '\0';
+ }
+ offset = (offset + length + (align - 1)) & ~(align - 1);
+ } else {
+ if (str) {
+ str[0] = '\0';
+ }
+ }
+}
+
+TalkSelected *Talk::talkSelected() {
+ return _vm->logic()->talkSelected(_uniqueKey);
+}
+
+int Talk::splitOption(const char *str, char optionText[5][MAX_STRING_SIZE]) {
+ char option[MAX_STRING_SIZE];
+ strcpy(option, str);
+ // option text ends at '*' char
+ char *p = strchr(option, '*');
+ if (p) {
+ *p = '\0';
+ }
+ int lines;
+ memset(optionText, 0, 5 * MAX_STRING_SIZE);
+ if (_vm->resource()->getLanguage() == ENGLISH || _vm->display()->textWidth(option) <= MAX_TEXT_WIDTH) {
+ strcpy(optionText[0], option);
+ lines = 1;
+ } else if (_vm->resource()->getLanguage() == HEBREW) {
+ lines = splitOptionHebrew(option, optionText);
+ } else {
+ lines = splitOptionDefault(option, optionText);
+ }
+ return lines;
+}
+
+int Talk::splitOptionHebrew(const char *str, char optionText[5][MAX_STRING_SIZE]) {
+ char tmpString[MAX_STRING_SIZE] = "";
+ uint16 len = 0;
+ uint16 spaceCharWidth = _vm->display()->textWidth(" ");
+ uint16 width = 0;
+ uint16 optionLines = 0;
+ uint16 maxTextLen = MAX_TEXT_WIDTH;
+ const char *p = strchr(str, '\0');
+ while (p != str - 1) {
+ while (*p != ' ' && p != str - 1) {
+ --p;
+ ++len;
+ }
+ if (p != str - 1) {
+ uint16 wordWidth = _vm->display()->textWidth(p, len);
+ width += wordWidth;
+ if (width > maxTextLen) {
+ ++optionLines;
+ strncpy(optionText[optionLines], p, len);
+ optionText[optionLines][len] = '\0';
+ width = wordWidth;
+ maxTextLen = MAX_TEXT_WIDTH - OPTION_TEXT_MARGIN;
+ } else {
+ strcpy(tmpString, optionText[optionLines]);
+ strncpy(optionText[optionLines], p, len);
+ optionText[optionLines][len] = '\0';
+ strcat(optionText[optionLines], tmpString);
+ }
+ --p;
+ len = 1;
+ width += spaceCharWidth;
+ } else {
+ if (len > 1) {
+ if (width + _vm->display()->textWidth(p + 1, len) > maxTextLen) {
+ ++optionLines;
+ }
+ strcpy(tmpString, optionText[optionLines]);
+ strncpy(optionText[optionLines], p + 1, len);
+ optionText[optionLines][len] = '\0';
+ strcat(optionText[optionLines], tmpString);
+ }
+ ++optionLines;
+ }
+ }
+ return optionLines;
+}
+
+int Talk::splitOptionDefault(const char *str, char optionText[5][MAX_STRING_SIZE]) {
+ // Split up multiple line option at closest space character
+ uint16 spaceCharWidth = _vm->display()->textWidth(" ");
+ uint16 width = 0;
+ uint16 optionLines = 0;
+ uint16 maxTextLen = MAX_TEXT_WIDTH;
+ const char *p = str;
+ while (p) {
+ p = strchr(str, ' ');
+ if (p) {
+ uint16 len = p - str;
+ uint16 wordWidth = _vm->display()->textWidth(str, len);
+ width += wordWidth;
+ if (width > maxTextLen) {
+ ++optionLines;
+ strncpy(optionText[optionLines], str, len + 1);
+ width = wordWidth;
+ maxTextLen = MAX_TEXT_WIDTH - OPTION_TEXT_MARGIN;
+ } else {
+ strncat(optionText[optionLines], str, len + 1);
+ }
+ width += spaceCharWidth;
+ str = p + 1;
+ } else {
+ if (str[0]) {
+ if (width + _vm->display()->textWidth(str) > maxTextLen) {
+ ++optionLines;
+ }
+ strcat(optionText[optionLines], str);
+ }
+ ++optionLines;
+ }
+ }
+ return optionLines;
+}
+
+int16 Talk::selectSentence() {
+ int selectedSentence = 0;
+
+ int startOption = 1;
+ int optionLines = 0;
+ char optionText[5][MAX_STRING_SIZE];
+ int talkZone[5];
+ int i;
+
+ _vm->display()->textCurrentColor(INK_TALK_NORMAL);
+
+ _vm->graphics()->setupArrows();
+ BobSlot *arrowBobUp = _vm->graphics()->bob(Graphics::ARROW_BOB_UP);
+ arrowBobUp->active = false;
+ BobSlot *arrowBobDown = _vm->graphics()->bob(Graphics::ARROW_BOB_DOWN);
+ arrowBobDown->active = false;
+
+ bool rezone = true;
+
+ while (rezone) {
+ rezone = false;
+
+ // Set zones for UP/DOWN text arrows when not English version
+
+ _vm->grid()->clear(GS_PANEL);
+
+ if (_vm->resource()->getLanguage() != ENGLISH) {
+ _vm->grid()->setZone(GS_PANEL, ARROW_ZONE_UP, MAX_TEXT_WIDTH + 1, 0, 319, 24);
+ _vm->grid()->setZone(GS_PANEL, ARROW_ZONE_DOWN, MAX_TEXT_WIDTH + 1, 25, 319, 49);
+ }
+
+ _vm->display()->clearTexts(151, 199);
+
+ int sentenceCount = 0;
+ int yOffset = 1;
+
+ for (i = startOption; i <= 4; i++) {
+ talkZone[i] = 0;
+
+ if (_talkString[i][0] != '\0') {
+ sentenceCount++;
+ optionLines = splitOption(_talkString[i], optionText);
+
+ if (yOffset < 5) {
+ _vm->grid()->setZone(
+ GS_PANEL,
+ i,
+ 0,
+ yOffset * LINE_HEIGHT - PUSHUP,
+ (_vm->resource()->getLanguage() == ENGLISH) ? 319 : MAX_TEXT_WIDTH,
+ (yOffset + optionLines) * LINE_HEIGHT - PUSHUP);
+ }
+
+ int j;
+ for (j = 0; j < optionLines; j++) {
+ if (yOffset < 5) {
+ _vm->display()->setText(
+ (j == 0) ? 0 : OPTION_TEXT_MARGIN,
+ 150 - PUSHUP + yOffset * LINE_HEIGHT,
+ optionText[j]);
+ }
+ yOffset++;
+ }
+
+ talkZone[i] = sentenceCount;
+ }
+ }
+
+ yOffset--;
+
+ // Up and down dialogue arrows
+
+ if (_vm->resource()->getLanguage() != ENGLISH) {
+ arrowBobUp->active = (startOption > 1);
+ arrowBobDown->active = (yOffset > 4);
+ }
+
+ _vm->input()->clearKeyVerb();
+
+ if (sentenceCount > 0) {
+ int zone = 0;
+ int oldZone = 0;
+
+ while (0 == selectedSentence) {
+
+ if (_vm->input()->talkQuit())
+ break;
+
+ _vm->update();
+
+ zone = _vm->grid()->findZoneForPos(GS_PANEL, _vm->input()->mousePosX(), _vm->input()->mousePosY());
+
+ int mouseButton = _vm->input()->mouseButton();
+ _vm->input()->clearMouseButton();
+
+ if (ARROW_ZONE_UP == zone || ARROW_ZONE_DOWN == zone) {
+ if (oldZone > 0) {
+ int16 y;
+ const Box *b = _vm->grid()->zone(GS_PANEL, oldZone);
+ for (y = b->y1; y < b->y2; y += 10)
+ _vm->display()->textColor(150 + y, INK_TALK_NORMAL);
+ oldZone = 0;
+ }
+ if (mouseButton != 0) {
+ if (zone == ARROW_ZONE_UP && arrowBobUp->active) {
+ startOption--;
+ } else if (zone == ARROW_ZONE_DOWN && arrowBobDown->active) {
+ startOption++;
+ }
+ }
+ rezone = true;
+ break;
+ } else {
+ if (oldZone != zone) {
+ // Changed zone, change text colors
+ int y;
+
+ debug(6, "Changed zone. oldZone = %i, zone = %i",
+ oldZone, zone);
+
+ if (zone > 0) {
+ const Box *b = _vm->grid()->zone(GS_PANEL, zone);
+ for (y = b->y1; y < b->y2; y += 10)
+ _vm->display()->textColor(150 + y, INK_JOE);
+ }
+
+ if (oldZone > 0) {
+ const Box *b = _vm->grid()->zone(GS_PANEL, oldZone);
+ for (y = b->y1; y < b->y2; y += 10)
+ _vm->display()->textColor(150 + y, INK_TALK_NORMAL);
+ }
+
+ oldZone = zone;
+ }
+
+ }
+
+ Verb v = _vm->input()->keyVerb();
+ if (v >= VERB_DIGIT_FIRST && v <= VERB_DIGIT_LAST) {
+ int n = v - VERB_DIGIT_FIRST + 1;
+ for (i = 1; i <= 4; i++) {
+ if (talkZone[i] == n) {
+ selectedSentence = i;
+ break;
+ }
+ }
+
+ _vm->input()->clearKeyVerb();
+ }
+ else if (mouseButton) {
+ selectedSentence = zone;
+ }
+
+ } // while ()
+ }
+ }
+
+ debug(6, "Selected sentence %i", selectedSentence);
+
+ arrowBobUp->active = false;
+ arrowBobDown->active = false;
+
+ if (selectedSentence > 0) {
+ _vm->display()->clearTexts(0, 198);
+
+ speak(_talkString[selectedSentence], NULL, _joeVoiceFilePrefix[selectedSentence]);
+ }
+
+ _vm->display()->clearTexts(151, 151);
+
+ return selectedSentence;
+}
+
+#ifndef PALMOS_68K
+const Talk::SpeechParameters Talk::_speechParameters[] = {
+ { "JOE", 0, 1, 1, 10, 2, 3, "", 0 },
+ { "JOE", 0, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 0, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 1, 1, 1, 45, -1, 0, "", 0 },
+ { "JOE", 1, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 1, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 2, 1, 1, 46, -1, 0, "", 0 },
+ { "JOE", 2, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 2, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 3, 1, 1, 47, -1, 0, "", 0 },
+ { "JOE", 3, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 3, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 4, 1, 1, 50, -1, 0, "", 0 },
+ { "JOE", 4, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 4, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 5, 1, 2, 0, 0, 0, "", 0 },
+ { "JOE", 5, 3, 4, 0, 0, 0, "", 0 },
+ { "JOE", 5, 4, 6, 0, 0, 0, "", 0 },
+
+ { "JOE", 6, 1, 1, 48, 0, 1, "", 0 },
+ { "JOE", 6, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 6, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 7, 1, 1, 51, 0, 1, "", 0 },
+ { "JOE", 7, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 7, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 8, 1, 1, 26, 0, 0, "", 0 },
+ { "JOE", 8, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 8, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 9, 1, 1, 29, 0, 0, "", 0 },
+ { "JOE", 9, 3, 3, 28, 0, 0, "", 0 },
+ { "JOE", 9, 4, 5, 38, 0, 0, "", 0 },
+
+ { "JOE", 10, 1, 1, 12, 0, 0, "T046,010,010,010,012,012,012,012,012,012,012,012,012,012,012,012,012,012,010,000", 0 },
+ { "JOE", 10, 3, 3, 18, 0, 0, "", 0 },
+ { "JOE", 10, 4, 5, 44, 0, 0, "", 0 },
+
+ { "JOE", 11, 1, 1, 53, -1, 0, "", 0 },
+ { "JOE", 11, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 11, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 12, 1, 1, 10, 2, 3, "", 0 },
+ { "JOE", 12, 3, 3, 28, 2, 0, "", 0 },
+ { "JOE", 12, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 13, 1, 1, 10, 2, 3, "T012,013,019,019,019,019,019,019,019,019,019,019,013,010,000", 0 },
+ { "JOE", 13, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 13, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 14, 1, 1, 16, 2, 3, "", 16 },
+ { "JOE", 14, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 14, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 15, 1, 1, 58, -1, 0, "", 0 },
+ { "JOE", 15, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 15, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 16, 1, 1, 59, -1, 0, "", 0 },
+ { "JOE", 16, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 16, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 17, 1, 1, 56, -1, 0, "", 0 },
+ { "JOE", 17, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 17, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 18, 1, 56, 16, 2, 3, "T056,057,057,057,056,056,000", 0 },
+ { "JOE", 18, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 18, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 19, 1, 54, 16, 2, 3, "T054,055,057,056,000", 0 },
+ { "JOE", 19, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 19, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 20, 1, 56, 16, 2, 3, "T056,057,055,054,001,000", 0 },
+ { "JOE", 20, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 20, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 21, 1, 1, 60, -1, 0, "", 0 },
+ { "JOE", 21, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 21, 4, 61, 38, 1, 0, "", 0 },
+
+ { "JOE", 22, 1, 1, 16, 2, 3, "T063,060,000", 0 },
+ { "JOE", 22, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 22, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 23, 1, 1, 16, 2, 3, "T060,063,001,000", 0 },
+ { "JOE", 23, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 23, 4, 5, 38, 1, 0, "", 0 },
+
+ { "JOE", 24, 1, 1, 47, -2, 0, "", 0 },
+ { "JOE", 24, 3, 3, 28, 2, 3, "", 0 },
+ { "JOE", 24, 4, 5, 38, 1, 0, "", 0 },
+
+ { "RICO", 0, 0, 1, 7, 1, 3, "", 7 },
+ { "RICO", 1, 0, 1, 5, -1, 0, "", 7 },
+ { "RICO", 2, 0, 1, 9, 0, 3, "", 7 },
+ { "RICO", 3, 0, 1, 4, -1, 0, "", 7 },
+
+ { "EDDY", 0, 0, 14, 18, 1, 3, "", 18 },
+ { "EDDY", 1, 0, 14, 0, 0, 0, "T016,017,017,016,016,017,017,016,016,017,017,000", 18 },
+
+ { "MIKE", 0, 0, 1, 2, 2, 3, "", 2 },
+
+ { "LOLA", 0, 0, 30, 33, 2, 3, "", 33 },
+ { "LOLA", 1, 0, 9, 10, 2, 3, "", 33 },
+ { "LOLA", 2, 0, 30, 33, 2, 3, "", 33 },
+ { "LOLA", 3, 0, 32, 33, 2, 3, "", 33 },
+ { "LOLA", 4, 0, 8, 0, 0, 0, "", 33 },
+ { "LOLA", 5, 0, 31, 0, 0, 0, "", 0 },
+ { "LOLA", 6, 0, 31, 0, 0, 0, "047,048,049,050,000", 33 },
+
+ { "LOLA_SHOWER", 0, 0, 7, 10, 2, 3, "", 10 },
+ { "LOLA_SHOWER", 1, 0, 9, 10, 2, 3, "", 10 },
+ { "LOLA_SHOWER", 2, 0, 30, 33, 2, 3, "", 10 },
+ { "LOLA_SHOWER", 3, 0, 32, 33, 2, 3, "", 10 },
+ { "LOLA_SHOWER", 4, 0, 8, 0, 0, 0, "", 0 },
+ { "LOLA_SHOWER", 5, 0, 61, 0, 0, 0, "", 0 },
+ { "LOLA_SHOWER", 6, 0, 64, 10, 2, 3, "", 0 },
+ { "LOLA_SHOWER", 7, 0, 31, 0, 0, 0, "062,063,064,000", 0 },
+
+ { "SECRETARY", 0, 0, 1, 12, 2, 3, "", 12 },
+ { "SECRETARY", 1, 0, 1, 12, 2, 0, "", 12 },
+ { "SECRETARY", 2, 0, 1, 12, 2, 0, "", 12 },
+
+ { "SPARKY", 0, 0, 21, 23, 2, 3, "", 23 },
+ { "SPARKY", 1, 0, 21, 22, 0, 0, "", 0 },
+ { "SPARKY", 2, 0, 21, 22, 0, 0, "021,042,043,000", 0 },
+ { "SPARKY", 3, 0, 21, 22, 0, 0, "043,042,021,000", 0 },
+ { "SPARKY", 4, 0, 43, 43, 1, 0, "", 0 },
+ { "SPARKY", 14, 0, 21, 29, 5, 0, "", 29 },
+
+ { "SPARKY-F", 0, 0, 45, 23, 5, 0, "", 23 },
+ { "SPARKY-F", 1, 0, 45, 47, 0, 0, "", 0 },
+ { "SPARKY-F", 2, 0, 45, 23, 5, 0, "045,046,046,045,000", 23 },
+ { "SPARKY-F", 14, 0, 45, 29, 5, 0, "", 29 },
+
+ { "FAYE", 0, 0, 19, 35, 2, 3, "", 35 },
+ { "FAYE", 1, 0, 19, 41, 2, 3, "", 35 },
+ { "FAYE", 2, 0, 19, 28, -1, 0, "", 35 },
+ { "FAYE", 3, 0, 19, 20, 0, 0, "", 0 },
+ { "FAYE", 4, 0, 19, 27, -1, 0, "", 35 },
+ { "FAYE", 5, 0, 19, 29, -1, 0, "", 35 },
+ { "FAYE", 6, 0, 59, 35, 2, 3, "", 35 },
+ { "FAYE", 7, 0, 19, 30, -1, 0, "", 35 },
+ { "FAYE", 8, 0, 19, 31, -1, 0, "", 35 },
+
+ { "BOB", 0, 0, 27, 34, 2, 3, "", 34 },
+ { "BOB", 1, 0, 27, 28, -1, 0, "", 34 },
+ { "BOB", 2, 0, 30, 0, 0, 0, "", 0 },
+ { "BOB", 3, 0, 31, 0, 0, 0, "", 0 },
+ { "BOB", 4, 0, 27, 61, -1, 0, "", 34 },
+ { "BOB", 5, 0, 27, 42, 1, 0, "", 42 },
+
+ { "PYGMY", 0, 0, 20, 21, 2, 6, "", 0 },
+ { "PYGMY", 1, 0, 20, 21, 2, 6, "020,068,068,068,068,068,068,068,068,020,000", 0 },
+ { "PYGMY", 2, 0, 20, 21, 2, 6, "T028,029,030,031,031,031,031,030,029,028,035,000", 0 },
+ { "PYGMY", 3, 0, 20, 21, 2, 6, "T035,036,037,038,037,038,037,038,036,035,000", 0 },
+ { "PYGMY", 4, 0, 20, 21, 2, 6, "T032,033,032,033,032,033,035,000", 0 },
+ { "PYGMY", 5, 0, 20, 21, 2, 6, "T023,022,021,022,023,024,025,026,027,026,025,024,023,000", 0 },
+ { "PYGMY", 6, 0, 20, 21, 2, 6, "T034,034,034,035,000", 0 },
+
+ { "WITCH", 0, 0, 39, 40, 2, 6, "", 40 },
+ { "WITCH", 1, 0, 39, 40, 2, 6, "073,074,000", 40 },
+ { "WITCH", 2, 0, 39, 40, 2, 6, "074,073,000", 40 },
+ { "WITCH", 3, 0, 39, 40, 2, 6, "T047,048,049,050,051,000", 40 },
+ { "WITCH", 4, 0, 39, 40, 2, 6, "T052,053,054,055,056,057,058,057,056,056,056,055,054,053,052,000", 40 },
+ { "WITCH", 5, 0, 39, 40, 2, 6, "069,070,071,072,073,074,000", 40 },
+ { "WITCH", 6, 0, 39, 40, 2, 6, "074,073,072,071,070,069,070,000", 40 },
+ { "WITCH", 7, 0, 39, 51, -1, 0, "", 40 },
+ { "WITCH", 8, 0, 39, 40, 2, 6, "T051,050,049,048,047,000", 40 },
+
+ { "CHIEF", 0, 0, 1, 7, 1, 7, "", 3 },
+ { "CHIEF", 1, 0, 1, 2, 2, 6, "062,063,064,065,066,000", 0 },
+ { "CHIEF", 2, 0, 1, 2, 2, 6, "066,065,064,063,062,000", 0 },
+ { "CHIEF", 3, 0, 1, 17, -1, 0, "", 3 },
+ { "CHIEF", 4, 0, 1, 18, -1, 0, "", 3 },
+ { "CHIEF", 5, 0, 1, 19, -1, 0, "", 3 },
+
+ { "NAOMI", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "NAOMI", 1, 0, 1, 2, 2, 6, "048,049,050,051,052,053,054,055,000", 0 },
+ { "NAOMI", 2, 0, 1, 2, 2, 6, "055,054,053,052,051,050,049,048,000", 0 },
+ { "NAOMI", 3, 0, 1, 13, -1, 0, "", 2 },
+ { "NAOMI", 4, 0, 1, 14, -1, 0, "", 2 },
+ { "NAOMI", 5, 0, 1, 10, -1, 0, "", 2 },
+ { "NAOMI", 6, 0, 1, 12, -1, 0, "", 2 },
+ { "NAOMI", 7, 0, 1, 12, -1, 0, "T008,008,008,002,000", 2 },
+
+ { "WEDGEWOOD", 0, 0, 8, 1, 2, 0, "", 8 },
+ { "WEDGEWOOD", 1, 0, 1, 1, 3, 0, "", 1 },
+
+ { "BUD", 0, 0, 1, 2, 3, 2, "", 2 },
+ { "BUD", 1, 0, 1, 2, 4, 2, "T017,018,000", 2 },
+ { "BUD", 2, 0, 1, 21, -1, 0, "", 2 },
+ { "BUD", 3, 0, 1, 14, -1, 0, "", 2 },
+ { "BUD", 4, 0, 1, 15, -1, 0, "", 2 },
+ { "BUD", 5, 0, 1, 20, -1, 0, "", 2 },
+ { "BUD", 6, 0, 1, 16, -1, 0, "", 2 },
+ { "BUD", 7, 0, 1, 19, -1, 0, "", 2 },
+ { "BUD", 8, 0, 1, 17, -1, 0, "", 2 },
+ { "BUD", 9, 0, 1, 14, -1, 0, "T014,008,008,003,003,008,008,003,003,010,010,012,012,000", 2 },
+
+ { "LOU", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "LOU", 1, 0, 1, 2, 4, 2, "013,014,015,016,017,018,000", 2 },
+ { "LOU", 2, 0, 1, 2, 4, 2, "018,017,016,015,014,013,000", 2 },
+
+ { "JIMMY", 0, 0, 16, 17, 2, 3, "", 17 },
+ { "JIMMY", 1, 0, 16, 25, -1, 0, "", 17 },
+ { "JIMMY", 2, 0, 16, 26, -1, 0, "", 17 },
+ { "JIMMY", 3, 0, 16, 27, -1, 0, "", 17 },
+ { "JIMMY", 4, 0, 16, 28, -1, 0, "", 17 },
+ { "JIMMY", 5, 0, 16, 29, -1, 0, "", 17 },
+
+ { "TAMMY", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "TAMMY", 1, 0, 1, 2, 2, 3, "T008,008,009,009,008,008,009,009,008,008,009,009,002,000", 2 },
+ { "TAMMY", 2, 0, 1, 2, 2, 3, "T002,010,010,010,002,000", 2 },
+ { "TAMMY", 3, 0, 1, 2, 2, 3, "T011,011,011,011,011,002,000", 2 },
+ { "TAMMY", 4, 0, 1, 2, 2, 3, "T013,014,015,013,014,015,013,009,001,000", 2 },
+
+ { "SKULL", 0, 0, 9, 9, 4, 0, "", 0 },
+ { "SKULL", 1, 0, 1, 9, 4, 0, "001,002,003,004,005,006,007,008,009,000", 0 },
+ { "SKULL", 2, 0, 1, 9, 4, 0, "009,008,007,006,005,004,003,002,001,000", 0 },
+
+ { "APE", 0, 0, 1, 6, 7, 0, "", 6 },
+ { "APE", 1, 0, 1, 6, 7, 0, "002,001,000", 6 },
+ { "APE", 2, 0, 1, 6, 7, 0, "002,003,001,000", 6 },
+ { "APE", 3, 0, 1, 6, 7, 0, "004,005,004,005,004,001,000", 6 },
+ { "APE", 4, 0, 1, 6, 7, 0, "001,003,005,004,005,004,001,000", 6 },
+
+ { "APE1", 0, 0, 15, 16, 7, 0, "", 16 },
+ { "APE2", 0, 0, 14, 6, 7, 0, "", 6 },
+
+ { "SHOWERAM", 0, 0, 1, 2, 3, 0, "", 2 },
+ { "SHOWERAM", 1, 0, 1, 2, 3, 0, "026,027,028,029,001,000", 2 },
+ { "SHOWERAM", 2, 0, 1, 2, 3, 0, "001,029,028,027,026,000", 2 },
+
+ { "PRINCESS1", 0, 0, 19, 23, 2, 3, "", 23 },
+ { "PRINCESS1", 1, 0, 19, 41, -1, 0, "", 23 },
+ { "PRINCESS1", 2, 0, 19, 42, -1, 0, "", 23 },
+ { "PRINCESS1", 3, 0, 19, 45, -1, 0, "", 23 },
+ { "PRINCESS1", 4, 0, 19, 40, -1, 0, "", 23 },
+ { "PRINCESS1", 5, 0, 19, 45, 2, 3, "T40,043,044,045,000", 45 },
+ { "PRINCESS1", 6, 0, 19, 45, -1, 0, "T041,038,000", 38 },
+ { "PRINCESS1", 7, 0, 22, 0, 0, 0, "", 0 },
+ { "PRINCESS1", 8, 0, 19, 45, 2, 3, "T045,044,043,040,039,000", 39 },
+
+ { "PRINCESS2", 0, 0, 46, 23, 2, 3, "", 23 },
+ { "PRINCESS2", 1, 0, 46, 29, 2, 3, "", 29 },
+ { "PRINCESS2", 2, 0, 46, 29, 2, 3, "T029,036,035,000", 35 },
+
+ { "GUARDS", 0, 0, 7, 7, 0, 0, "", 7 },
+
+ { "AMGUARD", 0, 0, 19, 22, 2, 3, "", 22 },
+
+ { "MAN1", 0, 0, 2, 3, 2, 3, "", 3 },
+ { "MAN2", 0, 0, 9, 10, 1, 2, "", 10 },
+
+ { "DOG", 0, 0, 6, 6, 1, 0, "", 0 },
+ { "DOG", 1, 0, 6, 6, 1, 0, "010,009,008,000", 0 },
+ { "DOG", 2, 0, 6, 6, 1, 0, "008,009,010,000", 0 },
+
+ { "CHEF", 0, 0, 5, 6, 2, 3, "", 6 },
+
+ { "HENRY", 0, 0, 7, 9, 2, 3, "", 9 },
+ { "HENRY", 1, 0, 7, 21, -1, 0, "", 9 },
+ { "HENRY", 2, 0, 7, 19, -1, 0, "", 9 },
+ { "HENRY", 3, 0, 7, 20, -1, 0, "", 9 },
+ { "HENRY", 4, 0, 8, 9, 2, 3, "", 9 },
+ { "HENRY", 5, 0, 23, 9, -1, 0, "", 9 },
+ { "HENRY", 6, 0, 7, 9, 2, 3, "T019,015,017,017,017,017,017,017,017,015,009,000", 9 },
+ { "HENRY", 7, 0, 7, 9, 2, 3, "T018,010,000", 10 },
+ { "HENRY", 8, 0, 7, 9, 2, 3, "T018,016,000", 16 },
+ { "HENRY", 9, 0, 7, 9, 2, 3, "T018,011,000", 11 },
+ { "HENRY", 10, 0, 29, 33, 1, 1, "", 33 },
+ { "HENRY", 11, 0, 7, 30, 2, 0, "", 9 },
+ { "HENRY", 12, 0, 7, 9, 2, 3, "025,026,000", 26 },
+ { "HENRY", 13, 0, 7, 9, 2, 3, "027,028,027,028,000", 28 },
+ { "HENRY", 14, 0, 7, 9, 2, 3, "026,025,007,000", 9 },
+
+ { "JOHAN", 0, 0, 1, 15, 2, 3, "", 15 },
+ { "JOHAN", 1, 0, 1, 0, 0, 0, "T006,007,008,000", 15 },
+ { "JOHAN", 2, 0, 1, 15, 2, 3, "T002,003,004,005,004,005,004,005,004,005,004,005,004,003,002,000", 15 },
+ { "JOHAN", 3, 0, 1, 8, -1, 0, "", 15 },
+ { "JOHAN", 4, 0, 1, 0, 0, 0, "T008,007,006,001,000", 15 },
+
+ { "KLUNK", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "KLUNK", 1, 0, 1, 2, 2, 3, "019,020,021,022,001,000", 2 },
+ { "KLUNK", 2, 0, 1, 2, 2, 3, "001,022,021,020,019,016,517,000", 2 },
+ { "KLUNK", 3, 0, 1, 2, 2, 3, "T010,011,010,011,010,011,009,000", 2 },
+
+ { "FRANK", 0, 0, 13, 14, 2, 3, "", 14 },
+ { "FRANK", 1, 0, 13, 20, 0, 1, "", 14 },
+ { "FRANK", 2, 0, 13, 14, 2, 3, "025,026,027,027,027,026,026,026,027,027,026,026,027,025,013,000", 14 },
+ { "FRANK", 3, 0, 28, 14, 2, 3, "", 14 },
+
+ { "DEATH", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "DEATH", 1, 0, 1, 2, 2, 3, "013,014,015,016,017,001,000", 0 },
+ { "DEATH", 2, 0, 1, 2, 2, 3, "001,017,016,015,014,013,000", 0 },
+ { "DEATH", 3, 0, 1, 2, 2, 3, "T018,019,020,021,021,022,022,020,021,022,020,021,022,023,024,524,000", 2 },
+ { "DEATH", 4, 0, 1, 2, 2, 3, "T025,026,027,028,028,028,028,028,028,028,028,028,029,035,000", 2 },
+ { "DEATH", 5, 0, 1, 2, 2, 3, "T030,031,032,033,033,033,033,033,033,033,033,033,034,035,000", 2 },
+ { "DEATH", 6, 0, 1, 2, 2, 3, "T023,022,020,019,018,001,000", 2 },
+
+ { "JASPAR", 0, 0, 1, 1, 22, 0, "026,027,028,029,028,029,028,029,030,023,000", 0 },
+ { "JASPAR", 1, 0, 1, 1, 22, 0, "023,026,000", 0 },
+
+ { "ORACLE", 0, 0, 1, 5, 3, 0, "", 0 },
+
+ { "ZOMBIE", 0, 0, 1, 5, 2, 3, "", 5 },
+ { "ZOMBIE", 1, 0, 1, 12, -1, 0, "", 5 },
+ { "ZOMBIE", 2, 0, 1, 13, -1, 0, "", 5 },
+ { "ZOMBIE", 3, 0, 1, 1, 5, 5, "", 5 },
+
+ { "ZOMBIE2", 0, 0, 14, 14, 0, 0, "", 0 },
+ { "ZOMBIE3", 0, 0, 18, 18, 0, 0, "", 0 },
+
+ { "ANDERSON", 0, 0, 7, 8, 2, 3, "", 8 },
+ { "ANDERSON", 1, 0, 7, 8, 1, 0, "", 8 },
+ { "ANDERSON", 2, 0, 7, 16, -1, 0, "", 8 },
+ { "ANDERSON", 3, 0, 7, 18, -1, 0, "", 8 },
+ { "ANDERSON", 4, 0, 7, 19, -1, 0, "", 8 },
+ { "ANDERSON", 5, 0, 7, 20, -1, 0, "", 8 },
+ { "ANDERSON", 6, 0, 7, 21, 1, 0, "", 8 },
+
+ { "COMPY", 0, 0, 12, 12, -1, 0, "", 0 },
+ { "COMPY", 1, 0, 10, 10, 10, 0, "010,011,012,012,013,014,014,000", 0 },
+ { "COMPY", 2, 0, 10, 10, 10, 0, "014,013,012,000", 0 },
+
+ { "DEINO", 0, 0, 13, 13, -1, 0, "", 0 },
+ { "DEINO", 1, 0, 9, 9, 9, 0, "009,010,000", 0 },
+
+ { "TMPD", 0, 0, 19, 22, 2, 3, "", 22 },
+
+ { "IAN", 0, 0, 7, 9, 2, 3, "", 9 },
+ { "IAN", 1, 0, 8, 25, 3, 0, "", 25 },
+ { "IAN", 2, 0, 7, 21, -1, 0, "", 9 },
+ { "IAN", 3, 0, 7, 22, 1, 0, "", 9 },
+ { "IAN", 4, 0, 7, 22, -1, 0, "", 9 },
+ { "IAN", 5, 0, 7, 24, -1, 0, "", 9 },
+ { "IAN", 6, 0, 7, 9, 2, 3, "034,034,034,035,035,036,036,035,035,036,035,036,035,000", 9 },
+ { "IAN", 7, 0, 7, 31, -1, 0, "", 9 },
+
+ { "FAYE-H", 0, 0, 1, 1, 4, 1, "", 1 },
+ { "FAYE-H", 1, 0, 1, 1, 4, 1, "007,000", 7 },
+ { "FAYE-H", 2, 0, 1, 1, 4, 1, "009,010,011,009,001,000", 1 },
+ { "FAYE-H", 3, 0, 1, 1, 4, 1, "E012,013,000", 1 },
+ { "FAYE-H", 4, 0, 1, 1, 4, 1, "E015,000", 1 },
+ { "FAYE-H", 5, 0, 1, 1, 4, 1, "E014,000", 1 },
+
+ { "AZURA-H", 0, 0, 1, 1, 4, 1, "", 1 },
+ { "AZURA-H", 1, 0, 1, 1, 4, 1, "007,000", 7 },
+ { "AZURA-H", 2, 0, 1, 1, 4, 1, "009,010,011,009,001,000", 1 },
+ { "AZURA-H", 3, 0, 1, 1, 4, 1, "E012,013, 000", 1 },
+ { "AZURA-H", 4, 0, 1, 1, 4, 1, "E015,000", 1 },
+ { "AZURA-H", 5, 0, 1, 1, 4, 1, "E014,000", 1 },
+
+ { "FRANK-H", 0, 0, 1, 1, 4, 1, "", 1 },
+ { "FRANK-H", 1, 0, 1, 1, 4, 1, "E009,000", 1 },
+ { "FRANK-H", 2, 0, 1, 1, 4, 1, "E007,000", 1 },
+ { "FRANK-H", 3, 0, 1, 1, 4, 1, "010,011,012,013,014,015,010,000", 1 },
+
+ { "JOE-E", 0, 0, 1, 2, 4, 1, "", 2 },
+ { "JOE-E", 6, 0, 1, 2, 4, 1, "008,009,008,002,000", 2 },
+
+ { "AZURA-E", 0, 0, 1, 1, 5, 1, "", 1 },
+ { "AZURA-E", 1, 0, 1, 1, 5, 1, "009,010,009,008,000", 1 },
+
+ { "FAYE-E", 0, 0, 1, 4, 4, 1, "", 1 },
+ { "FAYE-E", 1, 0, 1, 4, 4, 1, "002,003,002,001,000", 1 },
+
+ { "ANDSON-E", 0, 0, 1, 3, 4, 1, "", 1 },
+ { "ANDSON-E", 1, 0, 1, 3, 4, 1, "002,001,000", 1 },
+
+ { "JOE-H", 0, 0, 1, 1, 4, 4, "", 1 },
+ { "JOE-H", 1, 0, 1, 1, 2, 3, "012,013,014,000", 14 },
+ { "JOE-H", 2, 0, 1, 1, 2, 3, "010,011,000", 11 },
+ { "JOE-H", 3, 0, 1, 1, 2, 3, "014,013,012,001,000", 1 },
+ { "JOE-H", 4, 0, 1, 13, 1, 0, "", 13 },
+
+ { "RITA-H", 0, 0, 7, 1, 2, 3, "", 1 },
+ { "RITA-H", 1, 0, 7, 0, 0, 0, "009,010,011,012,013,000", 13 },
+ { "RITA-H", 2, 0, 7, 0, 0, 0, "014,015,016,000", 16 },
+ { "RITA-H", 3, 0, 7, 0, 0, 0, "013,012,011,010,000", 10 },
+ { "RITA-H", 4, 0, 7, 0, 0, 0, "009,007,008,007,009,000", 9 },
+ { "RITA-H", 5, 0, 7, 0, 0, 0, "016,015,014,000", 14 },
+
+ { "RITA", 0, 0, 1, 4, 2, 3, "", 4 },
+ { "RITA", 1, 0, 2, 4, 2, 3, "", 4 },
+
+ { "SPARKY-H", 0, 0, 1, 1, 2, 3, "", 1 },
+
+ { "HUGH", 0, 0, 1, 1, 2, 3, "", 1 },
+ { "HUGH", 1, 0, 7, 7, 2, 3, "", 7 },
+
+ { "X2_JOE", 0, 0, 1, 1, 2, 3, "", 1 },
+ { "X2_JOE", 1, 0, 1, 1, 2, 3, "001,007,008,008,007,001,000", 1 },
+
+ { "X2_RITA", 0, 0, 1, 1, 2, 3, "", 1 },
+ { "X2_RITA", 1, 0, 1, 1, 2, 3, "001,007,008,008,007,001,000", 1 },
+
+ { "X3_RITA", 0, 0, 1, 1, 4, 1, "", 1 },
+ { "X3_RITA", 1, 0, 1, 1, 4, 1, "007,000", 7 },
+ { "X3_RITA", 2, 0, 1, 1, 4, 1, "009,010,011,009,001,000", 1 },
+ { "X3_RITA", 3, 0, 1, 1, 4, 1, "E012,013,000", 1 },
+ { "X3_RITA", 4, 0, 1, 1, 4, 1, "E015,000", 1 },
+ { "X3_RITA", 5, 0, 1, 1, 4, 1, "E014,000", 1 },
+
+ { "X4_JOE", 0, 0, 1, 1, 3, 4, "", 1 },
+ { "X4_JOE", 1, 0, 1, 13, 2, 3, "", 13 },
+ { "X4_JOE", 2, 0, 1, 1, 3, 4, "009, 010, 011, 012, 013, 000", 13 },
+ { "X4_JOE", 3, 0, 1, 1, 3, 4, "012, 011, 010, 009, 000", 9 },
+ { "X4_JOE", 4, 0, 1, 1, 3, 4, "001, 019, 000", 19 },
+
+ { "X4_RITA", 0, 0, 1, 1, 0, 1, "", 1 },
+ { "X4_RITA", 1, 0, 1, 7, 0, 1, "", 7 },
+ { "X4_RITA", 2, 0, 1, 1, 3, 4, "004,005,006,006,006,006,007,000", 7 },
+ { "X4_RITA", 3, 0, 1, 1, 3, 4, "005,004,001,000", 1 },
+ { "X4_RITA", 4, 0, 1, 1, 3, 4, "001,003,000", 3 },
+
+ { "X5_SPARKY", 0, 0, 1, 1, 2, 3, "", 1 },
+ { "X5_SPARKY", 1, 0, 1, 1, 2, 3, "001,010,011,011,001,000", 1 },
+ { "X5_SPARKY", 2, 0, 1, 1, 2, 3, "001,007,008,009,000", 9 },
+
+ { "X6_HUGH", 0, 0, 1, 1, 2, 3, "", 1 },
+ { "X6_HUGH", 1, 0, 1, 1, 2, 3, "007,007,007,007,,001,000", 1 },
+ { "X6_HUGH", 2, 0, 1, 1, 2, 3, "008,008,008,008,008,009,009,008,008,008,009,008,000", 8 },
+
+ { "X10_JOE", 0, 0, 1, 2, 2, 3, "", 2 },
+ { "X10_JOE", 1, 0, 1, 8, 2, 3, "", 8 },
+ { "X10_JOE", 2, 0, 1, 2, 2, 3, "014,014,014,015,015,014,014,015,015,000", 2 },
+
+ { "X10_RITA", 0, 0, 1, 2, 2, 3, "", 2 },
+
+ { "X11_JOE", 0, 0, 1, 2, 0, 1, "", 2 },
+
+ { "X11_RITA", 0, 0, 1, 2, 0, 1, "", 2 },
+ { "X11_RITA", 1, 0, 1, 2, 1, 0, "003,004,000", 4 },
+
+ { "JOHN", 0, 0, 1, 2, 2, 3, "", 1 },
+ { "JOHN", 1, 0, 1, 15, -1, 0, "", 1 },
+ { "JOHN", 2, 0, 1, 16, -1, 0, "", 1 },
+ { "JOHN", 3, 0, 1, 17, -1, 0, "", 1 },
+
+ { "STEVE", 0, 0, 8, 2, 2, 3, "", 2 },
+ { "STEVE", 1, 0, 8, 16, -1, 0, "", 2 },
+ { "STEVE", 2, 0, 9, 18, -1, 0, "T016,017,017,016,008,000", 2 },
+ { "STEVE", 3, 0, 8, 18, -1, 0, "", 2 },
+
+ { "TONY", 0, 0, 1, 2, 2, 3, "", 1 },
+ { "TONY", 1, 0, 1, 12, -1, 0, "", 1 },
+
+ { "*", 0, 0, 0, 0, 0, 0, "", 0 }
+};
+#endif
+
+} // End of namespace Queen
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Queen_Talk)
+_GSETPTR(Queen::_speechParameters, GBVARS_SPEECHPARAMETERS_INDEX, Queen::Talk::SpeechParameters, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Queen_Talk)
+_GRELEASEPTR(GBVARS_SPEECHPARAMETERS_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/queen/talk.h b/engines/queen/talk.h
new file mode 100644
index 0000000000..d1469e2fe8
--- /dev/null
+++ b/engines/queen/talk.h
@@ -0,0 +1,244 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEEN_TALK_H
+#define QUEEN_TALK_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+class QueenEngine;
+
+class Talk {
+public:
+
+ //! Public interface to run a talk from a file
+ static void talk(const char *filename, int personInRoom, char *cutawayFilename, QueenEngine *vm);
+
+ //! Public interface to speak a sentence
+ static bool speak(const char *sentence, Person *person, const char *voiceFilePrefix, QueenEngine *vm);
+
+ //! Read a string from ptr and update offset
+ static void getString(const byte *ptr, uint16 &offset, char *str, int maxLength, int align = 2);
+
+private:
+
+ //! Collection of constants used by Talk
+ enum {
+ LINE_HEIGHT = 10,
+ MAX_STRING_LENGTH = 255,
+ MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
+ MAX_TEXT_WIDTH = (320-18),
+ PUSHUP = 4,
+ ARROW_ZONE_UP = 5,
+ ARROW_ZONE_DOWN = 6,
+ DOG_HEADER_SIZE = 20,
+ OPTION_TEXT_MARGIN = 24
+ };
+
+ //! Special commands for speech
+ enum {
+ SPEAK_DEFAULT = 0,
+ SPEAK_FACE_LEFT = -1,
+ SPEAK_FACE_RIGHT = -2,
+ SPEAK_FACE_FRONT = -3,
+ SPEAK_FACE_BACK = -4,
+ SPEAK_ORACLE = -5,
+ SPEAK_UNKNOWN_6 = -6,
+ SPEAK_AMAL_ON = -7,
+ SPEAK_PAUSE = -8,
+ SPEAK_NONE = -9
+ };
+
+ struct DialogueNode {
+ int16 head;
+ int16 dialogueNodeValue1;
+ int16 gameStateIndex;
+ int16 gameStateValue;
+ };
+
+#ifndef PALMOS_68K
+ struct SpeechParameters {
+ const char *name;
+ signed char state,faceDirection;
+ signed char body,bf,rf,af;
+ const char *animation;
+ signed char ff;
+ };
+#else
+public:
+ struct SpeechParameters {
+ const char name[11];
+ signed char state,faceDirection;
+ signed char body,bf,rf,af;
+ const char animation[80];
+ signed char ff;
+ };
+private:
+#endif
+
+ QueenEngine *_vm;
+
+ bool _wasFullscren;
+
+ //! Raw .dog file data (without 20 byte header)
+ byte *_fileData;
+
+ //! Number of dialogue levels
+ int16 _levelMax;
+
+ //! Unique key for this dialogue
+ int16 _uniqueKey;
+
+ //! Used to select voice files
+ int16 _talkKey;
+
+ int16 _jMax;
+
+ //! Used by findDialogueString
+ int16 _pMax;
+
+ // Update game state efter dialogue
+ int16 _gameState[2];
+ int16 _testValue[2];
+ int16 _itemNumber[2];
+
+ //! String data
+ uint16 _person1PtrOff;
+
+ //! Cutaway data
+ uint16 _cutawayPtrOff;
+
+ //! Data used if we have talked to the person before
+ uint16 _person2PtrOff;
+
+ //! Data used if we haven't talked to the person before
+ uint16 _joePtrOff;
+
+ //! Is a talking head
+ bool _talkHead;
+
+ //! IDs for sentences
+ DialogueNode _dialogueTree[18][6];
+
+ //! Greeting from person Joe has talked to before
+ char _person2String[MAX_STRING_SIZE];
+
+ int _oldSelectedSentenceIndex;
+ int _oldSelectedSentenceValue;
+
+ char _talkString[5][MAX_STRING_SIZE];
+ char _joeVoiceFilePrefix[5][MAX_STRING_SIZE];
+
+#ifndef PALMOS_68K
+ static const SpeechParameters _speechParameters[];
+#endif
+
+ Talk(QueenEngine *vm);
+ ~Talk();
+
+ //! Perform talk in file and return a cutaway filename
+ void talk(const char *filename, int personInRoom, char *cutawayFilename);
+
+ byte *loadDialogFile(const char *filename);
+
+ //! Load talk data from .dog file
+ void load(const char *filename);
+
+ //! First things spoken
+ void initialTalk();
+
+ //! Find a string in the dialogue tree
+ void findDialogueString(uint16 offset, int16 id, int16 max, char *str);
+
+ //! Get TalkSelected struct for this talk
+ TalkSelected *talkSelected();
+
+ //! Interface to the TalkSelected struct
+ bool hasTalkedTo() { return talkSelected()->hasTalkedTo; }
+
+ //! Interface to the TalkSelected struct
+ void setHasTalkedTo() { talkSelected()->hasTalkedTo = true; }
+
+ //! Get a selected value
+ int16 selectedValue(int index) {
+ return talkSelected()->values[index-1];
+ }
+
+ //! Set a selected value
+ void selectedValue(int index, int16 value) {
+ talkSelected()->values[index-1] = value;
+ }
+
+ //! The sentence will not be displayed again
+ void disableSentence(int oldLevel, int selectedSentence);
+
+ //! Select what to say
+ int16 selectSentence();
+
+ //! Speak sentence
+ bool speak(const char *sentence, Person *person, const char *voiceFilePrefix);
+
+ //! Convert command in sentence to command code
+ int getSpeakCommand(const Person *person, const char *sentence, unsigned &index);
+
+ //! Speak a part of a sentence
+ void speakSegment(
+ const char *segmentStart,
+ int length,
+ Person *person,
+ int command,
+ const char *voiceFilePrefix,
+ int index);
+
+ void headStringAnimation(const SpeechParameters *parameters, int bobNum, int bankNum);
+
+ void stringAnimation(const SpeechParameters *parameters, int startFrame, int bankNum);
+
+ void defaultAnimation(
+ const char *segment,
+ bool isJoe,
+ const SpeechParameters *parameters,
+ int startFrame,
+ int bankNum);
+
+ int countSpaces(const char *segment);
+
+ //! Get special parameters for speech
+ const SpeechParameters *findSpeechParameters(
+ const char *name,
+ int state,
+ int faceDirection);
+
+ int splitOption(const char *str, char optionText[5][MAX_STRING_SIZE]);
+
+ int splitOptionHebrew(const char *str, char optionText[5][MAX_STRING_SIZE]);
+
+ int splitOptionDefault(const char *str, char optionText[5][MAX_STRING_SIZE]);
+
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/walk.cpp b/engines/queen/walk.cpp
new file mode 100644
index 0000000000..69854b373a
--- /dev/null
+++ b/engines/queen/walk.cpp
@@ -0,0 +1,564 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "queen/walk.h"
+
+#include "queen/bankman.h"
+#include "queen/input.h"
+#include "queen/logic.h"
+#include "queen/graphics.h"
+#include "queen/grid.h"
+#include "queen/queen.h"
+
+namespace Queen {
+
+const MovePersonData Walk::_moveData[] = {
+ { "COMPY", -1, -6, 1, 6, 0, 0, 0, 0, 12, 12, 1, 14 },
+ { "DEINO", -1, -8, 1, 8, 0, 0, 0, 0, 11, 11, 1, 10 },
+ { "FAYE", -1, -6, 1, 6, 13, 18, 7, 12, 19, 22, 2, 5 },
+ { "GUARDS", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 5 },
+ { "PRINCESS1", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
+ { "PRINCESS2", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
+ { "AMGUARD", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
+ { "SPARKY", -1, -6, 1, 6, 13, 18, 7, 12, 21, 20, 2, 5 },
+ { "LOLA_SHOWER", -1, -6, 55, 60, 0, 0, 0, 0, 7, 7, 2, 5 },
+ { "LOLA", -24, -29, 24, 29, 0, 0, 0, 0, 30, 30, 2, 5 },
+ { "BOB", -15, -20, 15, 20, 21, 26, 0, 0, 27, 29, 2, 5 },
+ { "CHEF", -1, -4, 1, 4, 0, 0, 0, 0, 1, 5, 2, 4 },
+ { "HENRY", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 6 },
+ { "ANDERSON", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 5 },
+ { "JASPAR", -4, -9, 4, 9, 16, 21, 10, 15, 1, 3, 1, 10 },
+ { "PYGMY", -7, -12, 7, 12, 0, 0, 0, 0, 27, 27, 2, 5 },
+ { "FRANK", 7, 12, 1, 6, 0, 0, 0, 0, 13, 13, 2, 4 },
+ { "WEDGEWOOD", -20, -25, 20, 25, 0, 0, 0, 0, 1, 1, 1, 5 },
+ { "TMPD", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
+ { "IAN", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 6 },
+ { "*", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+Walk::Walk(QueenEngine *vm)
+ : _vm(vm) {
+}
+
+void Walk::animateJoePrepare() {
+ // queen.c l.2748-2788
+ uint16 i;
+ for (i = 1; i <= _walkDataCount; ++i) {
+
+ WalkData *pwd = &_walkData[i];
+
+ if (pwd->dx < 0) {
+ pwd->anim.set(11, 18, DIR_LEFT);
+ } else {
+ pwd->anim.set(11, 18, DIR_RIGHT);
+ }
+
+ int16 k = ABS(pwd->dy);
+ int16 ds = pwd->area->scaleDiff();
+ if (ds > 0) {
+ k *= ((k * ds) / pwd->area->box.yDiff()) / 2;
+ }
+
+ if (ABS(pwd->dx) < k) {
+ if (pwd->dy < 0) {
+ if (ds < 0) {
+ pwd->anim.set(19, 24, DIR_FRONT);
+ } else {
+ pwd->anim.set(25, 30, DIR_BACK);
+ }
+ } else if (pwd->dy > 0) {
+ if (ds < 0) {
+ pwd->anim.set(25, 30, DIR_BACK);
+ } else {
+ pwd->anim.set(19, 24, DIR_FRONT);
+ }
+ }
+ }
+ }
+}
+
+void Walk::animateJoe() {
+ // queen.c l.2789-2835
+ uint16 lastDirection = 0;
+ uint16 i;
+ BobSlot *pbs = _vm->graphics()->bob(0);
+ _vm->logic()->joeFacing(_walkData[1].anim.facing);
+ _vm->logic()->joeScale(_walkData[1].area->calcScale(pbs->y));
+ _vm->logic()->joeFace();
+ for (i = 1; i <= _walkDataCount && !_joeInterrupted; ++i) {
+
+ WalkData *pwd = &_walkData[i];
+
+ // area has been turned off, see if we should execute a cutaway
+ if (pwd->area->mapNeighbours < 0) {
+ // queen.c l.2838-2911
+ _vm->logic()->handleSpecialArea(pwd->anim.facing, pwd->areaNum, i);
+ _joeMoveBlock = true;
+ return;
+ }
+ if (lastDirection != pwd->anim.facing) {
+ pbs->animNormal(pwd->anim.firstFrame, pwd->anim.lastFrame, 1, false, false);
+ }
+
+ uint16 moveSpeed = _vm->grid()->findScale(pbs->x, pbs->y) * 6 / 100;
+ pbs->move(pbs->x + pwd->dx, pbs->y + pwd->dy, moveSpeed);
+ pbs->xflip = (pbs->xdir < 0);
+ while (pbs->moving) {
+ // adjust Joe's movespeed according to scale
+ pbs->scale = pwd->area->calcScale(pbs->y);
+ _vm->logic()->joeScale(pbs->scale);
+ pbs->scaleWalkSpeed(6);
+ _vm->update(true);
+ if (_vm->input()->cutawayQuit() || _vm->logic()->joeWalk() == JWM_EXECUTE) {
+ stopJoe();
+ break;
+ }
+ }
+ lastDirection = pwd->anim.facing;
+ }
+ _vm->logic()->joeFacing(lastDirection);
+}
+
+void Walk::animatePersonPrepare(const MovePersonData *mpd, int direction) {
+ // queen.c l.2469-2572
+ int i;
+ for (i = 1; i <= _walkDataCount; ++i) {
+
+ WalkData *pwd = &_walkData[i];
+
+ if (pwd->dx < 0) {
+ pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_LEFT);
+ } else if (pwd->dx > 0) {
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
+ } else {
+ if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
+ } else {
+ // we have specific moves for this actor, see what direction they were last facing
+ if (direction == -3) {
+ // previously facing right
+ pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_LEFT);
+ } else {
+ // previously facing left
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
+ }
+ }
+ }
+
+ int16 k = ABS(pwd->dy);
+ int16 ds = pwd->area->scaleDiff();
+ if (ds > 0) {
+ k *= ((k * ds) / pwd->area->box.yDiff()) / 2;
+ }
+
+ if (ABS(pwd->dx) < k) {
+ if (pwd->dy < 0) {
+ if (mpd->walkBack1 > 0) {
+ pwd->anim.set(mpd->walkBack1, mpd->walkBack2, DIR_BACK);
+ } else if (pwd->dx < 0) {
+ pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_BACK);
+ } else {
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_BACK);
+ }
+ } else if (pwd->dy > 0) {
+ if (mpd->walkFront1 > 0) {
+ pwd->anim.set(mpd->walkFront1, mpd->walkFront2, DIR_FRONT);
+ } else if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
+ if (pwd->dx < 0) {
+ pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_FRONT);
+ } else {
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_FRONT);
+ }
+ } else {
+ // we have a special move for left/right, so select that instead!
+ if (direction == -3) {
+ // previously facing right
+ pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_FRONT);
+ } else {
+ // previously facing left
+ pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_FRONT);
+ }
+ }
+ }
+ }
+ }
+}
+
+void Walk::animatePerson(const MovePersonData *mpd, uint16 image, uint16 bobNum, uint16 bankNum, int direction) {
+ // queen.c l.2572-2651
+ BobSlot *pbs = _vm->graphics()->bob(bobNum);
+
+ // check to see which way person should be facing
+ if (mpd->walkLeft1 == mpd->walkRight1) {
+ pbs->xflip = (direction == -3);
+ } else {
+ // they have special walk for left and right, so don't flip
+ pbs->xflip = false;
+ }
+
+ uint16 i;
+ for (i = 1; i <= _walkDataCount; ++i) {
+ WalkData *pwd = &_walkData[i];
+
+ // unpack necessary frames for bob animation
+ uint16 dstFrame = image;
+ uint16 srcFrame = ABS(pwd->anim.firstFrame);
+ while (srcFrame <= ABS(pwd->anim.lastFrame)) {
+ _vm->bankMan()->unpack(srcFrame, dstFrame, bankNum);
+ ++dstFrame;
+ ++srcFrame;
+ }
+ // pass across bobs direction ONLY if walk is a mirror flip!
+ if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
+ pbs->animNormal(image, dstFrame - 1, mpd->animSpeed, false, pbs->xflip);
+ } else {
+ pbs->animNormal(image, dstFrame - 1, mpd->animSpeed, false, false);
+ }
+
+ // move other actors at correct speed relative to scale
+ uint16 moveSpeed = _vm->grid()->findScale(pbs->x, pbs->y) * mpd->moveSpeed / 100;
+ pbs->move(pbs->x + pwd->dx, pbs->y + pwd->dy, moveSpeed);
+
+ // flip if one set of frames for actor
+ if (mpd->walkLeft1 < 0 || ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
+ pbs->xflip = pwd->dx < 0;
+ }
+
+ while (pbs->moving) {
+ _vm->update();
+ pbs->scale = pwd->area->calcScale(pbs->y);
+ pbs->scaleWalkSpeed(mpd->moveSpeed);
+ if (_vm->input()->cutawayQuit()) {
+ stopPerson(bobNum);
+ break;
+ }
+ }
+ }
+}
+
+int16 Walk::moveJoe(int direction, int16 endx, int16 endy, bool inCutaway) {
+ _joeInterrupted = false;
+ _joeMoveBlock = false;
+ int16 can = 0;
+ initWalkData();
+
+ uint16 oldx = _vm->graphics()->bob(0)->x;
+ uint16 oldy = _vm->graphics()->bob(0)->y;
+
+ _vm->logic()->joeWalk(JWM_MOVE);
+
+ uint16 oldPos = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
+ uint16 newPos = _vm->grid()->findAreaForPos(GS_ROOM, endx, endy);
+
+ debug(9, "Walk::moveJoe(%d, %d, %d, %d, %d) - old = %d, new = %d", direction, oldx, oldy, endx, endy, oldPos, newPos);
+
+ // if in cutaway, allow Joe to walk anywhere
+ if (newPos == 0 && inCutaway) {
+ incWalkData(oldx, oldy, endx, endy, oldPos);
+ } else {
+ if (calc(oldPos, newPos, oldx, oldy, endx, endy)) {
+ if (_walkDataCount > 0) {
+ animateJoePrepare();
+ animateJoe();
+ if (_joeInterrupted) {
+ can = -1;
+ }
+ }
+ } else {
+ // path has been blocked, make Joe say so
+ _vm->logic()->makeJoeSpeak(4);
+ can = -1;
+ }
+ }
+
+ _vm->graphics()->bob(0)->animating = false;
+ if (_joeMoveBlock) {
+ can = -2;
+ _joeMoveBlock = false;
+ } else if (direction > 0) {
+ _vm->logic()->joeFacing(direction);
+ }
+ _vm->logic()->joePrevFacing(_vm->logic()->joeFacing());
+ _vm->logic()->joeFace();
+ return can;
+}
+
+int16 Walk::movePerson(const Person *pp, int16 endx, int16 endy, uint16 curImage, int direction) {
+ if (endx == 0 && endy == 0) {
+ warning("Walk::movePerson() - endx == 0 && endy == 0");
+ return 0;
+ }
+
+ int16 can = 0;
+ initWalkData();
+
+ uint16 bobNum = pp->actor->bobNum;
+ uint16 bankNum = pp->actor->bankNum;
+
+ uint16 oldx = _vm->graphics()->bob(bobNum)->x;
+ uint16 oldy = _vm->graphics()->bob(bobNum)->y;
+
+ uint16 oldPos = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
+ uint16 newPos = _vm->grid()->findAreaForPos(GS_ROOM, endx, endy);
+
+ debug(9, "Walk::movePerson(%d, %d, %d, %d, %d) - old = %d, new = %d", direction, oldx, oldy, endx, endy, oldPos, newPos);
+
+ // find MovePersonData associated to Person
+ const MovePersonData *mpd = _moveData;
+ while (mpd->name[0] != '*') {
+ if (scumm_stricmp(mpd->name, pp->name) == 0) {
+ break;
+ }
+ ++mpd;
+ }
+
+ if (calc(oldPos, newPos, oldx, oldy, endx, endy)) {
+ if (_walkDataCount > 0) {
+ animatePersonPrepare(mpd, direction);
+ animatePerson(mpd, curImage, bobNum, bankNum, direction);
+ }
+ } else {
+ can = -1;
+ }
+
+ uint16 standingFrame = 31 + bobNum;
+
+ // make other person face the right direction
+ BobSlot *pbs = _vm->graphics()->bob(bobNum);
+ pbs->endx = endx;
+ pbs->endy = endy;
+ pbs->animating = false;
+ pbs->scale = _walkData[_walkDataCount].area->calcScale(endy);
+ if (_walkData[_walkDataCount].anim.facing == DIR_BACK) {
+ _vm->bankMan()->unpack(mpd->backStandingFrame, standingFrame, bankNum);
+ } else {
+ _vm->bankMan()->unpack(mpd->frontStandingFrame, standingFrame, bankNum);
+ }
+ uint16 obj = _vm->logic()->objectForPerson(bobNum);
+ if (_walkData[_walkDataCount].dx < 0) {
+ _vm->logic()->objectData(obj)->image = -3;
+ pbs->xflip = true;
+ } else {
+ _vm->logic()->objectData(obj)->image = -4;
+ pbs->xflip = false;
+ }
+ pbs->frameNum = standingFrame;
+ return can;
+}
+
+void Walk::stopJoe() {
+ BobSlot *pbs = _vm->graphics()->bob(0);
+ pbs->moving = false;
+ _joeInterrupted = true;
+}
+
+void Walk::stopPerson(uint16 bobNum) {
+ BobSlot *pbs = _vm->graphics()->bob(bobNum);
+ pbs->x = pbs->endx;
+ pbs->y = pbs->endy;
+ pbs->moving = false;
+}
+
+bool Walk::calc(uint16 oldPos, uint16 newPos, int16 oldx, int16 oldy, int16 x, int16 y) {
+ // if newPos is outside of an AREA then traverse Y axis until an AREA is found
+ if (newPos == 0) {
+ newPos = findAreaPosition(&x, &y, true);
+ }
+
+ // do the same for oldPos in case Joe somehow sits on the border of an AREA
+ // and does not register
+ if (oldPos == 0) {
+ oldPos = findAreaPosition(&oldx, &oldy, false);
+ }
+
+ if (oldPos == newPos) {
+ incWalkData(oldx, oldy, x, y, newPos);
+ return true;
+ } else if (calcPath(oldPos, newPos)) {
+ uint16 i;
+ int16 px = oldx;
+ int16 py = oldy;
+ for (i = 2; i <= _areaListCount; ++i) {
+ uint16 a1 = _areaList[i - 1];
+ uint16 a2 = _areaList[i];
+ const Area *pa1 = &_roomArea[a1];
+ const Area *pa2 = &_roomArea[a2];
+ uint16 x1 = calcC(pa1->box.x1, pa1->box.x2, pa2->box.x1, pa2->box.x2, px);
+ uint16 y1 = calcC(pa1->box.y1, pa1->box.y2, pa2->box.y1, pa2->box.y2, py);
+ incWalkData(px, py, x1, y1, a1);
+ px = x1;
+ py = y1;
+ }
+ incWalkData(px, py, x, y, newPos);
+ return true;
+ }
+ return false;
+}
+
+int16 Walk::calcC(int16 c1, int16 c2, int16 c3, int16 c4, int16 lastc) {
+ int16 s1 = MAX(c1, c3);
+ int16 s2 = MIN(c2, c4);
+ int16 c;
+ if ((lastc >= s1 && lastc <= s2) || (lastc >= s2 && lastc <= s1)) {
+ c = lastc;
+ } else {
+ c = (s1 + s2) / 2;
+ }
+ return c;
+}
+
+int16 Walk::findAreaPosition(int16 *x, int16 *y, bool recalibrate) {
+ // FIXME - in order to locate the nearest available area, the original
+ // algorithm computes the X (or Y) closest face distance for each available
+ // area. We simply added the case where the pointer is neither lying in the
+ // X range nor in the Y one.
+ // To get an example of this in action, in the room D1, make Joe walking
+ // to the wall at the right of the window (just above the radiator). On the
+ // original game, Joe will go to the left door...
+ uint16 i;
+ uint16 pos = 1;
+ uint32 minDist = (uint32)~0;
+ const Box *b = &_roomArea[1].box;
+ for (i = 1; i <= _roomAreaCount; ++i) {
+
+ b = &_roomArea[i].box;
+
+ uint16 dx1 = ABS(b->x1 - *x);
+ uint16 dx2 = ABS(b->x2 - *x);
+ uint16 dy1 = ABS(b->y1 - *y);
+ uint16 dy2 = ABS(b->y2 - *y);
+ uint16 csx = MIN(dx1, dx2);
+ uint16 csy = MIN(dy1, dy2);
+
+ bool inX = (*x >= b->x1) && (*x <= b->x2);
+ bool inY = (*y >= b->y1) && (*y <= b->y2);
+
+ uint32 dist = minDist;
+ if (!inX && !inY) {
+ dist = csx * csx + csy * csy;
+ } else if (inX) {
+ dist = csy * csy;
+ } else if (inY) {
+ dist = csx * csx;
+ }
+
+ if (dist < minDist) {
+ minDist = dist;
+ pos = i;
+ }
+ }
+ // we now have the closest area near X,Y, so we can recalibrate
+ // the X,Y coord to be in this area
+ if (recalibrate) {
+ b = &_roomArea[pos].box;
+ if (*x < b->x1) *x = b->x1;
+ if (*x > b->x2) *x = b->x2;
+ if (*y < b->y1) *y = b->y1;
+ if (*y > b->y2) *y = b->y2;
+ }
+ return pos;
+}
+
+uint16 Walk::findFreeArea(uint16 area) const {
+ uint16 testArea;
+ uint16 freeArea = 0;
+ uint16 map = ABS(_roomArea[area].mapNeighbours);
+ for (testArea = 1; testArea <= _roomAreaCount; ++testArea) {
+ int b = _roomAreaCount - testArea;
+ if (map & (1 << b)) {
+ // connecting area, check if it's been struck off
+ if (!isAreaStruck(testArea)) {
+ // legitimate connecting area, keep it
+ freeArea = testArea;
+ break;
+ }
+ }
+ }
+ return freeArea;
+}
+
+bool Walk::isAreaStruck(uint16 area) const {
+ uint16 i;
+ bool found = false;
+ for (i = 1; i <= _areaStrikeCount; ++i) {
+ if (_areaStrike[i] == area) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+bool Walk::calcPath(uint16 oldArea, uint16 newArea) {
+ debug(9, "Walk::calcPath(%d, %d)", oldArea, newArea);
+ _areaList[1] = _areaStrike[1] = oldArea;
+ _areaListCount = _areaStrikeCount = 1;
+ uint16 area = oldArea;
+ while (_areaListCount > 0 && area != newArea) {
+ area = findFreeArea(area);
+ if (!area) {
+ // wrong path, rolling back
+ _areaList[_areaListCount] = 0;
+ --_areaListCount;
+ area = _areaList[_areaListCount];
+ } else {
+ ++_areaListCount;
+ assert(_areaListCount < MAX_WALK_DATA);
+ _areaList[_areaListCount] = area;
+ if (!isAreaStruck(area)) {
+ ++_areaStrikeCount;
+ assert(_areaStrikeCount < MAX_WALK_DATA);
+ _areaStrike[_areaStrikeCount] = area;
+ }
+ }
+ }
+ return _areaList[1] != 0;
+}
+
+void Walk::initWalkData() {
+ uint16 curRoom = _vm->logic()->currentRoom();
+ _roomArea = _vm->grid()->area(curRoom, 0);
+ _roomAreaCount = _vm->grid()->areaMax(curRoom);
+
+ _walkDataCount = 0;
+ memset(_walkData, 0, sizeof(_walkData));
+ _areaStrikeCount = 0;
+ memset(_areaStrike, 0, sizeof(_areaStrike));
+ _areaListCount = 0;
+ memset(_areaList, 0, sizeof(_areaList));
+}
+
+void Walk::incWalkData(int16 px, int16 py, int16 x, int16 y, uint16 areaNum) {
+ debug(9, "Walk::incWalkData(%d, %d, %d)", (x - px), (y - py), areaNum);
+ if (px != x || py != y) {
+ ++_walkDataCount;
+ assert(_walkDataCount < MAX_WALK_DATA);
+ WalkData *pwd = &_walkData[_walkDataCount];
+ pwd->dx = x - px;
+ pwd->dy = y - py;
+ pwd->area = &_roomArea[areaNum];
+ pwd->areaNum = areaNum;
+ }
+}
+
+} // End of namespace Queen
diff --git a/engines/queen/walk.h b/engines/queen/walk.h
new file mode 100644
index 0000000000..02c8264db9
--- /dev/null
+++ b/engines/queen/walk.h
@@ -0,0 +1,144 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef QUEENWALK_H
+#define QUEENWALK_H
+
+#include "common/util.h"
+#include "queen/structs.h"
+
+namespace Queen {
+
+struct MovePersonAnim {
+ int16 firstFrame;
+ int16 lastFrame;
+ Direction facing;
+
+ void set(int16 ff, int16 lf, Direction dir) {
+ firstFrame = ff;
+ lastFrame = lf;
+ facing = dir;
+ }
+};
+
+struct WalkData {
+ int16 dx, dy;
+ const Area *area;
+ uint16 areaNum;
+ MovePersonAnim anim;
+};
+
+struct MovePersonData {
+ const char *name;
+ int16 walkLeft1, walkLeft2;
+ int16 walkRight1, walkRight2;
+ int16 walkBack1, walkBack2;
+ int16 walkFront1, walkFront2;
+ uint16 frontStandingFrame;
+ uint16 backStandingFrame;
+ uint16 animSpeed;
+ uint16 moveSpeed;
+};
+
+class QueenEngine;
+
+class Walk {
+public:
+
+ Walk(QueenEngine *vm);
+
+ int16 moveJoe(int direction, int16 endx, int16 endy, bool inCutaway);
+ int16 movePerson(const Person *pp, int16 endx, int16 endy, uint16 curImage, int direction);
+
+ void stopJoe();
+ void stopPerson(uint16 bobNum);
+
+ enum {
+ MAX_WALK_DATA = 16
+ };
+
+private:
+
+ void animateJoePrepare();
+ void animateJoe();
+
+ void animatePersonPrepare(const MovePersonData *mpd, int direction);
+ void animatePerson(const MovePersonData *mpd, uint16 image, uint16 bobNum, uint16 bankNum, int direction);
+
+ //! compute transition coordinate
+ static int16 calcC(int16 c1, int16 c2, int16 c3, int16 c4, int16 lastc);
+
+ //! find area for position
+ int16 findAreaPosition(int16 *x, int16 *y, bool recalibrate);
+
+ //! find an area not already struck
+ uint16 findFreeArea(uint16 area) const;
+
+ //! return true if the area is already on the walking path
+ bool isAreaStruck(uint16 area) const;
+
+ //! calculates the path list from oldArea to newArea
+ bool calcPath(uint16 oldArea, uint16 newArea);
+
+ //! resets path computed in calcPath()
+ void initWalkData();
+
+ //! add an area to the path
+ void incWalkData(int16 px, int16 py, int16 x, int16 y, uint16 area);
+
+ //! compute path (and populates _walkData) from current position to the new one
+ bool calc(uint16 oldPos, uint16 newPos, int16 oldx, int16 oldy, int16 x, int16 y);
+
+
+ //! areas for current room
+ const Area *_roomArea;
+
+ //! number of areas for current room
+ uint16 _roomAreaCount;
+
+ //! walking steps
+ WalkData _walkData[MAX_WALK_DATA];
+
+ //! number of walking steps
+ uint16 _walkDataCount;
+
+ uint16 _areaStrike[MAX_WALK_DATA];
+ uint16 _areaStrikeCount;
+
+ uint16 _areaList[MAX_WALK_DATA];
+ uint16 _areaListCount;
+
+ //! set if stopJoe() is called
+ bool _joeInterrupted;
+
+ //! set if handleSpecialArea() is called
+ bool _joeMoveBlock;
+
+ QueenEngine *_vm;
+
+ //! persons walking animation data
+ static const MovePersonData _moveData[];
+};
+
+} // End of namespace Queen
+
+#endif
diff --git a/engines/queen/xref.txt b/engines/queen/xref.txt
new file mode 100644
index 0000000000..55067aa922
--- /dev/null
+++ b/engines/queen/xref.txt
@@ -0,0 +1,496 @@
+$Id$
+
+Cross-reference for functions and variables for the original source code and
+the ScummVM implementation.
+
+
+BANKS
+=====
+erase() BankManager::close
+freeallframes() BankManager::eraseFrames(true)
+freeframes() BankManager::eraseFrames(false)
+loadbank() BankManager::load
+overpack() BankManager::overpack
+unpack() BankManager::unpack
+
+
+COMMAND
+=======
+ALTER_DEFAULT() *not needed* (use State::alterDefaultVerb)
+CLEAR_COMMAND() Command::clear
+EXECUTE_ACTION() Command::executeCurrentAction
+FIND_DEFAULT() *not needed* (use State::findDefaultVerb)
+LOOK() Command::lookAtSelectedObject
+LOOK_ICON(),LOOK_ITEM() Command::lookForCurrentIcon
+LOOK_ROOM() Command::lookForCurrentObject
+OPEN_CLOSE_OTHER() Command::openOrCloseAssociatedObject
+P1_SET_CONDITIONS() Command::setConditions
+P2_SET_AREAS() Command::setAreas
+P3_SET_OBJECTS() Command::setObjects
+P4_SET_ITEMS() Command::setItems
+SELECT() Command::grabCurrentSelection
+SELECT_ITEM() Command::grabSelectedItem
+SELECT_NOUN() Command::grabSelectedNoun
+SELECT_VERB() Command::grabSelectedVerb
+WALK() Command::makeJoeWalkTo
+-
+ACTION Command::_state.action
+ACTION2 Command::_state.selAction
+CLEVEL Command::_state.commandLevel
+COM_A Command::_cmdArea
+COM_A_MAX Command::_numCmdArea
+COM_O Command::_cmdObject
+COM_O_MAX Command::_numCmdObject
+COM_G Command::_cmdGameState
+COM_G_MAX Command::_numCmdGameState
+COM_I Command::_cmdInventory
+COM_I_MAX Command::_numCmdInventory
+COM_LIST Command::_cmdList
+COM_LIST_MAX Command::_numCmdList
+COMMANDstr Command::_cmdText
+DEFCOMM Command::_state.defaultVerb
+MKEY Command::_mouseKey
+OLDVERB,VERB Command::_state.*verb
+OLDNOUN,NOUN Command::_state.*noun
+NOUN2 Command::_state.selNoun
+PARSE Command::_parse
+SUBJ1,SUBJ2 Command::_state.subject*
+
+
+CREDIT SCRIPTING SYSTEM
+=======================
+Cinit() Credits::Credits()
+Ctext() *not needed* (included in Credits::update)
+Cupdate() Credits::update
+-
+Ccol Credits::_color
+Ccount Credits::_count
+Cfp
+Cflag Credits::_running
+Cfontsize Credits::_fontSize
+Cjustify Credits::_justify
+Cpausecount Credits::_pause
+Czone Credits::_zone
+
+
+CUTAWAY
+=======
+action_special_move() Cutaway::actionSpecialMove
+CUTAWAY() Cutaway::run
+MAKE_COMPLEX_ANIM() Cutaway::makeComplexAnimation
+SCENE_START() Logic::sceneStart
+SCENE_END() Logic::sceneStop
+-
+CUTON Input::_cutawayRunning
+CUTQUIT Input::_cutawayQuit
+FINAL_ROOM Cutaway::_finalRoom
+IROOM Cutaway::_initialRoom
+OBJ_CUT
+OBJ_ANIM
+OLDBANK
+PERSON_DATA
+SCENE Logic::_scene
+TROOM Cutaway::_temporaryRoom
+
+
+DEBUG
+=====
+cd_sample_check()
+debuginfo() Debugger::Cmd_Info
+select_new_room() Debugger::Cmd_Room
+-
+AREAVAR (boolean, if true display objects/areas boxes)
+
+
+GAME SETTINGS
+=============
+game_load() Logic::gameLoad
+game_save() Logic::gameSave
+-
+config_request
+MUSICTOGGLE Sound::_musicToggle / ConfMan.("music_mute")
+SFXTOGGLE Sound::_sfxToggle / ConfMan.("sfx_mute")
+TALKSPD QueenEngine::_talkSpeed / ConfMan.("talkspeed")
+TEXTTOGGLE QueenEngine::_subtitles / ConfMan.("subtitles")
+VersionStr GameVersion::versionString
+VOICETOGGLE Sound::_speechToggle / ConfMan.("speech_mute")
+VOLUME ? / ConfMan.("master_volume")
+
+
+GRAPHICS
+========
+bob() Graphics::drawBob
+CHECK_PARALLAX() Graphics::handleParallax
+clearallbobs() Graphics::clearBobs
+clearbob() BobSlot::clear
+DISP_OBJECTS() Graphics::setupRoomObjects
+drawbobs() Graphics::drawBobs
+invbob() Graphics::drawInventoryItem
+loadbackdrop() *not needed* (included in Display::setupNewRoom)
+loadpanel() Display::setupPanel
+MAKE_SPEAK_BOB() Graphics::setBobText
+makeanim() BobSlot::animNormal
+movebob() BobSlot::move
+pastebob() Graphics::pasteBob
+REDISP_OBJECT() Graphics::refreshObject
+requestor()
+shrinkbob() Graphics::shrinkFrame
+sortbobs() Graphics::sortBobs
+stringanim() BobSlot::animString
+-
+bobs Graphics::_bobs
+cambob Graphics::_cameraBob
+sortedbobs Graphics::_sortedBobs
+
+
+INPUT
+=====
+check_keys() Input::checkKeys()
+get_key() *not needed*
+-
+drawmouseflag *not needed* (equivalent to _display->showMouseCursor(bool))
+key_commands Input::_currentCommandKeys
+key_language Input::_commandKeys
+KEYVERB Input::_keyVerb
+MouseButton Input::_mouseButton
+mouseflag *not needed*
+no_check_keys Input::_noCheckKeys
+
+
+INVENTORY
+=========
+DEL_ITEM_NUM() Logic::inventoryDeleteItem
+INS_ITEM_NUM() Logic::inventoryInsertItem
+INVDWN() Logic::inventoryScroll
+INVENTORY() Logic::inventoryRefresh
+INVUP() Logic::inventoryScroll
+SETUP_ITEMS() Logic::inventorySetup
+-
+INV1,INV2,INV3,INV4 Logic::_inventoryItem
+
+
+JOE
+===
+FACE_JOE() Logic::joeFace
+GRAB_DIR(),GRAB_JOE() Logic::joeGrab
+SETUP_HERO() Logic::setupJoeInRoom
+SETUP_JOE() Logic::setupJoe
+USE_UNDERWEAR() Logic::joeUseUnderwear
+USE_CLOTHES() Logic::joeUseClothes
+USE_DRESS() Logic::joeUseDress
+-
+CUTJOEF Logic::_joe.cutFacing
+JOE_RESPstr Logic::_joeResponse
+JOEF,JX,JY,JDIR Logic::_joe.*
+JOEWALK Logic::_joe.walk
+
+
+JOURNAL
+=======
+clearlefttext() Journal::clearPanelTexts
+drawnames() Journal::drawSaveDescriptions
+findsaves() Journal::findSaveDescriptions
+menutext() Journal::drawPanelText
+predrawbobs() Journal::drawConfigPanel / Journal::drawNormalPanel
+prompt_do() *not needed*
+USE_JOURNAL() Logic::useJournal
+waitmousezone() *not needed*
+-
+choice Journal::_currentSaveSlot
+decbase Journal::_currentSavePage
+in_journal *not needed* (the hack in puttext() seems useless and CHECK_PARALLAX() is never called)
+save_descriptions Journal::_saveDescriptions
+walkgameload *not needed ?*
+
+
+LOGIC
+=====
+CHECK_PLAYER() QueenEngine::update
+CUTAWAY_SPECIAL() Logic::removeHotelItemsFromInventory
+DISP_ROOM() Logic::displayRoom
+FIND_BOB() Logic::findBob
+FIND_FRAME() Logic::findFrame
+FIND_GRAPHIC() Logic::graphicData
+P3_COPY_FROM() Logic::objectCopy
+R_MAP() Logic::handlePinnacleRoom
+restart_game()
+SETUP_BOBS() Graphics::unpackControlBank / Graphics::setupMouseCursor
+SETUP_FURNITURE() Graphics::setupRoomFurniture
+SETUP_ROOM() Logic::changeRoom
+SETUP_SCREENS() *not needed* (only calls Display::setupPanel)
+SETUP_VARS() *not needed* (equivalent to Command::clear(), SCENE=0, clear(gamestate))
+update() QueenEngine::update
+-
+A_ANIMstr Logic::_aAnim
+A_ANIM_MAX Logic::_numAAnim
+A_NAMEstr Logic::_aName
+A_NAME_MAX Logic::_numAName
+A_FILEstr Logic::_aFile
+A_FILE_MAX Logic::_numAFile
+ACTOR_DATA_MAX Logic::_numActors
+bamflag BamScene::_flag
+bamindex BamScene::_index
+DESCTOT Logic::_numDescriptions
+ENTRY_OBJ Logic::_entryObj
+FMAX Logic::_numFurnitureStatic
+FMAXA Logic::_numFurnitureAnimated
+FMAXLEN Logic::_numFurnitureAnimatedLen
+FRAMES Logic::_numFrames
+FURN_DATA_MAX Logic::_numFurniture
+GAMESTATE Logic::_gameState
+GRAPHIC_ANIM_MAX Logic::_numGraphicAnim
+GRAPHIC_DATA Logic::_graphicData
+GRAPHIC_MAX Logic::_numGraphics
+ITEMTOT Logic::_numItems
+ITEM_DATA Logic::_itemData
+NAMETOT Logic::_numNames
+OBJ_DESC_DATA Logic::_objectDescription
+OBJ_DESC_MAX Logic::_numObjDesc
+OBJECT_DATA Logic::_objectData
+OBJECT_DESCRstr Logic::_objDescription
+OBJECT_NAMEstr Logic::_objName
+OBJTOT Logic::_numObjects
+OLDROOM,ROOM,NEW_ROOM Logic::_*oom
+ROOMTOT Logic::_numRooms
+ROOM_DATA Logic::_roomData
+ROOM_NAMEstr Logic::_roomName
+SFACTOR Logic::_joe.scale
+VERB_NAMEstr Logic::_verbName
+WALK_OFF_DATA Logic::_walkOffData
+WALK_OFF_MAX Logic::_numWalkOffs
+
+
+PERSONS
+=======
+ALLOCATE_PERSON() Logic::allocatePersonFrames
+CREATE_ANIM() Graphics::setupPersonAnim
+SET_PERSON_DATA() Logic::initPerson
+SETUP_PERSON() Logic::setupPersonInRoom
+OBJ_PERSON() Logic::objectForPerson
+-
+NEW_ANIM Graphics::_newAnim
+PERSON_FACE
+PERSON_FACE_MAX
+PERSON_FRAMES Logic::_personFrames
+P_ANIMstr Person.anim
+P_NAMEstr Person.name
+P_STAND,P_BNUM,P_ROOM Person.actor->*
+P_BANK,P_X,P_Y,P_COLOR Person.actor->*
+P_VALUE,P_GAMES Person.actor->*
+SFRAME Person.bobFrame
+
+
+RESOURCE
+========
+tflen() Resource::fileSize
+topen() Resource::loadFile
+tseek() *not needed*
+
+
+SCREEN
+======
+Box() Display::drawBox
+calc_screen_scroll() Display::horizontalScrollUpdate
+changejoepal() Display::palSetJoe*
+check_colors() Display::palCustomColors
+check_pal_scroll Display::palCustomScroll
+clearpanel() Display::prepareUpdate
+drawbackdrop() Display::prepareUpdate
+drawpanel() Display::prepareUpdate
+drawscreen() Display::update
+dynalum() Display::dynalumUpdate
+fade_panel() Display::palGreyPanel
+fadein() Display::palFadeIn
+fadeout() Display::palFadeOut
+flashspecial() Display::palCustomFlash
+loadfont() Display::initFont
+palscroll() Display::palScroll
+putcharacter() Display::drawChar
+setpal() Display::palSet
+-
+BDxres Display::_bdWidth
+BDyres Display::_bdHeight
+clothespal Display::_palJoeClothes
+COMPANEL *not needed* (argument)
+dresspal Display::_palJoeDress
+font Display::_font
+font_sizes Display::_charWidth
+FULLSCREEN Display::_fullscreen
+nopalscroll Display::_pal.scrollable
+palette Display::_pal.room
+panelflag *not needed* (redundant with fullscreen)
+scrollx Display::_horizontalScroll
+tpal Display::_pal.screen
+
+
+SOUND
+=====
+alter_current_volume()
+playsong() Sound::playSong()
+sfxbusy() Sound::waitSfxFinished()
+sfxplay() Sound::playSfx()
+-
+song[] Sound::_song[]
+tunelist[] Sound::_tune[]
+CURRSONG Music::_currentSong
+SFXNAME Sound::_sfxName
+VOLUME
+
+
+STATE
+=====
+ALTER_STATE() State::alterState*
+FIND_STATE() State::findState*
+-
+
+
+TALK
+====
+FIND_SACTION() Talk::findSpeechParameters
+MOVE_SPEAK() *not needed* (included in Talk::getSpeakCommand)
+SPEAK() Talk::speak
+SPEAK_SUB() Talk::speakSegment
+talk() Talk::talk
+TALK_PROC() Talk::talk
+-
+A1,A12
+actiondata Talk::_speechParameters
+HEAD
+JMAX
+JOEKEYstr
+LEVEL
+LEVELMAX
+OLDLEVEL
+OLDS
+OWALK
+PERstr
+PKEYstr
+TALKHEAD
+TALKQUIT Input::_talkQuit
+TALKstr
+TALK_SELECTED Logic::_talkSelected
+
+
+TEXTS
+=====
+blanktexts() Display::clearTexts
+drawtext() Display::drawTexts
+Ink() Display::textCurrentColor
+MIDDLE() Display::textCenterX / Display::textSetCentered
+text() Display::setText
+textlen() Display::textWidth
+-
+textcol Display::_curTextColor
+texts Display::_texts
+
+
+WALK
+====
+CALC_PATH() Walk::calcPath
+CALC_WALK() Walk::incWalkData
+CALC_X() Walk::calcC
+CALC_Y() Walk::calcC
+CALCSCALE() Area::calcScale
+FIND_FREE_AREA Walk::findFreeArea
+FIND_NEWP() Walk::findAreaPosition
+FIND_OLDP() Walk::findAreaPosition
+MOVE_JOE() Walk::moveJoe
+MOVE_OTHER() Walk::movePerson
+-
+AREALIST Walk::_areaList
+AREASTRIKE Walk::_areaStrike
+movdata Walk::_moveData
+WALK_DATA Walk::_walkData
+WALKI Walk::_walkDataCount
+
+
+ZONES
+=====
+ClearZones() Grid::clear
+FIND_SCALE() Grid::findScale
+FIND_VERB() Grid::findVerbUnderCursor
+SETUP_PANEL_ZONES() Grid::setupPanel
+SETUP_ZONES() Grid::setupNewRoom
+SetZone() Grid::setZone
+zone() Grid::findZoneForPos / Logic::findAreaForPos
+-
+AREA Grid::_area
+AREAMAX Grid::_areaMax
+OBJECT_BOX Grid::_objectBox
+OBJMAX Grid::_objMax
+zones Grid::_zones
+
+
+(UNSORTED)
+==========
+in() Cutaway::inRange
+find_cd_cut() findCdCut
+find_cd_desc() *not needed* (included in Logic::joeSpeak)
+-
+Kstr
+bank9
+NEWDEF,
+M,A,
+FRAME,
+AM,
+WX,WY,
+PX,PY,
+LD,FD
+DESC2,DESC
+PERSON_OBJ
+FS,FE,FACE,
+TY,
+DY,
+I2,
+N,V,
+ds,bs,
+bx,by,
+dx,dy,
+SFAC,FDIR,
+OBJ,E,T,
+CH,
+OLDG,S2,S1,ITEM,TYPE,C,
+NAME,TL,TI,TS,WC,IMAGE,
+D,P,LI,R
+CANTQUIT !Input::_canQuit
+
+
+(NO NEED TO BE GLOBAL)
+======================
+Nstr,F1,F2,F3,F4,F5,F6,F7,F8,SF,BF,AS,MS // MOVE_OTHER (struct movdata *)
+Nstr,S,F,BODY,BF,RF,AF,SANIMstr,FF // FIND_SACTION (struct action *)
+CURRBOB // SETUP_FURNITURE, REDISP_OBJECT, DISP_OBJECTS
+PSY,PSX,CSX,DX1,DX2,DY1,DY2,PCF,CCF,CSY // FIND_NEWP, FIND_OLDP
+tx,ty,SFRAME,EFRAME,SPEED // FIND_GRAPHIC
+AREAMAXv
+CURRY
+OMAX,OMAXA
+TEMPA
+BANK,BNUM
+DIFF // LOOK local var
+RET // P1_SET_CONDITIONS local var
+BS,DS // CALC_SCALE
+SX,SY,
+NEWA // FIND_FREE_AREA local
+IX,IY // Cutaway locals
+COM // EXECUTE_ACTION local
+COMMAX // EXECUTE_ACTION local
+COND // EXECUTE_ACTION local
+CURRCOM // EXECUTE_ACTION local
+GSET // P1_SET_CONDITIONS local
+A2 // EXECUTE_ACTION local
+TEMPI // P1_SET_CONDITIONS local
+MAPC // findFreeArea local var
+NEWP,OLDP // locals in joeMove && personMove
+OLDX,X,OLDY,Y // passed as arguments
+X2,X1,XD,YD // incWalkData && findFreeArea locals
+Gstr // not needed, grab state
+Pstr // not needed, FIND_STATE result
+OUTLINE // not needed, textSet() Graphics::parameter
+FTOT // queen.c/SETUP_FURNITURE local var
+OBJMAXv // == Logic::_objMax[Logic::_currentRoom]
+TEMPstr
+WORDstr
+JOE2str,PERSON2str // locals in Talk::initialTalk
+SUBJECT
+tmpbamflag