/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1994-1998 Revolution Software Ltd.
*
* 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 3 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, see .
*/
#include "common/memstream.h"
#include "common/rect.h"
#include "common/system.h"
#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/header.h"
#include "sword2/console.h"
#include "sword2/logic.h"
#include "sword2/maketext.h"
#include "sword2/memory.h"
#include "sword2/mouse.h"
#include "sword2/resman.h"
#include "sword2/screen.h"
#include "sword2/sound.h"
namespace Sword2 {
Debugger::Debugger(Sword2Engine *vm)
: GUI::Debugger() {
_vm = vm;
memset(_debugTextBlocks, 0, sizeof(_debugTextBlocks));
memset(_showVar, 0, sizeof(_showVar));
_displayDebugText = false; // "INFO"
_displayWalkGrid = false; // "WALKGRID"
_displayMouseMarker = false; // "MOUSE"
_displayTime = false; // "TIME"
_displayPlayerMarker = false; // "PLAYER"
_displayTextNumbers = false; // "TEXT"
_definingRectangles = false; // "RECT"
_draggingRectangle = 0; // 0 = waiting to start new rect
// 1 = currently dragging a rectangle
_rectX1 = _rectY1 = 0;
_rectX2 = _rectY2 = 0;
_rectFlicker = false;
_testingSnR = false; // "SAVEREST" - for system to kill all
// object resources (except player) in
// fnAddHuman()
_speechScriptWaiting = 0; // The id of whoever we're waiting for
// in a speech script. See fnTheyDo(),
// fnTheyDoWeWait(), fnWeWait(), and
// fnTimedWait().
_startTime = 0; // "TIMEON" & "TIMEOFF" - system start
// time
_textNumber = 0; // Current system text line number
_graphNoFrames = 0; // No. of frames in currently displayed
// anim
// Register commands
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("q", WRAP_METHOD(Debugger, cmdExit));
registerCmd("mem", WRAP_METHOD(Debugger, Cmd_Mem));
registerCmd("tony", WRAP_METHOD(Debugger, Cmd_Tony));
registerCmd("res", WRAP_METHOD(Debugger, Cmd_Res));
registerCmd("reslist", WRAP_METHOD(Debugger, Cmd_ResList));
registerCmd("starts", WRAP_METHOD(Debugger, Cmd_Starts));
registerCmd("start", WRAP_METHOD(Debugger, Cmd_Start));
registerCmd("s", WRAP_METHOD(Debugger, Cmd_Start));
registerCmd("info", WRAP_METHOD(Debugger, Cmd_Info));
registerCmd("walkgrid", WRAP_METHOD(Debugger, Cmd_WalkGrid));
registerCmd("mouse", WRAP_METHOD(Debugger, Cmd_Mouse));
registerCmd("player", WRAP_METHOD(Debugger, Cmd_Player));
registerCmd("reslook", WRAP_METHOD(Debugger, Cmd_ResLook));
registerCmd("cur", WRAP_METHOD(Debugger, Cmd_CurrentInfo));
registerCmd("runlist", WRAP_METHOD(Debugger, Cmd_RunList));
registerCmd("kill", WRAP_METHOD(Debugger, Cmd_Kill));
registerCmd("nuke", WRAP_METHOD(Debugger, Cmd_Nuke));
registerCmd("var", WRAP_METHOD(Debugger, Cmd_Var));
registerCmd("rect", WRAP_METHOD(Debugger, Cmd_Rect));
registerCmd("clear", WRAP_METHOD(Debugger, Cmd_Clear));
registerCmd("debugon", WRAP_METHOD(Debugger, Cmd_DebugOn));
registerCmd("debugoff", WRAP_METHOD(Debugger, Cmd_DebugOff));
registerCmd("saverest", WRAP_METHOD(Debugger, Cmd_SaveRest));
registerCmd("timeon", WRAP_METHOD(Debugger, Cmd_TimeOn));
registerCmd("timeoff", WRAP_METHOD(Debugger, Cmd_TimeOff));
registerCmd("text", WRAP_METHOD(Debugger, Cmd_Text));
registerCmd("showvar", WRAP_METHOD(Debugger, Cmd_ShowVar));
registerCmd("hidevar", WRAP_METHOD(Debugger, Cmd_HideVar));
registerCmd("version", WRAP_METHOD(Debugger, Cmd_Version));
registerCmd("animtest", WRAP_METHOD(Debugger, Cmd_AnimTest));
registerCmd("texttest", WRAP_METHOD(Debugger, Cmd_TextTest));
registerCmd("linetest", WRAP_METHOD(Debugger, Cmd_LineTest));
registerCmd("events", WRAP_METHOD(Debugger, Cmd_Events));
registerCmd("sfx", WRAP_METHOD(Debugger, Cmd_Sfx));
registerCmd("english", WRAP_METHOD(Debugger, Cmd_English));
registerCmd("finnish", WRAP_METHOD(Debugger, Cmd_Finnish));
registerCmd("polish", WRAP_METHOD(Debugger, Cmd_Polish));
registerCmd("fxq", WRAP_METHOD(Debugger, Cmd_FxQueue));
}
void Debugger::varGet(int var) {
debugPrintf("%d\n", _vm->_logic->readVar(var));
}
void Debugger::varSet(int var, int val) {
debugPrintf("was %d, ", _vm->_logic->readVar(var));
_vm->_logic->writeVar(var, val);
debugPrintf("now %d\n", _vm->_logic->readVar(var));
}
void Debugger::preEnter() {
// Pause sound output
if (_vm->_sound) {
_vm->_sound->pauseFx();
_vm->_sound->pauseSpeech();
_vm->_sound->pauseMusic();
}
}
void Debugger::postEnter() {
if (_vm->_sound) {
// Resume previous sound state
_vm->_sound->unpauseFx();
_vm->_sound->unpauseSpeech();
_vm->_sound->unpauseMusic();
}
if (_vm->_mouse) {
// Restore old mouse cursor
_vm->_mouse->drawMouse();
}
}
// Now the fun stuff: Commands
static int compare_blocks(const void *p1, const void *p2) {
const MemBlock *m1 = *(const MemBlock * const *)p1;
const MemBlock *m2 = *(const MemBlock * const *)p2;
if (m1->size < m2->size)
return 1;
if (m1->size > m2->size)
return -1;
return 0;
}
bool Debugger::Cmd_Mem(int argc, const char **argv) {
int16 numBlocks = _vm->_memory->getNumBlocks();
MemBlock *memBlocks = _vm->_memory->getMemBlocks();
MemBlock **blocks = (MemBlock **)malloc(numBlocks * sizeof(MemBlock *));
int i, j;
for (i = 0, j = 0; i < MAX_MEMORY_BLOCKS; i++) {
if (memBlocks[i].ptr)
blocks[j++] = &memBlocks[i];
}
qsort(blocks, numBlocks, sizeof(MemBlock *), compare_blocks);
debugPrintf(" size id res type name\n");
debugPrintf("---------------------------------------------------------------------------\n");
for (i = 0; i < numBlocks; i++) {
const char *type;
switch (_vm->_resman->fetchType(blocks[i]->ptr)) {
case ANIMATION_FILE:
type = "ANIMATION_FILE";
break;
case SCREEN_FILE:
type = "SCREEN_FILE";
break;
case GAME_OBJECT:
type = "GAME_OBJECT";
break;
case WALK_GRID_FILE:
type = "WALK_GRID_FILE";
break;
case GLOBAL_VAR_FILE:
type = "GLOBAL_VAR_FILE";
break;
case PARALLAX_FILE_null:
type = "PARALLAX_FILE_null";
break;
case RUN_LIST:
type = "RUN_LIST";
break;
case TEXT_FILE:
type = "TEXT_FILE";
break;
case SCREEN_MANAGER:
type = "SCREEN_MANAGER";
break;
case MOUSE_FILE:
type = "MOUSE_FILE";
break;
case WAV_FILE:
type = "WAV_FILE";
break;
case ICON_FILE:
type = "ICON_FILE";
break;
case PALETTE_FILE:
type = "PALETTE_FILE";
break;
default:
type = "";
break;
}
debugPrintf("%9d %-3d %-4d %-20s %s\n",
blocks[i]->size, blocks[i]->id, blocks[i]->uid,
type, _vm->_resman->fetchName(blocks[i]->ptr));
}
free(blocks);
debugPrintf("---------------------------------------------------------------------------\n");
debugPrintf("%9d\n", _vm->_memory->getTotAlloc());
return true;
}
bool Debugger::Cmd_Tony(int argc, const char **argv) {
debugPrintf("What about him?\n");
return true;
}
bool Debugger::Cmd_Res(int argc, const char **argv) {
uint32 numClusters = _vm->_resman->getNumClusters();
if (!numClusters) {
debugPrintf("Argh! No resources!\n");
return true;
}
ResourceFile *resFiles = _vm->_resman->getResFiles();
for (uint i = 0; i < numClusters; i++) {
const char *locStr[3] = { "HDD", "CD1", "CD2" };
debugPrintf("%-20s %s\n", resFiles[i].fileName, locStr[resFiles[i].cd]);
}
debugPrintf("%d resources\n", _vm->_resman->getNumResFiles());
return true;
}
bool Debugger::Cmd_ResList(int argc, const char **argv) {
// By default, list only resources that are being held open.
uint32 minCount = 1;
if (argc > 1)
minCount = atoi(argv[1]);
uint32 numResFiles = _vm->_resman->getNumResFiles();
Resource *resList = _vm->_resman->getResList();
for (uint i = 0; i < numResFiles; i++) {
if (resList[i].ptr && resList[i].refCount >= minCount) {
debugPrintf("%-4d: %-35s refCount: %-3d\n", i, _vm->_resman->fetchName(resList[i].ptr), resList[i].refCount);
}
}
return true;
}
bool Debugger::Cmd_Starts(int argc, const char **argv) {
uint32 numStarts = _vm->getNumStarts();
if (!numStarts) {
debugPrintf("Sorry - no startup positions registered?\n");
uint32 numScreenManagers = _vm->getNumScreenManagers();
if (!numScreenManagers)
debugPrintf("There is a problem with startup.inf\n");
else
debugPrintf(" (%d screen managers found in startup.inf)\n", numScreenManagers);
return true;
}
StartUp *startList = _vm->getStartList();
for (uint i = 0; i < numStarts; i++)
debugPrintf("%d (%s)\n", i, startList[i].description);
return true;
}
bool Debugger::Cmd_Start(int argc, const char **argv) {
uint8 pal[3] = { 255, 255, 255 };
if (argc != 2) {
debugPrintf("Usage: %s number\n", argv[0]);
return true;
}
uint32 numStarts = _vm->getNumStarts();
if (!numStarts) {
debugPrintf("Sorry - there are no startups!\n");
return true;
}
int start = atoi(argv[1]);
if (start < 0 || start >= (int)numStarts) {
debugPrintf("Not a legal start position\n");
return true;
}
debugPrintf("Running start %d\n", start);
_vm->runStart(start);
_vm->_screen->setPalette(187, 1, pal, RDPAL_INSTANT);
return true;
}
bool Debugger::Cmd_Info(int argc, const char **argv) {
_displayDebugText = !_displayDebugText;
if (_displayDebugText)
debugPrintf("Info text on\n");
else
debugPrintf("Info Text off\n");
return true;
}
bool Debugger::Cmd_WalkGrid(int argc, const char **argv) {
_displayWalkGrid = !_displayWalkGrid;
if (_displayWalkGrid)
debugPrintf("Walk-grid display on\n");
else
debugPrintf("Walk-grid display off\n");
return true;
}
bool Debugger::Cmd_Mouse(int argc, const char **argv) {
_displayMouseMarker = !_displayMouseMarker;
if (_displayMouseMarker)
debugPrintf("Mouse marker on\n");
else
debugPrintf("Mouse marker off\n");
return true;
}
bool Debugger::Cmd_Player(int argc, const char **argv) {
_displayPlayerMarker = !_displayPlayerMarker;
if (_displayPlayerMarker)
debugPrintf("Player feet marker on\n");
else
debugPrintf("Player feet marker off\n");
return true;
}
bool Debugger::Cmd_ResLook(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Usage: %s number\n", argv[0]);
return true;
}
int res = atoi(argv[1]);
uint32 numResFiles = _vm->_resman->getNumResFiles();
if (res < 0 || res >= (int)numResFiles) {
debugPrintf("Illegal resource %d. There are %d resources, 0-%d.\n",
res, numResFiles, numResFiles - 1);
return true;
}
if (!_vm->_resman->checkValid(res)) {
debugPrintf("%d is a null & void resource number\n", res);
return true;
}
// Open up the resource and take a look inside!
uint8 type = _vm->_resman->fetchType(res);
switch (type) {
case ANIMATION_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case SCREEN_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case GAME_OBJECT:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case WALK_GRID_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case GLOBAL_VAR_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case PARALLAX_FILE_null:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case RUN_LIST:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case TEXT_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case SCREEN_MANAGER:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case MOUSE_FILE:
debugPrintf(" %s\n", _vm->_resman->fetchName(res));
break;
case ICON_FILE:
debugPrintf("