1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23
24 #include "queen/command.h"
25
26 #include "queen/display.h"
27 #include "queen/input.h"
28 #include "queen/graphics.h"
29 #include "queen/grid.h"
30 #include "queen/logic.h"
31 #include "queen/queen.h"
32 #include "queen/resource.h"
33 #include "queen/sound.h"
34 #include "queen/state.h"
35 #include "queen/walk.h"
36
37 namespace Queen {
38
CmdText(uint8 y,QueenEngine * vm)39 CmdText::CmdText(uint8 y, QueenEngine *vm)
40 : _y(y), _vm(vm) {
41 clear();
42 }
43
clear()44 void CmdText::clear() {
45 memset(_command, 0, sizeof(_command));
46 }
47
display(InkColor color,const char * command,bool outlined)48 void CmdText::display(InkColor color, const char *command, bool outlined) {
49 _vm->display()->textCurrentColor(_vm->display()->getInkColor(color));
50 if (!command) {
51 command = _command;
52 }
53 _vm->display()->setTextCentered(_y, command, outlined);
54 }
55
displayTemp(InkColor color,Verb v)56 void CmdText::displayTemp(InkColor color, Verb v) {
57 char temp[MAX_COMMAND_LEN];
58 strcpy(temp, _vm->logic()->verbName(v));
59 display(color, temp, false);
60 }
61
displayTemp(InkColor color,const char * name,bool outlined)62 void CmdText::displayTemp(InkColor color, const char *name, bool outlined) {
63 char temp[MAX_COMMAND_LEN + 2];
64 snprintf(temp, MAX_COMMAND_LEN + 1, "%s %s", _command, name);
65 display(color, temp, outlined);
66 }
67
setVerb(Verb v)68 void CmdText::setVerb(Verb v) {
69 strcpy(_command, _vm->logic()->verbName(v));
70 }
71
addLinkWord(Verb v)72 void CmdText::addLinkWord(Verb v) {
73 strcat(_command, " ");
74 strcat(_command, _vm->logic()->verbName(v));
75 }
76
addObject(const char * objName)77 void CmdText::addObject(const char *objName) {
78 strcat(_command, " ");
79 strcat(_command, objName);
80 }
81
82 class CmdTextHebrew : public CmdText {
83 public:
84
CmdTextHebrew(uint8 y,QueenEngine * vm)85 CmdTextHebrew(uint8 y, QueenEngine *vm) : CmdText(y, vm) {}
86
displayTemp(InkColor color,const char * name,bool outlined)87 void displayTemp(InkColor color, const char *name, bool outlined) override {
88 char temp[MAX_COMMAND_LEN + 2];
89
90 snprintf(temp, MAX_COMMAND_LEN + 1, "%s %s", name, _command);
91 display(color, temp, outlined);
92 }
93
addLinkWord(Verb v)94 void addLinkWord(Verb v) override {
95 char temp[MAX_COMMAND_LEN];
96
97 strcpy(temp, _command);
98 strcpy(_command, _vm->logic()->verbName(v));
99 strcat(_command, " ");
100 strcat(_command, temp);
101 }
102
addObject(const char * objName)103 void addObject(const char *objName) override {
104 char temp[MAX_COMMAND_LEN];
105
106 strcpy(temp, _command);
107 strcpy(_command, objName);
108 strcat(_command, " ");
109 strcat(_command, temp);
110 }
111 };
112
113 class CmdTextGreek : public CmdText {
114 public:
115
CmdTextGreek(uint8 y,QueenEngine * vm)116 CmdTextGreek(uint8 y, QueenEngine *vm) : CmdText(y, vm) {}
117
displayTemp(InkColor color,const char * name,bool outlined)118 void displayTemp(InkColor color, const char *name, bool outlined) override {
119 char temp[MAX_COMMAND_LEN + 2];
120 // don't show a space after the goto and give commands in the Greek version
121 if (_command[1] != (char)-34 && !(_command[1] == (char)-2 && strlen(_command) > 5))
122 snprintf(temp, MAX_COMMAND_LEN + 1, "%s %s", _command, name);
123 else
124 snprintf(temp, MAX_COMMAND_LEN + 1, "%s%s", _command, name);
125 display(color, temp, outlined);
126 }
127
addObject(const char * objName)128 void addObject(const char *objName) override {
129 // don't show a space after the goto and give commands in the Greek version
130 if (_command[1] != (char)-34 && !(_command[1] == (char)-2 && strlen(_command) > 5))
131 strcat(_command, " ");
132 strcat(_command, objName);
133 }
134 };
135
makeCmdTextInstance(uint8 y,QueenEngine * vm)136 CmdText *CmdText::makeCmdTextInstance(uint8 y, QueenEngine *vm) {
137 switch (vm->resource()->getLanguage()) {
138 case Common::HE_ISR:
139 return new CmdTextHebrew(y, vm);
140 case Common::GR_GRE:
141 return new CmdTextGreek(y, vm);
142 default:
143 return new CmdText(y, vm);
144 }
145 }
146
init()147 void CmdState::init() {
148 commandLevel = 1;
149 oldVerb = verb = action = VERB_NONE;
150 oldNoun = noun = subject[0] = subject[1] = 0;
151
152 selAction = VERB_NONE;
153 selNoun = 0;
154 }
155
Command(QueenEngine * vm)156 Command::Command(QueenEngine *vm)
157 : _cmdList(NULL), _cmdArea(NULL), _cmdObject(NULL), _cmdInventory(NULL), _cmdGameState(NULL), _vm(vm) {
158 _cmdText = CmdText::makeCmdTextInstance(CmdText::COMMAND_Y_POS, vm);
159 }
160
~Command()161 Command::~Command() {
162 delete _cmdText;
163 delete[] _cmdList;
164 delete[] _cmdArea;
165 delete[] _cmdObject;
166 delete[] _cmdInventory;
167 delete[] _cmdGameState;
168 }
169
clear(bool clearTexts)170 void Command::clear(bool clearTexts) {
171 debug(6, "Command::clear(%d)", clearTexts);
172 _cmdText->clear();
173 if (clearTexts) {
174 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
175 }
176 _parse = false;
177 _state.init();
178 }
179
executeCurrentAction()180 void Command::executeCurrentAction() {
181 _vm->logic()->entryObj(0);
182
183 if (_mouseKey == Input::MOUSE_RBUTTON && _state.subject[0] > 0) {
184
185 ObjectData *od = _vm->logic()->objectData(_state.subject[0]);
186 if (od == NULL || od->name <= 0) {
187 cleanupCurrentAction();
188 return;
189 }
190
191 _state.verb = State::findDefaultVerb(od->state);
192 _state.selAction = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
193 _cmdText->setVerb(_state.selAction);
194 _cmdText->addObject(_vm->logic()->objectName(od->name));
195 }
196
197 // always highlight the current command when actioned
198 _cmdText->display(INK_CMD_SELECT);
199
200 _state.selNoun = _state.noun;
201 _state.commandLevel = 1;
202
203 if (handleWrongAction()) {
204 cleanupCurrentAction();
205 return;
206 }
207
208 // get the commands associated with this object/item
209 uint16 comMax = 0;
210 uint16 matchingCmds[MAX_MATCHING_CMDS];
211 CmdListData *cmdList = &_cmdList[1];
212 uint16 i;
213 for (i = 1; i <= _numCmdList; ++i, ++cmdList) {
214 if (cmdList->match(_state.selAction, _state.subject[0], _state.subject[1])) {
215 assert(comMax < MAX_MATCHING_CMDS);
216 matchingCmds[comMax] = i;
217 ++comMax;
218 }
219 }
220
221 debug(6, "Command::executeCurrentAction() - comMax=%d subj1=%X subj2=%X", comMax, _state.subject[0], _state.subject[1]);
222
223 if (comMax == 0) {
224 sayInvalidAction(_state.selAction, _state.subject[0], _state.subject[1]);
225 clear(true);
226 cleanupCurrentAction();
227 return;
228 }
229
230 // process each associated command for the Object, until all done
231 // or one of the Gamestate tests fails...
232 int16 cond = 0;
233 CmdListData *com = &_cmdList[0];
234 uint16 comId = 0;
235 for (i = 1; i <= comMax; ++i) {
236
237 comId = matchingCmds[i - 1];
238
239 // WORKAROUND bug #2636: This command is triggered in room 56 (the
240 // room with two waterfalls in the maze part of the game) if the user
241 // tries to walk through the left waterfall (object 423).
242 //
243 // Normally, this would move Joe to room 101 on the upper level and
244 // start a cutscene. Joe would notice that Yan has been trapped (on
245 // the lower level of the same room). The problem would then appear :
246 // Joe is stuck behind the waterfall due to a walkbox issue. We could
247 // fix the walkbox issue, but then Joe would walk through the waterfall
248 // which wouldn't look that nice, graphically.
249 //
250 // Since this command isn't necessary to complete the game and doesn't
251 // really makes sense here, we just skip it for now. The same cutscene
252 // is already played in command 648, so the user don't miss anything
253 // from the story/experience pov.
254 //
255 // Note: this happens with the original engine, too.
256
257 if (comId == 649) {
258 continue;
259 }
260
261 com = &_cmdList[comId];
262
263 // check the Gamestates and set them if necessary
264 cond = 0;
265 if (com->setConditions) {
266 cond = setConditions(comId, (i == comMax));
267 }
268
269 if (cond == -1 && i == comMax) {
270 // only exit on a condition fail if at last command
271 // Joe hasnt spoken, so do normal LOOK command
272 break;
273 } else if (cond == -2 && i == comMax) {
274 // only exit on a condition fail if at last command
275 // Joe has spoken, so skip LOOK command
276 cleanupCurrentAction();
277 return;
278 } else if (cond >= 0) {
279 // we've had a successful Gamestate check, so we must now exit
280 cond = executeCommand(comId, cond);
281 break;
282 }
283 }
284
285 if (_state.selAction == VERB_USE_JOURNAL) {
286 clear(true);
287 } else {
288 if (cond <= 0 && _state.selAction == VERB_LOOK_AT) {
289 lookAtSelectedObject();
290 } else {
291 // only play song if it's a PLAY AFTER type
292 if (com->song < 0) {
293 _vm->sound()->playSong(-com->song);
294 }
295 clear(true);
296 }
297 cleanupCurrentAction();
298 }
299 }
300
updatePlayer()301 void Command::updatePlayer() {
302 if (_vm->logic()->joeWalk() != JWM_MOVE) {
303 Common::Point mouse = _vm->input()->getMousePos();
304 lookForCurrentObject(mouse.x, mouse.y);
305 lookForCurrentIcon(mouse.x, mouse.y);
306 }
307
308 if (_vm->input()->keyVerb() != VERB_NONE) {
309 if (_vm->input()->keyVerb() == VERB_USE_JOURNAL) {
310 _vm->logic()->useJournal();
311 } else if (_vm->input()->keyVerb() != VERB_SKIP_TEXT) {
312 _state.verb = _vm->input()->keyVerb();
313 if (isVerbInv(_state.verb)) {
314 _state.noun = _state.selNoun = 0;
315 _state.oldNoun = 0;
316 _state.oldVerb = VERB_NONE;
317 grabSelectedItem();
318 } else {
319 grabSelectedVerb();
320 }
321 }
322 _vm->input()->clearKeyVerb();
323 }
324
325 _mouseKey = _vm->input()->mouseButton();
326 _vm->input()->clearMouseButton();
327 if (_mouseKey > 0) {
328 grabCurrentSelection();
329 }
330 }
331
readCommandsFrom(byte * & ptr)332 void Command::readCommandsFrom(byte *&ptr) {
333 uint16 i;
334
335 _numCmdList = READ_BE_UINT16(ptr); ptr += 2;
336 _cmdList = new CmdListData[_numCmdList + 1];
337 if (_numCmdList == 0) {
338 _cmdList[0].readFromBE(ptr);
339 } else {
340 memset(&_cmdList[0], 0, sizeof(CmdListData));
341 for (i = 1; i <= _numCmdList; i++) {
342 _cmdList[i].readFromBE(ptr);
343 }
344 }
345
346 _numCmdArea = READ_BE_UINT16(ptr); ptr += 2;
347 _cmdArea = new CmdArea[_numCmdArea + 1];
348 if (_numCmdArea == 0) {
349 _cmdArea[0].readFromBE(ptr);
350 } else {
351 memset(&_cmdArea[0], 0, sizeof(CmdArea));
352 for (i = 1; i <= _numCmdArea; i++) {
353 _cmdArea[i].readFromBE(ptr);
354 }
355 }
356
357 _numCmdObject = READ_BE_UINT16(ptr); ptr += 2;
358 _cmdObject = new CmdObject[_numCmdObject + 1];
359 if (_numCmdObject == 0) {
360 _cmdObject[0].readFromBE(ptr);
361 } else {
362 memset(&_cmdObject[0], 0, sizeof(CmdObject));
363 for (i = 1; i <= _numCmdObject; i++) {
364 _cmdObject[i].readFromBE(ptr);
365
366 // WORKAROUND bug #3536: Fix an off by one error in the object
367 // command 175. Object 309 should be copied to 308 (disabled).
368 //
369 // _objectData[307].name = -195
370 // _objectData[308].name = 50
371 // _objectData[309].name = -50
372
373 if (i == 175 && _cmdObject[i].id == 320 && _cmdObject[i].dstObj == 307 && _cmdObject[i].srcObj == 309) {
374 _cmdObject[i].dstObj = 308;
375 }
376 }
377 }
378
379 _numCmdInventory = READ_BE_UINT16(ptr); ptr += 2;
380 _cmdInventory = new CmdInventory[_numCmdInventory + 1];
381 if (_numCmdInventory == 0) {
382 _cmdInventory[0].readFromBE(ptr);
383 } else {
384 memset(&_cmdInventory[0], 0, sizeof(CmdInventory));
385 for (i = 1; i <= _numCmdInventory; i++) {
386 _cmdInventory[i].readFromBE(ptr);
387 }
388 }
389
390 _numCmdGameState = READ_BE_UINT16(ptr); ptr += 2;
391 _cmdGameState = new CmdGameState[_numCmdGameState + 1];
392 if (_numCmdGameState == 0) {
393 _cmdGameState[0].readFromBE(ptr);
394 } else {
395 memset(&_cmdGameState[0], 0, sizeof(CmdGameState));
396 for (i = 1; i <= _numCmdGameState; i++) {
397 _cmdGameState[i].readFromBE(ptr);
398 }
399 }
400 }
401
findObjectData(uint16 objRoomNum) const402 ObjectData *Command::findObjectData(uint16 objRoomNum) const {
403 ObjectData *od = NULL;
404 if (objRoomNum != 0) {
405 objRoomNum += _vm->logic()->currentRoomData();
406 od = _vm->logic()->objectData(objRoomNum);
407 }
408 return od;
409 }
410
findItemData(Verb invNum) const411 ItemData *Command::findItemData(Verb invNum) const {
412 ItemData *id = NULL;
413 uint16 itNum = _vm->logic()->findInventoryItem(invNum - VERB_INV_FIRST);
414 if (itNum != 0) {
415 id = _vm->logic()->itemData(itNum);
416 }
417 return id;
418 }
419
executeCommand(uint16 comId,int16 condResult)420 int16 Command::executeCommand(uint16 comId, int16 condResult) {
421 // execute.c l.313-452
422 debug(6, "Command::executeCommand() - cond = %X, com = %X", condResult, comId);
423
424 CmdListData *com = &_cmdList[comId];
425
426 if (com->setAreas) {
427 setAreas(comId);
428 }
429
430 // don't try to grab if action is TALK or WALK
431 if (_state.selAction != VERB_TALK_TO && _state.selAction != VERB_WALK_TO) {
432 int i;
433 for (i = 0; i < 2; ++i) {
434 int16 obj = _state.subject[i];
435 if (obj > 0) {
436 _vm->logic()->joeGrab(State::findGrab(_vm->logic()->objectData(obj)->state));
437 }
438 }
439 }
440
441 bool cutDone = false;
442 if (condResult > 0) {
443 // check for cutaway/dialogs before updating Objects
444 const char *desc = _vm->logic()->objectTextualDescription(condResult);
445 if (executeIfCutaway(desc)) {
446 condResult = 0;
447 cutDone = true;
448 } else if (executeIfDialog(desc)) {
449 condResult = 0;
450 }
451 }
452
453 int16 oldImage = 0;
454 if (_state.subject[0] > 0) {
455 // an object (not an item)
456 oldImage = _vm->logic()->objectData(_state.subject[0])->image;
457 }
458
459 if (com->setObjects) {
460 setObjects(comId);
461 }
462
463 if (com->setItems) {
464 setItems(comId);
465 }
466
467 if (com->imageOrder != 0 && _state.subject[0] > 0) {
468 ObjectData *od = _vm->logic()->objectData(_state.subject[0]);
469 // we must update the graphic image of the object
470 if (com->imageOrder < 0) {
471 // instead of setting to -1 or -2, flag as negative
472 if (od->image > 0) {
473 // make sure that object is not already updated
474 od->image = -(od->image + 10);
475 }
476 } else {
477 od->image = com->imageOrder;
478 }
479 _vm->graphics()->refreshObject(_state.subject[0]);
480 } else {
481 // this object is not being updated by command list, see if
482 // it has another image copied to it
483 if (_state.subject[0] > 0) {
484 // an object (not an item)
485 if (_vm->logic()->objectData(_state.subject[0])->image != oldImage) {
486 _vm->graphics()->refreshObject(_state.subject[0]);
487 }
488 }
489 }
490
491 // don't play music on an OPEN/CLOSE command - in case the command fails
492 if (_state.selAction != VERB_NONE &&
493 _state.selAction != VERB_OPEN &&
494 _state.selAction != VERB_CLOSE) {
495 // only play song if it's a PLAY BEFORE type
496 if (com->song > 0) {
497 _vm->sound()->playSong(com->song);
498 }
499 }
500
501 // do a special hardcoded section
502 // l.419-452 execute.c
503 switch (com->specialSection) {
504 case 1:
505 _vm->logic()->useJournal();
506 _state.selAction = VERB_USE_JOURNAL;
507 return condResult;
508 case 2:
509 _vm->logic()->joeUseDress(true);
510 break;
511 case 3:
512 _vm->logic()->joeUseClothes(true);
513 break;
514 case 4:
515 _vm->logic()->joeUseUnderwear();
516 break;
517 default:
518 break;
519 }
520
521 if (_state.subject[0] > 0)
522 changeObjectState(_state.selAction, _state.subject[0], com->song, cutDone);
523
524 if (condResult > 0) {
525 _vm->logic()->makeJoeSpeak(condResult, true);
526 }
527 return condResult;
528 }
529
makeJoeWalkTo(int16 x,int16 y,int16 objNum,Verb v,bool mustWalk)530 int16 Command::makeJoeWalkTo(int16 x, int16 y, int16 objNum, Verb v, bool mustWalk) {
531 // Check to see if object is actually an exit to another
532 // room. If so, then set up new room
533 ObjectData *objData = _vm->logic()->objectData(objNum);
534 if (objData->x != 0 || objData->y != 0) {
535 x = objData->x;
536 y = objData->y;
537 }
538 if (v == VERB_WALK_TO) {
539 _vm->logic()->entryObj(objData->entryObj);
540 if (objData->entryObj > 0) {
541 _vm->logic()->newRoom(_vm->logic()->objectData(objData->entryObj)->room);
542 // because this is an exit object, see if there is
543 // a walk off point and set (x,y) accordingly
544 WalkOffData *wod = _vm->logic()->walkOffPointForObject(objNum);
545 if (wod != NULL) {
546 x = wod->x;
547 y = wod->y;
548 }
549 }
550 } else {
551 _vm->logic()->entryObj(0);
552 _vm->logic()->newRoom(0);
553 }
554
555 debug(6, "Command::makeJoeWalkTo() - x=%d y=%d newRoom=%d", x, y, _vm->logic()->newRoom());
556
557 int16 p = 0;
558 if (mustWalk) {
559 // determine which way for Joe to face Object
560 uint16 facing = State::findDirection(objData->state);
561 BobSlot *bobJoe = _vm->graphics()->bob(0);
562 if (x == bobJoe->x && y == bobJoe->y) {
563 _vm->logic()->joeFacing(facing);
564 _vm->logic()->joeFace();
565 } else {
566 p = _vm->walk()->moveJoe(facing, x, y, false);
567 if (p != 0) {
568 _vm->logic()->newRoom(0); // cancel makeJoeWalkTo, that should be equivalent to cr10 fix
569 }
570 }
571 }
572 return p;
573 }
574
grabCurrentSelection()575 void Command::grabCurrentSelection() {
576 Common::Point mouse = _vm->input()->getMousePos();
577 _selPosX = mouse.x;
578 _selPosY = mouse.y;
579
580 uint16 zone = _vm->grid()->findObjectUnderCursor(_selPosX, _selPosY);
581 _state.noun = _vm->grid()->findObjectNumber(zone);
582 _state.verb = _vm->grid()->findVerbUnderCursor(_selPosX, _selPosY);
583
584 _selPosX += _vm->display()->horizontalScroll();
585
586 if (isVerbAction(_state.verb) || isVerbInvScroll(_state.verb)) {
587 grabSelectedVerb();
588 } else if (isVerbInv(_state.verb)) {
589 grabSelectedItem();
590 } else if (_state.noun != 0) {
591 grabSelectedNoun();
592 } else if (_selPosY < ROOM_ZONE_HEIGHT && _state.verb == VERB_NONE) {
593 // select without a command, do a WALK
594 clear(true);
595 _vm->logic()->joeWalk(JWM_EXECUTE);
596 }
597 }
598
grabSelectedObject(int16 objNum,uint16 objState,uint16 objName)599 void Command::grabSelectedObject(int16 objNum, uint16 objState, uint16 objName) {
600 if (_state.action != VERB_NONE) {
601 _cmdText->addObject(_vm->logic()->objectName(objName));
602 }
603
604 _state.subject[_state.commandLevel - 1] = objNum;
605
606 // if first noun and it's a 2 level command then set up action word
607 if (_state.action == VERB_USE && _state.commandLevel == 1) {
608 if (State::findUse(objState) == STATE_USE_ON) {
609 // object supports 2 levels, command not fully constructed
610 _state.commandLevel = 2;
611 _cmdText->addLinkWord(VERB_PREP_WITH);
612 _cmdText->display(INK_CMD_NORMAL);
613 _parse = false;
614 } else {
615 _parse = true;
616 }
617 } else if (_state.action == VERB_GIVE && _state.commandLevel == 1) {
618 // command not fully constructed
619 _state.commandLevel = 2;
620 _cmdText->addLinkWord(VERB_PREP_TO);
621 _cmdText->display(INK_CMD_NORMAL);
622 _parse = false;
623 } else {
624 _parse = true;
625 }
626
627 if (_parse) {
628 _state.verb = VERB_NONE;
629 _vm->logic()->joeWalk(JWM_EXECUTE);
630 _state.selAction = _state.action;
631 _state.action = VERB_NONE;
632 }
633 }
634
grabSelectedItem()635 void Command::grabSelectedItem() {
636 ItemData *id = findItemData(_state.verb);
637 if (id == NULL || id->name <= 0) {
638 return;
639 }
640
641 int16 item = _vm->logic()->findInventoryItem(_state.verb - VERB_INV_FIRST);
642
643 // If we've selected via keyboard, and there is no VERB then do
644 // the ITEMs default, otherwise keep constructing!
645
646 if (_mouseKey == Input::MOUSE_LBUTTON ||
647 (_vm->input()->keyVerb() != VERB_NONE && _state.verb != VERB_NONE)) {
648 if (_state.action == VERB_NONE) {
649 if (_vm->input()->keyVerb() != VERB_NONE) {
650 // We've selected via the keyboard, no command is being
651 // constructed, so we shall find the item's default
652 _state.verb = State::findDefaultVerb(id->state);
653 if (_state.verb == VERB_NONE) {
654 // set to Look At
655 _state.verb = VERB_LOOK_AT;
656 _cmdText->setVerb(VERB_LOOK_AT);
657 }
658 _state.action = _state.verb;
659 } else {
660 // Action>0 ONLY if command has been constructed
661 // Left Mouse Button pressed just do Look At
662 _state.action = VERB_LOOK_AT;
663 _cmdText->setVerb(VERB_LOOK_AT);
664 }
665 }
666 _state.verb = VERB_NONE;
667 } else {
668 if (_cmdText->isEmpty()) {
669 _state.verb = VERB_LOOK_AT;
670 _state.action = VERB_LOOK_AT;
671 _cmdText->setVerb(VERB_LOOK_AT);
672 } else {
673 if (_state.commandLevel == 2 && _parse)
674 _state.verb = _state.action;
675 else
676 _state.verb = State::findDefaultVerb(id->state);
677 if (_state.verb == VERB_NONE) {
678 // No match made, so command not yet completed. Redefine as LOOK AT
679 _state.action = VERB_LOOK_AT;
680 _cmdText->setVerb(VERB_LOOK_AT);
681 } else {
682 _state.action = _state.verb;
683 }
684 _state.verb = VERB_NONE;
685 }
686 }
687
688 grabSelectedObject(-item, id->state, id->name);
689 }
690
grabSelectedNoun()691 void Command::grabSelectedNoun() {
692 ObjectData *od = findObjectData(_state.noun);
693 if (od == NULL || od->name <= 0) {
694 // selected a turned off object, so just walk
695 clear(true);
696 _state.noun = 0;
697 _vm->logic()->joeWalk(JWM_EXECUTE);
698 return;
699 }
700
701 if (_state.verb == VERB_NONE) {
702 if (_mouseKey == Input::MOUSE_LBUTTON) {
703 if ((_state.commandLevel != 2 && _state.action == VERB_NONE) ||
704 (_state.commandLevel == 2 && _parse)) {
705 _state.verb = VERB_WALK_TO;
706 _state.action = VERB_WALK_TO;
707 _cmdText->setVerb(VERB_WALK_TO);
708 }
709 } else if (_mouseKey == Input::MOUSE_RBUTTON) {
710 if (_cmdText->isEmpty()) {
711 _state.verb = State::findDefaultVerb(od->state);
712 _state.selAction = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
713 _cmdText->setVerb(_state.selAction);
714 _cmdText->addObject(_vm->logic()->objectName(od->name));
715 } else {
716 if ((_state.commandLevel == 2 && !_parse) || _state.action != VERB_NONE) {
717 _state.verb = _state.action;
718 } else {
719 _state.verb = State::findDefaultVerb(od->state);
720 }
721 _state.action = (_state.verb == VERB_NONE) ? VERB_WALK_TO : _state.verb;
722 _state.verb = VERB_NONE;
723 }
724 }
725 }
726
727 _state.selNoun = 0;
728 int16 objNum = _vm->logic()->currentRoomData() + _state.noun;
729 grabSelectedObject(objNum, od->state, od->name);
730 }
731
grabSelectedVerb()732 void Command::grabSelectedVerb() {
733 if (isVerbInvScroll(_state.verb)) {
734 // move through inventory (by four if right mouse button)
735 uint16 scroll = (_mouseKey == Input::MOUSE_RBUTTON) ? 4 : 1;
736 _vm->logic()->inventoryScroll(scroll, _state.verb == VERB_SCROLL_UP);
737 } else {
738 _state.action = _state.verb;
739 _state.subject[0] = 0;
740 _state.subject[1] = 0;
741
742 if (_vm->logic()->joeWalk() == JWM_MOVE && _state.verb != VERB_NONE) {
743 _vm->logic()->joeWalk(JWM_NORMAL);
744 }
745 _state.commandLevel = 1;
746 _state.oldVerb = VERB_NONE;
747 _state.oldNoun = 0;
748 _cmdText->setVerb(_state.verb);
749 _cmdText->display(INK_CMD_NORMAL);
750 }
751 }
752
executeIfCutaway(const char * description)753 bool Command::executeIfCutaway(const char *description) {
754 if (strlen(description) > 4 &&
755 scumm_stricmp(description + strlen(description) - 4, ".CUT") == 0) {
756
757 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
758
759 char nextCutaway[20];
760 memset(nextCutaway, 0, sizeof(nextCutaway));
761 _vm->logic()->playCutaway(description, nextCutaway);
762 while (nextCutaway[0] != '\0') {
763 _vm->logic()->playCutaway(nextCutaway, nextCutaway);
764 }
765 return true;
766 }
767 return false;
768 }
769
executeIfDialog(const char * description)770 bool Command::executeIfDialog(const char *description) {
771 if (strlen(description) > 4 &&
772 scumm_stricmp(description + strlen(description) - 4, ".DOG") == 0) {
773
774 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
775
776 char cutaway[20];
777 memset(cutaway, 0, sizeof(cutaway));
778 _vm->logic()->startDialogue(description, _state.selNoun, cutaway);
779
780 while (cutaway[0] != '\0') {
781 char currentCutaway[20];
782 strcpy(currentCutaway, cutaway);
783 _vm->logic()->playCutaway(currentCutaway, cutaway);
784 }
785 return true;
786 }
787 return false;
788 }
789
handleWrongAction()790 bool Command::handleWrongAction() {
791 // l.96-141 execute.c
792 uint16 objMax = _vm->grid()->objMax(_vm->logic()->currentRoom());
793 uint16 roomData = _vm->logic()->currentRoomData();
794
795 // select without a command or WALK TO ; do a WALK
796 if ((_state.selAction == VERB_WALK_TO || _state.selAction == VERB_NONE) &&
797 (_state.selNoun > objMax || _state.selNoun == 0)) {
798 if (_state.selAction == VERB_NONE) {
799 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
800 }
801 _vm->walk()->moveJoe(0, _selPosX, _selPosY, false);
802 return true;
803 }
804
805 // check to see if one of the objects is hidden
806 int i;
807 for (i = 0; i < 2; ++i) {
808 int16 obj = _state.subject[i];
809 if (obj > 0 && _vm->logic()->objectData(obj)->name <= 0) {
810 return true;
811 }
812 }
813
814 // check for USE command on exists
815 if (_state.selAction == VERB_USE &&
816 _state.subject[0] > 0 && _vm->logic()->objectData(_state.subject[0])->entryObj > 0) {
817 _state.selAction = VERB_WALK_TO;
818 }
819
820 if (_state.selNoun > 0 && _state.selNoun <= objMax) {
821 uint16 objNum = roomData + _state.selNoun;
822 if (makeJoeWalkTo(_selPosX, _selPosY, objNum, _state.selAction, true) != 0) {
823 return true;
824 }
825 if (_state.selAction == VERB_WALK_TO && _vm->logic()->objectData(objNum)->entryObj < 0) {
826 return true;
827 }
828 }
829 return false;
830 }
831
sayInvalidAction(Verb action,int16 subj1,int16 subj2)832 void Command::sayInvalidAction(Verb action, int16 subj1, int16 subj2) {
833 // l.158-272 execute.c
834 switch (action) {
835
836 case VERB_LOOK_AT:
837 lookAtSelectedObject();
838 break;
839
840 case VERB_OPEN:
841 // 'it doesn't seem to open'
842 _vm->logic()->makeJoeSpeak(1);
843 break;
844
845 case VERB_USE:
846 if (subj1 < 0) {
847 uint16 k = _vm->logic()->itemData(-subj1)->sfxDescription;
848 if (k > 0) {
849 _vm->logic()->makeJoeSpeak(k, true);
850 } else {
851 _vm->logic()->makeJoeSpeak(2);
852 }
853 } else {
854 _vm->logic()->makeJoeSpeak(2);
855 }
856 break;
857
858 case VERB_TALK_TO:
859 _vm->logic()->makeJoeSpeak(24 + _vm->randomizer.getRandomNumber(2));
860 break;
861
862 case VERB_CLOSE:
863 _vm->logic()->makeJoeSpeak(2);
864 break;
865
866 case VERB_MOVE:
867 // 'I can't move it'
868 if (subj1 > 0) {
869 int16 img = _vm->logic()->objectData(subj1)->image;
870 if (img == -4 || img == -3) {
871 _vm->logic()->makeJoeSpeak(18);
872 } else {
873 _vm->logic()->makeJoeSpeak(3);
874 }
875 } else {
876 _vm->logic()->makeJoeSpeak(3);
877 }
878 break;
879
880 case VERB_GIVE:
881 // 'I can't give the subj1 to subj2'
882 if (subj1 < 0) {
883 if (subj2 > 0) {
884 int16 img = _vm->logic()->objectData(subj2)->image;
885 if (img == -4 || img == -3) {
886 _vm->logic()->makeJoeSpeak(27 + _vm->randomizer.getRandomNumber(2));
887 }
888 } else {
889 _vm->logic()->makeJoeSpeak(11);
890 }
891 } else {
892 _vm->logic()->makeJoeSpeak(12);
893 }
894 break;
895
896 case VERB_PICK_UP:
897 if (subj1 < 0) {
898 _vm->logic()->makeJoeSpeak(14);
899 } else {
900 int16 img = _vm->logic()->objectData(subj1)->image;
901 if (img == -4 || img == -3) {
902 // Trying to get a person
903 _vm->logic()->makeJoeSpeak(20);
904 } else {
905 // 5 : 'I can't pick that up'
906 // 6 : 'I don't think I need that'
907 // 7 : 'I'd rather leave it here'
908 // 8 : 'I don't think I'd have any use for that'
909 _vm->logic()->makeJoeSpeak(5 + _vm->randomizer.getRandomNumber(3));
910 }
911 }
912 break;
913
914 default:
915 break;
916 }
917 }
918
changeObjectState(Verb action,int16 obj,int16 song,bool cutDone)919 void Command::changeObjectState(Verb action, int16 obj, int16 song, bool cutDone) {
920 // l.456-533 execute.c
921 ObjectData *objData = _vm->logic()->objectData(obj);
922
923 if (action == VERB_OPEN && !cutDone) {
924 if (State::findOn(objData->state) == STATE_ON_ON) {
925 State::alterOn(&objData->state, STATE_ON_OFF);
926 State::alterDefaultVerb(&objData->state, VERB_NONE);
927
928 // play music if it exists... (or SFX for open/close door)
929 if (song != 0) {
930 _vm->sound()->playSong(ABS(song));
931 }
932
933 if (objData->entryObj != 0) {
934 // if it's a door, then update door that it links to
935 openOrCloseAssociatedObject(action, ABS(objData->entryObj));
936 objData->entryObj = ABS(objData->entryObj);
937 }
938 } else {
939 // 'it's already open !'
940 _vm->logic()->makeJoeSpeak(9);
941 }
942 } else if (action == VERB_CLOSE && !cutDone) {
943 if (State::findOn(objData->state) == STATE_ON_OFF) {
944 State::alterOn(&objData->state, STATE_ON_ON);
945 State::alterDefaultVerb(&objData->state, VERB_OPEN);
946
947 // play music if it exists... (or SFX for open/close door)
948 if (song != 0) {
949 _vm->sound()->playSong(ABS(song));
950 }
951
952 if (objData->entryObj != 0) {
953 // if it's a door, then update door that it links to
954 openOrCloseAssociatedObject(action, ABS(objData->entryObj));
955 objData->entryObj = -ABS(objData->entryObj);
956 }
957 } else {
958 // 'it's already closed !'
959 _vm->logic()->makeJoeSpeak(10);
960 }
961 } else if (action == VERB_MOVE) {
962 State::alterOn(&objData->state, STATE_ON_OFF);
963 }
964 }
965
cleanupCurrentAction()966 void Command::cleanupCurrentAction() {
967 // l.595-597 execute.c
968 _vm->logic()->joeFace();
969 _state.oldNoun = 0;
970 _state.oldVerb = VERB_NONE;
971 }
972
openOrCloseAssociatedObject(Verb action,int16 otherObj)973 void Command::openOrCloseAssociatedObject(Verb action, int16 otherObj) {
974 CmdListData *cmdList = &_cmdList[1];
975 uint16 com = 0;
976 uint16 i;
977 for (i = 1; i <= _numCmdList && com == 0; ++i, ++cmdList) {
978 if (cmdList->match(action, otherObj, 0)) {
979 if (cmdList->setConditions) {
980 CmdGameState *cmdGs = _cmdGameState;
981 uint16 j;
982 for (j = 1; j <= _numCmdGameState; ++j) {
983 if (cmdGs[j].id == i && cmdGs[j].gameStateSlot > 0) {
984 if (_vm->logic()->gameState(cmdGs[j].gameStateSlot) == cmdGs[j].gameStateValue) {
985 com = i;
986 break;
987 }
988 }
989 }
990 } else {
991 com = i;
992 break;
993 }
994 }
995 }
996
997 if (com != 0) {
998
999 debug(6, "Command::openOrCloseAssociatedObject() com=%X", com);
1000
1001 cmdList = &_cmdList[com];
1002 ObjectData *objData = _vm->logic()->objectData(otherObj);
1003
1004 if (cmdList->imageOrder != 0) {
1005 objData->image = cmdList->imageOrder;
1006 }
1007
1008 if (action == VERB_OPEN) {
1009 if (State::findOn(objData->state) == STATE_ON_ON) {
1010 State::alterOn(&objData->state, STATE_ON_OFF);
1011 State::alterDefaultVerb(&objData->state, VERB_NONE);
1012 objData->entryObj = ABS(objData->entryObj);
1013 }
1014 } else if (action == VERB_CLOSE) {
1015 if (State::findOn(objData->state) == STATE_ON_OFF) {
1016 State::alterOn(&objData->state, STATE_ON_ON);
1017 State::alterDefaultVerb(&objData->state, VERB_OPEN);
1018 objData->entryObj = -ABS(objData->entryObj);
1019 }
1020 }
1021 }
1022 }
1023
setConditions(uint16 command,bool lastCmd)1024 int16 Command::setConditions(uint16 command, bool lastCmd) {
1025 debug(9, "Command::setConditions(%d, %d)", command, lastCmd);
1026
1027 int16 ret = 0;
1028 uint16 cmdState[21];
1029 memset(cmdState, 0, sizeof(cmdState));
1030 uint16 cmdStateCount = 0;
1031 uint16 i;
1032 CmdGameState *cmdGs = &_cmdGameState[1];
1033 for (i = 1; i <= _numCmdGameState; ++i, ++cmdGs) {
1034 if (cmdGs->id == command) {
1035 if (cmdGs->gameStateSlot > 0) {
1036 if (_vm->logic()->gameState(cmdGs->gameStateSlot) != cmdGs->gameStateValue) {
1037 debug(6, "Command::setConditions() - GS[%d] == %d (should be %d)", cmdGs->gameStateSlot, _vm->logic()->gameState(cmdGs->gameStateSlot), cmdGs->gameStateValue);
1038 // failed test
1039 ret = i;
1040 break;
1041 }
1042 } else {
1043 cmdState[cmdStateCount] = i;
1044 ++cmdStateCount;
1045 }
1046 }
1047 }
1048
1049 if (ret > 0) {
1050 // we've failed, so see if we need to make Joe speak
1051 cmdGs = &_cmdGameState[ret];
1052 if (cmdGs->speakValue > 0 && lastCmd) {
1053 // check to see if fail state is in fact a cutaway
1054 const char *objDesc = _vm->logic()->objectTextualDescription(cmdGs->speakValue);
1055 if (!executeIfCutaway(objDesc) && !executeIfDialog(objDesc)) {
1056 _vm->logic()->makeJoeSpeak(cmdGs->speakValue, true);
1057 }
1058 ret = -2;
1059 } else {
1060 // return -1 so Joe will be able to speak a normal description
1061 ret = -1;
1062 }
1063 } else {
1064 ret = 0;
1065 // all tests were okay, now set gamestates
1066 for (i = 0; i < cmdStateCount; ++i) {
1067 cmdGs = &_cmdGameState[cmdState[i]];
1068 _vm->logic()->gameState(ABS(cmdGs->gameStateSlot), cmdGs->gameStateValue);
1069 // set return value for Joe to say something
1070 ret = cmdGs->speakValue;
1071 }
1072 }
1073 return ret;
1074 }
1075
setAreas(uint16 command)1076 void Command::setAreas(uint16 command) {
1077 debug(9, "Command::setAreas(%d)", command);
1078
1079 CmdArea *cmdArea = &_cmdArea[1];
1080 for (uint16 i = 1; i <= _numCmdArea; ++i, ++cmdArea) {
1081 if (cmdArea->id == command) {
1082 uint16 areaNum = ABS(cmdArea->area);
1083 Area *area = _vm->grid()->area(cmdArea->room, areaNum);
1084 if (cmdArea->area > 0) {
1085 // turn on area
1086 area->mapNeighbors = ABS(area->mapNeighbors);
1087 } else {
1088 // turn off area
1089 area->mapNeighbors = -ABS(area->mapNeighbors);
1090 }
1091 }
1092 }
1093 }
1094
setObjects(uint16 command)1095 void Command::setObjects(uint16 command) {
1096 debug(9, "Command::setObjects(%d)", command);
1097
1098 CmdObject *cmdObj = &_cmdObject[1];
1099 for (uint16 i = 1; i <= _numCmdObject; ++i, ++cmdObj) {
1100 if (cmdObj->id == command) {
1101
1102 // found an object
1103 uint16 dstObj = ABS(cmdObj->dstObj);
1104 ObjectData *objData = _vm->logic()->objectData(dstObj);
1105
1106 debug(6, "Command::setObjects() - dstObj=%X srcObj=%X _state.subject[0]=%X", cmdObj->dstObj, cmdObj->srcObj, _state.subject[0]);
1107
1108 if (cmdObj->dstObj > 0) {
1109 // show the object
1110 objData->name = ABS(objData->name);
1111 // test that the object has not already been deleted
1112 // by checking if it is not equal to zero
1113 if (cmdObj->srcObj == -1 && objData->name != 0) {
1114 // delete object by setting its name to 0 and
1115 // turning off graphic image
1116 objData->name = 0;
1117 if (objData->room == _vm->logic()->currentRoom()) {
1118 if (dstObj != _state.subject[0]) {
1119 // if the new object we have updated is on screen and is not the
1120 // current object, then we can update. This is because we turn
1121 // current object off ourselves by COM_LIST(com, 8)
1122 if (objData->image != -3 && objData->image != -4) {
1123 // it is a normal object (not a person)
1124 // turn the graphic image off for the object
1125 objData->image = -(objData->image + 10);
1126 }
1127 }
1128 // invalidate object area
1129 uint16 objZone = dstObj - _vm->logic()->currentRoomData();
1130 _vm->grid()->setZone(GS_ROOM, objZone, 0, 0, 1, 1);
1131 }
1132 }
1133
1134 if (cmdObj->srcObj > 0) {
1135 // copy data from dummy object to object
1136 int16 image1 = objData->image;
1137 int16 image2 = _vm->logic()->objectData(cmdObj->srcObj)->image;
1138 _vm->logic()->objectCopy(cmdObj->srcObj, dstObj);
1139 if (image1 != 0 && image2 == 0 && objData->room == _vm->logic()->currentRoom()) {
1140 uint16 bobNum = _vm->logic()->findBob(dstObj);
1141 if (bobNum != 0) {
1142 _vm->graphics()->clearBob(bobNum);
1143 }
1144 }
1145 }
1146
1147 if (dstObj != _state.subject[0]) {
1148 // if the new object we have updated is on screen and
1149 // is not current object then update it
1150 _vm->graphics()->refreshObject(dstObj);
1151 }
1152 } else {
1153 // hide the object
1154 if (objData->name > 0) {
1155 objData->name = -objData->name;
1156 // may need to turn BOBs off for objects to be hidden on current
1157 // screen ! if the new object we have updated is on screen and
1158 // is not current object then update it
1159 _vm->graphics()->refreshObject(dstObj);
1160 }
1161 }
1162 }
1163 }
1164 }
1165
setItems(uint16 command)1166 void Command::setItems(uint16 command) {
1167 debug(9, "Command::setItems(%d)", command);
1168
1169 ItemData *items = _vm->logic()->itemData(0);
1170 CmdInventory *cmdInv = &_cmdInventory[1];
1171 for (uint16 i = 1; i <= _numCmdInventory; ++i, ++cmdInv) {
1172 if (cmdInv->id == command) {
1173 uint16 dstItem = ABS(cmdInv->dstItem);
1174 // found an item
1175 if (cmdInv->dstItem > 0) {
1176 // add item to inventory
1177 if (cmdInv->srcItem > 0) {
1178 // copy data from source item to item, then enable it
1179 items[dstItem] = items[cmdInv->srcItem];
1180 items[dstItem].name = ABS(items[dstItem].name);
1181 }
1182 _vm->logic()->inventoryInsertItem(cmdInv->dstItem);
1183 } else {
1184 // delete item
1185 if (items[dstItem].name > 0) {
1186 _vm->logic()->inventoryDeleteItem(dstItem);
1187 }
1188 if (cmdInv->srcItem > 0) {
1189 // copy data from source item to item, then disable it
1190 items[dstItem] = items[cmdInv->srcItem];
1191 items[dstItem].name = -ABS(items[dstItem].name);
1192 }
1193 }
1194 }
1195 }
1196 }
1197
nextObjectDescription(ObjectDescription * objDesc,uint16 firstDesc)1198 uint16 Command::nextObjectDescription(ObjectDescription* objDesc, uint16 firstDesc) {
1199 // l.69-103 select.c
1200 uint16 i;
1201 uint16 diff = objDesc->lastDescription - firstDesc;
1202 debug(6, "Command::nextObjectDescription() - diff = %d, type = %d", diff, objDesc->type);
1203 switch (objDesc->type) {
1204 case 0:
1205 // random type, start with first description
1206 if (objDesc->lastSeenNumber == 0) {
1207 // first time look at called
1208 objDesc->lastSeenNumber = firstDesc;
1209 break;
1210 }
1211 // already displayed first, do a random
1212 // fall through
1213 case 1:
1214 i = objDesc->lastSeenNumber;
1215 while (i == objDesc->lastSeenNumber) {
1216 i = firstDesc + _vm->randomizer.getRandomNumber(diff);
1217 }
1218 objDesc->lastSeenNumber = i;
1219 break;
1220 case 2:
1221 // sequential, but loop
1222 ++objDesc->lastSeenNumber;
1223 if (objDesc->lastSeenNumber > objDesc->lastDescription) {
1224 objDesc->lastSeenNumber = firstDesc;
1225 }
1226 break;
1227 case 3:
1228 // sequential without looping
1229 if (objDesc->lastSeenNumber != objDesc->lastDescription) {
1230 ++objDesc->lastSeenNumber;
1231 }
1232 break;
1233 default:
1234 break;
1235 }
1236 return objDesc->lastSeenNumber;
1237 }
1238
lookAtSelectedObject()1239 void Command::lookAtSelectedObject() {
1240 uint16 desc;
1241 if (_state.subject[0] < 0) {
1242 desc = _vm->logic()->itemData(-_state.subject[0])->description;
1243 } else {
1244 ObjectData *objData = _vm->logic()->objectData(_state.subject[0]);
1245 if (objData->name <= 0) {
1246 return;
1247 }
1248 desc = objData->description;
1249 }
1250
1251 debug(6, "Command::lookAtSelectedObject() - desc = %X, _state.subject[0] = %X", desc, _state.subject[0]);
1252
1253 // check to see if the object/item has a series of description
1254 ObjectDescription *objDesc = _vm->logic()->objectDescription(1);
1255 uint16 i;
1256 for (i = 1; i <= _vm->logic()->objectDescriptionCount(); ++i, ++objDesc) {
1257 if (objDesc->object == _state.subject[0]) {
1258 desc = nextObjectDescription(objDesc, desc);
1259 break;
1260 }
1261 }
1262 if (desc != 0) {
1263 _vm->logic()->makeJoeSpeak(desc, true);
1264 }
1265 _vm->logic()->joeFace();
1266 }
1267
lookForCurrentObject(int16 cx,int16 cy)1268 void Command::lookForCurrentObject(int16 cx, int16 cy) {
1269 uint16 obj = _vm->grid()->findObjectUnderCursor(cx, cy);
1270 _state.noun = _vm->grid()->findObjectNumber(obj);
1271
1272 if (_state.oldNoun == _state.noun) {
1273 return;
1274 }
1275
1276 ObjectData *od = findObjectData(_state.noun);
1277 if (od == NULL || od->name <= 0) {
1278 _state.oldNoun = _state.noun;
1279 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
1280 if (_state.action != VERB_NONE) {
1281 _cmdText->display(INK_CMD_NORMAL);
1282 }
1283 return;
1284 }
1285
1286 // if no command yet selected, then use DEFAULT command, if any
1287 if (_state.action == VERB_NONE) {
1288 Verb v = State::findDefaultVerb(od->state);
1289 _cmdText->setVerb((v == VERB_NONE) ? VERB_WALK_TO : v);
1290 if (_state.noun == 0) {
1291 _cmdText->clear();
1292 }
1293 }
1294 const char *name = _vm->logic()->objectName(od->name);
1295 _cmdText->displayTemp(INK_CMD_NORMAL, name, false);
1296 _state.oldNoun = _state.noun;
1297 }
1298
lookForCurrentIcon(int16 cx,int16 cy)1299 void Command::lookForCurrentIcon(int16 cx, int16 cy) {
1300 _state.verb = _vm->grid()->findVerbUnderCursor(cx, cy);
1301 if (_state.oldVerb != _state.verb) {
1302
1303 if (_state.action == VERB_NONE) {
1304 _cmdText->clear();
1305 }
1306 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
1307
1308 if (isVerbInv(_state.verb)) {
1309 ItemData *id = findItemData(_state.verb);
1310 if (id != NULL && id->name > 0) {
1311 if (_state.action == VERB_NONE) {
1312 Verb v = State::findDefaultVerb(id->state);
1313 _cmdText->setVerb((v == VERB_NONE) ? VERB_LOOK_AT : v);
1314 }
1315 const char *name = _vm->logic()->objectName(id->name);
1316 _cmdText->displayTemp(INK_CMD_NORMAL, name, false);
1317 }
1318 } else if (isVerbAction(_state.verb)) {
1319 _cmdText->displayTemp(INK_CMD_NORMAL, _state.verb);
1320 } else if (_state.verb == VERB_NONE) {
1321 _cmdText->display(INK_CMD_NORMAL);
1322 }
1323 _state.oldVerb = _state.verb;
1324 }
1325 }
1326
1327 } // End of namespace Queen
1328