/* 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 "titanic/debugger.h" #include "titanic/core/node_item.h" #include "titanic/core/room_item.h" #include "titanic/core/tree_item.h" #include "titanic/core/view_item.h" #include "titanic/game_manager.h" #include "titanic/game/movie_tester.h" #include "titanic/main_game_window.h" #include "titanic/pet_control/pet_control.h" #include "titanic/support/movie.h" #include "titanic/titanic.h" #include "common/str-array.h" namespace Titanic { Debugger::Debugger(TitanicEngine *vm) : GUI::Debugger(), _vm(vm) { registerCmd("continue", WRAP_METHOD(Debugger, cmdExit)); registerCmd("dump", WRAP_METHOD(Debugger, cmdDump)); registerCmd("room", WRAP_METHOD(Debugger, cmdRoom)); registerCmd("pet", WRAP_METHOD(Debugger, cmdPET)); registerCmd("item", WRAP_METHOD(Debugger, cmdItem)); registerCmd("movie", WRAP_METHOD(Debugger, cmdMovie)); registerCmd("sound", WRAP_METHOD(Debugger, cmdSound)); registerCmd("cheat", WRAP_METHOD(Debugger, cmdCheat)); registerCmd("frame", WRAP_METHOD(Debugger, cmdFrame)); } int Debugger::strToInt(const char *s) { if (!*s) // No string at all return 0; else if (toupper(s[strlen(s) - 1]) != 'H') // Standard decimal string return atoi(s); // Hexadecimal string uint tmp = 0; int read = sscanf(s, "%xh", &tmp); if (read < 1) error("strToInt failed on string \"%s\"", s); return (int)tmp; } CRoomItem *Debugger::findRoom(const char *name) { CTreeItem *root = g_vm->_window->_gameManager->_project; CRoomItem *roomItem = dynamic_cast(root->findByName(name)); if (roomItem) return roomItem; int roomNumber = strToInt(name); for (CTreeItem *treeItem = root; treeItem; treeItem = treeItem->scan(root)) { roomItem = dynamic_cast(treeItem); if (roomItem && roomItem->_roomNumber == roomNumber) return roomItem; } return nullptr; } CNodeItem *Debugger::findNode(CRoomItem *room, const char *name) { CNodeItem *nodeItem = dynamic_cast(room->findByName(name)); if (nodeItem) return nodeItem; int nodeNumber = strToInt(name); nodeItem = dynamic_cast(room->findChildInstanceOf(CNodeItem::_type)); while (nodeItem) { if (nodeItem->_nodeNumber == nodeNumber) return nodeItem; nodeItem = dynamic_cast(room->findNextInstanceOf(CNodeItem::_type, nodeItem)); } return nullptr; } CViewItem *Debugger::findView(CNodeItem *node, const char *name) { CViewItem *viewItem = dynamic_cast(node->findByName(name)); if (viewItem) return viewItem; int viewNumber = strToInt(name); viewItem = dynamic_cast(node->findChildInstanceOf(CViewItem::_type)); while (viewItem) { if (viewItem->_viewNumber == viewNumber) return viewItem; viewItem = dynamic_cast(node->findNextInstanceOf(CViewItem::_type, viewItem)); } return nullptr; } void Debugger::listRooms() { CGameManager &gm = *g_vm->_window->_gameManager; CTreeItem *root = gm._project; CViewItem *view = gm._gameState._gameLocation.getView(); CNodeItem *node = gm._gameState._gameLocation.getNode(); CRoomItem *room = gm._gameState._gameLocation.getRoom(); debugPrintf("Current location: %s, %s, %s\n", room->getName().c_str(), node->getName().c_str(), view->getName().c_str()); debugPrintf("Available rooms:\n"); for (CTreeItem *treeItem = root; treeItem; treeItem = treeItem->scan(root)) { CRoomItem *roomItem = dynamic_cast(treeItem); if (roomItem) debugPrintf("%d - %s\n", roomItem->_roomNumber, roomItem->_name.c_str()); } } void Debugger::listRoom(CRoomItem *room) { for (CTreeItem *treeItem = room; treeItem; treeItem = treeItem->scan(room)) { CNodeItem *nodeItem = dynamic_cast(treeItem); if (nodeItem) debugPrintf("%s\n", nodeItem->_name.c_str()); } } void Debugger::listNode(CNodeItem *node) { for (CTreeItem *treeItem = node; treeItem; treeItem = treeItem->scan(node)) { CViewItem *viewItem = dynamic_cast(treeItem); if (viewItem) debugPrintf("%s\n", viewItem->_name.c_str()); } } bool Debugger::cmdDump(int argc, const char **argv) { // Get the starting node CTreeItem *root = g_vm->_window->_gameManager->_project; if (argc == 2) root = root->findByName(argv[1]); if (root == nullptr) { debugPrintf("Could not find item\n"); } else { root->dump(0); debugPrintf("Item and it's content were dumped to stdout\n"); } return true; } bool Debugger::cmdRoom(int argc, const char **argv) { if (argc == 1) { listRooms(); } else if (argc >= 2) { CRoomItem *roomItem = findRoom(argv[1]); if (!roomItem && argc == 2) { // Presume it's a full view specified CProjectItem *project = g_vm->_window->_project; CViewItem *view = project->parseView(argv[1]); if (view) { project->changeView(argv[1]); return false; } else { debugPrintf("Could not find view - %s\n", argv[1]); } } else if (argc == 2) listRoom(roomItem); else { CNodeItem *nodeItem = findNode(roomItem, argv[2]); if (!nodeItem) debugPrintf("Could not find node - %s\n", argv[2]); else if (argc == 3) listNode(nodeItem); else { CViewItem *viewItem = findView(nodeItem, argv[3]); if (!viewItem) { debugPrintf("Could not find view - %s\n", argv[3]); } else { // Change to the specified view g_vm->_window->_gameManager->_gameState.changeView(viewItem, nullptr); return false; } } } } return true; } bool Debugger::cmdPET(int argc, const char **argv) { CGameManager &gameManager = *g_vm->_window->_gameManager; CGameState &gameState = gameManager._gameState; if (argc == 2) { CString s(argv[1]); s.toLowercase(); if (s == "on") { gameState._petActive = true; gameManager.markAllDirty(); debugPrintf("PET is now on\n"); return true; } else if (s == "off") { gameState._petActive = false; gameManager.update(); debugPrintf("PET is now off\n"); return true; } } debugPrintf("%s [on | off]\n", argv[0]); return true; } bool Debugger::cmdItem(int argc, const char **argv) { CGameManager &gameManager = *g_vm->_window->_gameManager; CGameState &gameState = gameManager._gameState; if (argc == 1) { // No parameters, so list the available items debugPrintf("item [ [ add ]]\n"); for (int idx = 0; idx < 40; ++idx) debugPrintf("%s\n", g_vm->_itemIds[idx].c_str()); } else { // Ensure the specified name is a valid inventory item int itemIndex; for (itemIndex = 0; itemIndex < 40; ++itemIndex) { if (g_vm->_itemIds[itemIndex] == argv[1]) break; } if (itemIndex == 40) { debugPrintf("Could not find item with that name\n"); return true; } // Get the item CCarry *item = dynamic_cast( g_vm->_window->_project->findByName(argv[1])); assert(item); if (argc == 2) { // List it's details CTreeItem *treeItem = item; CString fullName; while ((treeItem = treeItem->getParent()) != nullptr) { if (!treeItem->getName().empty()) fullName = treeItem->getName() + "." + fullName; } debugPrintf("Current location: %s\n", fullName.c_str()); } else if (CString(argv[2]) == "add") { // Ensure the PET is active and add the item to the inventory gameState._petActive = true; gameManager.markAllDirty(); item->petAddToInventory(); return false; } else { debugPrintf("Unknown command\n"); } } return true; } bool Debugger::cmdMovie(int argc, const char **argv) { if (argc < 2) { debugPrintf("movie filename.avi [startFrame endFrame]\n"); return true; } CViewItem *view = g_vm->_window->_gameManager->getView(); CMovieTester *tester = static_cast( view->findChildInstanceOf(CMovieTester::_type)); if (!tester) { // No movie tester present, so create one tester = new CMovieTester(); tester->addUnder(view); } CString filename(argv[1]); if (filename == "reverse" || filename == "doubletake") { // Tests reverse playback transparency frames tester->loadMovie("y457.avi"); if (filename == "reverse") { tester->playMovie(436, 0, MOVIE_STOP_PREVIOUS); } else { tester->playMovie(436, 432, MOVIE_STOP_PREVIOUS); tester->playMovie(432, 436, 0); tester->playMovie(436, 432, 0); tester->playMovie(432, 436, 0); } return false; } if (!filename.hasSuffix(".avi")) filename += ".avi"; tester->loadMovie(filename); if (argc == 2) { tester->playMovie(MOVIE_STOP_PREVIOUS); } else { uint startFrame = strToInt(argv[2]); uint endFrame = strToInt(argv[2]); tester->playMovie(startFrame, endFrame, MOVIE_STOP_PREVIOUS); } return false; } bool Debugger::cmdSound(int argc, const char **argv) { if (argc == 2) { Common::String name = argv[1]; if (!name.contains("#")) name = "z#" + name; CGameManager *gameManager = g_vm->_window->_gameManager; CProximity prox; gameManager->_sound.playSound(name, prox); return false; } else { debugPrintf("sound \n"); return true; } } bool Debugger::cmdCheat(int argc, const char **argv) { CGameManager *gameManager = g_vm->_window->_gameManager; CProjectItem *project = g_vm->_window->_project; CViewItem *newView = project->parseView("Cheat Room.Node 1.Cheat Rooms View"); gameManager->_gameState.changeView(newView, nullptr); return false; } bool Debugger::cmdFrame(int argc, const char **argv) { if (argc == 3) { CGameObject *obj = dynamic_cast( g_vm->_window->_project->findByName(argv[1])); if (obj) { obj->loadFrame(strToInt(argv[2])); return false; } else { debugPrintf("Object not found\n"); return true; } } else { debugPrintf("frame "); return true; } } } // End of namespace Titanic