diff options
Diffstat (limited to 'engines/lastexpress/debug.cpp')
| -rw-r--r-- | engines/lastexpress/debug.cpp | 1091 | 
1 files changed, 1091 insertions, 0 deletions
| diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp new file mode 100644 index 0000000000..cf81e162ae --- /dev/null +++ b/engines/lastexpress/debug.cpp @@ -0,0 +1,1091 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "lastexpress/debug.h" + +// Data +#include "lastexpress/data/animation.h" +#include "lastexpress/data/background.h" +#include "lastexpress/data/cursor.h" +#include "lastexpress/data/scene.h" +#include "lastexpress/data/sequence.h" +#include "lastexpress/data/snd.h" +#include "lastexpress/data/subtitle.h" + +#include "lastexpress/game/action.h" +#include "lastexpress/game/beetle.h" +#include "lastexpress/game/fight.h" +#include "lastexpress/game/inventory.h" +#include "lastexpress/game/logic.h" +#include "lastexpress/game/object.h" +#include "lastexpress/game/savegame.h" +#include "lastexpress/game/savepoint.h" +#include "lastexpress/game/scenes.h" +#include "lastexpress/game/sound.h" +#include "lastexpress/game/state.h" + +#include "lastexpress/graphics.h" +#include "lastexpress/helpers.h" +#include "lastexpress/lastexpress.h" +#include "lastexpress/resource.h" + +#include "common/debug-channels.h" +#include "common/events.h" + +namespace LastExpress { + +Debugger::Debugger(LastExpressEngine *engine) : _engine(engine), _command(NULL), _numParams(0), _commandParams(NULL) { + +	////////////////////////////////////////////////////////////////////////// +	// Register the debugger commands + +	// General +	DCmd_Register("help",      WRAP_METHOD(Debugger, cmdHelp)); + +	// Data +	DCmd_Register("ls",        WRAP_METHOD(Debugger, cmdListFiles)); + +	DCmd_Register("showframe", WRAP_METHOD(Debugger, cmdShowFrame)); +	DCmd_Register("showbg",    WRAP_METHOD(Debugger, cmdShowBg)); +	DCmd_Register("playseq",   WRAP_METHOD(Debugger, cmdPlaySeq)); +	DCmd_Register("playsnd",   WRAP_METHOD(Debugger, cmdPlaySnd)); +	DCmd_Register("playsbe",   WRAP_METHOD(Debugger, cmdPlaySbe)); +	DCmd_Register("playnis",   WRAP_METHOD(Debugger, cmdPlayNis)); + +	// Scene & interaction +	DCmd_Register("loadscene", WRAP_METHOD(Debugger, cmdLoadScene)); +	DCmd_Register("fight",     WRAP_METHOD(Debugger, cmdFight)); +	DCmd_Register("beetle",    WRAP_METHOD(Debugger, cmdBeetle)); + +	// Game +	DCmd_Register("delta",     WRAP_METHOD(Debugger, cmdTimeDelta)); +	DCmd_Register("dump",      WRAP_METHOD(Debugger, cmdDump)); +	DCmd_Register("entity",    WRAP_METHOD(Debugger, cmdEntity)); + +	// Misc +	DCmd_Register("loadgame",  WRAP_METHOD(Debugger, cmdLoadGame)); +	DCmd_Register("chapter",   WRAP_METHOD(Debugger, cmdSwitchChapter)); +	DCmd_Register("clear",     WRAP_METHOD(Debugger, cmdClear)); + +	resetCommand(); + +	_soundStream = new StreamedSound(); +} + +Debugger::~Debugger() { +	DebugMan.clearAllDebugChannels(); + +	delete _soundStream; + +	// Zero passed pointers +	_engine = NULL; +	_command = NULL; +	_commandParams = NULL; +} + +////////////////////////////////////////////////////////////////////////// +// Helper functions +////////////////////////////////////////////////////////////////////////// +bool Debugger::hasCommand() const { +	return (_numParams != 0); +} + +void Debugger::resetCommand() { +	_command = NULL; +	_commandParams = NULL; +	_numParams = 0; +} + +int Debugger::getNumber(const char *arg) const { +	return strtol(arg, (char **)NULL, 0); +} + +void Debugger::copyCommand(int argc, const char **argv) { +	_commandParams = (char **)malloc((uint)argc); +	if (!_commandParams) +		return; + +	_numParams = argc; + +	for (int i = 0; i < _numParams; i++) { +		_commandParams[i] = (char *)malloc(strlen(argv[i])); +		strcpy(_commandParams[i], ""); +		strcpy(_commandParams[i], argv[i]); +	} + +	// Exit the debugger! +	Cmd_Exit(0, 0); +} + +void Debugger::callCommand() { +	if (_command) +		(*_command)(_numParams, const_cast<const char **>(_commandParams)); +} + +void Debugger::loadArchive(ArchiveIndex index) const { +	_engine->getResourceManager()->loadArchive(index); +	getScenes()->loadSceneDataFile(index); +} + +// Restore loaded archive +void Debugger::restoreArchive() const { + +	ArchiveIndex index = kArchiveCd1; + +	switch (getProgress().chapter) { +	default: +	case kChapter1: +		index = kArchiveCd1; +		break; + +	case kChapter2: +	case kChapter3: +		index = kArchiveCd2; +		break; + +	case kChapter4: +	case kChapter5: +		index = kArchiveCd3; +		break; +	} + +	_engine->getResourceManager()->loadArchive(index); +	getScenes()->loadSceneDataFile(index); +} + +////////////////////////////////////////////////////////////////////////// +// Debugger commands +////////////////////////////////////////////////////////////////////////// +bool Debugger::cmdHelp(int, const char **) { +	DebugPrintf("Debug flags\n"); +	DebugPrintf("-----------\n"); +	DebugPrintf(" debugflag_list - Lists the available debug flags and their status\n"); +	DebugPrintf(" debugflag_enable - Enables a debug flag\n"); +	DebugPrintf(" debugflag_disable - Disables a debug flag\n"); +	DebugPrintf("\n"); +	DebugPrintf("Commands\n"); +	DebugPrintf("--------\n"); +	DebugPrintf(" ls - list files in the archive\n"); +	DebugPrintf("\n"); +	DebugPrintf(" showframe - show a frame from a sequence\n"); +	DebugPrintf(" showbg - show a background\n"); +	DebugPrintf(" playseq - play a sequence\n"); +	DebugPrintf(" playsnd - play a sound\n"); +	DebugPrintf(" playsbe - play a subtitle\n"); +	DebugPrintf(" playnis - play an animation\n"); +	DebugPrintf("\n"); +	DebugPrintf(" loadscene - load a scene\n"); +	DebugPrintf(" fight - start a fight\n"); +	DebugPrintf(" beetle - start the beetle game\n"); +	DebugPrintf("\n"); +	DebugPrintf(" delta - Adjust the time delta\n"); +	DebugPrintf(" dump - Dump game data\n"); +	DebugPrintf(" entity - Dump entity data\n"); +	DebugPrintf("\n"); +	DebugPrintf(" loadgame - load a saved game\n"); +	DebugPrintf(" chapter - switch to a specific chapter\n"); +	DebugPrintf(" clear - clear the screen\n"); +	DebugPrintf("\n"); +	return true; +} + +/** + * Command: list files in archive + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdListFiles(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		Common::String filter(const_cast<char *>(argv[1])); + +		// Load the proper archive +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		Common::ArchiveMemberList list; +		int count = _engine->getResourceManager()->listMatchingMembers(list, filter); + +		DebugPrintf("Number of matches: %d\n", count); +		for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) +			DebugPrintf(" %s\n", (*it)->getName().c_str()); + +		// Restore archive +		if (argc == 3) +			restoreArchive(); +	} else { +		DebugPrintf("Syntax: ls <filter> (use * for all)\n (<cd number>)"); +	} + +	return true; +} + +/** + * Command: Shows a frame + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdShowFrame(int argc, const char **argv) { +	if (argc == 3 || argc == 4) { +		Common::String filename(const_cast<char *>(argv[1])); +		filename += ".seq"; + +		if (argc == 4) +			loadArchive((ArchiveIndex)getNumber(argv[3])); + +		if (!_engine->getResourceManager()->hasFile(filename)) { +			DebugPrintf("Cannot find file: %s\n", filename.c_str()); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdShowFrame); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { +			Sequence sequence(filename); +			if (sequence.load(getArchive(filename))) { +				_engine->getCursor()->show(false); +				clearBg(GraphicsManager::kBackgroundOverlay); + +				AnimFrame *frame = sequence.getFrame((uint16)getNumber(argv[2])); +				if (!frame) { +					DebugPrintf("Invalid frame index: %i\n", filename.c_str()); +					resetCommand(); +					return true; +				} + +				_engine->getGraphicsManager()->draw(frame, GraphicsManager::kBackgroundOverlay); +				delete frame; + +				askForRedraw(); +				redrawScreen(); + +				_engine->_system->delayMillis(1000); +				_engine->getCursor()->show(true); +			} + +			resetCommand(); + +			if (argc == 4) +				restoreArchive(); +		} +	} else { +		DebugPrintf("Syntax: cmd_showframe <seqname> <index> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: shows a background + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdShowBg(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		Common::String filename(const_cast<char *>(argv[1])); + +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		if (!_engine->getResourceManager()->hasFile(filename + ".BG")) { +			DebugPrintf("Cannot find file: %s\n", (filename + ".BG").c_str()); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdShowBg); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { +			clearBg(GraphicsManager::kBackgroundC); + +			Background *background = _engine->getResourceManager()->loadBackground(filename); +			if (background) { +				_engine->getGraphicsManager()->draw(background, GraphicsManager::kBackgroundC); +				delete background; +				askForRedraw(); +			} + +			redrawScreen(); + +			if (argc == 3) +				restoreArchive(); + +			// Pause for a second to be able to see the background +			_engine->_system->delayMillis(1000); + +			resetCommand(); +		} +	} else { +		DebugPrintf("Syntax: showbg <bgname> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: plays a sequence. + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdPlaySeq(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		Common::String filename(const_cast<char *>(argv[1])); +		filename += ".seq"; + +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		if (!_engine->getResourceManager()->hasFile(filename)) { +			DebugPrintf("Cannot find file: %s\n", filename.c_str()); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdPlaySeq); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { +			Sequence *sequence = new Sequence(filename); +			if (sequence->load(getArchive(filename))) { + +				// Check that we have at least a frame to show +				if (sequence->count() == 0) { +					delete sequence; +					return false; +				} + +				_engine->getCursor()->show(false); + +				SequenceFrame player(sequence, 0, true); +				do { +					// Clear screen +					clearBg(GraphicsManager::kBackgroundA); + +					_engine->getGraphicsManager()->draw(&player, GraphicsManager::kBackgroundA); + +					askForRedraw(); +					redrawScreen(); + +					// Handle right-click to interrupt sequence +					Common::Event ev; +					_engine->getEventManager()->pollEvent(ev); +					if (ev.type == Common::EVENT_RBUTTONUP) +						break; + +					_engine->_system->delayMillis(175); + +					// go to the next frame +				} while (player.nextFrame()); +				_engine->getCursor()->show(true); +			} else { +				// Sequence player is deleting his reference to the sequence, but we need to take care of it if the +				// sequence could not be loaded +				delete sequence; +			} + +			resetCommand(); + +			if (argc == 3) +				restoreArchive(); +		} +	} else { +		DebugPrintf("Syntax: playseq <seqname> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: plays a sound + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdPlaySnd(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { + +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		// Add .SND at the end of the filename if needed +		Common::String name(const_cast<char *>(argv[1])); +		if (!name.contains('.')) +			name += ".SND"; + +		if (!_engine->getResourceManager()->hasFile(name)) { +			DebugPrintf("Cannot find file: %s\n", name.c_str()); +			return true; +		} + +		_engine->_system->getMixer()->stopAll(); + +		_soundStream->load(getArchive(name)); + +		if (argc == 3) +			restoreArchive(); +	} else { +		DebugPrintf("Syntax: playsnd <sndname> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: plays subtitles + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdPlaySbe(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		Common::String filename(const_cast<char *>(argv[1])); + +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		filename += ".sbe"; + +		if (!_engine->getResourceManager()->hasFile(filename)) { +			DebugPrintf("Cannot find file: %s\n", filename.c_str()); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdPlaySbe); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { +			SubtitleManager subtitle(_engine->getFont()); +			if (subtitle.load(getArchive(filename))) { +				_engine->getCursor()->show(false); +				for (uint16 i = 0; i < subtitle.getMaxTime(); i += 25) { +					clearBg(GraphicsManager::kBackgroundAll); + +					subtitle.setTime(i); +					_engine->getGraphicsManager()->draw(&subtitle, GraphicsManager::kBackgroundOverlay); + +					askForRedraw(); +					redrawScreen(); + +					// Handle right-click to interrupt sequence +					Common::Event ev; +					_engine->getEventManager()->pollEvent(ev); +					if (ev.type == Common::EVENT_RBUTTONUP) +						break; + +					_engine->_system->delayMillis(500); +				} +				_engine->getCursor()->show(true); +			} + +			if (argc == 3) +				restoreArchive(); + +			resetCommand(); +		} +	} else { +		DebugPrintf("Syntax: playsbe <sbename> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: plays a NIS animation sequence. + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdPlayNis(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		Common::String name(const_cast<char *>(argv[1])); + +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		// If we got a nis filename, check that the file exists +		if (name.contains('.') && _engine->getResourceManager()->hasFile(name)) { +			DebugPrintf("Cannot find file: %s\n", name.c_str()); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdPlayNis); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { +			// Make sure we are not called in a loop +			_numParams = 0; + + +			// Check if we got a nis filename or an animation index +			if (name.contains('.')) { +				Animation animation; +				if (animation.load(getArchive(name))) { +					_engine->getCursor()->show(false); +					animation.play(); +					_engine->getCursor()->show(true); +				} +			} else { +				getAction()->playAnimation((EventIndex)atoi(name.c_str()), true); +			} + +			if (argc == 3) +				restoreArchive(); + +			resetCommand(); +		} +	} else { +		DebugPrintf("Syntax: playnis <nisname.nis or animation index> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: loads a scene + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdLoadScene(int argc, const char **argv) { +	if (argc == 2 || argc == 3) { +		int cd = 1; +		SceneIndex index = (SceneIndex)getNumber(argv[1]);; + +		// Check args +		if (argc == 3) +			loadArchive((ArchiveIndex)getNumber(argv[2])); + +		if (index > 2500) { +			DebugPrintf("Error: invalid index value (0-2500)"); +			return true; +		} + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdLoadScene); +			copyCommand(argc, argv); + +			return Cmd_Exit(0, 0); +		} else { + +			clearBg(GraphicsManager::kBackgroundAll); + +			/************  DEBUG  *************************/ +			// Use to find scenes with certain values + +			//for (int i = index; i < 2500; i++) { +			//	loadSceneObject(scene, i); + +			//	if (scene.getHeader() && scene.getHeader()->car == 5 && scene.getHeader()->position == 81) { +			//		DebugPrintf("Found scene: %d", i); + +			//		// Draw scene found +			//		_engine->getGraphicsManager()->draw(&scene, GraphicsManager::kBackgroundC); + +			//		askForRedraw(); +			//		redrawScreen(); +			//		_engine->_system->delayMillis(500); + +			//		break; +			//	} +			//} + +			//delete _sceneLoader; +			//resetCommand(); +			//return true; + +			/*********************************************/ +			Scene *scene = getScenes()->get(index); +			if (!scene) { +				DebugPrintf("Cannot load scene %i from CD %i", index, cd); +				resetCommand(); + +				return true; +			} + +			_engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC); + +			askForRedraw(); +			redrawScreen(); + +			// Pause for a second to be able to see the scene +			_engine->_system->delayMillis(500); + +			if (argc == 3) +				restoreArchive(); + +			resetCommand(); +		} +	} else { +		DebugPrintf("Syntax: loadscene <scene index> (<cd number>)\n"); +	} +	return true; +} + +/** + * Command: starts a fight sequence + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdFight(int argc, const char **argv) { +	if (argc == 2) { +		FightType type = (FightType)getNumber(argv[1]); + +		// Load proper data file +		ArchiveIndex index = kArchiveCd1; +		switch (type) { +		default: +			goto error; + +		case kFightMilos: +			index = kArchiveCd1; +			break; + +		case kFightAnna: +			index = kArchiveCd2; +			break; + +		case kFightIvo: +		case kFightSalko: +		case kFightVesna: +			index = kArchiveCd3; +			break; +		} + +		loadArchive(index); + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdFight); +			copyCommand(argc, argv); + +			return false; +		} else { +			// Make sure we are not called in a loop +			_numParams = 0; + +			clearBg(GraphicsManager::kBackgroundAll); +			askForRedraw(); +			redrawScreen(); + +			SceneIndex lastScene = getState()->scene; + +			getFight()->setup(type) ? DebugPrintf("Lost fight!\n") : DebugPrintf("Won fight!\n"); + +			// Pause for a second to be able to see the final scene +			_engine->_system->delayMillis(1000); + +			// Restore loaded archive +			restoreArchive(); + +			// Stop audio and restore scene +			getSound()->stopAllSound(); + +			clearBg(GraphicsManager::kBackgroundAll); + +			Scene *scene = getScenes()->get(lastScene); +			_engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC); + +			askForRedraw(); +			redrawScreen(); + +			resetCommand(); +		} +	} else { +error: +		DebugPrintf("Syntax: fight <id> (id=2001-2005)\n"); +	} + +	return true; +} + +/** + * Command: starts the beetle sequence + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdBeetle(int argc, const char **argv) { +	if (argc == 1) { +		// Load proper data file (beetle game in in Cd2) +		loadArchive(kArchiveCd2); + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdBeetle); +			copyCommand(argc, argv); + +			return false; +		} else { +			clearBg(GraphicsManager::kBackgroundAll); +			askForRedraw(); +			redrawScreen(); + +			// Save current state +			SceneIndex previousScene = getState()->scene; +			ObjectLocation previousLocation = getInventory()->get(kItemBeetle)->location; +			ChapterIndex previousChapter = (ChapterIndex)getProgress().chapter; + +			// Setup scene & inventory +			getProgress().chapter = kChapter2; +			Scene *scene = getScenes()->get(kSceneBeetle); +			getInventory()->get(kItemBeetle)->location = kObjectLocation3; + +			askForRedraw(); +			redrawScreen(); + +			// Load the beetle game +			Action *action = NULL; +			Beetle *beetle = new Beetle(_engine); +			if (!beetle->isLoaded()) +				beetle->load(); + +			// Play the game +			Common::Event ev; +			bool playgame = true; +			while (playgame) { +				// Update beetle +				beetle->update(); + +				askForRedraw(); +				redrawScreen(); + +				while (g_engine->getEventManager()->pollEvent(ev)) { + +					switch (ev.type) { +					default: +						break; + +					case Common::EVENT_KEYDOWN: +						// Exit beetle game on escape +						if (ev.kbd.keycode == Common::KEYCODE_ESCAPE) +							playgame = false; + +						break; + +					case Common::EVENT_MOUSEMOVE: { +						// Update cursor +						CursorStyle style = kCursorNormal; +						SceneHotspot *hotspot = NULL; +						if (scene->checkHotSpot(ev.mouse, &hotspot)) { +							if (!action) +								action = new Action(_engine); + +							style = action->getCursor(*hotspot); +						} + +						_engine->getCursor()->setStyle(style); +						break; +					} + + +					case Common::EVENT_LBUTTONUP: +					case Common::EVENT_RBUTTONUP: +						// Update coordinates +						getLogic()->getGameState()->setCoordinates(ev.mouse); + +						if (beetle->catchBeetle()) +							playgame = false; +						break; +					} + +					_engine->_system->delayMillis(10); +				} +			} + +			// Cleanup +			beetle->unload(); +			delete beetle; +			SAFE_DELETE(action); + +			// Pause for a second to be able to see the final scene +			_engine->_system->delayMillis(1000); + +			// Restore state +			getProgress().chapter = previousChapter; +			getInventory()->get(kItemBeetle)->location = previousLocation; + +			// Restore loaded archive +			restoreArchive(); + +			// Stop audio and restore scene +			getSound()->stopAllSound(); + +			clearBg(GraphicsManager::kBackgroundAll); + +			Scene *oldScene = getScenes()->get(previousScene); +			_engine->getGraphicsManager()->draw(oldScene, GraphicsManager::kBackgroundC); + +			askForRedraw(); +			redrawScreen(); + +			resetCommand(); +		} +	} else { +		DebugPrintf("Syntax: beetle\n"); +	} + +	return true; +} + +/** + * Command: adjusts the time delta + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdTimeDelta(int argc, const char **argv) { +	if (argc == 2) { +		int delta =  getNumber(argv[1]); + +		if (delta <= 0 || delta > 500) +			goto label_error; + +		getState()->timeDelta = (uint)delta; +	} else { +label_error: +		DebugPrintf("Syntax: delta <time delta> (delta=1-500)\n"); +	} + +	return true; +} + +/** + * Command: dumps game logic data + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdDump(int argc, const char **argv) { +#define OUTPUT_DUMP(name, text) \ +	DebugPrintf(#name "\n"); \ +	DebugPrintf("--------------------------------------------------------------------\n\n"); \ +	DebugPrintf(text); \ +	DebugPrintf("\n"); + +	if (argc == 2) { +		switch (getNumber(argv[1])) { +		default: +			goto label_error; + +		// GameState +		case 1: +			OUTPUT_DUMP("Game state", getState()->toString().c_str()); +			break; + +		// Inventory +		case 2: +			OUTPUT_DUMP("Inventory", getInventory()->toString().c_str()); +			break; + +		// Objects +		case 3: +			OUTPUT_DUMP("Objects", getObjects()->toString().c_str()); +			break; + +		// SavePoints +		case 4: +			OUTPUT_DUMP("SavePoints", getSavePoints()->toString().c_str()); +			break; + +		case 5: +			OUTPUT_DUMP("Current scene", getScenes()->get(getState()->scene)->toString().c_str()); +		} +	} else { +label_error: +		DebugPrintf("Syntax: state <option>\n"); +		DebugPrintf("              1 : Game state\n"); +		DebugPrintf("              2 : Inventory\n"); +		DebugPrintf("              3 : Objects\n"); +		DebugPrintf("              4 : SavePoints\n"); +		DebugPrintf("              5 : Current scene\n"); +	} + +	return true; + +#undef OUTPUT_DUMP +} + +/** + * Command: shows entity data + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdEntity(int argc, const char **argv) { +	if (argc == 2) { +		EntityIndex index = (EntityIndex)getNumber(argv[1]); + +		if (index > 39) +			goto label_error; + +		DebugPrintf("Entity %s\n", ENTITY_NAME(index)); +		DebugPrintf("--------------------------------------------------------------------\n\n"); +		DebugPrintf(getEntities()->getData(index)->toString().c_str()); + +		// The Player entity does not have any callback data +		if (index != kEntityPlayer) { +			EntityData *data = getEntities()->get(index)->getParamData(); +			for (uint callback = 0; callback < 9; callback++) { +				DebugPrintf("Call parameters %d:\n", callback); +				for (byte ix = 0; ix < 4; ix++) +					DebugPrintf("  %s", data->getParameters(callback, ix)->toString().c_str()); +			} +		} + +		DebugPrintf("\n"); +	} else { +label_error: +		DebugPrintf("Syntax: entity <index>\n"); +		for (int i = 0; i < 40; i += 4) +			DebugPrintf(" %s - %d        %s - %d        %s - %d        %s - %d\n", ENTITY_NAME(i), i, ENTITY_NAME(i+1), i+1, ENTITY_NAME(i+2), i+2, ENTITY_NAME(i+3), i+3); +	} + +	return true; +} + +/** + * Command: loads a game + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdLoadGame(int argc, const char **argv) { +	if (argc == 2) { +		int id = getNumber(argv[1]); + +		if (id == 0 || id > 6) +			goto error; + +		if (!getSaveLoad()->loadGame((GameId)(id - 1))) +			DebugPrintf("Error loading game with id=%d", id); + +	} else { +error: +		DebugPrintf("Syntax: loadgame <id> (id=1-6)\n"); +	} + +	return true; +} + +/** + * Command: switch to a specific chapter + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdSwitchChapter(int argc, const char **argv) { +	if (argc == 2) { +		int id = getNumber(argv[1]); + +		if (id <= 1 || id > 6) +			goto error; + +		// Store command +		if (!hasCommand()) { +			_command = WRAP_METHOD(Debugger, cmdSwitchChapter); +			copyCommand(argc, argv); + +			return false; +		} else { +			// Sets the current chapter and then call Logic::switchChapter to proceed to the next chapter +			getState()->progress.chapter = (ChapterIndex)(id - 1); + +			getLogic()->switchChapter(); + +			resetCommand(); +		} +	} else { +error: +		DebugPrintf("Syntax: chapter <id> (id=2-6)\n"); +	} + +	return true; +} + +/** + * Command: clears the screen + * + * @param argc The argument count. + * @param argv The values. + * + * @return true if it was handled, false otherwise + */ +bool Debugger::cmdClear(int argc, const char **) { +	if (argc == 1) { +		clearBg(GraphicsManager::kBackgroundAll); +		askForRedraw(); +		redrawScreen(); +	} else { +		DebugPrintf("Syntax: clear - clear the screen\n"); +	} + +	return true; +} + +} // End of namespace LastExpress | 
