scummvm/debug.cpp
James Brown 17270d2ccd Fixed some more Sam and Max bugs. Is now playable to BumpusVille.
Added two new debug commands, one to read and set variables, the other
to set a 'watch' on variables.

svn-id: r3662
2002-03-06 10:03:00 +00:00

283 lines
6.3 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
/*
* Readline and command completion support by Tom Dunstan <tommyd@senet.com.au>
*/
#include "stdafx.h"
#include "scumm.h"
#ifdef HAVE_READLINE
#include "debugrl.h"
#endif
enum {
CMD_INVALID,
CMD_HELP,
CMD_QUIT,
CMD_GO,
CMD_ACTOR,
CMD_SCRIPTS,
CMD_LOAD_ROOM,
CMD_DUMPBOX,
CMD_VAR,
CMD_WATCH,
CMD_EXIT
};
void ScummDebugger::attach(Scumm *s) {
if (_s)
detach();
_welcome = true;
_s = s;
s->_debugger = this;
_go_amount = 1;
#ifdef HAVE_READLINE
initialize_readline();
#endif
}
void BoxTest(int num);
bool ScummDebugger::do_command() {
switch(get_command()) {
case CMD_HELP:
printf(
"Debugger commands:\n"
"(h)elp -> display this help text\n"
"(q)uit -> quit the debugger\n"
"(g)o [numframes] -> increase frame\n"
"(a)ctor [actornum] -> show actor information\n"
"(r)oom roomnum -> load room\n"
"(s)cripts -> show running scripts\n"
"(b)oxes -> list and draw boxen\n"
"(e)xit -> exit game\n"
);
return true;
case CMD_QUIT:
detach();
return false;
case CMD_GO:
if (!_parameters[0])
_go_amount = 1;
else
_go_amount = atoi(_parameters);
return false;
case CMD_ACTOR:
if (!_parameters[0])
printActors(-1);
else
printActors(atoi(_parameters));
return true;
case CMD_SCRIPTS:
printScripts();
return true;
case CMD_LOAD_ROOM:
if (!_parameters[0]) {
printf("Enter a room number...\n");
} else {
int room=atoi(_parameters);
_s->actor[_s->_vars[_s->VAR_EGO]].room=room;
_s->startScene(room, 0, 0);
_s->_fullRedraw = 1;
}
return true;
case CMD_DUMPBOX:
{
int num, i; BoxCoords box;
num = _s->getNumBoxes();
for (i=0; i<num; i++) {
BoxTest(i);
_s->getBoxCoordinates(i, &box);
printf("%d: [%d x %d] [%d x %d] [%d x %d] [%d x %d]\n", i,
box.ul.x, box.ul.y, box.ll.x, box.ll.y,
box.ur.x, box.ur.y, box.lr.x, box.lr.y);
}
}
return true;
case CMD_VAR:
if (!_parameters[0]) {
printf("Enter a variable\n");
} else {
char *tok = strtok(_parameters, " ");
int var = atoi(tok);
tok = strtok(NULL, "");
if (tok)
_s->writeVar(var, atoi(tok));
printf("Var[%d] = %d\n", var, _s->readVar(var));
}
return true;
case CMD_WATCH:
if (!_parameters[0]) {
printf("Clearing all watches..\n");
_s->_varwatch = -1;
} else {
_s->_varwatch = atoi(_parameters);
if (_s->_varwatch == 0)
printf("Watching all variables\n");
else
printf("Watching vars[%d]\n", _s->_varwatch);
}
return true;
case CMD_EXIT:
exit(1);
default: /* this line is never reached */
error("Unknown debug command");
}
}
void ScummDebugger::enter() {
if (_welcome) {
_welcome = false;
printf("Debugging Mode entered!, please switch to this console for input.\n"
"Enter h to list all the debug commands\n");
}
while(do_command()) {}
}
void ScummDebugger::on_frame() {
if (_go_amount==0)
return;
if (!--_go_amount)
enter();
}
void ScummDebugger::detach() {
_s->_debugger = NULL;
_s = NULL;
}
struct DebuggerCommands {
char text[8];
byte len;
byte id;
};
static const DebuggerCommands debugger_commands[] = {
{ "h", 1, CMD_HELP },
{ "q", 1, CMD_QUIT },
{ "g", 1, CMD_GO },
{ "a", 1, CMD_ACTOR },
{ "s", 1, CMD_SCRIPTS },
{ "r", 1, CMD_LOAD_ROOM },
{ "b", 1, CMD_DUMPBOX},
{ "v", 1, CMD_VAR},
{ "w", 1, CMD_WATCH},
{ "e", 1, CMD_EXIT },
{ 0, 0, 0 },
};
int ScummDebugger::get_command() {
const DebuggerCommands *dc;
char *s;
int i;
static char *buf;
do {
#ifndef HAVE_READLINE
buf = _cmd_buffer;
printf("debug> ");
if (!fgets(_cmd_buffer, sizeof(_cmd_buffer), stdin))
return CMD_QUIT;
i = strlen(_cmd_buffer);
while (i>0 && _cmd_buffer[i-1]==10)
_cmd_buffer[--i] = 0;
if (i==0)
continue;
#else // yes we do have readline
if(buf) {
free(buf);
}
buf = readline("debug> ");
if(!buf) {
printf("\n");
return CMD_QUIT;
}
if(strlen(buf) == 0) {
continue;
}
add_history(buf);
#endif
dc = debugger_commands;
do {
if (!strncmp(buf, dc->text, dc->len)) {
for(s=buf;*s;s++) {
if (*s==32) { s++; break; }
}
_parameters = s;
return _command = dc->id;
}
} while ((++dc)->text[0]);
for(s=buf;*s;s++)
if (*s==32) { *s=0; break; }
printf("Invalid command '%s'. Type 'help' for a list of available commands.\n", buf);
} while (1);
}
void ScummDebugger::printActors(int act) {
int i;
Actor *a;
printf("+--------------------------------------------------------------+\n");
printf("|# |room| x y |elev|cos|width|box|mov|zp|frame|scale|spd|dir|\n");
printf("+--+----+--------+----+---+-----+---+---+--+-----+-----+---+---+\n");
for(i=1; i<NUM_ACTORS; i++) {
if (act==-1 || act==i) {
a = &_s->actor[i];
if (a->visible)
printf("|%2d|%4d|%3d %3d|%4d|%3d|%5d|%3d|%3d|%2d|%5d|%5d|%3d|%3d|\n",
i,a->room,a->x,a->y,a->elevation,a->costume,a->width,a->walkbox,a->moving,a->forceClip,a->frame,a->scalex,a->speedx,a->facing);
}
}
printf("+--------------------------------------------------------------+\n");
}
void ScummDebugger::printScripts() {
int i;
ScriptSlot *ss;
printf("+---------------------------------+\n");
printf("|# |num|sta|typ|un1|un2|fc|cut|un5|\n");
printf("+--+---+---+---+---+---+--+---+---+\n");
for(i=0; i<25; i++) {
ss = &_s->vm.slot[i];
if (ss->number) {
printf("|%2d|%3d|%3d|%3d|%3d|%3d|%2d|%3d|%3d|\n",
i, ss->number, ss->status, ss->where, ss->unk1, ss->unk2, ss->freezeCount, ss->cutsceneOverride, ss->unk5);
}
}
printf("+---------------------------------+\n");
}