STARK: Add a debug command allowing to list the game's rooms

This commit is contained in:
Bastien Bouclet 2014-10-05 19:25:00 +02:00
parent ff9cd31820
commit 63f88fd167
4 changed files with 144 additions and 12 deletions

View file

@ -31,6 +31,7 @@ namespace Stark {
Console::Console(StarkEngine *vm) : GUI::Debugger(), _vm(vm) { Console::Console(StarkEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("dumpArchive", WRAP_METHOD(Console, Cmd_DumpArchive)); registerCmd("dumpArchive", WRAP_METHOD(Console, Cmd_DumpArchive));
registerCmd("dumpScript", WRAP_METHOD(Console, Cmd_DumpScript)); registerCmd("dumpScript", WRAP_METHOD(Console, Cmd_DumpScript));
registerCmd("listRooms", WRAP_METHOD(Console, Cmd_ListRooms));
} }
Console::~Console() { Console::~Console() {
@ -41,7 +42,7 @@ bool Console::Cmd_DumpArchive(int argc, const char **argv) {
debugPrintf("Extract all the files from a game archive.\n"); debugPrintf("Extract all the files from a game archive.\n");
debugPrintf("The destination folder, named 'dump', must exist.\n"); debugPrintf("The destination folder, named 'dump', must exist.\n");
debugPrintf("Usage :\n"); debugPrintf("Usage :\n");
debugPrintf("dumpArchive [file name]\n"); debugPrintf("dumpArchive [archive name]\n");
return true; return true;
} }
@ -85,26 +86,81 @@ bool Console::Cmd_DumpScript(int argc, const char **argv) {
if (argc != 2) { if (argc != 2) {
debugPrintf("Print the scripts from an archive.\n"); debugPrintf("Print the scripts from an archive.\n");
debugPrintf("Usage :\n"); debugPrintf("Usage :\n");
debugPrintf("dumpScript [file name]\n"); debugPrintf("dumpScript [archive name]\n");
return true; return true;
} }
XARCArchive xarc; XRCNode *node = loadXARCScripts(argv[1]);
if (!xarc.open(argv[1])) { if (node == nullptr) {
debugPrintf("Can't open archive with name '%s'\n", argv[1]); debugPrintf("Can't open archive with name '%s'\n", argv[1]);
return true; return true;
} }
node->print();
delete node;
return true;
}
XRCNode *Console::loadXARCScripts(Common::String archive) {
XARCArchive xarc;
if (!xarc.open(archive)) {
return nullptr;
}
Common::ArchiveMemberList members; Common::ArchiveMemberList members;
xarc.listMatchingMembers(members, "*.xrc"); xarc.listMatchingMembers(members, "*.xrc");
for (Common::ArchiveMemberList::const_iterator it = members.begin(); it != members.end(); it++) { if (members.size() == 0) {
debugPrintf("Dumping script '%s'\n", it->get()->getName().c_str()); error("No scripts in archive '%s'", archive.c_str());
XRCNode *node = XRCNode::read(xarc.createReadStreamForMember(it->get()->getName()));
node->print();
delete node;
} }
if (members.size() > 1) {
error("Too many scripts in archive '%s'", archive.c_str());
}
return XRCNode::read(xarc.createReadStreamForMember(members.front()->getName()));
}
bool Console::Cmd_ListRooms(int argc, const char **argv) {
XRCNode *root = loadXARCScripts("x.xarc");
if (root == nullptr) {
debugPrintf("Can't open archive 'x.xarc'\n");
return true;
}
// Loop over the levels
for (uint i = 0; i < root->getChildren().size(); i++) {
XRCNode *level = root->getChildren()[i];
// Only consider levels
if (level->getType() != XRCNode::kLevel) continue;
Common::String levelArchive = level->getArchive();
debugPrintf("%s - %s\n", levelArchive.c_str(), level->getName().c_str());
// Load the detailed level archive
level = loadXARCScripts(levelArchive);
if (!level)
error("Unable to load archive '%s'", levelArchive.c_str());
// Loop over the rooms
for (uint j = 0; j < level->getChildren().size(); j++) {
XRCNode *room = level->getChildren()[j];
// Only consider rooms
if (room->getType() != XRCNode::kRoom) continue;
Common::String roomArchive = room->getArchive();
debugPrintf("%s - %s\n", roomArchive.c_str(), room->getName().c_str());
}
delete level;
}
delete root;
return true; return true;
} }

View file

@ -31,6 +31,8 @@
namespace Stark { namespace Stark {
class XRCNode;
class Console : public GUI::Debugger { class Console : public GUI::Debugger {
public: public:
Console(StarkEngine *vm); Console(StarkEngine *vm);
@ -41,6 +43,9 @@ private:
bool Cmd_DumpArchive(int argc, const char **argv); bool Cmd_DumpArchive(int argc, const char **argv);
bool Cmd_DumpScript(int argc, const char **argv); bool Cmd_DumpScript(int argc, const char **argv);
bool Cmd_ListRooms(int argc, const char** argv);
XRCNode *loadXARCScripts(Common::String archive);
}; };
} // End of namespace Stark } // End of namespace Stark

View file

@ -28,7 +28,9 @@
namespace Stark { namespace Stark {
XRCNode::XRCNode() : _data(NULL) { XRCNode::XRCNode() :
_data(nullptr),
_parent(nullptr) {
} }
XRCNode::~XRCNode() { XRCNode::~XRCNode() {
@ -109,6 +111,9 @@ bool XRCNode::readInternal(Common::ReadStream *stream) {
if (!child) if (!child)
return false; return false;
// Set the child's parent to the current node
child->_parent = this;
// Save all children read correctly // Save all children read correctly
_children.push_back(child); _children.push_back(child);
} }
@ -117,12 +122,18 @@ bool XRCNode::readInternal(Common::ReadStream *stream) {
} }
void XRCNode::print(uint depth) { void XRCNode::print(uint depth) {
// Display value for the node type
Common::String type(getTypeName());
if (type.empty()) {
type = Common::String::format("%d", _dataType);
}
// Build the node description // Build the node description
Common::String description; Common::String description;
for (uint i = 0; i < depth; i++) { for (uint i = 0; i < depth; i++) {
description += "-"; description += "-";
} }
description += Common::String::format(" %s - (%d) - (unk1=%d, order=%d)", _name.c_str(), _dataType, _unknown1, _nodeOrder); description += Common::String::format(" %s - (%s) - (unk1=%d, order=%x)", _name.c_str(), type.c_str(), _unknown1, _nodeOrder);
// Print tge node description // Print tge node description
debug(description.c_str()); debug(description.c_str());
@ -138,4 +149,49 @@ void XRCNode::print(uint depth) {
} }
} }
const char *XRCNode::getTypeName() {
static const struct {
Type type;
const char *name;
} typeNames[] {
{ kLevel, "Level" },
{ kRoom, "Room" }
};
for (uint i = 0; i < ARRAYSIZE(typeNames); i++) {
if (typeNames[i].type == _dataType) {
return typeNames[i].name;
}
}
return nullptr;
}
Common::String XRCNode::getArchive() {
Common::String archive;
switch (getType()) {
case kLevel:
switch (_unknown1) {
case 1:
archive = Common::String::format("%s/%s.xarc", _name.c_str(), _name.c_str());
break;
case 2:
archive = Common::String::format("%02x/%02x.xarc", _nodeOrder, _nodeOrder);
break;
default:
error("Unknown level archive type %d", _unknown1);
}
break;
case kRoom:
assert(_parent);
archive = Common::String::format("%02x/%02x/%02x.xarc", _parent->_nodeOrder, _nodeOrder, _nodeOrder);
break;
default:
error("This type of node cannot load children %d", _dataType);
}
return archive;
}
} // End of namespace Stark } // End of namespace Stark

View file

@ -34,18 +34,31 @@ private:
XRCNode(); XRCNode();
public: public:
enum Type {
kLevel = 2,
kRoom = 3
};
~XRCNode(); ~XRCNode();
static XRCNode *read(Common::ReadStream *stream); static XRCNode *read(Common::ReadStream *stream);
Common::String getName() const { return _name; } Common::String getName() const { return _name; }
Type getType() const {return (Type) _dataType; }
const byte *getData() const { return _data; } const byte *getData() const { return _data; }
Common::Array<XRCNode *> getChildren() const { return _children; } Common::Array<XRCNode *> getChildren() const { return _children; }
/**
* Get the archive file name containing the data for this node.
* Only Levels and Rooms have archives.
*/
Common::String getArchive();
void print(uint depth = 0); void print(uint depth = 0);
protected: protected:
bool readInternal(Common::ReadStream *stream); bool readInternal(Common::ReadStream *stream);
const char *getTypeName();
byte _dataType; byte _dataType;
byte _unknown1; byte _unknown1;
@ -53,8 +66,10 @@ protected:
Common::String _name; Common::String _name;
uint32 _dataLength; uint32 _dataLength;
byte *_data; byte *_data;
Common::Array<XRCNode *> _children;
uint16 _unknown3; uint16 _unknown3;
XRCNode *_parent;
Common::Array<XRCNode *> _children;
}; };
} // End of namespace Stark } // End of namespace Stark