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 * This code is based on original Hugo Trilogy source code
25 *
26 * Copyright (c) 1989-1995 David P. Gray
27 *
28 */
29
30 // parser.c - handles all keyboard/command input
31
32 #include "common/debug.h"
33
34 #include "hugo/hugo.h"
35 #include "hugo/parser.h"
36 #include "hugo/file.h"
37 #include "hugo/schedule.h"
38 #include "hugo/route.h"
39 #include "hugo/display.h"
40 #include "hugo/util.h"
41 #include "hugo/sound.h"
42 #include "hugo/object.h"
43 #include "hugo/text.h"
44 #include "hugo/inventory.h"
45
46 namespace Hugo {
Parser_v1w(HugoEngine * vm)47 Parser_v1w::Parser_v1w(HugoEngine *vm) : Parser_v3d(vm) {
48 }
49
~Parser_v1w()50 Parser_v1w::~Parser_v1w() {
51 }
52
53 /**
54 * Parse the user's line of text input. Generate events as necessary
55 */
lineHandler()56 void Parser_v1w::lineHandler() {
57 debugC(1, kDebugParser, "lineHandler()");
58
59 Status &gameStatus = _vm->getGameStatus();
60
61 // Toggle God Mode
62 if (!strncmp(_vm->_line, "PPG", 3)) {
63 _vm->_sound->playSound(!_vm->_soundTest, kSoundPriorityHigh);
64 gameStatus._godModeFl = !gameStatus._godModeFl;
65 return;
66 }
67
68 Utils::strlwr(_vm->_line); // Convert to lower case
69
70 // God Mode cheat commands:
71 // goto <screen> Takes hero to named screen
72 // fetch <object name> Hero carries named object
73 // fetch all Hero carries all possible objects
74 // find <object name> Takes hero to screen containing named object
75 if (gameStatus._godModeFl) {
76 // Special code to allow me to go straight to any screen
77 if (strstr(_vm->_line, "goto")) {
78 for (int i = 0; i < _vm->_numScreens; i++) {
79 if (!scumm_stricmp(&_vm->_line[strlen("goto") + 1], _vm->_text->getScreenNames(i))) {
80 _vm->_scheduler->newScreen(i);
81 return;
82 }
83 }
84 }
85
86 // Special code to allow me to get objects from anywhere
87 if (strstr(_vm->_line, "fetch all")) {
88 for (int i = 0; i < _vm->_object->_numObj; i++) {
89 if (_vm->_object->_objects[i]._genericCmd & TAKE)
90 takeObject(&_vm->_object->_objects[i]);
91 }
92 return;
93 }
94
95 if (strstr(_vm->_line, "fetch")) {
96 for (int i = 0; i < _vm->_object->_numObj; i++) {
97 if (!scumm_stricmp(&_vm->_line[strlen("fetch") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) {
98 takeObject(&_vm->_object->_objects[i]);
99 return;
100 }
101 }
102 }
103
104 // Special code to allow me to goto objects
105 if (strstr(_vm->_line, "find")) {
106 for (int i = 0; i < _vm->_object->_numObj; i++) {
107 if (!scumm_stricmp(&_vm->_line[strlen("find") + 1], _vm->_text->getNoun(_vm->_object->_objects[i]._nounIndex, 0))) {
108 _vm->_scheduler->newScreen(_vm->_object->_objects[i]._screenIndex);
109 return;
110 }
111 }
112 }
113 }
114
115 // Special meta commands
116 // EXIT/QUIT
117 if (!strcmp("exit", _vm->_line) || strstr(_vm->_line, "quit")) {
118 if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d)))
119 _vm->endGame();
120 return;
121 }
122
123 // SAVE/RESTORE
124 if (!strcmp("save", _vm->_line) && gameStatus._viewState == kViewPlay) {
125 _vm->_file->saveGame(-1, Common::String());
126 return;
127 }
128
129 if (!strcmp("restore", _vm->_line) && (gameStatus._viewState == kViewPlay || gameStatus._viewState == kViewIdle)) {
130 _vm->_file->restoreGame(-1);
131 return;
132 }
133
134 // Empty line
135 if (*_vm->_line == '\0') // Empty line
136 return;
137 if (strspn(_vm->_line, " ") == strlen(_vm->_line)) // Nothing but spaces!
138 return;
139
140 if (gameStatus._gameOverFl) {
141 // No commands allowed!
142 _vm->gameOverMsg();
143 return;
144 }
145
146 char farComment[kCompLineSize * 5] = ""; // hold 5 line comment if object not nearby
147
148 // Test for nearby objects referenced explicitly
149 for (int i = 0; i < _vm->_object->_numObj; i++) {
150 Object *obj = &_vm->_object->_objects[i];
151 if (isWordPresent(_vm->_text->getNounArray(obj->_nounIndex))) {
152 if (isObjectVerb_v3(obj, farComment) || isGenericVerb_v3(obj, farComment))
153 return;
154 }
155 }
156
157 // Test for nearby objects that only require a verb
158 // Note comment is unused if not near.
159 for (int i = 0; i < _vm->_object->_numObj; i++) {
160 Object *obj = &_vm->_object->_objects[i];
161 if (obj->_verbOnlyFl) {
162 char contextComment[kCompLineSize * 5] = ""; // Unused comment for context objects
163 if (isObjectVerb_v3(obj, contextComment) || isGenericVerb_v3(obj, contextComment))
164 return;
165 }
166 }
167
168 // No objects match command line, try background and catchall commands
169 if (isBackgroundWord_v3(_backgroundObjects[*_vm->_screenPtr]))
170 return;
171 if (isCatchallVerb_v3(_backgroundObjects[*_vm->_screenPtr]))
172 return;
173
174 if (isBackgroundWord_v3(_catchallList))
175 return;
176 if (isCatchallVerb_v3(_catchallList))
177 return;
178
179 // If a not-near comment was generated, print it
180 if (*farComment != '\0') {
181 Utils::notifyBox(farComment);
182 return;
183 }
184
185 // Nothing matches. Report recognition success to user.
186 const char *verb = findVerb();
187 const char *noun = findNoun();
188 if (verb == _vm->_text->getVerb(_vm->_look, 0) && _vm->_maze._enabledFl) {
189 Utils::notifyBox(_vm->_text->getTextParser(kTBMaze));
190 _vm->_object->showTakeables();
191 } else if (verb && noun) { // A combination I didn't think of
192 Utils::notifyBox(_vm->_text->getTextParser(kTBNoPoint));
193 } else if (noun) {
194 Utils::notifyBox(_vm->_text->getTextParser(kTBNoun));
195 } else if (verb) {
196 Utils::notifyBox(_vm->_text->getTextParser(kTBVerb));
197 } else {
198 Utils::notifyBox(_vm->_text->getTextParser(kTBEh));
199 }
200 }
201
showInventory() const202 void Parser_v1w::showInventory() const {
203 Status &gameStatus = _vm->getGameStatus();
204 Istate inventState = _vm->_inventory->getInventoryState();
205 if (gameStatus._gameOverFl) {
206 _vm->gameOverMsg();
207 } else if ((inventState == kInventoryOff) && (gameStatus._viewState == kViewPlay)) {
208 _vm->_inventory->setInventoryState(kInventoryDown);
209 gameStatus._viewState = kViewInvent;
210 } else if (inventState == kInventoryActive) {
211 _vm->_inventory->setInventoryState(kInventoryUp);
212 gameStatus._viewState = kViewInvent;
213 }
214 }
215
216 } // End of namespace Hugo
217