aboutsummaryrefslogtreecommitdiff
path: root/engines/lastexpress/debug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/lastexpress/debug.cpp')
-rw-r--r--engines/lastexpress/debug.cpp1177
1 files changed, 1177 insertions, 0 deletions
diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp
new file mode 100644
index 0000000000..520b4cfee3
--- /dev/null
+++ b/engines/lastexpress/debug.cpp
@@ -0,0 +1,1177 @@
+/* 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"
+#include "common/md5.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("dump", WRAP_METHOD(Debugger, cmdDumpFiles));
+
+ 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("time", WRAP_METHOD(Debugger, cmdTime));
+ DCmd_Register("show", WRAP_METHOD(Debugger, cmdShow));
+ 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();
+
+ SAFE_DELETE(_soundStream);
+ resetCommand();
+
+ _command = NULL;
+ _commandParams = NULL;
+
+ // Zero passed pointers
+ _engine = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////
+bool Debugger::hasCommand() const {
+ return (_numParams != 0);
+}
+
+void Debugger::resetCommand() {
+ SAFE_DELETE(_command);
+
+ if (_commandParams)
+ for (int i = 0; i < _numParams; i++)
+ free(_commandParams[i]);
+
+ free(_commandParams);
+ _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(sizeof(char *) * (uint)argc);
+ if (!_commandParams)
+ return;
+
+ _numParams = argc;
+
+ for (int i = 0; i < _numParams; i++) {
+ _commandParams[i] = (char *)malloc(strlen(argv[i]) + 1);
+ memset(_commandParams[i], 0, strlen(argv[i]) + 1);
+ 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(" dump - dump a list of files in all archives\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(" show - show game data\n");
+ DebugPrintf(" entity - show 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) (<cd number>)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: Dump the list of files in the archive
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdDumpFiles(int argc, const char **) {
+#define OUTPUT_ARCHIVE_FILES(name, filename) { \
+ _engine->getResourceManager()->reset(); \
+ _engine->getResourceManager()->loadArchive(filename); \
+ Common::ArchiveMemberList list; \
+ int count = _engine->getResourceManager()->listMatchingMembers(list, "*"); \
+ debugC(1, kLastExpressDebugResource, "\n\n--------------------------------------------------------------------\n"); \
+ debugC(1, kLastExpressDebugResource, "-- " #name " (%d files)\n", count); \
+ debugC(1, kLastExpressDebugResource, "--------------------------------------------------------------------\n\n"); \
+ debugC(1, kLastExpressDebugResource, "Filename,Size,MD5\n"); \
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) { \
+ Common::SeekableReadStream *stream = getArchive((*it)->getName()); \
+ if (!stream) { \
+ DebugPrintf("ERROR: Cannot create stream for file: %s\n", (*it)->getName().c_str()); \
+ restoreArchive(); \
+ return true; \
+ } \
+ Common::String md5str = Common::computeStreamMD5AsString(*stream); \
+ debugC(1, kLastExpressDebugResource, "%s, %d, %s", (*it)->getName().c_str(), stream->size(), md5str.c_str()); \
+ delete stream; \
+ } \
+}
+
+ if (argc == 1) {
+ // For each archive file, dump the list of files
+ if (_engine->isDemo()) {
+ OUTPUT_ARCHIVE_FILES("DEMO", "DEMO.HPF");
+ } else {
+ OUTPUT_ARCHIVE_FILES("HD", "HD.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 1", "CD1.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 2", "CD2.HPF");
+ OUTPUT_ARCHIVE_FILES("CD 3", "CD3.HPF");
+ }
+
+ // Restore current loaded archive
+ restoreArchive();
+ } else {
+ DebugPrintf("Syntax: dump");
+ }
+
+ 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 '%s'\n", argv[2]);
+ 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;
+ 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: Convert between in-game time and human readable time
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdTime(int argc, const char **argv) {
+ if (argc == 2) {
+ int32 time = getNumber(argv[1]);
+
+ if (time < 0)
+ goto label_error;
+
+ // Convert to human-readable form
+ uint8 hours = 0;
+ uint8 minutes = 0;
+ State::getHourMinutes((uint32)time, &hours, &minutes);
+
+ DebugPrintf("%02d:%02d\n", hours, minutes);
+ } else {
+label_error:
+ DebugPrintf("Syntax: time <time to convert> (time=0-INT_MAX)\n");
+ }
+
+ return true;
+}
+
+/**
+ * Command: show game logic data
+ *
+ * @param argc The argument count.
+ * @param argv The values.
+ *
+ * @return true if it was handled, false otherwise
+ */
+bool Debugger::cmdShow(int argc, const char **argv) {
+#define OUTPUT_DUMP(name, text) \
+ DebugPrintf(#name "\n"); \
+ DebugPrintf("--------------------------------------------------------------------\n\n"); \
+ DebugPrintf("%s", text); \
+ DebugPrintf("\n");
+
+ if (argc == 2) {
+
+ Common::String name(const_cast<char *>(argv[1]));
+
+ if (name == "state" || name == "st") {
+ OUTPUT_DUMP("Game state", getState()->toString().c_str());
+ } else if (name == "progress" || name == "pr") {
+ OUTPUT_DUMP("Progress", getProgress().toString().c_str());
+ } else if (name == "flags" || name == "fl") {
+ OUTPUT_DUMP("Flags", getFlags()->toString().c_str());
+ } else if (name == "inventory" || name == "inv") {
+ OUTPUT_DUMP("Inventory", getInventory()->toString().c_str());
+ } else if (name == "objects" || name == "obj") {
+ OUTPUT_DUMP("Objects", getObjects()->toString().c_str());
+ } else if (name == "savepoints" || name == "pt") {
+ OUTPUT_DUMP("SavePoints", getSavePoints()->toString().c_str());
+ } else if (name == "scene" || name == "sc") {
+ OUTPUT_DUMP("Current scene", getScenes()->get(getState()->scene)->toString().c_str());
+ } else {
+ goto label_error;
+ }
+
+ } else {
+label_error:
+ DebugPrintf("Syntax: state <option>\n");
+ DebugPrintf(" state / st\n");
+ DebugPrintf(" progress / pr\n");
+ DebugPrintf(" flags / fl\n");
+ DebugPrintf(" inventory / inv\n");
+ DebugPrintf(" objects / obj\n");
+ DebugPrintf(" savepoints / pt\n");
+ DebugPrintf(" scene / sc\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("%s", 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;
+
+ getSaveLoad()->loadGame((GameId)(id - 1));
+ } 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