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