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 #include "mutationofjb/debug.h"
24 #include "mutationofjb/game.h"
25 #include "mutationofjb/gamedata.h"
26 #include "mutationofjb/inventory.h"
27 #include "mutationofjb/mutationofjb.h"
28 #include "mutationofjb/script.h"
29 #include "mutationofjb/commands/command.h"
30 #include "mutationofjb/commands/seqcommand.h"
31 #include "mutationofjb/commands/conditionalcommand.h"
32 #include "mutationofjb/commands/callmacrocommand.h"
33 #include "mutationofjb/commands/randomcommand.h"
34 #include "common/debug-channels.h"
35 #include "common/scummsys.h"
36 
37 namespace MutationOfJB {
38 
39 /* Converts CP895 string to 7bit ASCII, so we can show it in the console. */
convertToASCII(const Common::String & str)40 static Common::String convertToASCII(const Common::String &str) {
41 	static const char conversionTable[] = {
42 		'C', 'u', 'e', 'd', 'a', 'D', 'T', 'c', 'e', 'E', 'L', 'I', 'l', 'l', 'A', 'A', /* 0x80-0x8F */
43 		'E', 'z', 'Z', 'o', 'o', 'O', 'u', 'U', 'y', 'O', 'U', 'S', 'L', 'Y', 'R', 't', /* 0x90-0x9F */
44 		'a', 'i', 'o', 'u', 'n', 'N', 'U', 'O', 's', 'r', 'r', 'R'                      /* 0xA0-0xAB */
45 	};
46 
47 	Common::String ret = str;
48 	for (Common::String::iterator it = ret.begin(); it != ret.end(); ++it) {
49 		const byte cp895Byte = reinterpret_cast<const byte &>(*it);
50 		if (cp895Byte >= 0x80 && cp895Byte <= 0xAB) {
51 			*it = conversionTable[cp895Byte - 0x80];
52 		} else if (cp895Byte == 0xE1) { // ß
53 			*it = 's';
54 		}
55 	}
56 	return ret;
57 }
58 
Console(MutationOfJBEngine * vm)59 Console::Console(MutationOfJBEngine *vm) : _vm(vm) {
60 	registerCmd("showallcommands", WRAP_METHOD(Console, cmd_showallcommands));
61 	registerCmd("listsections", WRAP_METHOD(Console, cmd_listsections));
62 	registerCmd("showsection", WRAP_METHOD(Console, cmd_showsection));
63 	registerCmd("listmacros", WRAP_METHOD(Console, cmd_listmacros));
64 	registerCmd("showmacro", WRAP_METHOD(Console, cmd_showmacro));
65 	registerCmd("liststartups", WRAP_METHOD(Console, cmd_liststartups));
66 	registerCmd("showstartup", WRAP_METHOD(Console, cmd_showstartup));
67 	registerCmd("changescene", WRAP_METHOD(Console, cmd_changescene));
68 	registerCmd("dumpsceneinfo", WRAP_METHOD(Console, cmd_dumpsceneinfo));
69 	registerCmd("dumpdoorinfo", WRAP_METHOD(Console, cmd_dumpdoorinfo));
70 	registerCmd("dumpobjectinfo", WRAP_METHOD(Console, cmd_dumpobjectinfo));
71 	registerCmd("dumpstaticinfo", WRAP_METHOD(Console, cmd_dumpstaticinfo));
72 	registerCmd("dumpbitmapinfo", WRAP_METHOD(Console, cmd_dumpbitmapinfo));
73 	registerCmd("listinventory", WRAP_METHOD(Console, cmd_listinventory));
74 }
75 
cmd_showallcommands(int argc,const char ** argv)76 bool Console::cmd_showallcommands(int argc, const char **argv) {
77 	if (argc == 2) {
78 		Script *const script = getScriptFromArg(argv[1]);
79 		if (script) {
80 			const Commands &commands = script->getAllCommands();
81 
82 			for (Commands::const_iterator it = commands.begin(); it != commands.end(); ++it) {
83 				debugPrintf("%s\n", convertToASCII((*it)->debugString()).c_str());
84 			}
85 		}
86 	} else {
87 		debugPrintf("showallcommands <G|L>\n");
88 	}
89 
90 	return true;
91 }
92 
cmd_listsections(int argc,const char ** argv)93 bool Console::cmd_listsections(int argc, const char **argv) {
94 	if (argc == 3) {
95 		Script *const script = getScriptFromArg(argv[1]);
96 		if (script) {
97 			ActionInfo::Action action = ActionInfo::Look;
98 			const char *word = nullptr;
99 			if (strcmp(argv[2], "L") == 0) {
100 				action = ActionInfo::Look;
101 				word = "Look";
102 			} else if (strcmp(argv[2], "W") == 0) {
103 				action = ActionInfo::Walk;
104 				word = "Walk";
105 			} else if (strcmp(argv[2], "T") == 0) {
106 				action = ActionInfo::Talk;
107 				word = "Talk";
108 			} else if (strcmp(argv[2], "U") == 0) {
109 				action = ActionInfo::Use;
110 				word = "Use";
111 			} else if (strcmp(argv[2], "P") == 0) {
112 				action = ActionInfo::PickUp;
113 				word = "Pick up";
114 			} else {
115 				debugPrintf("Choose 'L' (look), 'W' (walk), 'T' (talk), 'U' (use) or 'P' (pick up).\n");
116 			}
117 			if (word) {
118 				const ActionInfos &actionInfos = script->getActionInfos(action);
119 				for (ActionInfos::const_iterator it = actionInfos.begin(); it != actionInfos.end(); ++it) {
120 					const ActionInfo &actionInfo = *it;
121 					if (action != ActionInfo::Use || actionInfo._entity2Name.empty()) {
122 						debugPrintf("%s %s\n", word, convertToASCII(actionInfo._entity1Name).c_str());
123 					} else {
124 						debugPrintf("%s %s %s\n", word, convertToASCII(actionInfo._entity1Name).c_str(), convertToASCII(actionInfo._entity2Name).c_str());
125 					}
126 				}
127 			}
128 		}
129 	} else {
130 		debugPrintf("listsections <G|L> <L|W|T|U|P>\n");
131 	}
132 	return true;
133 }
134 
showIndent(int indentLevel)135 void Console::showIndent(int indentLevel) {
136 	for (int i = 0; i < indentLevel; ++i) {
137 		debugPrintf("  ");
138 	}
139 }
140 
showCommands(Command * command,int indentLevel)141 void Console::showCommands(Command *command, int indentLevel) {
142 	while (command) {
143 		showIndent(indentLevel);
144 		debugPrintf("%s\n", convertToASCII(command->debugString()).c_str());
145 
146 		if (SeqCommand *const seqCmd = dynamic_cast<SeqCommand *>(command)) {
147 			command = seqCmd->next();
148 		} else if (ConditionalCommand *const condCmd = dynamic_cast<ConditionalCommand *>(command)) {
149 			showCommands(condCmd->getTrueCommand(), indentLevel + 1);
150 			showIndent(indentLevel);
151 			debugPrintf("ELSE\n");
152 			showCommands(condCmd->getFalseCommand(), indentLevel + 1);
153 			command = nullptr;
154 		} else if (CallMacroCommand *const callMacroCmd = dynamic_cast<CallMacroCommand *>(command)) {
155 			command = callMacroCmd->getReturnCommand();
156 		} else if (RandomCommand *const randomCmd = dynamic_cast<RandomCommand *>(command)) {
157 			const RandomCommand::Choices &choices = randomCmd->getChoices();
158 			for (RandomCommand::Choices::size_type i = 0; i < choices.size(); ++i) {
159 				showIndent(indentLevel + 1);
160 				debugPrintf("CASE %u\n", i);
161 				showCommands(choices[i], indentLevel + 2);
162 			}
163 			command = nullptr;
164 		} else {
165 			command = nullptr;
166 		}
167 	}
168 }
169 
cmd_showsection(int argc,const char ** argv)170 bool Console::cmd_showsection(int argc, const char **argv) {
171 	if (argc >= 4) {
172 		Script *const script = getScriptFromArg(argv[1]);
173 		if (script) {
174 			Command *command = nullptr;
175 			ActionInfo::Action action = ActionInfo::Look;
176 			bool correctAction = true;
177 			bool found = false;
178 
179 			if (strcmp(argv[2], "L") == 0) {
180 				action = ActionInfo::Look;
181 			} else if (strcmp(argv[2], "W") == 0) {
182 				action = ActionInfo::Walk;
183 			} else if (strcmp(argv[2], "T") == 0) {
184 				action = ActionInfo::Talk;
185 			} else if (strcmp(argv[2], "U") == 0) {
186 				action = ActionInfo::Use;
187 			} else if (strcmp(argv[2], "P") == 0) {
188 				action = ActionInfo::PickUp;
189 			} else {
190 				debugPrintf("Choose 'L' (look), 'W' (walk), 'T' (talk), 'U' (use) or 'P' (pick up).\n");
191 				correctAction = false;
192 			}
193 
194 			if (correctAction) {
195 				const ActionInfos &actionInfos = script->getActionInfos(action);
196 				for (ActionInfos::const_iterator it = actionInfos.begin(); it != actionInfos.end(); ++it) {
197 					const ActionInfo &actionInfo = *it;
198 					if (convertToASCII(actionInfo._entity1Name) == argv[3] && (action != ActionInfo::Use || ((argc == 4 && actionInfo._entity2Name.empty()) || (argc > 4 && convertToASCII(actionInfo._entity2Name) == argv[4])))) {
199 						found = true;
200 						command = actionInfo._command;
201 						break;
202 					}
203 				}
204 
205 				if (found) {
206 					if (command) {
207 						showCommands(command);
208 					}
209 				} else {
210 					debugPrintf("Section not found.\n");
211 				}
212 			}
213 		}
214 	} else {
215 		debugPrintf("showsection <G|L> <L|W|T|U|P> <sectionname>\n");
216 	}
217 
218 	return true;
219 }
220 
cmd_listmacros(int argc,const char ** argv)221 bool Console::cmd_listmacros(int argc, const char **argv) {
222 	if (argc == 2) {
223 		Script *const script = getScriptFromArg(argv[1]);
224 		if (script) {
225 			const Macros &macros = script->getMacros();
226 			for (Macros::const_iterator it = macros.begin(); it != macros.end(); ++it) {
227 				debugPrintf("%s\n", it->_key.c_str());
228 			}
229 		}
230 	} else {
231 		debugPrintf("listmacros <G|L>\n");
232 	}
233 
234 	return true;
235 }
236 
cmd_showmacro(int argc,const char ** argv)237 bool Console::cmd_showmacro(int argc, const char **argv) {
238 	if (argc == 3) {
239 		Script *script = nullptr;
240 		if (strcmp(argv[1], "G") == 0) {
241 			script = _vm->getGame().getGlobalScript();
242 		} else if (strcmp(argv[1], "L") == 0) {
243 			script = _vm->getGame().getLocalScript();
244 		}
245 		if (!script) {
246 			debugPrintf("Choose 'G' (global) or 'L' (local) script.\n");
247 		} else {
248 			const Macros &macros = script->getMacros();
249 			Macros::const_iterator itMacro = macros.find(argv[2]);
250 			if (itMacro != macros.end()) {
251 				if (itMacro->_value) {
252 					showCommands(itMacro->_value);
253 				}
254 			} else {
255 				debugPrintf("Macro not found.\n");
256 			}
257 		}
258 	} else {
259 		debugPrintf("showmacro <G|L> <macroname>\n");
260 	}
261 
262 	return true;
263 }
264 
cmd_liststartups(int argc,const char ** argv)265 bool Console::cmd_liststartups(int argc, const char **argv) {
266 	if (argc == 2) {
267 		Script *const script = getScriptFromArg(argv[1]);
268 		if (script) {
269 			const Startups &startups = script->getStartups();
270 			for (Startups::const_iterator it = startups.begin(); it != startups.end(); ++it) {
271 				debugPrintf("%u\n", (unsigned int) it->_key);
272 			}
273 		}
274 	} else {
275 		debugPrintf("liststartups <G|L>\n");
276 	}
277 
278 	return true;
279 }
280 
cmd_showstartup(int argc,const char ** argv)281 bool Console::cmd_showstartup(int argc, const char **argv) {
282 	if (argc == 3) {
283 		Script *const script = getScriptFromArg(argv[1]);
284 		if (script) {
285 			const Startups &startups = script->getStartups();
286 			Startups::const_iterator itMacro = startups.find(static_cast<uint8>(atoi(argv[2])));
287 			if (itMacro != startups.end()) {
288 				if (itMacro->_value) {
289 					showCommands(itMacro->_value);
290 				}
291 			} else {
292 				debugPrintf("Startup not found.\n");
293 			}
294 		}
295 	} else {
296 		debugPrintf("showstartup <G|L> <startupid>\n");
297 	}
298 
299 	return true;
300 }
301 
cmd_changescene(int argc,const char ** argv)302 bool Console::cmd_changescene(int argc, const char **argv) {
303 	if (argc == 2) {
304 		const uint8 sceneId = atoi(argv[1]);
305 		const bool partB = argv[1][strlen(argv[1]) - 1] == 'B';
306 
307 		_vm->getGame().changeScene(sceneId, partB);
308 	} else {
309 		debugPrintf("changescene <scenename>\n");
310 	}
311 
312 	return true;
313 }
314 
cmd_dumpsceneinfo(int argc,const char ** argv)315 bool Console::cmd_dumpsceneinfo(int argc, const char **argv) {
316 	uint8 sceneId = _vm->getGame().getGameData()._currentScene;
317 
318 	if (argc == 2) {
319 		sceneId = atoi(argv[1]);
320 	} else if (argc != 1) {
321 		debugPrintf("dumpsceneinfo [<sceneid>]\n");
322 	}
323 
324 	if (Scene *const scene = _vm->getGame().getGameData().getScene(sceneId)) {
325 		debugPrintf("Scene ID: %u\n", (unsigned int) sceneId);
326 		debugPrintf("Startup: %u\n", (unsigned int) scene->_startup);
327 		debugPrintf("Delay: %u\n", (unsigned int) scene->_delay);
328 		debugPrintf("Doors: %u\n", (unsigned int) scene->_noDoors);
329 		debugPrintf("Objects: %u\n", (unsigned int) scene->_noObjects);
330 		debugPrintf("Statics: %u\n", (unsigned int) scene->_noStatics);
331 		debugPrintf("ObstacleY1: %u\n", (unsigned int) scene->_obstacleY1);
332 		debugPrintf("PalRotFirst: %u\n", (unsigned int) scene->_palRotFirst);
333 		debugPrintf("PalRotLast: %u\n", (unsigned int) scene->_palRotLast);
334 		debugPrintf("PalRotDelay: %u\n", (unsigned int) scene->_palRotDelay);
335 	} else {
336 		debugPrintf("Scene %u not found.\n", (unsigned int) sceneId);
337 	}
338 
339 	return true;
340 }
341 
cmd_dumpdoorinfo(int argc,const char ** argv)342 bool Console::cmd_dumpdoorinfo(int argc, const char **argv) {
343 	if (argc == 3) {
344 		const uint8 sceneId = atoi(argv[1]);
345 		const uint8 doorId = atoi(argv[2]);
346 
347 		Scene *const scene = _vm->getGame().getGameData().getScene(sceneId);
348 		if (scene) {
349 			Door *const door = scene->getDoor(doorId);
350 			if (door) {
351 				debugPrintf("Name: '%s'\n", convertToASCII(door->_name).c_str());
352 				debugPrintf("DestSceneId: %u\n", (unsigned int) door->_destSceneId);
353 				debugPrintf("DestX: %u\n", (unsigned int) door->_destX);
354 				debugPrintf("DestY: %u\n", (unsigned int) door->_destY);
355 				debugPrintf("X: %u\n", (unsigned int) door->_x);
356 				debugPrintf("Y: %u\n", (unsigned int) door->_y);
357 				debugPrintf("Width: %u\n", (unsigned int) door->_width);
358 				debugPrintf("Height: %u\n", (unsigned int) door->_height);
359 				debugPrintf("WalkToX: %u\n", (unsigned int) door->_walkToX);
360 				debugPrintf("WalkToY: %u\n", (unsigned int) door->_walkToY);
361 				debugPrintf("SP: %u\n", (unsigned int) door->_SP);
362 			} else {
363 				debugPrintf("Door %u not found.\n", (unsigned int) doorId);
364 			}
365 		} else {
366 			debugPrintf("Scene %u not found.\n", (unsigned int) sceneId);
367 		}
368 	} else {
369 		debugPrintf("dumpdoorinfo <sceneid> <doorid>\n");
370 	}
371 
372 	return true;
373 }
cmd_dumpobjectinfo(int argc,const char ** argv)374 bool Console::cmd_dumpobjectinfo(int argc, const char **argv) {
375 	if (argc == 3) {
376 		const uint8 sceneId = atoi(argv[1]);
377 		const uint8 objectId = atoi(argv[2]);
378 
379 		Scene *const scene = _vm->getGame().getGameData().getScene(sceneId);
380 		if (scene) {
381 			Object *const object = scene->getObject(objectId);
382 			if (object) {
383 				debugPrintf("AC: %u\n", (unsigned int) object->_active);
384 				debugPrintf("FA: %u\n", (unsigned int) object->_firstFrame);
385 				debugPrintf("FR: %u\n", (unsigned int) object->_randomFrame);
386 				debugPrintf("NA: %u\n", (unsigned int) object->_numFrames);
387 				debugPrintf("FS: %u\n", (unsigned int) object->_roomFrameLSB);
388 				debugPrintf("Jump chance: %u\n", (unsigned int) object->_jumpChance);
389 				debugPrintf("CA: %u\n", (unsigned int) object->_currentFrame);
390 				debugPrintf("X: %u\n", (unsigned int) object->_x);
391 				debugPrintf("Y: %u\n", (unsigned int) object->_y);
392 				debugPrintf("XL: %u\n", (unsigned int) object->_width);
393 				debugPrintf("YL: %u\n", (unsigned int) object->_height);
394 				debugPrintf("WX: %u\n", (unsigned int) object->_WX);
395 				debugPrintf("WY: %u\n", (unsigned int) object->_roomFrameMSB);
396 				debugPrintf("SP: %u\n", (unsigned int) object->_SP);
397 			} else {
398 				debugPrintf("Object %u not found.\n", (unsigned int) objectId);
399 			}
400 		} else {
401 			debugPrintf("Scene %u not found.\n", (unsigned int) sceneId);
402 		}
403 	} else {
404 		debugPrintf("dumpobjectinfo <sceneid> <objectid>\n");
405 	}
406 
407 	return true;
408 }
409 
cmd_dumpstaticinfo(int argc,const char ** argv)410 bool Console::cmd_dumpstaticinfo(int argc, const char **argv) {
411 	if (argc == 3) {
412 		const uint8 sceneId = atoi(argv[1]);
413 		const uint8 staticId = atoi(argv[2]);
414 
415 		Scene *const scene = _vm->getGame().getGameData().getScene(sceneId);
416 		if (scene) {
417 			Static *const stat = scene->getStatic(staticId, true);
418 			if (stat) {
419 				debugPrintf("Active: %u\n", (unsigned int) stat->_active);
420 				debugPrintf("Name: '%s'\n", convertToASCII(stat->_name).c_str());
421 				debugPrintf("X: %u\n", (unsigned int) stat->_x);
422 				debugPrintf("Y: %u\n", (unsigned int) stat->_y);
423 				debugPrintf("Width: %u\n", (unsigned int) stat->_width);
424 				debugPrintf("Height: %u\n", (unsigned int) stat->_height);
425 				debugPrintf("WalkToX: %u\n", (unsigned int) stat->_walkToY);
426 				debugPrintf("WalkToY: %u\n", (unsigned int) stat->_walkToX);
427 				debugPrintf("WalkToFrame: %u\n", (unsigned int) stat->_walkToFrame);
428 			} else {
429 				debugPrintf("Static %u not found.\n", (unsigned int) staticId);
430 			}
431 		} else {
432 			debugPrintf("Scene %u not found.\n", (unsigned int) sceneId);
433 		}
434 	} else {
435 		debugPrintf("dumpstaticinfo <sceneid> <staticid>\n");
436 	}
437 
438 	return true;
439 }
440 
cmd_dumpbitmapinfo(int argc,const char ** argv)441 bool Console::cmd_dumpbitmapinfo(int argc, const char **argv) {
442 	if (argc == 3) {
443 		const uint8 sceneId = atoi(argv[1]);
444 		const uint8 bitmapId = atoi(argv[2]);
445 
446 		Scene *const scene = _vm->getGame().getGameData().getScene(sceneId);
447 		if (scene) {
448 			Bitmap *const bitmap = scene->getBitmap(bitmapId);
449 			if (bitmap) {
450 				debugPrintf("Room Frame: %u\n", (unsigned int) bitmap->_roomFrame);
451 				debugPrintf("Visible: %u\n", (unsigned int) bitmap->_isVisible);
452 				debugPrintf("X1: %u\n", (unsigned int) bitmap->_x1);
453 				debugPrintf("Y1: %u\n", (unsigned int) bitmap->_y1);
454 				debugPrintf("X2: %u\n", (unsigned int) bitmap->_x2);
455 				debugPrintf("Y2: %u\n", (unsigned int) bitmap->_y2);
456 			} else {
457 				debugPrintf("Bitmap %u not found.\n", (unsigned int) bitmapId);
458 			}
459 		} else {
460 			debugPrintf("Scene %u not found.\n", (unsigned int) sceneId);
461 		}
462 	} else {
463 		debugPrintf("dumpbitmapinfo <sceneid> <bitmapid>\n");
464 	}
465 
466 	return true;
467 }
468 
getScriptFromArg(const char * arg)469 Script *Console::getScriptFromArg(const char *arg) {
470 	Script *script = nullptr;
471 	if (strcmp(arg, "G") == 0) {
472 		script = _vm->getGame().getGlobalScript();
473 	} else if (strcmp(arg, "L") == 0) {
474 		script = _vm->getGame().getLocalScript();
475 	}
476 	if (!script) {
477 		debugPrintf("Choose 'G' (global) or 'L' (local) script.\n");
478 	}
479 
480 	return script;
481 }
482 
cmd_listinventory(int,const char **)483 bool Console::cmd_listinventory(int, const char **) {
484 	Inventory &inventory = _vm->getGame().getGameData().getInventory();
485 	const Inventory::Items &items = inventory.getItems();
486 	for (Inventory::Items::const_iterator it = items.begin(); it != items.end(); ++it) {
487 		debugPrintf("%s\n", convertToASCII(*it).c_str());
488 	}
489 	return true;
490 }
491 
492 }
493