diff options
Diffstat (limited to 'engines/agi/console.cpp')
-rw-r--r-- | engines/agi/console.cpp | 423 |
1 files changed, 400 insertions, 23 deletions
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp index 6d7f9384cd..9a4a357b44 100644 --- a/engines/agi/console.cpp +++ b/engines/agi/console.cpp @@ -22,6 +22,7 @@ #include "agi/agi.h" #include "agi/opcodes.h" +#include "agi/graphics.h" #include "agi/preagi.h" #include "agi/preagi_mickey.h" @@ -32,22 +33,28 @@ namespace Agi { Console::Console(AgiEngine *vm) : GUI::Debugger() { _vm = vm; - registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug)); - registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont)); - registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver)); - registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags)); - registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0)); - registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs)); - registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode)); - registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode)); - registerCmd("step", WRAP_METHOD(Console, Cmd_Step)); - registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger)); - registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars)); - registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar)); - registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag)); - registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj)); - registerCmd("room", WRAP_METHOD(Console, Cmd_Room)); - registerCmd("bt", WRAP_METHOD(Console, Cmd_BT)); + registerCmd("debug", WRAP_METHOD(Console, Cmd_Debug)); + registerCmd("cont", WRAP_METHOD(Console, Cmd_Cont)); + registerCmd("agiver", WRAP_METHOD(Console, Cmd_Agiver)); + registerCmd("version", WRAP_METHOD(Console, Cmd_Version)); + registerCmd("flags", WRAP_METHOD(Console, Cmd_Flags)); + registerCmd("logic0", WRAP_METHOD(Console, Cmd_Logic0)); + registerCmd("objs", WRAP_METHOD(Console, Cmd_Objs)); + registerCmd("runopcode", WRAP_METHOD(Console, Cmd_RunOpcode)); + registerCmd("opcode", WRAP_METHOD(Console, Cmd_Opcode)); + registerCmd("step", WRAP_METHOD(Console, Cmd_Step)); + registerCmd("trigger", WRAP_METHOD(Console, Cmd_Trigger)); + registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars)); + registerCmd("setvar", WRAP_METHOD(Console, Cmd_SetVar)); + registerCmd("setflag", WRAP_METHOD(Console, Cmd_SetFlag)); + registerCmd("setobj", WRAP_METHOD(Console, Cmd_SetObj)); + registerCmd("room", WRAP_METHOD(Console, Cmd_Room)); + registerCmd("bt", WRAP_METHOD(Console, Cmd_BT)); + registerCmd("show_map", WRAP_METHOD(Console, Cmd_ShowMap)); + registerCmd("screenobj", WRAP_METHOD(Console, Cmd_ScreenObj)); + registerCmd("vmvars", WRAP_METHOD(Console, Cmd_VmVars)); + registerCmd("vmflags", WRAP_METHOD(Console, Cmd_VmFlags)); + registerCmd("disableautosave", WRAP_METHOD(Console, Cmd_DisableAutomaticSave)); } bool Console::Cmd_SetVar(int argc, const char **argv) { @@ -57,7 +64,7 @@ bool Console::Cmd_SetVar(int argc, const char **argv) { } int p1 = (int)atoi(argv[1]); int p2 = (int)atoi(argv[2]); - _vm->setvar(p1, p2); + _vm->setVar(p1, p2); return true; } @@ -69,7 +76,7 @@ bool Console::Cmd_SetFlag(int argc, const char **argv) { } int p1 = (int)atoi(argv[1]); int p2 = (int)atoi(argv[2]); - _vm->setflag(p1, !!p2); + _vm->setFlag(p1, !!p2); return true; } @@ -125,11 +132,154 @@ bool Console::Cmd_Agiver(int argc, const char **argv) { maj = (ver >> 12) & 0xf; min = ver & 0xfff; + debugPrintf("AGI version: "); debugPrintf(maj <= 2 ? "%x.%03x\n" : "%x.002.%03x\n", maj, min); return true; } +#define CONSOLE_VERSION_MAXLEN 10 + +bool Console::Cmd_Version(int argc, const char **argv) { + AgiGame *game = &_vm->_game; + int scriptNr = 0; + int scriptTextCount = 0; + int scriptTextNr = 0; + const char *scriptTextPtr = NULL; + const char *wordScanPtr = NULL; + const char *wordStartPtr = NULL; + const char *versionStartPtr = NULL; + int wordLen = 0; + char curChar = 0; + int versionLen = 0; + bool wordFound = false; + bool versionFound = false; + char versionString[CONSOLE_VERSION_MAXLEN]; + bool scriptLoadedByUs = false; + + // Show AGI version + Cmd_Agiver(argc, argv); + + // And now try to figure out the version of the game + // We do this by scanning through all script texts + // This is the best we can do about it. There is no special location for the game version number. + // There are multiple variations, like "ver. X.XX", "ver X.XX" and even "verion X.XX". + for (scriptNr = 0; scriptNr < MAX_DIRECTORY_ENTRIES; scriptNr++) { + if (game->dirLogic[scriptNr].offset != _EMPTY) { + // Script is supposed to exist? + scriptLoadedByUs = false; + if (!(game->dirLogic[scriptNr].flags & RES_LOADED)) { + // But not currently loaded? -> load it now + if (_vm->agiLoadResource(RESOURCETYPE_LOGIC, scriptNr) != errOK) { + // In case we can't load the source, skip it + continue; + } + scriptLoadedByUs = true; + } + // Script currently loaded + // Now scan all texts + scriptTextCount = game->logics[scriptNr].numTexts; + for (scriptTextNr = 0; scriptTextNr < scriptTextCount; scriptTextNr++) { + scriptTextPtr = game->logics[scriptNr].texts[scriptTextNr]; + + // Now scan this text for version information + wordScanPtr = scriptTextPtr; + + do { + curChar = *wordScanPtr; + + if ((curChar == 'V') || (curChar == 'v')) { + // "V" gefunden, ggf. beginning of version? + wordStartPtr = wordScanPtr; + wordFound = false; + + do { + curChar = *wordScanPtr; + if (curChar == ' ') { + break; + } + wordScanPtr++; + } while (curChar); + + if (curChar) { + // end of "version" found + wordLen = wordScanPtr - wordStartPtr; + + if (wordLen >= 3) { + if (strncmp(wordStartPtr, "ver", wordLen) == 0) + wordFound = true; + if (strncmp(wordStartPtr, "Ver", wordLen) == 0) + wordFound = true; + } + if ((!wordFound) && (wordLen >= 4)) { + if (strncmp(wordStartPtr, "ver.", wordLen) == 0) + wordFound = true; + if (strncmp(wordStartPtr, "Ver.", wordLen) == 0) + wordFound = true; + } + if ((!versionFound) && (wordLen >= 7)) { + if (strncmp(wordStartPtr, "version", wordLen) == 0) + wordFound = true; + if (strncmp(wordStartPtr, "Version", wordLen) == 0) + wordFound = true; + if (strncmp(wordStartPtr, "VERSION", wordLen) == 0) + wordFound = true; + } + + if (wordFound) { + // We found something interesting + //debugPrintf("%d: %s\n", scriptNr, scriptTextPtr); + + wordScanPtr++; // skip space + versionStartPtr = wordScanPtr; + curChar = *wordScanPtr; + if ((curChar >= '0') && (curChar <= '9')) { + // Next word starts with a number + wordScanPtr++; + curChar = *wordScanPtr; + if (curChar == '.') { + // Followed by a point? then we assume that we found a version number + // Now we try to find the end of it + wordScanPtr++; + do { + curChar = *wordScanPtr; + if ((curChar == ' ') || (curChar == '\\') || (!curChar)) + break; // space or potential new line or NUL? -> found the end + wordScanPtr++; + } while (1); + + versionLen = wordScanPtr - versionStartPtr; + if (versionLen < CONSOLE_VERSION_MAXLEN) { + // Looks fine, now extract and show it + memcpy(versionString, versionStartPtr, versionLen); + versionString[versionLen] = 0; + debugPrintf("Scanned game version: %s\n", versionString); + versionFound = true; + } + } + } + } + } + + // Seek back + wordScanPtr = wordStartPtr; + } + wordScanPtr++; + } while (curChar); + } + + if (scriptLoadedByUs) { + _vm->agiUnloadResource(RESOURCETYPE_LOGIC, scriptNr); + } + } + } + + if (!versionFound) { + debugPrintf("Scanned game version: [not found]\n"); + } + return true; +} + bool Console::Cmd_Flags(int argc, const char **argv) { int i, j; @@ -141,7 +291,7 @@ bool Console::Cmd_Flags(int argc, const char **argv) { for (i = 0; i < 255;) { debugPrintf("%3d ", i); for (j = 0; j < 10; j++, i++) { - debugPrintf("%c ", _vm->getflag(i) ? 'T' : 'F'); + debugPrintf("%c ", _vm->getFlag(i) ? 'T' : 'F'); } debugPrintf("\n"); } @@ -154,7 +304,7 @@ bool Console::Cmd_Vars(int argc, const char **argv) { for (i = 0; i < 255;) { for (j = 0; j < 5; j++, i++) { - debugPrintf("%03d:%3d ", i, _vm->getvar(i)); + debugPrintf("%03d:%3d ", i, _vm->getVar(i)); } debugPrintf("\n"); } @@ -199,7 +349,7 @@ bool Console::Cmd_Trigger(int argc, const char **argv) { debugPrintf("Usage: trigger on|off\n"); return true; } - _vm->_debug.ignoretriggers = strcmp (argv[1], "on"); + _vm->_debug.ignoretriggers = strcmp(argv[1], "on"); return true; } @@ -236,13 +386,13 @@ bool Console::Cmd_Room(int argc, const char **argv) { _vm->newRoom(strtoul(argv[1], NULL, 0)); } - debugPrintf("Current room: %d\n", _vm->getvar(0)); + debugPrintf("Current room: %d\n", _vm->getVar(0)); return true; } bool Console::Cmd_BT(int argc, const char **argv) { - debugPrintf("Current script: %d\nStack depth: %d\n", _vm->_game.lognum, _vm->_game.execStack.size()); + debugPrintf("Current script: %d\nStack depth: %d\n", _vm->_game.curLogicNr, _vm->_game.execStack.size()); uint8 *code = NULL; uint8 op = 0; @@ -268,6 +418,233 @@ bool Console::Cmd_BT(int argc, const char **argv) { return true; } +bool Console::Cmd_ShowMap(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Switches to one of the following screen maps\n"); + debugPrintf("Usage: %s <screen map>\n", argv[0]); + debugPrintf("Screen maps:\n"); + debugPrintf("- 0: visual map\n"); + debugPrintf("- 1: priority map\n"); + return true; + } + + int map = atoi(argv[1]); + + switch (map) { + case 0: + case 1: + _vm->_gfx->debugShowMap(map); + break; + + default: + debugPrintf("Map %d is not available.\n", map); + return true; + } + return cmdExit(0, 0); +} + +bool Console::Cmd_ScreenObj(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Shows information about a specific screen object\n"); + debugPrintf("Usage: %s <screenobj number>\n", argv[0]); + return true; + } + + int16 screenObjNr = atoi(argv[1]); + + if ((screenObjNr >= 0) && (screenObjNr < SCREENOBJECTS_MAX)) { + ScreenObjEntry *screenObj = &_vm->_game.screenObjTable[screenObjNr]; + + debugPrintf("Screen Object ID %d\n", screenObj->objectNr); + debugPrintf("current view: %d, loop: %d, cel: %d\n", screenObj->currentViewNr, screenObj->currentLoopNr, screenObj->currentCelNr); + + // Figure out flags + Common::String flagsString; + + if (screenObj->flags & fDrawn) + flagsString += "Drawn "; + if (screenObj->flags & fIgnoreBlocks) + flagsString += "IgnoreBlocks "; + if (screenObj->flags & fFixedPriority) + flagsString += "FixedPriority "; + if (screenObj->flags & fIgnoreHorizon) + flagsString += "IgnoreHorizon "; + if (screenObj->flags & fUpdate) + flagsString += "Update "; + if (screenObj->flags & fCycling) + flagsString += "Cycling "; + if (screenObj->flags & fAnimated) + flagsString += "Animated "; + if (screenObj->flags & fMotion) + flagsString += "Motion "; + if (screenObj->flags & fOnWater) + flagsString += "OnWater "; + if (screenObj->flags & fIgnoreObjects) + flagsString += "IgnoreObjects "; + if (screenObj->flags & fUpdatePos) + flagsString += "UpdatePos "; + if (screenObj->flags & fOnLand) + flagsString += "OnLand "; + if (screenObj->flags & fDontupdate) + flagsString += "DontUpdate "; + if (screenObj->flags & fFixLoop) + flagsString += "FixLoop "; + if (screenObj->flags & fDidntMove) + flagsString += "DidntMove "; + if (screenObj->flags & fAdjEgoXY) + flagsString += "AdjEgoXY "; + + if (flagsString.size() == 0) { + flagsString += "*none*"; + } + + debugPrintf("flags: %s\n", flagsString.c_str()); + + debugPrintf("\n"); + debugPrintf("xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize); + debugPrintf("previous: xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos_prev, screenObj->yPos_prev, screenObj->xSize_prev, screenObj->ySize_prev); + debugPrintf("direction: %d, priority: %d\n", screenObj->direction, screenObj->priority); + debugPrintf("stepTime: %d, timeCount: %d, size: %d\n", screenObj->stepTime, screenObj->stepTimeCount, screenObj->stepSize); + debugPrintf("cycleTime: %d, timeCount: %d\n", screenObj->cycleTime, screenObj->cycleTimeCount); + + switch (screenObj->motionType) { + case kMotionNormal: + debugPrintf("motion: normal\n"); + break; + case kMotionWander: + debugPrintf("motion: wander\n"); + debugPrintf("wanderCount: %d\n", screenObj->wander_count); + break; + case kMotionFollowEgo: + debugPrintf("motion: follow ego\n"); + debugPrintf("stepSize: %d, flag: %x, count: %d", screenObj->follow_stepSize, screenObj->follow_flag, screenObj->follow_count); + break; + case kMotionMoveObj: + case kMotionEgo: + if (screenObj->motionType == kMotionMoveObj) { + debugPrintf("motion: move obj\n"); + } else { + debugPrintf("motion: ego\n"); + } + debugPrintf("x: %d, y: %d, stepSize: %d, flag: %x\n", screenObj->move_x, screenObj->move_y, screenObj->move_stepSize, screenObj->move_flag); + break; + } + } + return true; +} + +bool Console::Cmd_VmVars(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Shows the content of a VM variable / sets it\n"); + debugPrintf("Usage: %s <variable number> [<value>]\n", argv[0]); + return true; + } + + int varNr = 0; + int newValue = 0; + + if (!parseInteger(argv[1], varNr)) + return true; + + if ((varNr < 0) || (varNr > 255)) { + debugPrintf("invalid variable number\n"); + return true; + } + + if (argc < 3) { + // show contents + debugPrintf("variable %d == %d\n", varNr, _vm->getVar(varNr)); + } else { + if (!parseInteger(argv[2], newValue)) + return true; + + _vm->setVar(varNr, newValue); + + debugPrintf("value set.\n"); + } + return true; +} + +bool Console::Cmd_VmFlags(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Shows the content of a VM flag / sets it\n"); + debugPrintf("Usage: %s <flag number> [<value>]\n", argv[0]); + return true; + } + + int flagNr = 0; + int newFlagState = 0; + + if (!parseInteger(argv[1], flagNr)) + return true; + + if ((flagNr < 0) || (flagNr > 255)) { + debugPrintf("invalid flag number\n"); + return true; + } + + if (argc < 3) { + // show contents + if (_vm->getFlag(flagNr)) { + debugPrintf("flag %d == set\n", flagNr); + } else { + debugPrintf("flag %d == not set\n", flagNr); + } + } else { + if (!parseInteger(argv[2], newFlagState)) + return true; + + if ((newFlagState != 0) && (newFlagState != 1)) { + debugPrintf("new state must bei either 0 or 1\n"); + return true; + } + + if (!newFlagState) { + _vm->setFlag(flagNr, false); + debugPrintf("flag %d reset.\n", flagNr); + } else { + _vm->setFlag(flagNr, true); + debugPrintf("flag %d set.\n", flagNr); + } + } + return true; +} + +bool Console::Cmd_DisableAutomaticSave(int argc, const char **argv) { + if (!_vm->_game.automaticSave) { + debugPrintf("Automatic saving is currently not enabled\n"); + return true; + } + + _vm->_game.automaticSave = false; + + debugPrintf("Automatic saving DISABLED!\n"); + return true; +} + +bool Console::parseInteger(const char *argument, int &result) { + char *endPtr = 0; + int idxLen = strlen(argument); + const char *lastChar = argument + idxLen - (idxLen == 0 ? 0 : 1); + + if ((strncmp(argument, "0x", 2) == 0) || (*lastChar == 'h')) { + // hexadecimal number + result = strtol(argument, &endPtr, 16); + if ((*endPtr != 0) && (*endPtr != 'h')) { + debugPrintf("Invalid hexadecimal number '%s'\n", argument); + return false; + } + } else { + // decimal number + result = strtol(argument, &endPtr, 10); + if (*endPtr != 0) { + debugPrintf("Invalid decimal number '%s'\n", argument); + return false; + } + } + return true; +} + MickeyConsole::MickeyConsole(MickeyEngine *mickey) : GUI::Debugger() { _mickey = mickey; |