MUTATIONOFJB: Continue implementation of if/else script commands.

This commit is contained in:
Ľubomír Remák 2018-02-25 04:14:32 +01:00 committed by Eugene Sandulenko
parent f7d5a825a0
commit 3672ea5572
14 changed files with 330 additions and 16 deletions

View file

@ -24,6 +24,10 @@
#include "common/scummsys.h" #include "common/scummsys.h"
namespace MutationOfJB { namespace MutationOfJB {
void CommandParser::transition(ScriptParseContext &, Command *, Command *) {}
CommandParser::~CommandParser() {}
Command::~Command() {} Command::~Command() {}
SeqCommand *Command::asSeqCommand() { SeqCommand *Command::asSeqCommand() {

View file

@ -38,6 +38,15 @@ class Command;
typedef bool (*CommandParseFunc)(const Common::String &line, ScriptParseContext &parseContext, Command *&command); typedef bool (*CommandParseFunc)(const Common::String &line, ScriptParseContext &parseContext, Command *&command);
class CommandParser {
public:
virtual ~CommandParser();
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) = 0;
/* Old command - created by this parser. */
virtual void transition(ScriptParseContext &parseCtx, Command *oldCommand, Command *newCommand);
};
class Command { class Command {
public: public:
enum ExecuteResult { enum ExecuteResult {

View file

@ -31,6 +31,23 @@ ConditionalCommand::ConditionalCommand() :
_cachedResult(false) _cachedResult(false)
{} {}
Command *ConditionalCommand::getTrueCommand() const {
return _trueCommand;
}
Command *ConditionalCommand::getFalseCommand() const {
return _falseCommand;
}
void ConditionalCommand::setTrueCommand(Command *command) {
_trueCommand = command;
}
void ConditionalCommand::setFalseCommand(Command *command) {
_falseCommand = command;
}
Command *ConditionalCommand::next() const { Command *ConditionalCommand::next() const {
if (_cachedResult) { if (_cachedResult) {
return _trueCommand; return _trueCommand;
@ -38,4 +55,4 @@ Command *ConditionalCommand::next() const {
return _falseCommand; return _falseCommand;
} }
} }
}; }

View file

@ -28,6 +28,10 @@ namespace MutationOfJB {
class ConditionalCommand : public Command { class ConditionalCommand : public Command {
public: public:
ConditionalCommand(); ConditionalCommand();
Command *getTrueCommand() const;
Command *getFalseCommand() const;
void setTrueCommand(Command *command); void setTrueCommand(Command *command);
void setFalseCommand(Command *command); void setFalseCommand(Command *command);

View file

@ -0,0 +1,108 @@
/* 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 "mutationofjb/commands/endblockcommand.h"
#include "mutationofjb/script.h"
#include "mutationofjb/commands/conditionalcommand.h"
#include "common/str.h"
#include "common/debug.h"
namespace MutationOfJB {
bool EndBlockCommandParser::parse(const Common::String &line, ScriptParseContext &parseCtx, Command *& command) {
if (line.empty()) {
return false;
}
const char firstChar = line.firstChar();
if (firstChar != '#' && firstChar != '=' && firstChar != '-') {
return false;
}
// This is the start or end of section/block.
if (line.size() >= 4 && (line.hasPrefix("#L ") || line.hasPrefix("-L "))) {
ScriptParseContext::ActionInfo ai = {ScriptParseContext::Look, line.c_str() + 3, "", firstChar == '#'};
parseCtx._actionInfos.push_back(ai);
debug("# Look: %s", line.c_str() + 3);
} else if (line.size() >= 4 && (line.hasPrefix("#W ") || line.hasPrefix("-W "))) {
ScriptParseContext::ActionInfo ai = {ScriptParseContext::Walk, line.c_str() + 3, "", firstChar == '#'};
parseCtx._actionInfos.push_back(ai);
} else if (line.size() >= 4 && (line.hasPrefix("#T ") || line.hasPrefix("-T "))) {
ScriptParseContext::ActionInfo ai = {ScriptParseContext::Talk, line.c_str() + 3, "", firstChar == '#'};
parseCtx._actionInfos.push_back(ai);
} else if (line.size() >= 4 && (line.hasPrefix("#U ") || line.hasPrefix("-U "))) {
int secondObjPos = -1;
for (int i = 3; i < (int) line.size(); ++i) {
if (line[i] == ' ') {
secondObjPos = i + 1;
break;
}
}
ScriptParseContext::ActionInfo ai = {
ScriptParseContext::Talk,
line.c_str() + 3,
(secondObjPos != -1) ? line.c_str() + secondObjPos : "",
firstChar == '#'
};
parseCtx._actionInfos.push_back(ai);
} else if ((line.hasPrefix("#ELSE") || line.hasPrefix("=ELSE"))) {
_elseFound = true;
_ifTag = 0;
if (line.size() >= 6) {
_ifTag = line[5];
}
}
command = new EndBlockCommand();
return true;
}
void EndBlockCommandParser::transition(ScriptParseContext &parseCtx, Command *, Command *newCommand) {
if (_elseFound) {
if (newCommand) {
ScriptParseContext::ConditionalCommandInfos::iterator it = parseCtx._pendingCondCommands.begin();
while (it != parseCtx._pendingCondCommands.end()) {
if (it->_tag == _ifTag) {
it->_command->setFalseCommand(newCommand);
it = parseCtx._pendingCondCommands.erase(it);
} else {
++it;
}
}
}
_elseFound = false;
_ifTag = 0;
}
}
Command::ExecuteResult EndBlockCommand::execute(GameData &) {
return Finished;
}
Command *EndBlockCommand::next() const {
return nullptr;
}
}

View file

@ -0,0 +1,53 @@
/* 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.
*
*/
#ifndef MUTATIONOFJB_ENDBLOCKCOMMAND_H
#define MUTATIONOFJB_ENDBLOCKCOMMAND_H
#include "mutationofjb/commands/command.h"
#include "common/scummsys.h"
namespace MutationOfJB {
class EndBlockCommandParser : public CommandParser {
public:
EndBlockCommandParser() : _elseFound(false), _ifTag(0) {}
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command);
virtual void transition(ScriptParseContext &parseCtx, Command *oldCommand, Command *newCommand);
private:
bool _elseFound;
char _ifTag;
};
class EndBlockCommand : public Command {
public:
static bool ParseFunc(const Common::String &line, ScriptParseContext &parseContext, Command *&command);
virtual ExecuteResult execute(GameData &gameData) override;
virtual Command *next() const override;
};
}
#endif

View file

@ -28,8 +28,7 @@
namespace MutationOfJB { namespace MutationOfJB {
bool IfCommand::ParseFunc(const Common::String &line, ScriptParseContext &parseContext, Command *&command) bool IfCommandParser::parse(const Common::String &line, ScriptParseContext &parseContext, Command *&command) {
{
// IFtss oo val! // IFtss oo val!
// <t> 1B Tag. // <t> 1B Tag.
// <ss> 2B Scene. // <ss> 2B Scene.
@ -59,6 +58,15 @@ bool IfCommand::ParseFunc(const Common::String &line, ScriptParseContext &parseC
return true; return true;
} }
void IfCommandParser::transition(ScriptParseContext &, Command *oldCommand, Command *newCommand) {
if (!oldCommand || !newCommand) {
warning(_("Unexpected empty command in transition"));
return;
}
static_cast<IfCommand *>(oldCommand)->setTrueCommand(newCommand);
}
IfCommand::IfCommand(uint8 sceneId, uint8 objectId, uint16 value, bool negative) : IfCommand::IfCommand(uint8 sceneId, uint8 objectId, uint16 value, bool negative) :
_sceneId(sceneId), _sceneId(sceneId),
_objectId(objectId), _objectId(objectId),

View file

@ -30,6 +30,12 @@ namespace MutationOfJB {
class ScriptParseContext; class ScriptParseContext;
class IfCommandParser : public CommandParser {
public:
virtual bool parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command);
virtual void transition(ScriptParseContext &parseCtx, Command *oldCommand, Command *newCommand);
};
class IfCommand : public ConditionalCommand { class IfCommand : public ConditionalCommand {
public: public:
static bool ParseFunc(const Common::String &line, ScriptParseContext &parseContext, Command *&command); static bool ParseFunc(const Common::String &line, ScriptParseContext &parseContext, Command *&command);

View file

@ -20,10 +20,20 @@
* *
*/ */
#include "seqcommand.h" #include "mutationofjb/commands/seqcommand.h"
#include "common/translation.h"
namespace MutationOfJB { namespace MutationOfJB {
void SeqCommandParser::transition(ScriptParseContext &, Command * oldCommand, Command * newCommand) {
if (!oldCommand || !newCommand) {
warning(_("Unexpected empty command in transition"));
return;
}
static_cast<SeqCommand *>(oldCommand)->setNextCommand(newCommand);
}
void SeqCommand::setNextCommand(Command *nextCommand) void SeqCommand::setNextCommand(Command *nextCommand)
{ {
_nextCommand = nextCommand; _nextCommand = nextCommand;

View file

@ -28,6 +28,11 @@
namespace MutationOfJB { namespace MutationOfJB {
class SeqCommandParser : public CommandParser
{
virtual void transition(ScriptParseContext &parseCtx, Command *oldCommand, Command *newCommand) override;
};
class SeqCommand : public Command { class SeqCommand : public Command {
public: public:
void setNextCommand(Command *nextCommand); void setNextCommand(Command *nextCommand);

View file

@ -3,6 +3,7 @@ MODULE := engines/mutationofjb
MODULE_OBJS := \ MODULE_OBJS := \
commands/command.o \ commands/command.o \
commands/conditionalcommand.o \ commands/conditionalcommand.o \
commands/endblockcommand.o \
commands/ifcommand.o \ commands/ifcommand.o \
commands/seqcommand.o \ commands/seqcommand.o \
detection.o \ detection.o \

View file

@ -36,6 +36,7 @@
#include "mutationofjb/game.h" #include "mutationofjb/game.h"
#include "mutationofjb/encryptedfile.h" #include "mutationofjb/encryptedfile.h"
#include "mutationofjb/util.h" #include "mutationofjb/util.h"
#include "mutationofjb/script.h"
namespace MutationOfJB { namespace MutationOfJB {
@ -96,10 +97,24 @@ Common::Error MutationOfJBEngine::run() {
_room = new Room(_screen); _room = new Room(_screen);
_room->load(_gameData->_currentScene, false); _room->load(_gameData->_currentScene, false);
EncryptedFile globalScriptFile;
globalScriptFile.open("global.atn");
Script *script = new Script;
script->loadFromStream(globalScriptFile);
globalScriptFile.close();
while(!shouldQuit()) { while(!shouldQuit()) {
Common::Event event; Common::Event event;
while (_eventMan->pollEvent(event)) { while (_eventMan->pollEvent(event)) {
switch (event.type) { switch (event.type) {
case Common::EVENT_KEYDOWN:
{
if ((event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) ||
event.kbd.ascii == '~' || event.kbd.ascii == '#') {
_console->attach();
}
break;
}
case Common::EVENT_LBUTTONDOWN: case Common::EVENT_LBUTTONDOWN:
{ {
const Scene* const scene = _gameData->getScene(_gameData->_currentScene); const Scene* const scene = _gameData->getScene(_gameData->_currentScene);
@ -119,6 +134,7 @@ Common::Error MutationOfJBEngine::run() {
} }
} }
_console->onFrame();
_system->delayMillis(40); _system->delayMillis(40);
_screen->update(); _screen->update();
} }

View file

@ -25,25 +25,37 @@
#include "common/hashmap.h" #include "common/hashmap.h"
#include "common/hash-str.h" #include "common/hash-str.h"
#include "common/stream.h" #include "common/stream.h"
#include "common/debug.h"
#include "mutationofjb/commands/command.h" #include "mutationofjb/commands/command.h"
#include "mutationofjb/commands/ifcommand.h"
#include "mutationofjb/commands/endblockcommand.h"
namespace MutationOfJB { namespace MutationOfJB {
static CommandParseFunc* getParseFuncs() { static CommandParser** getParsers() {
static CommandParseFunc funcs[] = { static CommandParser* parsers[] = {
new IfCommandParser,
new EndBlockCommandParser,
nullptr nullptr
}; };
return funcs; return parsers;
} }
ScriptParseContext::ScriptParseContext(Common::SeekableReadStream &stream) : _stream(stream) {} ScriptParseContext::ScriptParseContext(Common::SeekableReadStream &stream) :
_stream(stream),
_currentCommand(nullptr),
_lastCommand(nullptr)
{}
bool ScriptParseContext::readLine(Common::String &line) { bool ScriptParseContext::readLine(Common::String &line) {
do { do {
Common::String str = _stream.readLine(); Common::String str = _stream.readLine();
if (str.empty() || str[0] != '.') { if (str.empty())
continue;
if (str[0] != '.') {
line = str; line = str;
if (line[0] == '*') { if (line[0] == '*') {
line.deleteChar(0); line.deleteChar(0);
@ -61,15 +73,52 @@ void ScriptParseContext::addConditionalCommand(ConditionalCommand *command, char
} }
bool Script::loadFromStream(Common::SeekableReadStream &stream) { bool Script::loadFromStream(Common::SeekableReadStream &stream) {
destroy();
CommandParseFunc * const parseFuncs = getParseFuncs(); CommandParser **parsers = getParsers();
ScriptParseContext parseCtx(stream); ScriptParseContext parseCtx(stream);
Common::String line;
Command *lastCmd = nullptr;
CommandParser *lastParser = nullptr;
while (parseCtx.readLine(line)) {
Command *currentCmd = nullptr;
CommandParser *currentParser = nullptr;
for (CommandParser **parser = parsers; *parser; ++parser) {
if ((*parser)->parse(line, parseCtx, currentCmd)) {
currentParser = *parser;
break;
}
}
if (lastParser) {
lastParser->transition(parseCtx, lastCmd, currentCmd);
}
if (currentCmd) {
_allCommands.push_back(currentCmd);
}
lastParser = currentParser;
}
Common::HashMap<Common::String, Command *> macros; Common::HashMap<Common::String, Command *> macros;
Common::HashMap<Common::String, Command *> labels; Common::HashMap<Common::String, Command *> labels;
return true; return true;
} }
void Script::destroy() {
for (Commands::iterator it = _allCommands.begin(); it != _allCommands.end(); ++it) {
delete *it;
}
_allCommands.clear();
}
Script::~Script() {
destroy();
}
} }

View file

@ -32,7 +32,9 @@ namespace Common {
namespace MutationOfJB { namespace MutationOfJB {
class Command;
class ConditionalCommand; class ConditionalCommand;
typedef Common::Array<Command*> Commands;
class ScriptParseContext class ScriptParseContext
{ {
@ -40,23 +42,45 @@ public:
ScriptParseContext(Common::SeekableReadStream &stream); ScriptParseContext(Common::SeekableReadStream &stream);
bool readLine(Common::String &line); bool readLine(Common::String &line);
void addConditionalCommand(ConditionalCommand *command, char tag); void addConditionalCommand(ConditionalCommand *command, char tag);
//void setLastIfCommand(IfCommand *command); void addLookSection(const Common::String & item, bool walkTo);
private:
Common::SeekableReadStream &_stream; Common::SeekableReadStream &_stream;
Command *_currentCommand;
Command *_lastCommand;
struct ConditionalCommandInfo { struct ConditionalCommandInfo {
ConditionalCommand *command; ConditionalCommand *_command;
char tag; char _tag;
}; };
Common::Array<ConditionalCommandInfo> _pendingCondCommands; typedef Common::Array<ConditionalCommandInfo> ConditionalCommandInfos;
ConditionalCommandInfos _pendingCondCommands;
enum Action {
Walk,
Talk,
Look,
Use
};
struct ActionInfo {
Action _action;
Common::String _object1Name;
Common::String _object2Name;
bool walkTo;
};
typedef Common::Array<ActionInfo> ActionInfos;
ActionInfos _actionInfos;
private:
}; };
class Script { class Script {
public: public:
bool loadFromStream(Common::SeekableReadStream &stream); bool loadFromStream(Common::SeekableReadStream &stream);
~Script();
private: private:
void destroy();
Commands _allCommands;
}; };
} }