/* 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 */ #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" "(v)ariable -> set or show a variable value\n" "(w)atch [varnum] -> set a variable watch. 0 means all variables.\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 = 0; BoxCoords box; byte *boxm = _s->getBoxMatrixBaseAddr(); num = _s->getNumBoxes(); printf("Walk matrix:\n"); for (i=0;igetBoxCoordinates(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("v 123 will show the value of 123, v 123 456 will set the value of 123 to 456.\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"); return true; } } 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 } }; 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<_s->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"); }