/* 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. * * $URL$ * $Id$ * */ #include "mohawk/console.h" #include "mohawk/myst.h" #include "mohawk/myst_scripts.h" #include "mohawk/graphics.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" #include "mohawk/livingbooks.h" #include "mohawk/sound.h" #include "mohawk/video.h" namespace Mohawk { MystConsole::MystConsole(MohawkEngine_Myst *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("changeCard", WRAP_METHOD(MystConsole, Cmd_ChangeCard)); DCmd_Register("curCard", WRAP_METHOD(MystConsole, Cmd_CurCard)); DCmd_Register("var", WRAP_METHOD(MystConsole, Cmd_Var)); DCmd_Register("curStack", WRAP_METHOD(MystConsole, Cmd_CurStack)); DCmd_Register("changeStack", WRAP_METHOD(MystConsole, Cmd_ChangeStack)); DCmd_Register("drawImage", WRAP_METHOD(MystConsole, Cmd_DrawImage)); DCmd_Register("drawRect", WRAP_METHOD(MystConsole, Cmd_DrawRect)); DCmd_Register("setResourceEnable", WRAP_METHOD(MystConsole, Cmd_SetResourceEnable)); DCmd_Register("playSound", WRAP_METHOD(MystConsole, Cmd_PlaySound)); DCmd_Register("stopSound", WRAP_METHOD(MystConsole, Cmd_StopSound)); DCmd_Register("playMovie", WRAP_METHOD(MystConsole, Cmd_PlayMovie)); DCmd_Register("disableInitOpcodes", WRAP_METHOD(MystConsole, Cmd_DisableInitOpcodes)); DCmd_Register("cache", WRAP_METHOD(MystConsole, Cmd_Cache)); } MystConsole::~MystConsole() { } void MystConsole::preEnter() { _vm->_sound->pauseSound(); } void MystConsole::postEnter() { _vm->_sound->resumeSound(); } bool MystConsole::Cmd_ChangeCard(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Usage: changeCard \n"); return true; } _vm->_sound->stopSound(); _vm->changeToCard((uint16)atoi(argv[1]), true); return false; } bool MystConsole::Cmd_CurCard(int argc, const char **argv) { DebugPrintf("Current Card: %d\n", _vm->getCurCard()); return true; } bool MystConsole::Cmd_Var(int argc, const char **argv) { if (argc == 1) { DebugPrintf("Usage: var ()\n"); return true; } if (argc > 2) _vm->_scriptParser->setVarValue((uint16)atoi(argv[1]), (uint16)atoi(argv[2])); DebugPrintf("%d = %d\n", (uint16)atoi(argv[1]), _vm->_scriptParser->getVar((uint16)atoi(argv[1]))); return true; } static const char *mystStackNames[12] = { "Channelwood", "Credits", "Demo", "D'ni", "Intro", "MakingOf", "Mechanical", "Myst", "Selenitic", "Slideshow", "SneakPreview", "Stoneship" }; static const uint16 default_start_card[12] = { 3137, 10000, 2001, // TODO: Should be 2000? 5038, 2, // TODO: Should be 1? 1, 6122, 4134, 1282, 1000, 3000, 2029 }; bool MystConsole::Cmd_CurStack(int argc, const char **argv) { DebugPrintf("Current Stack: %s\n", mystStackNames[_vm->getCurStack()]); return true; } bool MystConsole::Cmd_ChangeStack(int argc, const char **argv) { if (argc != 2 && argc != 3) { DebugPrintf("Usage: changeStack []\n\n"); DebugPrintf("Stacks:\n=======\n"); for (byte i = 0; i < ARRAYSIZE(mystStackNames); i++) DebugPrintf(" %s\n", mystStackNames[i]); DebugPrintf("\n"); return true; } byte stackNum = 0; for (byte i = 1; i <= ARRAYSIZE(mystStackNames); i++) if (!scumm_stricmp(argv[1], mystStackNames[i - 1])) { stackNum = i; break; } if (!stackNum) { DebugPrintf("\'%s\' is not a stack name!\n", argv[1]); return true; } // We need to stop any playing sound when we change the stack // as the next card could continue playing it if it. _vm->_sound->stopSound(); _vm->changeToStack(stackNum - 1); if (argc == 3) _vm->changeToCard((uint16)atoi(argv[2]), true); else _vm->changeToCard(default_start_card[stackNum - 1], true); return false; } bool MystConsole::Cmd_DrawImage(int argc, const char **argv) { if (argc != 2 && argc != 6) { DebugPrintf("Usage: drawImage [ ]\n"); return true; } Common::Rect rect; if (argc == 2) rect = Common::Rect(0, 0, 544, 333); else rect = Common::Rect((uint16)atoi(argv[2]), (uint16)atoi(argv[3]), (uint16)atoi(argv[4]), (uint16)atoi(argv[5])); _vm->_gfx->copyImageToScreen((uint16)atoi(argv[1]), rect); return false; } bool MystConsole::Cmd_DrawRect(int argc, const char **argv) { if (argc < 5) { DebugPrintf("Usage: drawRect \n"); return true; } _vm->_gfx->drawRect(Common::Rect((uint16)atoi(argv[1]), (uint16)atoi(argv[2]), (uint16)atoi(argv[3]), (uint16)atoi(argv[4])), kRectEnabled); return false; } bool MystConsole::Cmd_SetResourceEnable(int argc, const char **argv) { if (argc < 3) { DebugPrintf("Usage: setResourceEnable \n"); return true; } _vm->setResourceEnabled((uint16)atoi(argv[1]), atoi(argv[2]) == 1); return true; } bool MystConsole::Cmd_PlaySound(int argc, const char **argv) { if (argc == 1) { DebugPrintf("Usage: playSound \n"); return true; } _vm->_sound->stopSound(); _vm->_sound->playSound((uint16)atoi(argv[1])); return false; } bool MystConsole::Cmd_StopSound(int argc, const char **argv) { DebugPrintf("Stopping Sound\n"); _vm->_sound->stopSound(); return true; } bool MystConsole::Cmd_PlayMovie(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Usage: playMovie [] [ ]\n"); DebugPrintf("NOTE: The movie will play *once* in the background.\n"); return true; } int8 stackNum = 0; if (argc == 3 || argc > 4) { for (byte i = 1; i <= ARRAYSIZE(mystStackNames); i++) if (!scumm_stricmp(argv[2], mystStackNames[i - 1])) { stackNum = i; break; } if (!stackNum) { DebugPrintf("\'%s\' is not a stack name!\n", argv[2]); return true; } } if (argc == 2) _vm->_video->playBackgroundMovie(argv[1], 0, 0); else if (argc == 3) _vm->_video->playBackgroundMovie(_vm->wrapMovieFilename(argv[1], stackNum - 1), 0, 0); else if (argc == 4) _vm->_video->playBackgroundMovie(argv[1], atoi(argv[2]), atoi(argv[3])); else _vm->_video->playBackgroundMovie(_vm->wrapMovieFilename(argv[1], stackNum - 1), atoi(argv[3]), atoi(argv[4])); return false; } bool MystConsole::Cmd_DisableInitOpcodes(int argc, const char **argv) { if (argc != 1) { DebugPrintf("Usage: disableInitOpcodes\n"); return true; } _vm->_scriptParser->disablePersistentScripts(); return true; } bool MystConsole::Cmd_Cache(int argc, const char **argv) { if (argc > 2) { DebugPrintf("Usage: cache on/off - Omit parameter to get current state\n"); return true; } bool state = false; if (argc == 1) { state = _vm->getCacheState(); } else { if (!scumm_stricmp(argv[1], "on")) state = true; _vm->setCacheState(state); } DebugPrintf("Cache: %s\n", state ? "Enabled" : "Disabled"); return true; } RivenConsole::RivenConsole(MohawkEngine_Riven *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("changeCard", WRAP_METHOD(RivenConsole, Cmd_ChangeCard)); DCmd_Register("curCard", WRAP_METHOD(RivenConsole, Cmd_CurCard)); DCmd_Register("var", WRAP_METHOD(RivenConsole, Cmd_Var)); DCmd_Register("playSound", WRAP_METHOD(RivenConsole, Cmd_PlaySound)); DCmd_Register("playSLST", WRAP_METHOD(RivenConsole, Cmd_PlaySLST)); DCmd_Register("stopSound", WRAP_METHOD(RivenConsole, Cmd_StopSound)); DCmd_Register("curStack", WRAP_METHOD(RivenConsole, Cmd_CurStack)); DCmd_Register("changeStack", WRAP_METHOD(RivenConsole, Cmd_ChangeStack)); DCmd_Register("restart", WRAP_METHOD(RivenConsole, Cmd_Restart)); DCmd_Register("hotspots", WRAP_METHOD(RivenConsole, Cmd_Hotspots)); DCmd_Register("zipMode", WRAP_METHOD(RivenConsole, Cmd_ZipMode)); DCmd_Register("dumpScript", WRAP_METHOD(RivenConsole, Cmd_DumpScript)); DCmd_Register("listZipCards", WRAP_METHOD(RivenConsole, Cmd_ListZipCards)); DCmd_Register("getRMAP", WRAP_METHOD(RivenConsole, Cmd_GetRMAP)); DCmd_Register("combos", WRAP_METHOD(RivenConsole, Cmd_Combos)); DCmd_Register("sliderState", WRAP_METHOD(RivenConsole, Cmd_SliderState)); } RivenConsole::~RivenConsole() { } void RivenConsole::preEnter() { _vm->_sound->pauseSound(); _vm->_sound->pauseSLST(); } void RivenConsole::postEnter() { _vm->_sound->resumeSound(); _vm->_sound->resumeSLST(); } bool RivenConsole::Cmd_ChangeCard(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Usage: changeCard \n"); return true; } _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); _vm->changeToCard((uint16)atoi(argv[1])); return false; } bool RivenConsole::Cmd_CurCard(int argc, const char **argv) { DebugPrintf("Current Card: %d\n", _vm->getCurCard()); return true; } bool RivenConsole::Cmd_Var(int argc, const char **argv) { if (argc == 1) { DebugPrintf("Usage: var ()\n"); return true; } uint32 *globalVar = _vm->getVar(argv[1]); if (!globalVar) { DebugPrintf("Unknown variable \'%s\'\n", argv[1]); return true; } if (argc > 2) *globalVar = (uint32)atoi(argv[2]); DebugPrintf("%s = %d\n", argv[1], *globalVar); return true; } bool RivenConsole::Cmd_PlaySound(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Usage: playSound \n"); return true; } _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); _vm->_sound->playSound((uint16)atoi(argv[1])); return false; } bool RivenConsole::Cmd_PlaySLST(int argc, const char **argv) { if (argc < 2) { DebugPrintf("Usage: playSLST \n"); return true; } _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); uint16 card = (argc == 3) ? (uint16)atoi(argv[2]) : _vm->getCurCard(); _vm->_sound->playSLST((uint16)atoi(argv[1]), card); return false; } bool RivenConsole::Cmd_StopSound(int argc, const char **argv) { DebugPrintf("Stopping Sound\n"); _vm->_sound->stopSound(); _vm->_sound->stopAllSLST(); return true; } bool RivenConsole::Cmd_CurStack(int argc, const char **argv) { DebugPrintf("Current Stack: %s\n", _vm->getStackName(_vm->getCurStack()).c_str()); return true; } bool RivenConsole::Cmd_ChangeStack(int argc, const char **argv) { byte i; if (argc < 3) { DebugPrintf("Usage: changeStack \n\n"); DebugPrintf("Stacks:\n=======\n"); for (i = 0; i <= tspit; i++) DebugPrintf(" %s\n", _vm->getStackName(i).c_str()); DebugPrintf("\n"); return true; } byte stackNum = 0; for (i = 1; i <= tspit + 1; i++) if (!scumm_stricmp(argv[1], _vm->getStackName(i - 1).c_str())) { stackNum = i; break; } if (!stackNum) { DebugPrintf("\'%s\' is not a stack name!\n", argv[1]); return true; } _vm->changeToStack(stackNum - 1); _vm->changeToCard((uint16)atoi(argv[2])); return false; } bool RivenConsole::Cmd_Restart(int argc, const char **argv) { _vm->initVars(); _vm->changeToStack(aspit); _vm->changeToCard(1); return false; } bool RivenConsole::Cmd_Hotspots(int argc, const char **argv) { DebugPrintf("Current card (%d) has %d hotspots:\n", _vm->getCurCard(), _vm->getHotspotCount()); for (uint16 i = 0; i < _vm->getHotspotCount(); i++) { DebugPrintf("Hotspot %d, index %d, BLST ID %d (", i, _vm->_hotspots[i].index, _vm->_hotspots[i].blstID); if (_vm->_hotspots[i].enabled) DebugPrintf("enabled"); else DebugPrintf("disabled"); DebugPrintf(") - (%d, %d, %d, %d)\n", _vm->_hotspots[i].rect.left, _vm->_hotspots[i].rect.top, _vm->_hotspots[i].rect.right, _vm->_hotspots[i].rect.bottom); DebugPrintf(" Name = %s\n", _vm->getHotspotName(i).c_str()); } return true; } bool RivenConsole::Cmd_ZipMode(int argc, const char **argv) { uint32 *zipModeActive = _vm->getVar("azip"); *zipModeActive = !(*zipModeActive); DebugPrintf("Zip Mode is "); DebugPrintf((*zipModeActive) ? "Enabled" : "Disabled"); DebugPrintf("\n"); return true; } bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) { if (argc < 4) { DebugPrintf("Usage: dumpScript \n"); return true; } uint16 oldStack = _vm->getCurStack(); byte newStack = 0; for (byte i = 1; i <= tspit + 1; i++) if (!scumm_stricmp(argv[1], _vm->getStackName(i - 1).c_str())) { newStack = i; break; } if (!newStack) { DebugPrintf("\'%s\' is not a stack name!\n", argv[1]); return true; } newStack--; _vm->changeToStack(newStack); // Load in Variable Names Common::SeekableReadStream *nameStream = _vm->getResource(ID_NAME, VariableNames); Common::StringArray varNames; uint16 namesCount = nameStream->readUint16BE(); uint16 *stringOffsets = new uint16[namesCount]; for (uint16 i = 0; i < namesCount; i++) stringOffsets[i] = nameStream->readUint16BE(); nameStream->seek(namesCount * 2, SEEK_CUR); int32 curNamesPos = nameStream->pos(); for (uint32 i = 0; i < namesCount; i++) { nameStream->seek(curNamesPos + stringOffsets[i]); Common::String name; for (char c = nameStream->readByte(); c; c = nameStream->readByte()) name += c; varNames.push_back(name); } delete nameStream; // Load in External Command Names nameStream = _vm->getResource(ID_NAME, ExternalCommandNames); Common::StringArray xNames; namesCount = nameStream->readUint16BE(); stringOffsets = new uint16[namesCount]; for (uint16 i = 0; i < namesCount; i++) stringOffsets[i] = nameStream->readUint16BE(); nameStream->seek(namesCount * 2, SEEK_CUR); curNamesPos = nameStream->pos(); for (uint32 i = 0; i < namesCount; i++) { nameStream->seek(curNamesPos + stringOffsets[i]); Common::String name; for (char c = nameStream->readByte(); c; c = nameStream->readByte()) name += c; xNames.push_back(name); } delete nameStream; // Get CARD/HSPT data and dump their scripts if (!scumm_stricmp(argv[2], "CARD")) { // Use debugN to print these because the scripts can get very large and would // really be useless if the the text console is not used. A DumpFile could also // theoretically be used, but I (clone2727) typically use this dynamically and // don't want countless files laying around without game context. If one would // want a file of a script they could just redirect stdout to a file or use // deriven. debugN("\n\nDumping scripts for %s\'s card %d!\n", argv[1], (uint16)atoi(argv[3])); debugN("==================================\n\n"); Common::SeekableReadStream *cardStream = _vm->getResource(MKID_BE('CARD'), (uint16)atoi(argv[3])); cardStream->seek(4); RivenScriptList scriptList = _vm->_scriptMan->readScripts(cardStream, false); for (uint32 i = 0; i < scriptList.size(); i++) { scriptList[i]->dumpScript(varNames, xNames, 0); delete scriptList[i]; } delete cardStream; } else if (!scumm_stricmp(argv[2], "HSPT")) { // See above for why this is printed via debugN debugN("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3])); debugN("===========================================\n\n"); Common::SeekableReadStream *hsptStream = _vm->getResource(MKID_BE('HSPT'), (uint16)atoi(argv[3])); uint16 hotspotCount = hsptStream->readUint16BE(); for (uint16 i = 0; i < hotspotCount; i++) { debugN("Hotspot %d:\n", i); hsptStream->seek(22, SEEK_CUR); // Skip non-script related stuff RivenScriptList scriptList = _vm->_scriptMan->readScripts(hsptStream, false); for (uint32 j = 0; j < scriptList.size(); j++) { scriptList[j]->dumpScript(varNames, xNames, 1); delete scriptList[j]; } } delete hsptStream; } else { DebugPrintf("%s doesn't have any scripts!\n", argv[2]); } // See above for why this is printed via debugN debugN("\n\n"); _vm->changeToStack(oldStack); DebugPrintf("Script dump complete.\n"); return true; } bool RivenConsole::Cmd_ListZipCards(int argc, const char **argv) { if (_vm->_zipModeData.size() == 0) { DebugPrintf("No zip card data.\n"); } else { DebugPrintf("Listing zip cards:\n"); for (uint32 i = 0; i < _vm->_zipModeData.size(); i++) DebugPrintf("ID = %d, Name = %s\n", _vm->_zipModeData[i].id, _vm->_zipModeData[i].name.c_str()); } return true; } bool RivenConsole::Cmd_GetRMAP(int argc, const char **argv) { uint32 rmapCode = _vm->getCurCardRMAP(); DebugPrintf("RMAP for %s %d = %08x\n", _vm->getStackName(_vm->getCurStack()).c_str(), _vm->getCurCard(), rmapCode); return true; } bool RivenConsole::Cmd_Combos(int argc, const char **argv) { // In the vain of SCUMM's 'drafts' command, this command will list // out all combinations needed in Riven, decoded from the variables. // You'll need to look up the Rebel Tunnel puzzle on your own; the // solution is constant. uint32 teleCombo = *_vm->getVar("tcorrectorder"); uint32 prisonCombo = *_vm->getVar("pcorrectorder"); uint32 domeCombo = *_vm->getVar("adomecombo"); DebugPrintf("Telescope Combo:\n "); for (int i = 0; i < 5; i++) DebugPrintf("%d ", _vm->_externalScriptHandler->getComboDigit(teleCombo, i)); DebugPrintf("\nPrison Combo:\n "); for (int i = 0; i < 5; i++) DebugPrintf("%d ", _vm->_externalScriptHandler->getComboDigit(prisonCombo, i)); DebugPrintf("\nDome Combo:\n "); for (int i = 1; i <= 25; i++) if (domeCombo & (1 << (25 - i))) DebugPrintf("%d ", i); DebugPrintf("\n"); return true; } bool RivenConsole::Cmd_SliderState(int argc, const char **argv) { if (argc > 1) _vm->_externalScriptHandler->setDomeSliderState((uint32)atoi(argv[1])); DebugPrintf("Dome Slider State = %08x\n", _vm->_externalScriptHandler->getDomeSliderState()); return true; } LivingBooksConsole::LivingBooksConsole(MohawkEngine_LivingBooks *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("playSound", WRAP_METHOD(LivingBooksConsole, Cmd_PlaySound)); DCmd_Register("stopSound", WRAP_METHOD(LivingBooksConsole, Cmd_StopSound)); DCmd_Register("drawImage", WRAP_METHOD(LivingBooksConsole, Cmd_DrawImage)); } LivingBooksConsole::~LivingBooksConsole() { } void LivingBooksConsole::preEnter() { _vm->_sound->pauseSound(); } void LivingBooksConsole::postEnter() { _vm->_sound->resumeSound(); } bool LivingBooksConsole::Cmd_PlaySound(int argc, const char **argv) { if (argc == 1) { DebugPrintf("Usage: playSound \n"); return true; } _vm->_sound->stopSound(); _vm->_sound->playSound((uint16)atoi(argv[1])); return false; } bool LivingBooksConsole::Cmd_StopSound(int argc, const char **argv) { DebugPrintf("Stopping Sound\n"); _vm->_sound->stopSound(); return true; } bool LivingBooksConsole::Cmd_DrawImage(int argc, const char **argv) { if (argc == 1) { DebugPrintf("Usage: drawImage \n"); return true; } _vm->_gfx->copyImageToScreen((uint16)atoi(argv[1])); _vm->_system->updateScreen(); return false; } } // End of namespace Mohawk