diff options
Diffstat (limited to 'engines/sci/console.cpp')
-rw-r--r-- | engines/sci/console.cpp | 217 |
1 files changed, 145 insertions, 72 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 9607a8e66d..1889d53480 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -53,6 +53,7 @@ #include "video/avi_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/frameout.h" #include "video/coktel_decoder.h" #include "sci/video/robot_decoder.h" #endif @@ -131,6 +132,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), DCmd_Register("al", WRAP_METHOD(Console, cmdAnimateList)); // alias DCmd_Register("window_list", WRAP_METHOD(Console, cmdWindowList)); DCmd_Register("wl", WRAP_METHOD(Console, cmdWindowList)); // alias + DCmd_Register("plane_list", WRAP_METHOD(Console, cmdPlaneList)); + DCmd_Register("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias + DCmd_Register("plane_items", WRAP_METHOD(Console, cmdPlaneItemList)); + DCmd_Register("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias DCmd_Register("saved_bits", WRAP_METHOD(Console, cmdSavedBits)); DCmd_Register("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits)); // Segments @@ -245,20 +250,18 @@ void Console::postEnter() { #endif if (_videoFile.hasSuffix(".seq")) { - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(_videoFrameDelay); - videoDecoder = seqDecoder; + videoDecoder = new SEQDecoder(_videoFrameDelay); #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); } else if (_videoFile.hasSuffix(".rbt")) { - videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); + videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { duckMode = true; - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); #endif } else if (_videoFile.hasSuffix(".avi")) { - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); } else { warning("Unrecognized video type"); } @@ -365,7 +368,10 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" pic_visualize - Enables visualization of the drawing process of EGA pictures\n"); DebugPrintf(" undither - Enable/disable undithering\n"); DebugPrintf(" play_video - Plays a SEQ, AVI, VMD, RBT or DUK video\n"); - DebugPrintf(" animate_object_list / al - Shows the current list of objects in kAnimate's draw list\n"); + DebugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n"); + DebugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n"); DebugPrintf(" saved_bits - List saved bits on the hunk\n"); DebugPrintf(" show_saved_bits - Display saved bits\n"); DebugPrintf("\n"); @@ -1209,12 +1215,33 @@ bool Console::cmdRestartGame(int argc, const char **argv) { return Cmd_Exit(0, 0); } +// The scripts get IDs ranging from 100->199, because the scripts require us to assign unique ids THAT EVEN STAY BETWEEN +// SAVES and the scripts also use "saves-count + 1" to create a new savedgame slot. +// SCI1.1 actually recycles ids, in that case we will currently get "0". +// This behavior is required especially for LSL6. In this game, it's possible to quick save. The scripts will use +// the last-used id for that feature. If we don't assign sticky ids, the feature will overwrite different saves all the +// time. And sadly we can't just use the actual filename ids directly, because of the creation method for new slots. + +extern void listSavegames(Common::Array<SavegameDesc> &saves); + +bool Console::cmdListSaves(int argc, const char **argv) { + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + for (uint i = 0; i < saves.size(); i++) { + Common::String filename = g_sci->getSavegameName(saves[i].id); + DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name); + } + + return true; +} + bool Console::cmdClassTable(int argc, const char **argv) { DebugPrintf("Available classes (parse a parameter to filter the table by a specific class):\n"); for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) { Class temp = _engine->_gamestate->_segMan->_classTable[i]; - if (temp.reg.segment) { + if (temp.reg.getSegment()) { const char *className = _engine->_gamestate->_segMan->getObjectName(temp.reg); if (argc == 1 || (argc == 2 && !strcmp(className, argv[1]))) { DebugPrintf(" Class 0x%x (%s) at %04x:%04x (script %d)\n", i, @@ -1589,6 +1616,8 @@ bool Console::cmdAnimateList(int argc, const char **argv) { if (_engine->_gfxAnimate) { DebugPrintf("Animate list:\n"); _engine->_gfxAnimate->printAnimateList(this); + } else { + DebugPrintf("This SCI version does not have an animate list\n"); } return true; } @@ -1597,9 +1626,52 @@ bool Console::cmdWindowList(int argc, const char **argv) { if (_engine->_gfxPorts) { DebugPrintf("Window list:\n"); _engine->_gfxPorts->printWindowList(this); + } else { + DebugPrintf("This SCI version does not have a list of ports\n"); } return true; +} + +bool Console::cmdPlaneList(int argc, const char **argv) { +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane list:\n"); + _engine->_gfxFrameout->printPlaneList(this); + } else { + DebugPrintf("This SCI version does not have a list of planes\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} +bool Console::cmdPlaneItemList(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Shows the list of items for a plane\n"); + DebugPrintf("Usage: %s <plane address>\n", argv[0]); + return true; + } + + reg_t planeObject = NULL_REG; + + if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) { + DebugPrintf("Invalid address passed.\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane item list:\n"); + _engine->_gfxFrameout->printPlaneItemList(this, planeObject); + } else { + DebugPrintf("This SCI version does not have a list of plane items\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; } bool Console::cmdSavedBits(int argc, const char **argv) { @@ -1614,7 +1686,7 @@ bool Console::cmdSavedBits(int argc, const char **argv) { Common::Array<reg_t> entries = hunks->listAllDeallocatable(id); for (uint i = 0; i < entries.size(); ++i) { - uint16 offset = entries[i].offset; + uint16 offset = entries[i].getOffset(); const Hunk& h = hunks->_table[offset]; if (strcmp(h.type, "SaveBits()") == 0) { byte* memoryPtr = (byte *)h.mem; @@ -1677,12 +1749,12 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) { return true; } - if (memoryHandle.segment != id || !hunks->isValidOffset(memoryHandle.offset)) { + if (memoryHandle.getSegment() != id || !hunks->isValidOffset(memoryHandle.getOffset())) { DebugPrintf("Invalid address.\n"); return true; } - const Hunk& h = hunks->_table[memoryHandle.offset]; + const Hunk& h = hunks->_table[memoryHandle.getOffset()]; if (strcmp(h.type, "SaveBits()") != 0) { DebugPrintf("Invalid address.\n"); @@ -2192,16 +2264,16 @@ bool Console::cmdGCShowReachable(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return 1; } DebugPrintf("Reachable from %04x:%04x:\n", PRINT_REG(addr)); const Common::Array<reg_t> tmp = mobj->listAllOutgoingReferences(addr); for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - if (it->segment) + if (it->getSegment()) g_sci->getSciDebugger()->DebugPrintf(" %04x:%04x\n", PRINT_REG(*it)); return true; @@ -2224,16 +2296,16 @@ bool Console::cmdGCShowFreeable(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return true; } - DebugPrintf("Freeable in segment %04x:\n", addr.segment); - const Common::Array<reg_t> tmp = mobj->listAllDeallocatable(addr.segment); + DebugPrintf("Freeable in segment %04x:\n", addr.getSegment()); + const Common::Array<reg_t> tmp = mobj->listAllDeallocatable(addr.getSegment()); for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - if (it->segment) + if (it->getSegment()) g_sci->getSciDebugger()->DebugPrintf(" %04x:%04x\n", PRINT_REG(*it)); return true; @@ -2257,9 +2329,9 @@ bool Console::cmdGCNormalize(int argc, const char **argv) { return true; } - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.segment); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegmentObj(addr.getSegment()); if (!mobj) { - DebugPrintf("Unknown segment : %x\n", addr.segment); + DebugPrintf("Unknown segment : %x\n", addr.getSegment()); return true; } @@ -2498,12 +2570,12 @@ bool Console::cmdViewReference(int argc, const char **argv) { DebugPrintf("%04x:%04x is of type 0x%x: ", PRINT_REG(reg), type_mask); - if (reg.segment == 0 && reg.offset == 0) { + if (reg.getSegment() == 0 && reg.getOffset() == 0) { DebugPrintf("Null.\n"); return true; } - if (reg_end.segment != reg.segment && reg_end != NULL_REG) { + if (reg_end.getSegment() != reg.getSegment() && reg_end != NULL_REG) { DebugPrintf("Ending segment different from starting segment. Assuming no bound on dump.\n"); reg_end = NULL_REG; } @@ -2539,7 +2611,7 @@ bool Console::cmdViewReference(int argc, const char **argv) { printObject(reg); break; case SIG_TYPE_REFERENCE: { - switch (_engine->_gamestate->_segMan->getSegmentType(reg.segment)) { + switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) { #ifdef ENABLE_SCI32 case SEG_TYPE_STRING: { DebugPrintf("SCI32 string\n"); @@ -2555,21 +2627,20 @@ bool Console::cmdViewReference(int argc, const char **argv) { } #endif default: { - int size; const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg); - size = block.maxSize; + uint16 size = block.maxSize; DebugPrintf("raw data\n"); - if (reg_end.segment != 0 && size < reg_end.offset - reg.offset) { + if (reg_end.getSegment() != 0 && (size < reg_end.getOffset() - reg.getOffset())) { DebugPrintf("Block end out of bounds (size %d). Resetting.\n", size); reg_end = NULL_REG; } - if (reg_end.segment != 0 && (size >= reg_end.offset - reg.offset)) - size = reg_end.offset - reg.offset; + if (reg_end.getSegment() != 0 && (size >= reg_end.getOffset() - reg.getOffset())) + size = reg_end.getOffset() - reg.getOffset(); - if (reg_end.segment != 0) + if (reg_end.getSegment() != 0) DebugPrintf("Block size less than or equal to %d\n", size); if (block.isRaw) @@ -2581,7 +2652,7 @@ bool Console::cmdViewReference(int argc, const char **argv) { break; } case SIG_TYPE_INTEGER: - DebugPrintf("arithmetic value\n %d (%04x)\n", (int16) reg.offset, reg.offset); + DebugPrintf("arithmetic value\n %d (%04x)\n", (int16) reg.getOffset(), reg.getOffset()); break; default: DebugPrintf("unknown type %d.\n", type); @@ -2651,7 +2722,7 @@ bool Console::cmdBacktrace(int argc, const char **argv) { switch (call.type) { case EXEC_STACK_TYPE_CALL: // Normal function if (call.type == EXEC_STACK_TYPE_CALL) - DebugPrintf(" %x: script %d - ", i, (*(Script *)_engine->_gamestate->_segMan->_heap[call.addr.pc.segment]).getScriptNumber()); + DebugPrintf(" %x: script %d - ", i, (*(Script *)_engine->_gamestate->_segMan->_heap[call.addr.pc.getSegment()]).getScriptNumber()); if (call.debugSelector != -1) { DebugPrintf("%s::%s(", objname, _engine->getKernel()->getSelectorName(call.debugSelector).c_str()); } else if (call.debugExportId != -1) { @@ -2840,10 +2911,11 @@ bool Console::cmdDisassemble(int argc, const char **argv) { if (jumpTarget > farthestTarget) farthestTarget = jumpTarget; } - addr = disassemble(_engine->_gamestate, addr, printBWTag, printBytecode); + // TODO: Use a true 32-bit reg_t for the position (addr) + addr = disassemble(_engine->_gamestate, make_reg32(addr.getSegment(), addr.getOffset()), printBWTag, printBytecode); if (addr.isNull() && prevAddr < farthestTarget) addr = prevAddr + 1; // skip past the ret - } while (addr.offset > 0); + } while (addr.getOffset() > 0); return true; } @@ -2860,10 +2932,10 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } reg_t vpc = NULL_REG; - int opCount = 1; + uint opCount = 1; bool printBWTag = false; bool printBytes = false; - int size; + uint16 size; if (parse_reg_t(_engine->_gamestate, argv[1], &vpc, false)) { DebugPrintf("Invalid address passed.\n"); @@ -2872,7 +2944,7 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } SegmentRef ref = _engine->_gamestate->_segMan->dereference(vpc); - size = ref.maxSize + vpc.offset; // total segment size + size = ref.maxSize + vpc.getOffset(); // total segment size for (int i = 2; i < argc; i++) { if (!scumm_stricmp(argv[i], "bwt")) @@ -2887,14 +2959,10 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } } - if (opCount < 0) { - DebugPrintf("Invalid op_count\n"); - return true; - } - do { - vpc = disassemble(_engine->_gamestate, vpc, printBWTag, printBytes); - } while ((vpc.offset > 0) && (vpc.offset + 6 < size) && (--opCount)); + // TODO: Use a true 32-bit reg_t for the position (vpc) + vpc = disassemble(_engine->_gamestate, make_reg32(vpc.getSegment(), vpc.getOffset()), printBWTag, printBytes); + } while ((vpc.getOffset() > 0) && (vpc.getOffset() + 6 < size) && (--opCount)); return true; } @@ -2917,8 +2985,9 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // Ignore specific leftover scripts, which require other non-existing scripts if ((_engine->getGameId() == GID_HOYLE3 && itr->getNumber() == 995) || (_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) || - (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947) || - (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980)) { + (_engine->getGameId() == GID_KQ7 && itr->getNumber() == 111) || + (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980) || + (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947)) { continue; } @@ -2937,7 +3006,7 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // Now dissassemble each method of the script object for (uint16 i = 0; i < obj->getMethodCount(); i++) { reg_t fptr = obj->getFunction(i); - uint16 offset = fptr.offset; + uint16 offset = fptr.getOffset(); int16 opparams[4]; byte extOpcode; byte opcode; @@ -3584,10 +3653,14 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV relativeOffset = true; if (!scumm_strnicmp(str + 1, "PC", 2)) { - *dest = s->_executionStack.back().addr.pc; + // TODO: Handle 32-bit PC addresses + reg32_t pc = s->_executionStack.back().addr.pc; + *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset()); offsetStr = str + 3; } else if (!scumm_strnicmp(str + 1, "P", 1)) { - *dest = s->_executionStack.back().addr.pc; + // TODO: Handle 32-bit PC addresses + reg32_t pc = s->_executionStack.back().addr.pc; + *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset()); offsetStr = str + 2; } else if (!scumm_strnicmp(str + 1, "PREV", 4)) { *dest = s->r_prev; @@ -3625,8 +3698,8 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV return 1; // Now lookup the script's segment - dest->segment = s->_segMan->getScriptSegment(script_nr); - if (!dest->segment) { + dest->setSegment(s->_segMan->getScriptSegment(script_nr)); + if (!dest->getSegment()) { return 1; } @@ -3708,19 +3781,19 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV offsetStr = colon + 1; Common::String segmentStr(str, colon); - dest->segment = strtol(segmentStr.c_str(), &endptr, 16); + dest->setSegment(strtol(segmentStr.c_str(), &endptr, 16)); if (*endptr) return 1; } else { int val = 0; - dest->segment = 0; + dest->setSegment(0); if (charsCountNumber == charsCount) { // Only numbers in input, assume decimal value val = strtol(str, &endptr, 10); if (*endptr) return 1; // strtol failed? - dest->offset = val; + dest->setOffset(val); return 0; } else { // We also got letters, check if there were only hexadecimal letters and '0x' at the start or 'h' at the end @@ -3728,7 +3801,7 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV val = strtol(str, &endptr, 16); if ((*endptr != 'h') && (*endptr != 0)) return 1; - dest->offset = val; + dest->setOffset(val); return 0; } else { // Something else was in input, assume object name @@ -3777,9 +3850,9 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV int val = strtol(offsetStr, &endptr, 16); if (relativeOffset) - dest->offset += val; + dest->incOffset(val); else - dest->offset = val; + dest->setOffset(val); if (*endptr) return 1; @@ -3859,15 +3932,15 @@ void Console::printList(List *list) { while (!pos.isNull()) { Node *node; - NodeTable *nt = (NodeTable *)_engine->_gamestate->_segMan->getSegment(pos.segment, SEG_TYPE_NODES); + NodeTable *nt = (NodeTable *)_engine->_gamestate->_segMan->getSegment(pos.getSegment(), SEG_TYPE_NODES); - if (!nt || !nt->isValidEntry(pos.offset)) { + if (!nt || !nt->isValidEntry(pos.getOffset())) { DebugPrintf(" WARNING: %04x:%04x: Doesn't contain list node!\n", PRINT_REG(pos)); return; } - node = &(nt->_table[pos.offset]); + node = &(nt->_table[pos.getOffset()]); DebugPrintf("\t%04x:%04x : %04x:%04x -> %04x:%04x\n", PRINT_REG(pos), PRINT_REG(node->key), PRINT_REG(node->value)); @@ -3886,37 +3959,37 @@ void Console::printList(List *list) { } int Console::printNode(reg_t addr) { - SegmentObj *mobj = _engine->_gamestate->_segMan->getSegment(addr.segment, SEG_TYPE_LISTS); + SegmentObj *mobj = _engine->_gamestate->_segMan->getSegment(addr.getSegment(), SEG_TYPE_LISTS); if (mobj) { ListTable *lt = (ListTable *)mobj; List *list; - if (!lt->isValidEntry(addr.offset)) { + if (!lt->isValidEntry(addr.getOffset())) { DebugPrintf("Address does not contain a list\n"); return 1; } - list = &(lt->_table[addr.offset]); + list = &(lt->_table[addr.getOffset()]); DebugPrintf("%04x:%04x : first x last = (%04x:%04x, %04x:%04x)\n", PRINT_REG(addr), PRINT_REG(list->first), PRINT_REG(list->last)); } else { NodeTable *nt; Node *node; - mobj = _engine->_gamestate->_segMan->getSegment(addr.segment, SEG_TYPE_NODES); + mobj = _engine->_gamestate->_segMan->getSegment(addr.getSegment(), SEG_TYPE_NODES); if (!mobj) { - DebugPrintf("Segment #%04x is not a list or node segment\n", addr.segment); + DebugPrintf("Segment #%04x is not a list or node segment\n", addr.getSegment()); return 1; } nt = (NodeTable *)mobj; - if (!nt->isValidEntry(addr.offset)) { + if (!nt->isValidEntry(addr.getOffset())) { DebugPrintf("Address does not contain a node\n"); return 1; } - node = &(nt->_table[addr.offset]); + node = &(nt->_table[addr.getOffset()]); DebugPrintf("%04x:%04x : prev x next = (%04x:%04x, %04x:%04x); maps %04x:%04x -> %04x:%04x\n", PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(node->succ), PRINT_REG(node->key), PRINT_REG(node->value)); @@ -3954,8 +4027,8 @@ int Console::printObject(reg_t pos) { reg_t val = obj->getVariable(i); DebugPrintf("%04x:%04x", PRINT_REG(val)); - if (!val.segment) - DebugPrintf(" (%d)", val.offset); + if (!val.getSegment()) + DebugPrintf(" (%d)", val.getOffset()); const Object *ref = s->_segMan->getObject(val); if (ref) @@ -3968,8 +4041,8 @@ int Console::printObject(reg_t pos) { reg_t fptr = obj->getFunction(i); DebugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), _engine->getKernel()->getSelectorName(obj->getFuncSelector(i)).c_str(), PRINT_REG(fptr)); } - if (s->_segMan->_heap[pos.segment]->getType() == SEG_TYPE_SCRIPT) - DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.segment)->getScriptNumber()); + if (s->_segMan->_heap[pos.getSegment()]->getType() == SEG_TYPE_SCRIPT) + DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.getSegment())->getScriptNumber()); return 0; } |