scummvm/queen/command.cpp

1563 lines
40 KiB
C++
Raw Normal View History

/* 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"
2003-12-11 22:16:35 +00:00
#include "queen/display.h"
#include "queen/input.h"
#include "queen/graphics.h"
#include "queen/logic.h"
2003-12-11 22:16:35 +00:00
#include "queen/queen.h"
#include "queen/sound.h"
#include "queen/state.h"
#include "queen/talk.h"
#include "queen/walk.h"
namespace Queen {
void CmdText::clear() {
memset(_command, 0, sizeof(_command));
}
void CmdText::display(uint8 color) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->textCurrentColor(color);
_vm->graphics()->textSetCentered(COMMAND_Y_POS, _command, false);
}
2003-12-12 10:33:34 +00:00
void CmdText::displayTemp(uint8 color, bool locked, Verb v, const char *name) {
char temp[MAX_COMMAND_LEN];
if (locked) {
2003-12-12 10:33:34 +00:00
sprintf(temp, "%s%s", _vm->logic()->joeResponse(39), _vm->logic()->verbName(v));
}
else {
2003-12-12 10:33:34 +00:00
strcpy(temp, _vm->logic()->verbName(v));
}
if (name != NULL) {
strcat(temp, " ");
strcat(temp, name);
}
2003-12-11 22:16:35 +00:00
_vm->graphics()->textCurrentColor(color);
_vm->graphics()->textSetCentered(COMMAND_Y_POS, temp, false);
}
void CmdText::displayTemp(uint8 color, const char *name) {
char temp[MAX_COMMAND_LEN];
sprintf(temp, "%s %s", _command, name);
2003-12-11 22:16:35 +00:00
_vm->graphics()->textCurrentColor(color);
_vm->graphics()->textSetCentered(COMMAND_Y_POS, temp, false);
}
2003-12-12 10:33:34 +00:00
void CmdText::setVerb(Verb v) {
2003-12-12 10:33:34 +00:00
strcpy(_command, _vm->logic()->verbName(v));
}
2003-12-12 10:33:34 +00:00
void CmdText::addLinkWord(Verb v) {
strcat(_command, " ");
2003-12-12 10:33:34 +00:00
strcat(_command, _vm->logic()->verbName(v));
}
void CmdText::addObject(const char *objName) {
strcat(_command, " ");
strcat(_command, objName);
}
bool CmdText::isEmpty() const {
return _command[0] == 0;
}
2003-11-03 19:52:14 +00:00
void CurrentCmdState::init() {
commandLevel = 1;
2003-12-12 10:33:34 +00:00
oldVerb = verb = action = VERB_NONE;
2003-11-03 19:52:14 +00:00
oldNoun = noun = subject1 = subject2 = 0;
}
void CurrentCmdState::addObject(int16 objNum) {
switch (commandLevel) {
case 1:
subject1 = objNum;
break;
case 2:
subject2 = objNum;
break;
}
}
void SelectedCmdState::init() {
2003-12-12 10:33:34 +00:00
action = defaultVerb = VERB_NONE;
2003-11-03 19:52:14 +00:00
noun = 0;
}
2003-12-11 22:16:35 +00:00
Command::Command(QueenEngine *vm)
: _vm(vm) {
_cmdText._vm = vm;
}
void Command::clear(bool clearTexts) {
_cmdText.clear();
if (clearTexts) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
}
_parse = false;
2003-11-03 19:52:14 +00:00
_curCmd.init();
_selCmd.init();
}
// FIXME: walk argument is useless (always true), as we don't handle the
// pinnacle room exactly like the original
void Command::executeCurrentAction(bool walk) {
2003-12-11 22:16:35 +00:00
_vm->logic()->entryObj(0);
if (_curCmd.commandLevel == 2 && _mouseKey == Input::MOUSE_RBUTTON) {
_mouseKey = Input::MOUSE_LBUTTON;
}
// XXX SUBJ1=SUBJECT[1]; SUBJ2=SUBJECT[2];
2003-11-03 19:52:14 +00:00
if (_mouseKey == Input::MOUSE_RBUTTON && _curCmd.subject1 != 0) {
// check to see if selecting default command for object/item
2003-11-03 19:52:14 +00:00
if (_curCmd.subject1 > 0) {
2003-12-11 22:16:35 +00:00
int16 i = _vm->logic()->findObjectGlobalNumber(_curCmd.noun);
if (_curCmd.noun == 0 ||
2003-12-11 22:16:35 +00:00
_curCmd.noun > _vm->logic()->currentRoomObjMax() ||
_vm->logic()->objectData(i)->name <= 0) {
cleanupCurrentAction();
return;
}
2003-12-11 22:16:35 +00:00
uint16 obj = _vm->logic()->currentRoomData() + _curCmd.noun;
_curCmd.verb = findDefault(obj, false);
2003-12-12 10:33:34 +00:00
if (_curCmd.verb == VERB_NONE) {
// no match made, so command not yet completed, redefine as WALK_TO
2003-12-12 10:33:34 +00:00
_cmdText.setVerb(VERB_WALK_TO);
_selCmd.action = VERB_WALK_TO;
}
else {
_cmdText.setVerb(_curCmd.verb);
_selCmd.action = _curCmd.verb;
}
2003-12-11 22:16:35 +00:00
_cmdText.addObject(_vm->logic()->objectName(_vm->logic()->objectData(obj)->name));
}
}
// make sure that command is always highlighted when actioned!
_cmdText.display(INK_CMD_SELECT);
_selCmd.noun = _curCmd.noun;
_curCmd.commandLevel = 1;
// XXX SUBJECT[2]=0;
if (handleDefaultCommand(walk)) {
cleanupCurrentAction();
return;
}
// get the commands associated with 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(_selCmd.action, _curCmd.subject1, _curCmd.subject2)) {
matchingCmds[comMax] = i;
++comMax;
}
}
if (comMax == 0) {
// no command match was found, so exit
2003-11-03 19:52:14 +00:00
// pass ACTION2 as parameter, as a new Command (and a new ACTION2)
// can be constructed while Joe speaks
2003-11-03 19:52:14 +00:00
executeStandardStuff(_selCmd.action, _curCmd.subject1, _curCmd.subject2);
cleanupCurrentAction();
return;
}
2003-11-08 23:45:45 +00:00
// process each associated command for the Object, until all done
// or one of the Gamestate tests fails...
int16 cond = 0;
2003-11-03 20:48:27 +00:00
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;
}
}
2003-12-12 10:33:34 +00:00
if (cond <= 0 && _selCmd.action == VERB_LOOK_AT) {
look();
}
else {
// only play song if it's a PLAY AFTER type
if (com->song < 0) {
2003-12-11 22:16:35 +00:00
_vm->sound()->playSong(-com->song);
}
clear(true);
2003-11-08 23:45:45 +00:00
}
cleanupCurrentAction();
}
void Command::updatePlayer() {
2003-12-11 22:16:35 +00:00
if (_vm->input()->cutawayRunning()) return;
lookCurrentRoom();
lookCurrentIcon();
2003-12-12 10:33:34 +00:00
if (_vm->input()->keyVerb() != VERB_NONE) {
2003-12-12 10:33:34 +00:00
if (_vm->input()->keyVerb() == VERB_USE_JOURNAL) {
2003-12-11 22:16:35 +00:00
_vm->input()->clearKeyVerb();
_vm->logic()->useJournal();
}
2003-12-12 10:33:34 +00:00
else if (_vm->input()->keyVerb() != VERB_SKIP_TEXT) {
2003-12-11 22:16:35 +00:00
_curCmd.verb = _vm->input()->keyVerb();
2003-12-12 10:33:34 +00:00
if (isVerbInv(_curCmd.verb)) {
_curCmd.noun = _selCmd.noun = 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.
_curCmd.oldNoun = 0;
2003-12-12 10:33:34 +00:00
_curCmd.oldVerb = VERB_NONE;
grabSelectedItem();
}
else {
grabSelectedVerb();
}
2003-12-11 22:16:35 +00:00
_vm->input()->clearKeyVerb();
}
}
2003-12-11 22:16:35 +00:00
_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];
memset(&_cmdList[0], 0, sizeof(CmdListData));
for (i = 1; i <= _numCmdList; i++) {
_cmdList[i].readFrom(ptr);
}
_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);
}
2003-11-08 23:45:45 +00:00
_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);
}
_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);
}
2003-11-08 23:45:45 +00:00
_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);
}
}
int16 Command::executeCommand(uint16 comId, int16 condResult) {
// execute.c l.313-452
debug(0, "Command::executeCommand() - cond = %X, com = %X", condResult, comId);
CmdListData *com = &_cmdList[comId];
if (com->setAreas) {
setAreas(comId);
}
// Don't grab if action is TALK or WALK
2003-12-12 10:33:34 +00:00
if (_selCmd.action != VERB_TALK_TO && _selCmd.action != VERB_WALK_TO) {
if (_curCmd.subject1 > 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeGrab(State::findGrab(_vm->logic()->objectData(_curCmd.subject1)->state));
}
if (_curCmd.subject2 > 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeGrab(State::findGrab(_vm->logic()->objectData(_curCmd.subject2)->state));
}
}
bool cutDone = false;
if (condResult > 0) {
// as we don't handle the pinnacle room exactly like the original,
// the hack described on l.334-339 in execute.c became useless
// check for cutaway/dialogs before updating Objects
2003-12-11 22:16:35 +00:00
const char *desc = _vm->logic()->objectTextualDescription(condResult);
if (executeIfCutaway(desc)) {
condResult = 0;
cutDone = true;
}
else if (executeIfDialog(desc)) {
condResult = 0;
}
}
int16 oldImage = 0;
if (_curCmd.subject1 > 0) {
// an object (not an item)
2003-12-11 22:16:35 +00:00
oldImage = _vm->logic()->objectData(_curCmd.subject1)->image;
}
if (com->setObjects) {
setObjects(comId);
}
if (com->setItems) {
setItems(comId);
}
if (com->imageOrder != 0) {
2003-12-11 22:16:35 +00:00
ObjectData *od = _vm->logic()->objectData(_curCmd.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;
}
2003-12-11 22:16:35 +00:00
_vm->logic()->roomRefreshObject(_curCmd.subject1);
}
else {
// this object is not being updated by command list, see if
// it has another image copied to it
if (_curCmd.subject1 > 0) {
// an object (not an item)
2003-12-11 22:16:35 +00:00
if (_vm->logic()->objectData(_curCmd.subject1)->image != oldImage) {
_vm->logic()->roomRefreshObject(_curCmd.subject1);
}
}
}
// don't play music on an OPEN/CLOSE command - in case the command fails
2003-12-12 10:33:34 +00:00
if (_selCmd.action != VERB_OPEN && _selCmd.action != VERB_CLOSE) {
// only play song if it's a PLAY BEFORE type
if (com->song > 0) {
2003-12-11 22:16:35 +00:00
_vm->sound()->playSong(com->song);
}
}
// do a special hardcoded section
// l.419-452 execute.c
switch (com->specialSection) {
case 1:
2003-12-11 22:16:35 +00:00
_vm->logic()->useJournal();
return condResult;
case 2:
2003-12-11 22:16:35 +00:00
_vm->logic()->joeUseDress(true);
break;
case 3:
2003-12-11 22:16:35 +00:00
_vm->logic()->joeUseClothes(true);
break;
case 4:
2003-12-11 22:16:35 +00:00
_vm->logic()->joeUseUnderwear();
break;
}
changeObjectState(_selCmd.action, _curCmd.subject1, com->song, cutDone);
// execute.c l.533-548
// FIXME: useless test, as .dog has already been played
2003-12-12 10:33:34 +00:00
// if (_selCmd.action == VERB_TALK_TO && cond > 0) {
2003-12-11 22:16:35 +00:00
// if (executeIfDialog(_vm->logic()->objectTextualDescription(cond))) {
// cleanupCurrentAction();
// return;
// }
// }
// execute.c l.550-589
// FIXME: the EXECUTE_EXIT1 stuff can be omitted as it is
// more or less redundant code
if (condResult > 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(condResult, true);
}
return condResult;
}
2003-12-12 10:33:34 +00:00
int16 Command::makeJoeWalkTo(int16 x, int16 y, int16 objNum, Verb v, bool mustWalk) {
2003-11-03 19:52:14 +00:00
// Check to see if object is actually an exit to another
// room. If so, then set up new room
2003-12-11 22:16:35 +00:00
ObjectData *objData = _vm->logic()->objectData(objNum);
2003-11-03 19:52:14 +00:00
if (objData->x != 0 || objData->y != 0) {
x = objData->x;
y = objData->y;
}
2003-12-12 10:33:34 +00:00
if (v == VERB_WALK_TO) {
2003-12-11 22:16:35 +00:00
_vm->logic()->entryObj(objData->entryObj);
if (_vm->logic()->entryObj() != 0) {
_vm->logic()->newRoom(_vm->logic()->objectData(_vm->logic()->entryObj())->room);
2003-11-03 19:52:14 +00:00
// because this is an exit object, see if there is
// a walk off point and set (x,y) accordingly
2003-12-11 22:16:35 +00:00
WalkOffData *wod = _vm->logic()->walkOffPointForObject(objNum);
2003-11-03 19:52:14 +00:00
if (wod != NULL) {
x = wod->x;
y = wod->y;
}
}
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->entryObj(0);
_vm->logic()->newRoom(0);
2003-11-03 19:52:14 +00:00
}
2003-12-11 22:16:35 +00:00
debug(0, "Command::makeJoeWalkTo() - x=%d y=%d newRoom=%d", x, y, _vm->logic()->newRoom());
2003-11-03 19:52:14 +00:00
int16 p = 0;
if (mustWalk) {
// determine which way for Joe to face Object
uint16 facing = State::findDirection(objData->state);
2003-12-11 22:16:35 +00:00
BobSlot *bobJoe = _vm->graphics()->bob(0);
2003-11-03 19:52:14 +00:00
if (x == bobJoe->x && y == bobJoe->y) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeFacing(facing);
_vm->logic()->joeFace();
2003-11-03 19:52:14 +00:00
}
else {
2003-12-11 22:16:35 +00:00
p = _vm->walk()->moveJoe(facing, x, y, false); // XXX inCutaway parameter
if (p != 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->newRoom(0); // cancel makeJoeWalkTo, that should be equivalent to cr10 fix
// XXX if(P != 0) P = FIND_VERB
}
2003-11-03 19:52:14 +00:00
}
}
return p;
}
void Command::grabCurrentSelection() {
2003-12-11 22:16:35 +00:00
_selPosX = _vm->input()->mousePosX();
_selPosY = _vm->input()->mousePosY();
2003-12-11 22:16:35 +00:00
uint16 zone = _vm->logic()->findObjectUnderCursor(_selPosX, _selPosY);
_curCmd.noun = _vm->logic()->findObjectRoomNumber(zone);
_curCmd.verb = _vm->logic()->findVerbUnderCursor(_selPosX, _selPosY);
2003-12-11 22:16:35 +00:00
_selPosX += _vm->display()->horizontalScroll();
2003-12-12 10:33:34 +00:00
if (isVerbPanel(_curCmd.verb) || _curCmd.verb == VERB_WALK_TO || isVerbScrollInv(_curCmd.verb)) {
grabSelectedVerb();
}
2003-12-12 10:33:34 +00:00
else if (isVerbInv(_curCmd.verb)) {
grabSelectedItem();
}
2003-12-11 22:16:35 +00:00
else if (_curCmd.noun > 0 && _curCmd.noun <= _vm->logic()->currentRoomObjMax()) {
grabSelectedNoun();
}
2003-12-12 10:33:34 +00:00
else if (_selPosY < ROOM_ZONE_HEIGHT && _curCmd.verb == VERB_NONE) {
// select without a command, do a WALK
clear(true);
2003-12-11 22:16:35 +00:00
_vm->logic()->joeWalk(JWM_EXECUTE);
}
}
2003-11-03 19:52:14 +00:00
void Command::grabSelectedObject(int16 objNum, uint16 objState, uint16 objName) {
2003-12-12 10:33:34 +00:00
if (_curCmd.action != VERB_NONE) {
2003-12-11 22:16:35 +00:00
_cmdText.addObject(_vm->logic()->objectName(objName));
2003-11-03 19:52:14 +00:00
}
_curCmd.addObject(objNum);
2003-11-08 23:45:45 +00:00
// if first noun and it's a 2 level command then set up action word
2003-12-12 10:33:34 +00:00
if (_curCmd.action == VERB_USE && _curCmd.commandLevel == 1) {
2003-11-03 19:52:14 +00:00
if (State::findUse(objState) == STATE_USE_ON) {
// object supports 2 levels
_curCmd.commandLevel = 2;
2003-12-12 10:33:34 +00:00
_cmdText.addLinkWord(VERB_PREP_WITH);
2003-11-03 19:52:14 +00:00
// command not fully constructed
_cmdText.display(INK_CMD_NORMAL);
_parse = false;
}
else {
_cmdText.display(INK_CMD_SELECT);
_parse = true;
}
}
2003-12-12 10:33:34 +00:00
else if (_curCmd.action == VERB_GIVE && _curCmd.commandLevel == 1) {
2003-11-03 19:52:14 +00:00
_curCmd.commandLevel = 2;
2003-12-12 10:33:34 +00:00
_cmdText.addLinkWord(VERB_PREP_TO);
2003-11-03 19:52:14 +00:00
// command not fully constructed
_cmdText.display(INK_CMD_NORMAL);
_parse = false;
}
else {
_cmdText.display(INK_CMD_SELECT);
_parse = true;
}
if (_parse) {
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_NONE;
2003-12-11 22:16:35 +00:00
//_vm->logic()->newRoom(0);
_vm->logic()->joeWalk(JWM_EXECUTE);
2003-11-03 19:52:14 +00:00
_selCmd.action = _curCmd.action;
2003-12-12 10:33:34 +00:00
_curCmd.action = VERB_NONE;
2003-11-03 19:52:14 +00:00
}
}
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;
2003-12-12 10:33:34 +00:00
uint16 item = _vm->logic()->findInventoryItem(_curCmd.verb - VERB_INV_FIRST);
2003-12-11 22:16:35 +00:00
if (item == 0 || _vm->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 ||
2003-12-12 10:33:34 +00:00
(_vm->input()->keyVerb() != VERB_NONE && _curCmd.verb != VERB_NONE)) {
if (_curCmd.action == VERB_NONE) {
if (_vm->input()->keyVerb() != VERB_NONE) {
/* 2 - We've selected via the keyboard, no command is being */
/* constructed, so we shall find the item's default */
_curCmd.verb = findDefault(item, true);
2003-12-12 10:33:34 +00:00
if (_curCmd.verb == VERB_NONE) {
// set to Look At
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_LOOK_AT;
_cmdText.setVerb(VERB_LOOK_AT);
}
_curCmd.action = _curCmd.verb;
}
else {
// Action>0 ONLY if command has been constructed
// Left Mouse Button pressed just do Look At
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_LOOK_AT;
_curCmd.action = VERB_LOOK_AT;
_cmdText.setVerb(VERB_LOOK_AT);
}
}
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_NONE;
}
else {
2003-12-11 22:16:35 +00:00
if (_vm->logic()->joeWalk() == JWM_MOVE) {
_cmdText.clear();
_curCmd.commandLevel = 1;
2003-12-11 22:16:35 +00:00
_vm->logic()->joeWalk(JWM_NORMAL);
2003-12-12 10:33:34 +00:00
_curCmd.action = VERB_NONE;
lookCurrentIcon();
}
2003-12-12 10:33:34 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
alterDefault(_selCmd.defaultVerb, true);
2003-12-12 10:33:34 +00:00
_selCmd.defaultVerb = VERB_NONE;
clear(true);
return;
}
if (_cmdText.isEmpty()) {
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_LOOK_AT;
_curCmd.action = VERB_LOOK_AT;
_cmdText.setVerb(VERB_LOOK_AT);
}
else {
if (_curCmd.commandLevel == 2 && _parse) {
_curCmd.verb = _curCmd.action;
}
else {
_curCmd.verb = findDefault(item, true);
}
2003-12-12 10:33:34 +00:00
if (_curCmd.verb == VERB_NONE) {
// No match made, so command not yet completed. Redefine as LOOK AT
2003-12-12 10:33:34 +00:00
_curCmd.action = VERB_LOOK_AT;
_cmdText.setVerb(VERB_LOOK_AT);
}
else {
_curCmd.action = _curCmd.verb;
}
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_NONE;
}
}
2003-12-11 22:16:35 +00:00
grabSelectedObject(-item, _vm->logic()->itemData(item)->state, _vm->logic()->itemData(item)->name);
}
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
2003-11-08 23:45:45 +00:00
// set PARSE to TRUE, default FALSE if command half complete
// click object without a command, if DEFAULT then
// do that, otherwise do a WALK!
2003-12-11 22:16:35 +00:00
uint16 objNum = _vm->logic()->currentRoomData() + _curCmd.noun;
int16 objName = _vm->logic()->objectData(objNum)->name;
if (objName <= 0) {
// selected a turned off object, so just walk
clear(true);
_curCmd.noun = 0;
2003-12-11 22:16:35 +00:00
//_vm->logic()->newRoom(0);
_vm->logic()->joeWalk(JWM_EXECUTE);
return;
}
2003-12-12 10:33:34 +00:00
if (_curCmd.verb == VERB_NONE) {
if (_mouseKey == Input::MOUSE_LBUTTON) {
2003-12-12 10:33:34 +00:00
if ((_curCmd.commandLevel != 2 && _curCmd.action == VERB_NONE) ||
(_curCmd.commandLevel == 2 && _parse)) {
// action2 > 0 only if command has been constructed
// lmb pressed, just walk
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_WALK_TO;
_curCmd.action = VERB_WALK_TO;
_cmdText.setVerb(VERB_WALK_TO);
}
}
else if (_mouseKey == Input::MOUSE_RBUTTON) {
// rmb pressed, do default if one exists
2003-12-12 10:33:34 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
// change default of command
alterDefault(_selCmd.defaultVerb, false);
2003-12-12 10:33:34 +00:00
_selCmd.defaultVerb = VERB_NONE;
clear(true);
return;
}
if (_cmdText.isEmpty()) {
2003-11-08 23:45:45 +00:00
// Ensures that Right Mkey will select correct default
_curCmd.verb = findDefault(objNum, false);
2003-12-12 10:33:34 +00:00
if (_curCmd.verb != VERB_NONE) {
// no match made, redefine as Walk To
2003-12-12 10:33:34 +00:00
_selCmd.action = VERB_WALK_TO;
}
else {
_selCmd.action = _curCmd.verb;
}
_cmdText.setVerb(_selCmd.action);
2003-12-11 22:16:35 +00:00
_cmdText.addObject(_vm->logic()->objectName(_vm->logic()->objectData(objNum)->name));
}
else {
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_NONE;
if ((_curCmd.commandLevel == 2 && !_parse) || _curCmd.action != VERB_NONE) {
_curCmd.verb = _curCmd.action;
}
else {
_curCmd.verb = findDefault(objNum, false);
}
2003-12-12 10:33:34 +00:00
if (_curCmd.verb != VERB_NONE) {
_curCmd.action = VERB_WALK_TO;
_cmdText.setVerb(VERB_WALK_TO);
}
else {
_curCmd.action = _curCmd.verb;
}
2003-12-12 10:33:34 +00:00
_curCmd.verb = VERB_NONE;
}
}
}
_selCmd.noun = 0;
// XXX PARSE=1;
// XXX if((ACTION==6 || ACTION==5) && CLEVEL==1) PARSE=0;
2003-12-11 22:16:35 +00:00
grabSelectedObject(objNum, _vm->logic()->objectData(objNum)->state, objName);
}
2003-11-08 23:45:45 +00:00
void Command::grabSelectedVerb() {
2003-12-12 10:33:34 +00:00
if (isVerbScrollInv(_curCmd.verb)) {
2003-11-08 23:45:45 +00:00
// move through inventory (by four if right mouse button)
uint16 scroll = _mouseKey == Input::MOUSE_RBUTTON ? 4 : 1;
2003-12-12 10:33:34 +00:00
_vm->logic()->inventoryScroll(scroll, _curCmd.verb == VERB_SCROLL_UP);
}
2003-12-12 10:33:34 +00:00
else if (isVerbPanel(_curCmd.verb) || _curCmd.verb == VERB_WALK_TO) {
_curCmd.action = _curCmd.verb;
2003-11-03 19:52:14 +00:00
_curCmd.subject1 = 0;
_curCmd.subject2 = 0;
// if right mouse key selected, then store command VERB
if (_mouseKey == Input::MOUSE_RBUTTON) {
_selCmd.defaultVerb = _curCmd.verb;
_cmdText.displayTemp(11, true, _curCmd.verb);
2003-11-08 23:45:45 +00:00
}
else {
2003-12-12 10:33:34 +00:00
_selCmd.defaultVerb = VERB_NONE;
if (_vm->logic()->joeWalk() == JWM_MOVE && _curCmd.verb != VERB_NONE) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeWalk(JWM_NORMAL);
}
_curCmd.commandLevel = 1;
2003-12-12 10:33:34 +00:00
_curCmd.oldVerb = VERB_NONE;
_curCmd.oldNoun = 0;
_cmdText.setVerb(_curCmd.verb);
_cmdText.display(INK_CMD_NORMAL);
}
}
}
bool Command::executeIfCutaway(const char *description) {
2003-11-02 16:46:12 +00:00
if (strlen(description) > 4 &&
scumm_stricmp(description + strlen(description) - 4, ".cut") == 0) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
char nextCutaway[20];
memset(nextCutaway, 0, sizeof(nextCutaway));
2003-12-11 22:16:35 +00:00
_vm->logic()->playCutaway(description, nextCutaway);
while (nextCutaway[0] != '\0') {
2003-12-11 22:16:35 +00:00
_vm->logic()->playCutaway(nextCutaway, nextCutaway);
}
return true;
}
return false;
}
bool Command::executeIfDialog(const char *description) {
2003-11-06 08:53:09 +00:00
if (strlen(description) > 4 &&
scumm_stricmp(description + strlen(description) - 4, ".dog") == 0) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
2003-11-06 08:53:09 +00:00
char cutaway[20];
memset(cutaway, 0, sizeof(cutaway));
2003-12-11 22:16:35 +00:00
_vm->logic()->dialogue(description, _selCmd.noun, cutaway);
2003-11-06 08:53:09 +00:00
while (cutaway[0] != '\0') {
char currentCutaway[20];
strcpy(currentCutaway, cutaway);
2003-12-11 22:16:35 +00:00
_vm->logic()->playCutaway(currentCutaway, cutaway);
2003-11-06 08:53:09 +00:00
}
2003-11-06 08:53:09 +00:00
return true;
}
return false;
}
bool Command::handleDefaultCommand(bool walk) {
// l.96-141 execute.c
2003-12-11 22:16:35 +00:00
uint16 objMax = _vm->logic()->currentRoomObjMax();
uint16 roomData = _vm->logic()->currentRoomData();
// select without a command or WALK TO ; do a WALK
2003-12-12 10:33:34 +00:00
if ((_selCmd.action == VERB_WALK_TO || _selCmd.action == VERB_NONE) &&
(_selCmd.noun > objMax || _selCmd.noun == 0)) {
2003-12-12 10:33:34 +00:00
if (_selCmd.action == VERB_NONE) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
}
2003-12-12 20:26:20 +00:00
_vm->walk()->moveJoe(0, _selPosX, _selPosY, false);
return true;
}
// check to see if one of the objects is hidden
2003-12-11 22:16:35 +00:00
if (_curCmd.subject1 > 0 && _vm->logic()->objectData(_curCmd.subject1)->name <= 0) {
return true;
}
2003-12-12 10:33:34 +00:00
if (// _selCmd.action == VERB_GIVE && // can be TALK_TO !
2003-12-11 22:16:35 +00:00
_curCmd.subject2 > 0 && _vm->logic()->objectData(_curCmd.subject2)->name <= 0) {
return true;
}
2003-11-08 23:45:45 +00:00
// check for USE command on exists
2003-12-12 10:33:34 +00:00
if (_selCmd.action == VERB_USE &&
2003-12-11 22:16:35 +00:00
_curCmd.subject1 > 0 && _vm->logic()->objectData(_curCmd.subject1)->entryObj > 0) {
2003-12-12 10:33:34 +00:00
_selCmd.action = VERB_WALK_TO;
}
if (_selCmd.noun > 0 && _selCmd.noun <= objMax) {
2003-12-11 22:16:35 +00:00
uint16 objNum = _vm->logic()->currentRoomData() + _selCmd.noun;
2003-11-03 19:52:14 +00:00
if (makeJoeWalkTo(_selPosX, _selPosY, objNum, _selCmd.action, walk) != 0) {
return true;
}
2003-12-12 10:33:34 +00:00
if (_selCmd.action == VERB_WALK_TO && _vm->logic()->objectData(roomData + _selCmd.noun)->entryObj < 0) {
return true;
}
}
return false;
}
2003-12-12 10:33:34 +00:00
void Command::executeStandardStuff(Verb action, int16 subj1, int16 subj2) {
// l.158-272 execute.c
uint16 k;
2003-12-12 10:33:34 +00:00
switch (action) {
case VERB_LOOK_AT:
look();
break;
2003-11-08 23:45:45 +00:00
case VERB_OPEN:
// 'it doesn't seem to open'
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(1);
break;
case VERB_USE:
if (subj1 < 0) {
2003-12-11 22:16:35 +00:00
k = _vm->logic()->itemData(-subj1)->sfxDescription;
if (k > 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(k, true);
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(2);
}
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(2);
}
break;
2003-11-08 23:45:45 +00:00
case VERB_TALK_TO:
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(24 + _vm->randomizer.getRandomNumber(2));
break;
2003-11-08 23:45:45 +00:00
case VERB_CLOSE:
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(2);
break;
case VERB_MOVE:
// 'I can't move it'
if (subj1 > 0) {
2003-12-11 22:16:35 +00:00
int16 img = _vm->logic()->objectData(subj1)->image;
if (img == -4 || img == -3) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(18);
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(3);
}
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(3);
}
break;
case VERB_GIVE:
// 'I can't give the subj1 to subj2'
if (subj1 < 0) {
k = 11;
if (subj2 > 0) {
2003-12-11 22:16:35 +00:00
int16 img = _vm->logic()->objectData(subj2)->image;
if (img == -4 || img == -3) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(27 + _vm->randomizer.getRandomNumber(2));
}
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(11);
}
}
else {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(12);
}
break;
case VERB_PICK_UP:
if (subj1 < 0) {
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(14);
}
else {
2003-12-11 22:16:35 +00:00
int16 img = _vm->logic()->objectData(subj2)->image;
if (img == -4 || img == -3) {
// Trying to get a person
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(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'
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(5 + _vm->randomizer.getRandomNumber(3));
}
}
break;
default:
break;
}
}
2003-12-12 10:33:34 +00:00
void Command::changeObjectState(Verb action, int16 obj, int16 song, bool cutDone) {
// l.456-533 execute.c
2003-12-11 22:16:35 +00:00
ObjectData *objData = _vm->logic()->objectData(obj);
2003-12-12 10:33:34 +00:00
if (action == VERB_OPEN && !cutDone) {
if (State::findOn(objData->state) == STATE_ON_ON) {
State::alterOn(&objData->state, STATE_ON_OFF);
2003-12-12 10:33:34 +00:00
State::alterDefaultVerb(&objData->state, VERB_NONE);
// play music if it exists... (or SFX for open/close door)
if (song != 0) {
2003-12-11 22:16:35 +00:00
_vm->sound()->playSong(ABS(song));
}
if (objData->entryObj != 0) {
2003-11-08 23:45:45 +00:00
// 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 !'
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(9);
}
}
2003-12-12 10:33:34 +00:00
else if (action == VERB_CLOSE && !cutDone) {
if (State::findOn(objData->state) == STATE_ON_OFF) {
State::alterOn(&objData->state, STATE_ON_ON);
2003-12-12 10:33:34 +00:00
State::alterDefaultVerb(&objData->state, VERB_OPEN);
// play music if it exists... (or SFX for open/close door)
if (song != 0) {
2003-12-11 22:16:35 +00:00
_vm->sound()->playSong(ABS(song));
}
if (objData->entryObj != 0) {
2003-11-08 23:45:45 +00:00
// 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 !'
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(10);
}
}
2003-12-12 10:33:34 +00:00
else if (action == VERB_MOVE) {
State::alterOn(&objData->state, STATE_ON_OFF);
}
}
void Command::cleanupCurrentAction() {
// l.595-597 execute.c
2003-12-11 22:16:35 +00:00
_vm->logic()->joeFace();
_curCmd.oldNoun = 0;
2003-12-12 10:33:34 +00:00
_curCmd.oldVerb = VERB_NONE;
}
Verb Command::findDefault(uint16 obj, bool itemType) {
2003-12-11 22:16:35 +00:00
uint16 s = itemType ? _vm->logic()->itemData(obj)->state : _vm->logic()->objectData(obj)->state;
return State::findDefaultVerb(s);
}
2003-12-12 10:33:34 +00:00
void Command::alterDefault(Verb def, bool itemType) {
uint16 *newDefaultState = 0;
const char *name = NULL;
2003-12-11 22:16:35 +00:00
_curCmd.noun = _vm->logic()->findObjectUnderCursor(_selPosX, _selPosY);
if (!itemType) {
if (_curCmd.noun == 0) {
return;
}
2003-12-11 22:16:35 +00:00
uint16 i = _vm->logic()->findObjectGlobalNumber(_curCmd.noun);
ObjectData *od = _vm->logic()->objectData(i);
if (od->name < 0) {
return;
}
newDefaultState = &od->state;
2003-12-11 22:16:35 +00:00
name = _vm->logic()->objectTextualDescription(od->name);
}
else {
2003-12-12 10:33:34 +00:00
uint16 item = _vm->logic()->findInventoryItem(_curCmd.verb - VERB_INV_FIRST);
2003-12-11 22:16:35 +00:00
if (item == 0 || _vm->logic()->itemData(item)->name == 0) {
return;
}
2003-12-11 22:16:35 +00:00
ItemData *id = _vm->logic()->itemData(item);
newDefaultState = &id->state;
2003-12-11 22:16:35 +00:00
name = _vm->logic()->objectTextualDescription(id->name);
}
State::alterDefaultVerb(newDefaultState, def);
if (_curCmd.noun == 0) {
_cmdText.clear();
}
else {
2003-12-12 10:33:34 +00:00
_cmdText.setVerb(def == VERB_NONE ? VERB_WALK_TO : def);
}
_cmdText.displayTemp(INK_CMD_NORMAL, name);
_curCmd.oldNoun = _curCmd.noun;
}
2003-12-12 10:33:34 +00:00
void Command::openOrCloseAssociatedObject(Verb action, int16 otherObj) {
CmdListData *cmdList = &_cmdList[1];
uint16 com = 0;
uint16 i;
for (i = 1; i <= _numCmdList; ++i, ++cmdList) {
if (cmdList->match(action, otherObj, 0)) {
if (cmdList->setConditions) {
warning("using Command::openOrCloseAssociatedObject() with setConditions");
CmdGameState *cmdGs = _cmdGameState;
uint16 j;
for (j = 1; j <= _numCmdGameState; ++j) {
if (cmdGs[j].id == i && cmdGs[i].gameStateSlot > 0) {
2003-11-03 19:52:14 +00:00
// FIXME: weird, why using 'i' instead of 'j' ?
2003-12-11 22:16:35 +00:00
if (_vm->logic()->gameState(cmdGs[i].gameStateSlot) == cmdGs[i].gameStateValue) {
com = i;
break;
}
}
}
}
else {
com = i;
break;
}
}
}
debug(0, "Command::openOrCloseAssociatedObject() - com=%X", com);
if (com != 0) {
cmdList = &_cmdList[com];
2003-12-11 22:16:35 +00:00
ObjectData *objData = _vm->logic()->objectData(otherObj);
if (cmdList->imageOrder != 0) {
// update the graphic image of object
objData->image = cmdList->imageOrder;
}
2003-12-12 10:33:34 +00:00
if (action == VERB_OPEN) {
if (State::findOn(objData->state) == STATE_ON_ON) {
State::alterOn(&objData->state, STATE_ON_OFF);
2003-12-12 10:33:34 +00:00
State::alterDefaultVerb(&objData->state, VERB_NONE);
objData->entryObj = ABS(objData->entryObj);
}
}
2003-12-12 10:33:34 +00:00
else if (action == VERB_CLOSE) {
if (State::findOn(objData->state) == STATE_ON_OFF) {
State::alterOn(&objData->state, STATE_ON_ON);
2003-12-12 10:33:34 +00:00
State::alterDefaultVerb(&objData->state, VERB_OPEN);
objData->entryObj = -ABS(objData->entryObj);
}
}
}
}
2003-11-08 23:45:45 +00:00
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) {
2003-12-11 22:16:35 +00:00
if (_vm->logic()->gameState(cmdGs->gameStateSlot) != cmdGs->gameStateValue) {
debug(0, "Command::setConditions() - GS[%d] == %d (should be %d)", cmdGs->gameStateSlot, _vm->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];
2003-11-05 10:09:54 +00:00
if (cmdGs->speakValue > 0 && lastCmd) {
// check to see if fail state is in fact a cutaway
2003-12-11 22:16:35 +00:00
const char *objDesc = _vm->logic()->objectTextualDescription(cmdGs->speakValue);
if (!executeIfCutaway(objDesc) && !executeIfDialog(objDesc)) {
2003-12-11 22:16:35 +00:00
_vm->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]];
2003-12-11 22:16:35 +00:00
_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];
uint16 i;
for (i = 1; i <= _numCmdArea; ++i, ++cmdArea) {
if (cmdArea->id == command) {
uint16 areaNum = ABS(cmdArea->area);
2003-12-11 22:16:35 +00:00
Area *area = _vm->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) {
2003-11-08 23:45:45 +00:00
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);
2003-12-11 22:16:35 +00:00
ObjectData *objData = _vm->logic()->objectData(dstObj);
debug(0, "Command::setObjects() - dstObj=%X srcObj=%X _curCmd.subject1=%X", cmdObj->dstObj, cmdObj->srcObj, _curCmd.subject1);
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;
2003-12-11 22:16:35 +00:00
if (objData->room == _vm->logic()->currentRoom()) {
2003-11-03 19:52:14 +00:00
if (dstObj != _curCmd.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
2003-12-11 22:16:35 +00:00
uint16 objZone = dstObj - _vm->logic()->currentRoomData();
_vm->logic()->zoneSet(ZONE_ROOM, objZone, 0, 0, 1, 1);
}
}
if (cmdObj->srcObj > 0) {
// copy data from dummy object to object
int16 image1 = objData->image;
2003-12-11 22:16:35 +00:00
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) {
2003-12-11 22:16:35 +00:00
_vm->graphics()->bobClear(bobNum);
}
}
}
2003-11-03 19:52:14 +00:00
if (dstObj != _curCmd.subject1) {
// if the new object we have updated is on screen and
// is not current object then update it
2003-12-11 22:16:35 +00:00
_vm->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
2003-12-11 22:16:35 +00:00
_vm->logic()->roomRefreshObject(dstObj);
}
}
}
}
}
void Command::setItems(uint16 command) {
debug(9, "Command::setItems(%d)", command);
CmdInventory *cmdInv = &_cmdInventory[1];
2003-12-11 22:16:35 +00:00
ItemData *items = _vm->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);
}
2003-12-11 22:16:35 +00:00
_vm->logic()->inventoryInsertItem(cmdInv->dstItem);
}
else {
// delete item
if (items[dstItem].name > 0) {
2003-12-11 22:16:35 +00:00
_vm->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) {
2003-12-11 22:16:35 +00:00
i = firstDesc + _vm->randomizer.getRandomNumber(diff);
}
objDesc->lastSeenNumber = i;
}
break;
case 1:
i = objDesc->lastSeenNumber;
while (i == objDesc->lastSeenNumber) {
2003-12-11 22:16:35 +00:00
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::look() {
2003-12-11 22:16:35 +00:00
if (_selCmd.noun > 0 && _selCmd.noun <= _vm->logic()->currentRoomObjMax()) {
uint16 objNum = _vm->logic()->currentRoomData() + _selCmd.noun;
if (_vm->logic()->objectData(objNum)->entryObj == 0) {
if (makeJoeWalkTo(_selPosX, _selPosY, objNum, _selCmd.action, false) == -2) { // XXX inCutaway parameter
// 'I can't get close enough to have a look.'
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(13);
}
}
}
// if object type and disabled, don't look
2003-12-11 22:16:35 +00:00
if (_curCmd.subject1 > 0 && _vm->logic()->objectData(_curCmd.subject1)->name <= 0) {
return;
}
uint16 desc;
2003-11-03 19:52:14 +00:00
if (_curCmd.subject1 < 0) {
2003-12-11 22:16:35 +00:00
desc = _vm->logic()->itemData(-_curCmd.subject1)->description;
}
else {
2003-12-11 22:16:35 +00:00
desc = _vm->logic()->objectData(_curCmd.subject1)->description;
}
2003-11-03 19:52:14 +00:00
debug(0, "Command::look() - desc = %X, _curCmd.subject1 = %X", desc, _curCmd.subject1);
// check to see if the object/item has a series of description
2003-12-11 22:16:35 +00:00
ObjectDescription *objDesc = _vm->logic()->objectDescription(1);
uint16 i;
2003-12-11 22:16:35 +00:00
for (i = 1; i <= _vm->logic()->objectDescriptionCount(); ++i, ++objDesc) {
2003-11-03 19:52:14 +00:00
if (objDesc->object == _curCmd.subject1) {
desc = nextObjectDescription(objDesc, desc);
break;
}
}
2003-12-11 22:16:35 +00:00
_vm->logic()->joeSpeak(desc, true);
_vm->logic()->joeFace();
}
void Command::lookCurrentItem() {
2003-12-12 10:33:34 +00:00
if (isVerbInv(_curCmd.verb)) {
uint16 item = _vm->logic()->findInventoryItem(_curCmd.verb - VERB_INV_FIRST);
if (item != 0) {
2003-12-11 22:16:35 +00:00
ItemData *itemData = _vm->logic()->itemData(item);
const char *name = _vm->logic()->objectName(itemData->name);
2003-12-12 10:33:34 +00:00
if (_curCmd.action == VERB_NONE) {
Verb v = State::findDefaultVerb(itemData->state);
2003-12-12 10:33:34 +00:00
_cmdText.setVerb(v == VERB_NONE ? VERB_LOOK_AT : v);
}
2003-12-12 10:33:34 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
_cmdText.displayTemp(INK_CMD_LOCK, true, _selCmd.defaultVerb, name);
}
else {
_cmdText.displayTemp(INK_CMD_NORMAL, name);
}
_curCmd.oldVerb = _curCmd.verb;
}
}
}
void Command::lookCurrentRoom() {
2003-12-11 22:16:35 +00:00
_curCmd.noun = _vm->logic()->findObjectUnderCursor(_vm->input()->mousePosX(), _vm->input()->mousePosY());
2003-12-11 22:16:35 +00:00
if (_vm->logic()->joeWalk() == JWM_MOVE) {
return;
}
int16 aObjName = 0;
2003-12-11 22:16:35 +00:00
uint16 k = _vm->logic()->currentRoomData();
int16 i = 0;
2003-12-11 22:16:35 +00:00
if (_curCmd.noun > _vm->logic()->currentRoomObjMax()) {
uint16 obj = _vm->logic()->currentRoomArea(_curCmd.noun - _vm->logic()->currentRoomObjMax())->object;
if (obj) {
2003-12-11 22:16:35 +00:00
aObjName = _vm->logic()->objectData(obj)->name;
if (aObjName > 0) {
i = aObjName;
_curCmd.noun = obj - k;
}
}
}
else {
2003-12-11 22:16:35 +00:00
i = _vm->logic()->objectData(k + _curCmd.noun)->name;
}
if (_curCmd.oldNoun == _curCmd.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
2003-12-11 22:16:35 +00:00
if (_curCmd.noun > _vm->logic()->currentRoomObjMax() && aObjName <= 0) {
if (_curCmd.oldNoun != 0) {
2003-12-12 10:33:34 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
_cmdText.displayTemp(INK_CMD_LOCK, true, _selCmd.defaultVerb);
}
2003-12-12 10:33:34 +00:00
else if (_curCmd.action != VERB_NONE) {
_cmdText.display(INK_CMD_NORMAL);
}
_curCmd.oldNoun = 0;
return;
}
}
if (i <= 0) {
_curCmd.oldNoun = _curCmd.noun;
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
2003-12-12 20:26:20 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
_cmdText.displayTemp(INK_CMD_LOCK, true, _selCmd.defaultVerb);
}
2003-12-12 10:33:34 +00:00
else if (_curCmd.action != VERB_NONE) {
_cmdText.display(INK_CMD_NORMAL);
}
return;
}
// if no command yet selected, then use DEFAULT command, if any
2003-12-12 10:33:34 +00:00
if (_curCmd.action == VERB_NONE) {
2003-12-11 22:16:35 +00:00
Verb v = State::findDefaultVerb(_vm->logic()->objectData(k + _curCmd.noun)->state);
2003-12-12 10:33:34 +00:00
_cmdText.setVerb(v == VERB_NONE ? VERB_WALK_TO : v);
if (_curCmd.noun == 0) {
_cmdText.clear();
}
}
const char *objName = "";
if (_curCmd.noun > 0) {
2003-12-11 22:16:35 +00:00
objName = _vm->logic()->objectName(i);
}
2003-12-12 10:33:34 +00:00
if (_selCmd.defaultVerb != VERB_NONE) {
_cmdText.displayTemp(INK_CMD_LOCK, true, _selCmd.defaultVerb, objName);
}
else {
_cmdText.displayTemp(INK_CMD_NORMAL, objName);
}
_curCmd.oldNoun = _curCmd.noun;
}
void Command::lookCurrentIcon() {
2003-12-11 22:16:35 +00:00
_curCmd.verb = _vm->logic()->findVerbUnderCursor(_vm->input()->mousePosX(), _vm->input()->mousePosY());
if (_curCmd.verb != _curCmd.oldVerb && _vm->logic()->joeWalk() != JWM_MOVE) {
2003-12-12 10:33:34 +00:00
if (_curCmd.action == VERB_NONE) {
_cmdText.clear();
}
2003-12-11 22:16:35 +00:00
_vm->graphics()->textClear(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
lookCurrentItem();
// ensure that registers when move to top screen
if (_curCmd.noun > 0) {
_curCmd.oldNoun = -1;
}
_curCmd.oldVerb = _curCmd.verb;
2003-12-12 10:33:34 +00:00
if (_curCmd.verb == VERB_NONE) {
_cmdText.display(INK_CMD_NORMAL);
}
else if (isVerbPanel(_curCmd.verb) || _curCmd.verb == VERB_WALK_TO) {
_cmdText.displayTemp(INK_CMD_NORMAL, false, _curCmd.verb);
}
}
}
2003-12-12 10:33:34 +00:00
} // End of namespace Queen