From 23188d5188c658557d34c4a38666981dd96a8ecb Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Fri, 31 Oct 2003 13:46:45 +0000 Subject: initial version of Command class svn-id: r11016 --- queen/command.cpp | 1596 +++++++++++++++++++++++++++++++++++++++++++++++++++++ queen/command.h | 180 ++++++ queen/module.mk | 1 + 3 files changed, 1777 insertions(+) create mode 100644 queen/command.cpp create mode 100644 queen/command.h (limited to 'queen') 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 \ -- cgit v1.2.3