scummvm/engines/lastexpress/debug.cpp
Littleboy 6ab8db638e LASTEXPRESS: Implement more savegame loading
- Rename existing function to load the last saved game
 - Remove loadgame debugger command
2012-08-27 23:30:23 -04:00

1178 lines
29 KiB
C++

/* 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.
*
*/
#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/subtitle.h"
#include "lastexpress/fight/fight.h"
#include "lastexpress/game/action.h"
#include "lastexpress/game/beetle.h"
#include "lastexpress/game/entities.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/state.h"
#include "lastexpress/sound/queue.h"
#include "lastexpress/graphics.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
#include "common/debug-channels.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("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);
if (_commandParams[i] == NULL)
error("[Debugger::copyCommand] Cannot allocate memory for command parameters");
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));
}
bool Debugger::loadArchive(int index) {
if (index < 1 || index > 3) {
DebugPrintf("Invalid cd number (was: %d, valid: [1-3])\n", index);
return false;
}
if (!_engine->getResourceManager()->loadArchive((ArchiveIndex)index))
return false;
getScenes()->loadSceneDataFile((ArchiveIndex)index);
return true;
}
// 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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
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) {
if (!loadArchive(getNumber(argv[3])))
return true;
}
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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
// 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), 16);
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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
// 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) {
if (!loadArchive(getNumber(argv[2])))
return true;
}
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
getSoundQueue()->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_system->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
getSoundQueue()->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: 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