MUTATIONOFJB: Add support for macro definitions.

This commit is contained in:
Ľubomír Remák 2018-03-22 16:08:14 +01:00 committed by Eugene Sandulenko
parent 3928c52c0e
commit 63c0dac961
7 changed files with 94 additions and 3 deletions

View File

@ -24,7 +24,7 @@
#define MUTATIONOFJB_COMMAND_H
namespace Common {
class String;
class String;
}
namespace MutationOfJB {

View File

@ -26,6 +26,26 @@
#include "common/str.h"
#include "common/debug.h"
/*
("#L " | "-L ") <object>
("#W " | "-W ") <object>
("#T " | "-T ") <object>
("#U " | "-U ") <object1> [<object2>]
("#ELSE" | "-ELSE") [<tag>]
"#MACRO " <name>
If a line starts with '#', '=', '-', it is treated as the end of a section.
However, at the same time it can also start a new section depending on what follows.
#L (look), #W (walk), #T (talk), #U (use) sections are executed
when the user starts corresponding action on the object or in case of "use" up to two objects.
The difference between '#' and '-' version is whether the player walks towards the object ('#') or not ('-').
#ELSE is used by conditional commands (see comments for IfCommand and others).
#MACRO starts a new macro. Global script can call macros from local script and vice versa.
*/
namespace MutationOfJB {
bool EndBlockCommandParser::parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) {
@ -85,6 +105,8 @@ bool EndBlockCommandParser::parse(const Common::String &line, ScriptParseContext
if (line.size() >= 6) {
_ifTag = line[5];
}
} else if (line.size() >= 8 && line.hasPrefix("#MACRO")) {
_foundMacro = line.c_str() + 7;
}
if (firstChar == '#') {
@ -116,6 +138,13 @@ void EndBlockCommandParser::transition(ScriptParseContext &parseCtx, Command *,
_ifTag = 0;
}
if (!_foundMacro.empty() && newCommand) {
if (!parseCtx._macros.contains(_foundMacro)) {
parseCtx._macros[_foundMacro] = newCommand;
}
_foundMacro = "";
}
if (newCommandParser != this) {
if (!_pendingActionInfos.empty()) {
for (Common::Array<uint>::iterator it = _pendingActionInfos.begin(); it != _pendingActionInfos.end(); ++it) {
@ -135,6 +164,7 @@ void EndBlockCommandParser::finish(ScriptParseContext &) {
debug("Problem: Pending action infos from end block parser is not empty!");
}
_pendingActionInfos.clear();
_foundMacro = "";
}
Command::ExecuteResult EndBlockCommand::execute(GameData &) {

View File

@ -44,6 +44,7 @@ private:
char _ifTag;
Common::Array<uint> _pendingActionInfos;
Common::String _foundMacro;
};
class EndBlockCommand : public Command {

View File

@ -204,4 +204,55 @@ bool Console::cmd_showsection(int argc, const char **argv) {
return true;
}
bool Console::cmd_listmacros(int argc, const char **argv) {
if (argc == 2) {
Script *script = nullptr;
if (strcmp(argv[1], "G") == 0) {
script = _vm->getGame().getGlobalScript();
} else if (strcmp(argv[1], "L") == 0) {
script = _vm->getGame().getLocalScript();
}
if (!script) {
debugPrintf(_("Choose 'G' (global) or 'L' (local) script.\n"));
} else {
const Macros &macros = script->getMacros();
for (Macros::const_iterator it = macros.begin(); it != macros.end(); ++it) {
debugPrintf("%s\n", it->_key.c_str());
}
}
} else {
debugPrintf(_("listmacros <G|L>\n"));
}
return true;
}
bool Console::cmd_showmacro(int argc, const char **argv) {
if (argc == 3) {
Script *script = nullptr;
if (strcmp(argv[1], "G") == 0) {
script = _vm->getGame().getGlobalScript();
} else if (strcmp(argv[1], "L") == 0) {
script = _vm->getGame().getLocalScript();
}
if (!script) {
debugPrintf(_("Choose 'G' (global) or 'L' (local) script.\n"));
} else {
const Macros &macros = script->getMacros();
Macros::const_iterator itMacro = macros.find(argv[2]);
if (itMacro != macros.end()) {
if (itMacro->_value) {
showCommands(itMacro->_value);
}
} else {
debugPrintf("Macro not found.\n");
}
}
} else {
debugPrintf(_("showmacro <G|L> <macroname>\n"));
}
return true;
}
}

View File

@ -37,6 +37,8 @@ public:
private:
bool cmd_listsections(int argc, const char **argv);
bool cmd_showsection(int argc, const char **argv);
bool cmd_listmacros(int argc, const char **argv);
bool cmd_showmacro(int argc, const char **argv);
void showIndent(int indentLevel);
void showCommands(Command *command, int indentLevel = 0);

View File

@ -151,8 +151,7 @@ bool Script::loadFromStream(Common::SeekableReadStream &stream) {
}
}
Common::HashMap<Common::String, Command *> macros;
Common::HashMap<Common::String, Command *> labels;
_macros = parseCtx._macros;
return true;
}
@ -184,4 +183,8 @@ const ActionInfos &Script::getUseActionInfos() const {
return _useActionInfos;
}
const Macros &Script::getMacros() const {
return _macros;
}
}

View File

@ -58,6 +58,7 @@ struct ActionInfo {
typedef Common::Array<ActionInfo> ActionInfos;
typedef Common::Array<GotoCommand *> GotoCommands;
typedef Common::HashMap<Common::String, Command *> Macros;
class ScriptParseContext {
public:
@ -85,6 +86,7 @@ public:
PendingGotoMap _pendingGotos;
ActionInfos _actionInfos;
Macros _macros;
private:
};
@ -98,6 +100,7 @@ public:
const ActionInfos &getWalkActionInfos() const;
const ActionInfos &getTalkActionInfos() const;
const ActionInfos &getUseActionInfos() const;
const Macros &getMacros() const;
private:
void destroy();
@ -106,6 +109,7 @@ private:
ActionInfos _walkActionInfos;
ActionInfos _talkActionInfos;
ActionInfos _useActionInfos;
Macros _macros;
};
}