aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Montoir2003-10-31 13:46:45 +0000
committerGregory Montoir2003-10-31 13:46:45 +0000
commit23188d5188c658557d34c4a38666981dd96a8ecb (patch)
tree086d85e6756627fcf1d25ebb5dfdc8c6f7bfca65
parent55cb72e5faf954e29991dc88a3e161dd59f01a98 (diff)
downloadscummvm-rg350-23188d5188c658557d34c4a38666981dd96a8ecb.tar.gz
scummvm-rg350-23188d5188c658557d34c4a38666981dd96a8ecb.tar.bz2
scummvm-rg350-23188d5188c658557d34c4a38666981dd96a8ecb.zip
initial version of Command class
svn-id: r11016
-rw-r--r--queen/command.cpp1596
-rw-r--r--queen/command.h180
-rw-r--r--queen/module.mk1
3 files changed, 1777 insertions, 0 deletions
diff --git a/queen/command.cpp b/queen/command.cpp
new file mode 100644
index 0000000000..7772d781e4
--- /dev/null
+++ b/queen/command.cpp
@@ -0,0 +1,1596 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "queen/command.h"
+#include "queen/display.h"
+#include "queen/input.h"
+#include "queen/graphics.h"
+#include "queen/logic.h"
+#include "queen/walk.h"
+
+namespace Queen {
+
+
+
+void CmdText::clear() {
+
+ memset(_command, 0, sizeof(_command));
+}
+
+
+void CmdText::display(uint8 color) {
+
+ _graphics->textCurrentColor(color);
+ _graphics->textSetCentered(COMMAND_Y_POS, _command);
+}
+
+
+void CmdText::displayTemp(uint8 color, bool locked, const Verb& v, const char *name) {
+
+ char temp[MAX_COMMAND_LEN];
+ if (locked) {
+ sprintf(temp, "%s%s", lockedVerbPrefix, v.name());
+ }
+ else {
+ strcpy(temp, v.name());
+ }
+ if (name != NULL) {
+ strcat(temp, " ");
+ strcat(temp, name);
+ }
+ _graphics->textCurrentColor(color);
+ _graphics->textSetCentered(COMMAND_Y_POS, temp);
+}
+
+
+void CmdText::displayTemp(uint8 color, const char *name) {
+
+ char temp[MAX_COMMAND_LEN];
+ sprintf(temp, "%s %s", _command, name);
+ _graphics->textCurrentColor(color);
+ _graphics->textSetCentered(COMMAND_Y_POS, temp);
+}
+
+
+void CmdText::setVerb(const Verb& v) {
+
+ strcpy(_command, v.name());
+}
+
+
+void CmdText::addLinkWord(const Verb& v) {
+
+ strcat(_command, " ");
+ strcat(_command, v.name());
+}
+
+
+void CmdText::addObject(const char *objName) {
+
+ strcat(_command, " ");
+ strcat(_command, objName);
+}
+
+
+bool CmdText::isEmpty() const {
+ return _command[0] == 0;
+}
+
+
+
+Command::Command(Logic *l, Graphics *g, Input *i, Walk *w)
+ : _logic(l), _graphics(g), _input(i), _walk(w) {
+ _cmdText._graphics = _graphics;
+ _cmdText.lockedVerbPrefix = _logic->lockedVerbPrefix();
+}
+
+
+void Command::clear(bool clearTexts) {
+
+ _cmdText.clear();
+ if (clearTexts) {
+ _graphics->textClear(151, 151);
+ }
+ _parse = false;
+ _commandLevel = 1;
+ _oldVerb = _verb = Verb(VERB_NONE);
+ _oldNoun = _noun = _selectedNoun = 0;
+ _currentAction = Verb(VERB_NONE);
+ _selectedAction = Verb(VERB_NONE);
+ _subject1 = _subject2 = 0;
+}
+
+
+void Command::executeCurrentAction(bool walk) {
+
+ _logic->entryObj(0);
+
+ const char *obj1Name = NULL;
+ const char *obj2Name = NULL;
+
+ if (_commandLevel == 2 && _mouseKey == Input::MOUSE_RBUTTON) {
+ _mouseKey = Input::MOUSE_LBUTTON;
+ }
+
+ // XXX SUBJ1=SUBJECT[1]; SUBJ2=SUBJECT[2];
+
+ uint16 objMax = _logic->currentRoomObjMax();
+ uint16 roomData = _logic->currentRoomData();
+
+ if (_mouseKey == Input::MOUSE_RBUTTON && _subject1 != 0) {
+ // check to see if selecting default command for object/item
+ if (_subject1 > 0) {
+ // an object
+ int16 i = _subject1;
+ if (_noun > objMax) {
+ int16 aObj = _logic->currentRoomArea(_noun - objMax)->object;
+ int16 aObjName = _logic->objectData(aObj)->name;
+ if (aObjName > 0) {
+ _noun = objMax;
+ i = aObj;
+ }
+ }
+ ObjectData *od = _logic->objectData(ABS(i));
+ obj1Name = _logic->objectName(od->name);
+
+ if (_noun == 0 || _noun > objMax || _logic->objectData(i)->name <= 0) {
+ cleanupCurrentAction();
+ return;
+ }
+
+ uint16 obj = roomData + _noun;
+ _verb = findDefault(obj, false);
+ if (_verb.isNone()) {
+ // no match made, so command not yet completed, redefine as WALK_TO
+ _cmdText.setVerb(Verb(VERB_WALK_TO));
+ _selectedAction = Verb(VERB_WALK_TO);
+ }
+ else {
+ _cmdText.setVerb(_verb);
+ _selectedAction = _verb;
+ }
+ _cmdText.addObject(_logic->objectName(_logic->objectData(obj)->name));
+ }
+ else {
+ // an item
+ int16 name = _logic->itemData(ABS(_subject1))->name;
+ obj1Name = _logic->objectName(name);
+ }
+ }
+
+ // make sure that command is always highlighted when actioned!
+ _cmdText.display(INK_CMD_SELECT);
+
+ _selectedNoun = _noun;
+ _commandLevel = 1;
+
+ // XXX SUBJECT[2]=0;
+
+ // get objects names
+ obj1Name = _logic->objectOrItemName(_subject1);
+ obj2Name = _logic->objectOrItemName(_subject2);
+
+ if (handleBadCommand(walk)) {
+ cleanupCurrentAction();
+ return;
+ }
+
+ // get the number of commands associated with Object/Item
+ uint16 comMax = countAssociatedCommands(_selectedAction, _subject1, _subject2);
+ if (comMax == 0) {
+ // no command match was found, so exit
+ // pass ACTION2 as paramater, as a new Command (and a new ACTION2)
+ // can be constructed while Joe speaks
+ executeStandardStuff(_selectedAction, _subject1, _subject2);
+ 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;
+ uint16 curCommand;
+ for (curCommand = 1; curCommand <= comMax; ++curCommand) {
+ ++com;
+ ++comId;
+ // try to find a match for the command in COM_LIST
+ for (; comId <= _numCmdList; ++comId, ++com) {
+ if (com->match(_selectedAction, _subject1, _subject2)) {
+ break;
+ }
+ }
+
+ // check the Gamestates and set them if necessary
+ cond = 0;
+ if (com->setConditions) {
+ cond = setConditions(comId, (curCommand == comMax));
+ }
+
+ if (cond == -1 && curCommand == comMax) {
+ // only exit on a condition fail if at last command
+ // Joe hasnt spoken, so do normal LOOK command
+ if (_selectedAction.value() == VERB_LOOK_AT) {
+ // Look At, do standard look at routine
+ look();
+ cleanupCurrentAction();
+ return;
+ }
+ }
+ else if (cond == -2 && curCommand == 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
+ break;
+ }
+ }
+
+ debug(0, "Command::executeCurrentAction() - cond = %X", cond);
+
+ if (com->setAreas) {
+ setAreas(comId);
+ }
+
+ // Don't grab if action is TALK or WALK
+ if (_selectedAction.value() != VERB_TALK_TO && _selectedAction.value() != VERB_WALK_TO) {
+ if (_subject1 > 0) {
+ _logic->joeGrab(_logic->objectData(_subject1)->state, 0);
+ }
+ if (_subject2 > 0) {
+ _logic->joeGrab(_logic->objectData(_subject2)->state, 0);
+ }
+ }
+
+ bool cutDone = false;
+ if (cond > 0) {
+ // FIXME: this stuff must be seriously re-designed !
+
+ // CR 2 - 7/3/95, Because we may be calling a cutaway triggered from walking
+ // to the pinnacle (which connects to Map room 7), we'll be caught in the
+ // R_MAP routine until we select a location and then call this very procedure
+ // again - the result being that COM will be reset. So to avoid that, we'll
+ // keep a copy of COM until we return from the recursive call...
+ // Otherwise, all remaining commands will be wiped and not carried out!
+ uint16 comTempId = comId;
+ CmdListData *comTemp = com;
+
+ const char *desc = _logic->objectTextualDescription(cond);
+ if (executeIfCutaway(desc)) {
+ cond = 0;
+ cutDone = true;
+ }
+
+ comId = comTempId;
+ com = comTemp;
+
+ // check for dialogs before updating Objects
+ if (executeIfDialog(desc)) {
+ cond = 0;
+ }
+ }
+
+ int16 oldImage = 0;
+ if (_subject1 > 0) {
+ // an object (not an item)
+ oldImage = _logic->objectData(_subject1)->image;
+ }
+
+ if (com->setObjects) {
+ setObjects(comId);
+ }
+ if (com->setItems) {
+ setItems(comId);
+ }
+
+ if (com->imageOrder != 0) {
+ ObjectData* od = _logic->objectData(_subject1);
+ // 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;
+ }
+ _logic->roomRefreshObject(_subject1);
+ }
+ else {
+ // this object is not being updated by command list, see if
+ // it has another image copied to it
+ if (_subject1 > 0) {
+ // an object (not an item)
+ if (_logic->objectData(_subject1)->image != oldImage) {
+ _logic->roomRefreshObject(_subject1);
+ }
+ }
+ }
+
+ // don't play music on an OPEN/CLOSE command - in case the command fails
+ if (_selectedAction.value() != VERB_OPEN && _selectedAction.value() != VERB_CLOSE) {
+ // only play song if it's a PLAY BEFORE type
+ if (com->song > 0) {
+ // XXX playsong(com->song);
+ }
+ }
+
+
+ // do a special hardcoded section
+ // l.419-452 execute.c
+ switch (com->specialSection) {
+ case 1:
+ // XXX l.428-438
+ warning("Command::executeCurrentAction() - Journal unimplemented");
+ return;
+ case 2:
+ _logic->joeUseDress(true);
+ break;
+ case 3:
+ _logic->joeUseClothes(true);
+ break;
+ case 4:
+ _logic->joeUseUnderwear();
+ break;
+ }
+
+ changeObjectState(_selectedAction, _subject1, com->song, cutDone);
+
+ if (_selectedAction.value() == VERB_TALK_TO && cond > 0) {
+ if (executeIfDialog(_logic->objectTextualDescription(cond))) {
+ cleanupCurrentAction();
+ return;
+ }
+ }
+
+// EXECUTE_EXIT1:
+
+ if (cond > 0) {
+ const char *desc = _logic->objectTextualDescription(cond);
+ // Joe needs to say something as a result of a Gamestate
+ // check first to see if it is a cutaway scene!
+ if (executeIfCutaway(desc)) {
+ }
+ else if (executeIfDialog(desc)) {
+ cleanupCurrentAction();
+ return;
+ }
+ else {
+ _logic->joeSpeak(cond, true);
+ }
+ }
+ else {
+ // we've failed commands with nothing to say
+ if (_selectedAction.value() == VERB_LOOK_AT) {
+ // Look At, do standard look at routine
+ look();
+ cleanupCurrentAction();
+ return;
+ }
+ }
+
+ // only play song if it's a PLAY AFTER type
+ if (com->song > 0) {
+ // XXX playsong(com->song);
+ }
+
+ clear(true);
+ cleanupCurrentAction();
+}
+
+
+void Command::updatePlayer() {
+
+ if (_input->cutawayRunning()) return;
+
+ lookCurrentRoom();
+ lookCurrentIcon();
+
+ if (!_input->keyVerb().isNone()) {
+
+ if (_input->keyVerb().isJournal()) {
+ // XXX queen.c l.348-365
+ warning("Command::updatePlayer() - Journal not implemented");
+ }
+ else if (!_input->keyVerb().isSkipText()) {
+ _verb = _input->keyVerb();
+ if (_verb.isInventory()) {
+ _noun = _selectedNoun = 0;
+ // Clear old noun and old verb in case we're pointing at an
+ // object (noun) or item (verb) and we want to use an item
+ // on it. This was the command will be redisplayed with the
+ // object/item that the cursor is currently on.
+ _oldNoun = 0;
+ _oldVerb = Verb(VERB_NONE);
+ grabSelectedItem();
+ }
+ else {
+ grabSelectedVerb();
+ }
+ _input->clearKeyVerb();
+ }
+ }
+
+ _mouseKey = _input->mouseButton();
+ _input->clearMouseButton();
+ if (_mouseKey > 0) {
+ grabCurrentSelection();
+ }
+}
+
+
+void Command::readCommandsFrom(byte *&ptr) {
+
+ uint16 i;
+
+ // Command List Data
+ _numCmdList = READ_BE_UINT16(ptr); ptr += 2;
+
+ _cmdList = new CmdListData[_numCmdList + 1];
+ memset(&_cmdList[0], 0, sizeof(CmdListData));
+ for (i = 1; i <= _numCmdList; i++) {
+ _cmdList[i].readFrom(ptr);
+ }
+
+ // Command AREA
+ _numCmdArea = READ_BE_UINT16(ptr); ptr += 2;
+
+ _cmdArea = new CmdArea[_numCmdArea + 1];
+ memset(&_cmdArea[0], 0, sizeof(CmdArea));
+ for (i = 1; i <= _numCmdArea; i++) {
+ _cmdArea[i].readFrom(ptr);
+ }
+
+ // Command OBJECT
+ _numCmdObject = READ_BE_UINT16(ptr); ptr += 2;
+
+ _cmdObject = new CmdObject[_numCmdObject + 1];
+ memset(&_cmdObject[0], 0, sizeof(CmdObject));
+ for (i = 1; i <= _numCmdObject; i++) {
+ _cmdObject[i].readFrom(ptr);
+ }
+
+ // Command INVENTORY
+ _numCmdInventory = READ_BE_UINT16(ptr); ptr += 2;
+
+ _cmdInventory = new CmdInventory[_numCmdInventory + 1];
+ memset(&_cmdInventory[0], 0, sizeof(CmdInventory));
+ for (i = 1; i <= _numCmdInventory; i++) {
+ _cmdInventory[i].readFrom(ptr);
+ }
+
+ // Command GAMESTATE
+ _numCmdGameState = READ_BE_UINT16(ptr); ptr += 2;
+ _cmdGameState = new CmdGameState[_numCmdGameState + 1];
+ memset(&_cmdGameState[0], 0, sizeof(CmdGameState));
+ for (i = 1; i <= _numCmdGameState; i++) {
+ _cmdGameState[i].readFrom(ptr);
+ }
+}
+
+
+void Command::grabCurrentSelection() {
+
+ _selPosX = _input->mousePosX();
+ _selPosY = _input->mousePosY();
+
+ uint16 zone = _logic->findObjectUnderCursor(_selPosX, _selPosY);
+ _noun = _logic->findObjectRoomNumber(zone);
+ _verb = _logic->findVerbUnderCursor(_selPosX, _selPosY);
+
+ _selPosX += _logic->display()->horizontalScroll();
+
+ debug(0, "Command::grabCurrentSelection() - _noun = %d, _verb = %d", _noun, _verb.value());
+ if (_verb.isAction()) {
+ grabSelectedVerb();
+ }
+ else if (_verb.isInventory()) {
+ grabSelectedItem();
+ }
+ else if (_noun > 0 && _noun <= _logic->currentRoomObjMax()) {
+ grabSelectedNoun();
+ }
+ else if (_selPosY < ROOM_ZONE_HEIGHT && _verb.isNone()) {
+ // select without a command, do a WALK
+ clear(true);
+ _logic->joeWalk(2);
+ }
+}
+
+
+void Command::grabSelectedItem() {
+
+ // if the NOUN has been selected from screen then it is positive
+ // Otherwise it has been selected from inventory and is negative
+ // Set PARSE to TRUE, default FALSE if command half complete
+
+ _parse = true;
+ uint16 item = _logic->findInventoryItem(_verb.inventoryItem());
+ if (item == 0 || _logic->itemData(item)->name == 0) {
+ return;
+ }
+
+ // If we've selected via keyboard, and there is no VERB then do
+ // the ITEMs default, otherwise keep constructing!
+
+ if (_mouseKey == Input::MOUSE_LBUTTON ||
+ (!_input->keyVerb().isNone() && !_verb.isNone())) {
+ if (_currentAction.isNone()) {
+ if (!_input->keyVerb().isNone()) {
+ /* 2 - We've selected via the keyboard, no command is being */
+ /* constructed, so we shall find the item's default */
+ _verb = findDefault(item, true);
+ if (_verb.isNone()) {
+ // set to Look At
+ _verb = Verb(VERB_LOOK_AT);
+ _cmdText.setVerb(Verb(VERB_LOOK_AT));
+ }
+ _currentAction = _verb;
+ }
+ else {
+ // Action>0 ONLY if command has been constructed
+ // Left Mouse Button pressed just do Look At
+ _verb = Verb(VERB_LOOK_AT);
+ _currentAction = Verb(VERB_LOOK_AT);
+ _cmdText.setVerb(Verb(VERB_LOOK_AT));
+ }
+ }
+ _verb = Verb(VERB_NONE);
+ }
+ else {
+ if (_logic->joeWalk() == 1) {
+ _cmdText.clear();
+ _commandLevel = 1;
+ _logic->joeWalk(0);
+ _currentAction = Verb(VERB_NONE);
+ lookCurrentIcon();
+ }
+
+ if (!_defaultVerb.isNone()) {
+ alterDefault(_defaultVerb, true);
+ _defaultVerb = Verb(VERB_NONE);
+ clear(true);
+ return;
+ }
+
+ if (_cmdText.isEmpty()) {
+ _verb = Verb(VERB_LOOK_AT);
+ _currentAction = Verb(VERB_LOOK_AT);
+ _cmdText.setVerb(Verb(VERB_LOOK_AT));
+ }
+ else {
+ if (_commandLevel == 2 && _parse) {
+ _verb = _currentAction;
+ }
+ else {
+ _verb = findDefault(item, true);
+ }
+ if (!_verb.isNone()) {
+ // No match made, so command not yet completed. Redefine as LOOK AT
+ _verb = Verb(VERB_LOOK_AT);
+ _cmdText.setVerb(Verb(VERB_LOOK_AT));
+ }
+ _currentAction = _verb;
+ }
+ }
+
+ if (_currentAction.isTwoLevelsCommand() && _commandLevel == 1) {
+ _parse = false;
+ }
+ if (!_currentAction.isNone()) {
+ _cmdText.addObject(_logic->objectName(_logic->itemData(item)->name));
+ }
+
+ switch (_commandLevel) {
+ case 1:
+ _subject1 = -item;
+ break;
+ case 2:
+ _subject2 = -item;
+ break;
+ }
+
+ if (_currentAction.value() == VERB_USE && _commandLevel == 1) {
+ if (State::findUse(_logic->itemData(item)->state) == STATE_USE_ON) {
+ _cmdText.addLinkWord(Verb(VERB_PREP_WITH));
+ _commandLevel = 2;
+ }
+ else {
+ _parse = true;
+ }
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ else if (_currentAction.value() == VERB_GIVE && _commandLevel == 1) {
+ _cmdText.addLinkWord(Verb(VERB_PREP_TO));
+ _commandLevel = 2;
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ else {
+ _cmdText.display(INK_CMD_SELECT);
+ }
+
+ if (_parse) {
+ _verb = Verb(VERB_NONE);
+ _logic->joeWalk(2); // set JOEWALK flag to perform EXECUTE_ACTION procedure
+ _selectedAction = _currentAction;
+ _currentAction = Verb(VERB_NONE);
+ }
+}
+
+
+void Command::grabSelectedNoun() {
+
+ // if the NOUN has been selected from screen then it is positive
+ // otherwise it has been selected from inventory and is negative
+ // set PARSE to TRUE, default FALSE if command half complete
+ // click object without a command, if DEFAULT then
+ // do that, otherwise do a WALK!
+
+ uint16 objNum = _logic->currentRoomData() + _noun;
+ int16 objName = _logic->objectData(objNum)->name;
+ if (objName < 0) {
+ // selected a turned off object, so just walk
+ _noun = 0;
+ clear(true);
+ _logic->joeWalk(2);
+ return;
+ }
+
+ if (_verb.isNone()) {
+ if (_mouseKey == Input::MOUSE_LBUTTON) {
+ if ((_commandLevel != 2 && _currentAction.isNone()) ||
+ (_commandLevel == 2 && _parse)) {
+ // action2 > 0 only if command has been constructed
+ // lmb pressed, just walk
+ _verb = Verb(VERB_WALK_TO);
+ _currentAction = Verb(VERB_WALK_TO);
+ _cmdText.setVerb(Verb(VERB_WALK_TO));
+ }
+ }
+ else if (_mouseKey == Input::MOUSE_RBUTTON) {
+
+ // rmb pressed, do default if one exists
+ if (!_defaultVerb.isNone()) {
+ // change default of command
+ alterDefault(_defaultVerb, false);
+ _defaultVerb = Verb(VERB_NONE);
+ clear(true);
+ return;
+ }
+
+ if (_cmdText.isEmpty()) {
+ // Ensures that Right Mkey will select correct default
+ _verb = findDefault(objNum, false);
+ if (!_verb.isNone()) {
+ // no match made, redefine as Walk To
+ _selectedAction = Verb(VERB_WALK_TO);
+ }
+ else {
+ _selectedAction = _verb;
+ }
+ _cmdText.setVerb(_selectedAction);
+ _cmdText.addObject(_logic->objectName(_logic->objectData(objNum)->name));
+ }
+ else {
+ _verb = Verb(VERB_NONE);
+ if ((_commandLevel == 2 && !_parse) || !_currentAction.isNone()) {
+ _verb = _currentAction;
+ }
+ else {
+ _verb = findDefault(objNum, false);
+ }
+
+ if (_verb.value() == VERB_NONE) {
+ _currentAction = Verb(VERB_WALK_TO);
+ _cmdText.setVerb(Verb(VERB_WALK_TO));
+ }
+ else {
+ _currentAction = _verb;
+ }
+ _verb = Verb(VERB_NONE);
+ }
+ }
+ }
+
+ _selectedNoun = 0;
+
+ if (_currentAction.isTwoLevelsCommand() && _commandLevel == 1) {
+ // command not fully constructed
+ _parse = false;
+ }
+ else {
+ _parse = true;
+ }
+
+ if (!_currentAction.isNone()) {
+ _cmdText.addObject(_logic->objectName(objName));
+ }
+
+ switch (_commandLevel) {
+ case 1:
+ _subject1 = objNum;
+ break;
+ case 2:
+ _subject2 = objNum;
+ break;
+ }
+
+ // if first noun and it's a 2 level command then set up action word
+
+ if (_currentAction.value() == VERB_USE && _commandLevel == 1) {
+ if (State::findUse(_logic->objectData(objNum)->state) == STATE_USE_ON) {
+ _cmdText.addLinkWord(Verb(VERB_PREP_WITH));
+ _commandLevel = 2;
+ }
+ else {
+ // object does not support 2nd level
+ _parse = true;
+ }
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ else if (_currentAction.value() == VERB_GIVE && _commandLevel == 1) {
+ _cmdText.addLinkWord(Verb(VERB_PREP_TO));
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ else {
+ _cmdText.display(INK_CMD_SELECT);
+ }
+
+ if (_parse) {
+ _verb = Verb(VERB_NONE);
+ _logic->joeWalk(2); // set JOEWALK flag to perform EXECUTE_ACTION procedure
+ _selectedAction = _currentAction;
+ _currentAction = Verb(VERB_NONE);
+ }
+}
+
+
+void Command::grabSelectedVerb() {
+
+ if (_verb.isScrollInventory()) {
+ // move through inventory (by four if right mouse button)
+ uint16 scroll = _mouseKey == Input::MOUSE_RBUTTON ? 4 : 1;
+ _logic->inventoryScroll(scroll, _verb.value() == VERB_SCROLL_UP);
+
+ }
+ else if (_verb.isPanelCommand() || _verb.value() == VERB_WALK_TO) {
+ _currentAction = _verb;
+ _subject1 = 0;
+ _subject2 = 0;
+
+ // if right mouse key selected, then store command VERB
+ if (_mouseKey == Input::MOUSE_RBUTTON) {
+ _defaultVerb = _verb;
+ _cmdText.displayTemp(11, true, _verb);
+ }
+ else {
+ _defaultVerb = Verb(VERB_NONE);
+ if (_logic->joeWalk() == 1 && !_verb.isNone()) {
+ _logic->joeWalk(0);
+ }
+ _commandLevel = 1;
+ _oldVerb = Verb(VERB_NONE);
+ _oldNoun = 0;
+ _cmdText.setVerb(_verb);
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ }
+}
+
+
+bool Command::executeIfCutaway(const char *description) {
+
+ warning("Command::executeIfCutaway(%s) unimplemented", description);
+
+ if(scumm_stricmp(description + strlen(description) - 4, ".cut") == 0) {
+ /* XXX
+ CUTAWAY(description);
+ strcpy(Kstr,Paramstr);
+ while(Kstr[0]) {
+ CUTAWAY(Kstr);
+ strcpy(Kstr,Paramstr);
+ }*/
+ return true;
+ }
+ return false;
+}
+
+
+bool Command::executeIfDialog(const char *description) {
+
+ warning("Command::executeIfDialog(%s) unimplemented", description);
+
+ if(scumm_stricmp(description + strlen(description) - 4, ".dog") == 0) {
+ /* XXX
+ talk(Kstr);
+ strcpy(Kstr,Paramstr);
+ while(Kstr[0]) {
+ CUTAWAY(Kstr);
+ strcpy(Kstr,Paramstr);
+ }*/
+ return true;
+ }
+ return false;
+}
+
+
+uint16 Command::countAssociatedCommands(const Verb& verb, int16 subj1, int16 subj2) {
+
+ // l.145-150 execute.c
+ uint16 comMax = 0;
+ CmdListData *cmdList = &_cmdList[1];
+ uint16 i;
+ for (i = 1; i <= _numCmdList; ++i, ++cmdList) {
+ if (cmdList->match(verb, subj1, subj2)) {
+ ++comMax;
+ }
+ }
+ return comMax;
+}
+
+
+bool Command::handleBadCommand(bool walk) {
+
+ // l.96-141 execute.c
+ uint16 objMax = _logic->currentRoomObjMax();
+ uint16 roomData = _logic->roomData(_logic->currentRoom());
+
+ // select without a command or WALK TO ; do a WALK
+ if ((_selectedAction.value() == VERB_WALK_TO || _selectedAction.isNone()) &&
+ (_selectedNoun > objMax || _selectedNoun == 0)) {
+ if (_selectedAction.isNone()) {
+ _graphics->textClear(151, 151);
+ }
+ _walk->joeMove(0, _selPosX, _selPosY, false); // XXX inCutaway parameter
+ return true;
+ }
+ // check to see if one of the objects is hidden
+ if (_subject1 > 0 && _logic->objectData(_subject1)->name <= 0) {
+ return true;
+ }
+ if (_selectedAction.value() == VERB_GIVE && _subject2 > 0 && _logic->objectData(_subject2)->name <= 0) {
+ return true;
+ }
+ // check for USE command on exists
+ if (_selectedAction.value() == VERB_USE && _subject1 > 0 && _logic->objectData(_subject1)->entryObj > 0) {
+ _selectedAction = Verb(VERB_WALK_TO);
+ }
+ if (_selectedNoun > 0 && _selectedNoun <= objMax) {
+ int16 p = _logic->joeWalkTo(_selPosX, _selPosY, walk);
+ if (p != 0) {
+ return true;
+ }
+ if (_selectedAction.value() == VERB_WALK_TO && _logic->objectData(roomData + _selectedNoun)->entryObj < 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void Command::executeStandardStuff(const Verb& action, int16 subj1, int16 subj2) {
+
+ // l.158-272 execute.c
+ uint16 k;
+
+ switch (action.value()) {
+
+ case VERB_LOOK_AT:
+ look();
+ break;
+
+ case VERB_OPEN:
+ // 'it doesn't seem to open'
+ _logic->joeSpeak(1);
+ break;
+
+ case VERB_USE:
+ if (subj1 < 0) {
+ k = _logic->itemData(ABS(subj1))->sfxDescription;
+ if (k > 0) {
+ _logic->joeSpeak(k, true);
+ }
+ else {
+ _logic->joeSpeak(2);
+ }
+ }
+ else {
+ _logic->joeSpeak(1);
+ }
+ break;
+
+ case VERB_TALK_TO:
+ _logic->joeSpeak(24 + Logic::randomizer.getRandomNumber(2));
+ break;
+
+ case VERB_CLOSE:
+ _logic->joeSpeak(2);
+ break;
+
+ case 4: // weird, isn't it ? l.193 execute.c
+ case VERB_MOVE:
+ // 'I can't move it'
+ if (subj1 > 0) {
+ int16 img = _logic->objectData(subj1)->image;
+ if (img == -4 || img == -3) {
+ _logic->joeSpeak(18);
+ }
+ else {
+ _logic->joeSpeak(3);
+ }
+ }
+ else {
+ _logic->joeSpeak(3);
+ }
+ break;
+
+ case VERB_GIVE:
+ // 'I can't give the subj1 to subj2'
+ if (subj1 < 0) {
+ k = 11;
+ if (subj2 > 0) {
+ int16 img = _logic->objectData(subj2)->image;
+ if (img == -4 || img == -3) {
+ _logic->joeSpeak(27 + Logic::randomizer.getRandomNumber(2));
+ }
+ }
+ else {
+ _logic->joeSpeak(11);
+ }
+ }
+ else {
+ _logic->joeSpeak(12);
+ }
+ break;
+
+ case VERB_PICK_UP:
+ if (subj1 < 0) {
+ _logic->joeSpeak(14);
+ }
+ else {
+ int16 img = _logic->objectData(subj2)->image;
+ if (img == -4 || img == -3) {
+ // Trying to get a person
+ _logic->joeSpeak(20);
+ }
+ else {
+ switch(Logic::randomizer.getRandomNumber(3)) {
+ case 0:
+ // 'I can't pick that up'
+ _logic->joeSpeak(5);
+ break;
+ case 1:
+ // 'I don't think I need that'
+ _logic->joeSpeak(6);
+ break;
+ case 2:
+ // 'I'd rather leave it here'
+ _logic->joeSpeak(7);
+ break;
+ case 3:
+ // 'I don't think I'd have any use for that'
+ _logic->joeSpeak(8);
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void Command::changeObjectState(const Verb& action, int16 obj, int16 song, bool cutDone) {
+
+ // l.456-533 execute.c
+ ObjectData *objData = _logic->objectData(obj);
+
+ if (action.value() == VERB_OPEN && !cutDone) {
+ if (State::findOn(objData->state) == STATE_ON_ON) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ State::alterDefaultVerb(&objData->state, Verb(VERB_NONE));
+
+ // play music if it exists... (or SFX for open/close door)
+ if (song != 0) {
+ // XXX playsong(abs(song));
+ }
+
+ if (objData->entryObj != 0) {
+ // if it's a door, then update door that it links to
+ openOrCloseAssociatedObject(action, objData->entryObj);
+ objData->entryObj = ABS(objData->entryObj);
+ }
+ }
+ else {
+ // 'it's already open !'
+ _logic->joeSpeak(9);
+ }
+ }
+ else if (action.value() == VERB_CLOSE && !cutDone) {
+
+ if (State::findOn(objData->state) == STATE_ON_OFF) {
+ State::alterOn(&objData->state, STATE_ON_ON);
+ State::alterDefaultVerb(&objData->state, Verb(VERB_OPEN));
+
+ // play music if it exists... (or SFX for open/close door)
+ if (song != 0) {
+ // XXX playsong(abs(song));
+ }
+
+ if (objData->entryObj != 0) {
+ // if it's a door, then update door that it links to
+ openOrCloseAssociatedObject(action, objData->entryObj);
+ objData->entryObj = -ABS(objData->entryObj);
+ }
+ }
+ else {
+ // 'it's already closed !'
+ _logic->joeSpeak(10);
+ }
+ }
+ else if (action.value() == VERB_MOVE) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ }
+}
+
+
+void Command::cleanupCurrentAction() {
+
+ // l.595-597 execute.c
+ _logic->joeFace();
+ _oldNoun = 0;
+ _oldVerb = Verb(VERB_NONE);
+}
+
+
+Verb Command::findDefault(uint16 obj, bool itemType) {
+
+ uint16 s = itemType ? _logic->itemData(obj)->state : _logic->objectData(obj)->state;
+ return State::findDefaultVerb(s);
+}
+
+
+void Command::alterDefault(const Verb& def, bool itemType) {
+
+ uint16 *newDefaultState = 0;
+ const char *name = NULL;
+
+ _noun = _logic->findObjectUnderCursor(_selPosX, _selPosY);
+ if (!itemType) {
+ if (_noun == 0) {
+ return;
+ }
+ uint16 i = _logic->findObjectGlobalNumber(_noun);
+ ObjectData *od = _logic->objectData(i);
+ if (od->name < 0) {
+ return;
+ }
+ newDefaultState = &od->state;
+ name = _logic->objectTextualDescription(od->name);
+ }
+ else {
+ uint16 item = _logic->findInventoryItem(_verb.inventoryItem());
+ if (item == 0 || _logic->itemData(item)->name == 0) {
+ return;
+ }
+ ItemData *id = _logic->itemData(item);
+ newDefaultState = &id->state;
+ name = _logic->objectTextualDescription(id->name);
+ }
+
+ State::alterDefaultVerb(newDefaultState, def);
+ if (_noun == 0) {
+ _cmdText.clear();
+ }
+ else {
+ _cmdText.setVerb(def.isNone() ? Verb(VERB_WALK_TO) : def);
+ }
+ _cmdText.displayTemp(INK_CMD_NORMAL, name);
+ _oldNoun = _noun;
+}
+
+
+
+
+void Command::openOrCloseAssociatedObject(const 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;
+ // FIXME: weird loop...
+ uint16 j;
+ for (j = 1; j <= _numCmdGameState; ++j) {
+ if (cmdGs[j].id == i && cmdGs[i].gameStateSlot > 0) {
+ if (_logic->gameState(cmdGs[i].gameStateSlot) == cmdGs[i].gameStateValue) {
+ com = i;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ com = i;
+ break;
+ }
+ }
+ }
+
+ if (com != 0) {
+
+ cmdList = &_cmdList[com];
+ ObjectData *objData = _logic->objectData(otherObj);
+
+ if (cmdList->imageOrder != 0) {
+ // update the graphic image of object
+ objData->image = cmdList->imageOrder;
+ }
+
+ if (action.value() == VERB_OPEN) {
+ if (State::findOn(objData->state) == STATE_ON_ON) {
+ State::alterOn(&objData->state, STATE_ON_OFF);
+ State::alterDefaultVerb(&objData->state, Verb(VERB_NONE));
+ objData->entryObj = ABS(objData->entryObj);
+ }
+ }
+ else if (action.value() == VERB_CLOSE) {
+ if (State::findOn(objData->state) == STATE_ON_OFF) {
+ State::alterOn(&objData->state, STATE_ON_ON);
+ State::alterDefaultVerb(&objData->state, Verb(VERB_OPEN));
+ objData->entryObj = -ABS(objData->entryObj);
+ }
+ }
+ }
+}
+
+int16 Command::setConditions(uint16 command, bool lastCmd) {
+
+ debug(9, "Command::setConditions(%d, %d)", command, lastCmd);
+ // Test conditions, if FAIL write && exit, Return -1
+ // if(Joe speaks before he returns, -2 is returned
+ // This way a -1 return will allow Joe to speak normal description
+
+ uint16 temp[21];
+ memset(temp, 0, sizeof(temp));
+ uint16 tempInd = 0;
+
+ int16 ret = 0;
+ uint16 i;
+ CmdGameState *cmdGs = &_cmdGameState[1];
+ for (i = 1; i <= _numCmdGameState; ++i, ++cmdGs) {
+ if (cmdGs->id == command) {
+ if (cmdGs->gameStateSlot > 0) {
+ if (_logic->gameState(cmdGs->gameStateSlot) != cmdGs->gameStateValue) {
+ // failed test
+ ret = i;
+ break;
+ }
+ }
+ else {
+ temp[tempInd] = i;
+ ++tempInd;
+ }
+ }
+ }
+
+ if (ret > 0) {
+ // we've failed, so see if we need to make Joe speak
+ cmdGs = &_cmdGameState[ret];
+ if (cmdGs->gameStateValue > 0 && lastCmd) {
+ // check to see if fail state is in fact a cutaway
+ const char *objDesc = _logic->objectTextualDescription(cmdGs->speakValue);
+ if (!executeIfCutaway(objDesc) && !executeIfDialog(objDesc)) {
+ _logic->joeSpeak(cmdGs->speakValue, true);
+ }
+ ret = -2;
+ }
+ else {
+ ret = -1;
+ }
+ }
+ else {
+ ret = 0;
+ // all tests were okay, now set gamestates
+ for (i = 0; i < tempInd; ++i) {
+ cmdGs = &_cmdGameState[temp[i]];
+ _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];
+ uint16 i;
+ for (i = 1; i <= _numCmdArea; ++i, ++cmdArea) {
+ if (cmdArea->id == command) {
+ uint16 areaNum = ABS(cmdArea->area);
+ Area *area = _logic->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];
+ uint16 i;
+ for (i = 1; i <= _numCmdObject; ++i, ++cmdObj) {
+ if (cmdObj->id == command) {
+
+ // found an object
+ uint16 dstObj = ABS(cmdObj->dstObj);
+ ObjectData *objData = _logic->objectData(dstObj);
+
+ 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 == _logic->currentRoom()) {
+ if (dstObj != _subject1) {
+ // 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 - _logic->currentRoomData();
+ _logic->zoneSet(ZONE_ROOM, objZone, 0, 0, 1, 1);
+ }
+ }
+
+ if (cmdObj->srcObj > 0) {
+ // copy data from dummy object to object
+ int16 image1 = objData->image;
+ int16 image2 = _logic->objectData(cmdObj->srcObj)->image;
+ _logic->objectCopy(cmdObj->srcObj, dstObj);
+ if (image1 != 0 && image2 == 0 && objData->room == _logic->currentRoom()) {
+ uint16 bobNum = _logic->findBob(dstObj);
+ if (bobNum != 0) {
+ _graphics->bobClear(bobNum);
+ }
+ }
+ }
+
+ if (dstObj != _subject1) {
+ // if the new object we have updated is on screen and
+ // is not current object then update it
+ _logic->roomRefreshObject(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
+ _logic->roomRefreshObject(dstObj);
+ }
+ }
+ }
+ }
+}
+
+
+void Command::setItems(uint16 command) {
+
+ debug(9, "Command::setItems(%d)", command);
+
+ CmdInventory *cmdInv = &_cmdInventory[1];
+ ItemData *items = _logic->itemData(0);
+ uint16 i;
+ for (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
+ items[dstItem] = items[cmdInv->srcItem];
+ // enable it
+ items[dstItem].name = ABS(items[dstItem].name);
+ }
+ _logic->inventoryInsertItem(cmdInv->dstItem);
+ }
+ else {
+ // delete item
+ if (items[dstItem].name > 0) {
+ _logic->inventoryDeleteItem(dstItem);
+ }
+ if (cmdInv->srcItem > 0) {
+ // copy data from source item to item
+ items[dstItem] = items[cmdInv->srcItem];
+ // disable it
+ 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(0, "Command::updateNextDescription() - 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;
+ }
+ else {
+ // already displayed first, do a random
+ i = objDesc->lastSeenNumber;
+ while (i == objDesc->lastSeenNumber) {
+ i = firstDesc + Logic::randomizer.getRandomNumber(diff);
+ }
+ objDesc->lastSeenNumber = i;
+ }
+ break;
+ case 1:
+ i = objDesc->lastSeenNumber;
+ while (i == objDesc->lastSeenNumber) {
+ i = firstDesc + Logic::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::look() {
+
+ if (_selectedNoun > 0 && _selectedNoun <= _logic->currentRoomObjMax()) {
+ uint16 k = _logic->currentRoomData();
+ if (_logic->objectData(k + _selectedNoun)->entryObj == 0) {
+ if (_logic->joeWalkTo(_selPosX, _selPosY, true) == -2) {
+ // 'I can't get close enough to have a look.'
+ _logic->joeSpeak(13);
+ }
+ }
+ }
+
+ // if object type and disabled, don't look
+ if (_subject1 > 0 && _logic->objectData(_subject1)->name <= 0) {
+ return;
+ }
+
+ uint16 desc;
+ if (_subject1 < 0) {
+ desc = _logic->itemData(ABS(_subject1))->description;
+ }
+ else {
+ desc = _logic->objectData(_subject1)->description;
+ }
+
+ debug(0, "Command::look() - desc = %X, _subject1 = %X", desc, _subject1);
+
+ // check to see if the object/item has a series of description
+ ObjectDescription *objDesc = _logic->objectDescription(1);
+ uint16 i;
+ for (i = 1; i <= _logic->objectDescriptionCount(); ++i, ++objDesc) {
+ if (objDesc->object == _subject1) {
+ desc = nextObjectDescription(objDesc, desc);
+ break;
+ }
+ }
+
+ _logic->joeSpeak(desc, true);
+ _logic->joeFace();
+}
+
+
+void Command::lookCurrentItem() {
+
+ if (_verb.isInventory()) {
+ uint16 item = _logic->findInventoryItem(_verb.inventoryItem());
+ if (item != 0) {
+ ItemData *itemData = _logic->itemData(item);
+ const char *name = _logic->objectName(itemData->name);
+ if (_currentAction.isNone()) {
+ Verb v = State::findDefaultVerb(itemData->state);
+ _cmdText.setVerb(v.isNone() ? Verb(VERB_LOOK_AT) : v);
+ }
+
+ if (!_defaultVerb.isNone()) {
+ _cmdText.displayTemp(INK_CMD_LOCK, true, _defaultVerb, name);
+ }
+ else {
+ _cmdText.displayTemp(INK_CMD_NORMAL, name);
+ }
+ _oldVerb = _verb;
+ }
+ }
+}
+
+
+
+void Command::lookCurrentRoom() {
+
+ _noun = _logic->findObjectUnderCursor(_input->mousePosX(), _input->mousePosY());
+
+ if (_logic->joeWalk() == 1) {
+ return;
+ }
+
+ int16 aObjName = 0;
+ uint16 k = _logic->currentRoomData();
+ int16 i = 0;
+ if (_noun > _logic->currentRoomObjMax()) {
+ uint16 obj = _logic->currentRoomArea(_noun - _logic->currentRoomObjMax())->object;
+ aObjName = _logic->objectData(obj)->name;
+ if (aObjName > 0) {
+ i = aObjName;
+ _noun = obj - k;
+ }
+ }
+ else {
+ i = _logic->objectData(k + _noun)->name;
+ }
+
+ if (_oldNoun == _noun) {
+ return;
+ }
+
+ // if pointing at an Area then exit
+ // if the AREA is linked to an object, then dont exit. Find
+ // the object its linked to && store in AOBJ
+
+ if (_noun > _logic->currentRoomObjMax() && aObjName <= 0) {
+ if (_oldNoun != 0) {
+ if (!_defaultVerb.isNone()) {
+ _cmdText.displayTemp(INK_CMD_LOCK, true, _defaultVerb);
+ }
+ else if (!_currentAction.isNone()) {
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ _oldNoun = 0;
+ return;
+ }
+ }
+
+// cyx: useless as (_oldNoun==_noun) already tested
+// if (i <= 0 && _oldNoun == _noun) { return; }
+
+ if (i <= 0) {
+ _oldNoun = _noun;
+ _graphics->textClear(151, 151);
+ if (!_defaultVerb.isNone()) {
+ _cmdText.displayTemp(INK_CMD_LOCK, true, _defaultVerb);
+ }
+ else if (!_currentAction.isNone()) {
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ return;
+ }
+
+ // if no command yet selected, then use DEFAULT command, if any
+ if (_currentAction.isNone()) {
+ Verb v = State::findDefaultVerb(_logic->objectData(k + _noun)->state);
+ _cmdText.setVerb(v.isNone() ? Verb(VERB_WALK_TO) : v);
+ if (_noun == 0) {
+ _cmdText.clear();
+ }
+ }
+ const char *objName = "";
+ if (_noun > 0) {
+ objName = _logic->objectName(i);
+ }
+ if (!_defaultVerb.isNone()) {
+ _cmdText.displayTemp(INK_CMD_LOCK, true, _defaultVerb, objName);
+ }
+ else {
+ _cmdText.displayTemp(INK_CMD_NORMAL, objName);
+ }
+ _oldNoun = _noun;
+}
+
+
+void Command::lookCurrentIcon() {
+
+ _verb = _logic->findVerbUnderCursor(_input->mousePosX(), _input->mousePosY());
+ if (_verb != _oldVerb && _logic->joeWalk() != 1) {
+
+ if (_currentAction.isNone()) {
+ _cmdText.clear();
+ }
+ _graphics->textClear(151, 151);
+ lookCurrentItem();
+
+ // ensure that registers when move to top screen
+ if (_noun > 0) {
+ _oldNoun = -1;
+ }
+
+ _oldVerb = _verb;
+ if (_verb.isPanelCommand() || _verb.value() == VERB_WALK_TO) {
+ if (_verb.isNone()) {
+ _cmdText.display(INK_CMD_NORMAL);
+ }
+ else {
+ _cmdText.displayTemp(INK_CMD_NORMAL, false, _verb);
+ }
+ }
+ }
+}
+
+
+}
+
+
+
diff --git a/queen/command.h b/queen/command.h
new file mode 100644
index 0000000000..9e43cb80e6
--- /dev/null
+++ b/queen/command.h
@@ -0,0 +1,180 @@
+ /* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef QUEENCOMMAND_H
+#define QUEENCOMMAND_H
+
+#include "queen/queen.h"
+#include "queen/defs.h"
+#include "queen/verb.h"
+
+namespace Queen {
+
+class Logic;
+class Graphics;
+class Input;
+class Walk;
+
+
+struct CmdText {
+
+ void clear();
+ void display(uint8 color);
+ void displayTemp(uint8 color, bool locked, const Verb& v, const char *name = NULL);
+ void displayTemp(uint8 color, const char *name);
+ void setVerb(const Verb& v);
+ void addLinkWord(const Verb& v);
+ void addObject(const char *objName);
+ bool isEmpty() const;
+
+ enum {
+ MAX_COMMAND_LEN = 256,
+ COMMAND_Y_POS = 151
+ };
+
+ char _command[MAX_COMMAND_LEN];
+ const char* lockedVerbPrefix;
+ Graphics* _graphics;
+};
+
+
+class Command {
+public:
+
+ Command(Logic*, Graphics*, Input*, Walk*);
+
+ void clear(bool clearTexts);
+
+ void executeCurrentAction(bool walk);
+
+ void updatePlayer();
+
+ void readCommandsFrom(byte *&ptr);
+
+ Verb selectedAction() const { return _selectedAction; }
+ int16 selectedNoun() const { return _selectedNoun; }
+ bool parse() const { return _parse; }
+
+private:
+
+ void grabCurrentSelection();
+ void grabSelectedItem();
+ void grabSelectedNoun();
+ void grabSelectedVerb();
+
+ bool executeIfCutaway(const char* description);
+ bool executeIfDialog(const char* description);
+
+ uint16 countAssociatedCommands(const Verb& verb, int16 subj1, int16 subj2);
+ bool handleBadCommand(bool walk);
+ void executeStandardStuff(const Verb& action, int16 subj1, int16 subj2);
+ void changeObjectState(const Verb& action, int16 obj, int16 song, bool cutDone);
+ void cleanupCurrentAction();
+
+ Verb findDefault(uint16 obj, bool itemType);
+ void alterDefault(const Verb& def, bool itemType);
+
+ //! Opens/closes the object associated with object - OPEN_CLOSE_OTHER(OBJECT_DATA[S][4])
+ void openOrCloseAssociatedObject(const 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);
+
+ uint16 nextObjectDescription(ObjectDescription* objDesc, uint16 firstDesc);
+
+ //! Look at Objects/Items and speak their description
+ void look();
+ void lookCurrentItem();
+ void lookCurrentRoom();
+ void lookCurrentIcon();
+
+
+ CmdListData *_cmdList;
+ uint16 _numCmdList;
+
+ CmdArea *_cmdArea;
+ uint16 _numCmdArea;
+
+ CmdObject *_cmdObject;
+ uint16 _numCmdObject;
+
+ CmdInventory *_cmdInventory;
+ uint16 _numCmdInventory;
+
+ CmdGameState *_cmdGameState;
+ uint16 _numCmdGameState;
+
+ //! Textual form of the command (displayed between room and panel areas)
+ CmdText _cmdText;
+
+ //! Locked verb (using 2nd mouse button)
+ Verb _defaultVerb;
+
+ //! OLDVERB, VERB
+ Verb _oldVerb, _verb;
+
+ //! OLDNOUN, NOUN
+ int16 _oldNoun, _noun;
+
+ //! If true, command string is executed
+ bool _parse;
+
+ //! Current level of the command (max=2 for GIVE and USE verbs)
+ int _commandLevel;
+
+ //! Object selected for action
+ int16 _selectedNoun;
+
+ //! Last selected action
+ Verb _currentAction;
+
+ //! Action to perform
+ Verb _selectedAction;
+
+ //! SUBJECT[3]
+ int16 _subject1, _subject2;
+
+ //! MKEY
+ int _mouseKey;
+
+ //! Position of last selection
+ int _selPosX, _selPosY;
+
+ Logic *_logic;
+ Graphics *_graphics;
+ Input *_input;
+ Walk *_walk;
+
+};
+
+} // End of namespace Queen
+
+#endif
+
diff --git a/queen/module.mk b/queen/module.mk
index 0836a5fe05..be9b6d7999 100644
--- a/queen/module.mk
+++ b/queen/module.mk
@@ -1,6 +1,7 @@
MODULE := queen
MODULE_OBJS = \
+ queen/command.o \
queen/cutaway.o \
queen/display.o \
queen/graphics.o \