MUTATIONOFJB: Run extra sections from conversation.

This commit is contained in:
Ľubomír Remák 2018-07-15 15:52:29 +02:00 committed by Eugene Sandulenko
parent d22da95282
commit d358a65bbc
8 changed files with 119 additions and 9 deletions

View File

@ -35,6 +35,7 @@
("#U " | "-U ") <object1> [<object2>]
("#ELSE" | "-ELSE") [<tag>]
"#MACRO " <name>
"#EXTRA" <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.
@ -46,6 +47,8 @@
#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.
#EXTRA defines an "extra" section. This is called from dialog responses ("TALK TO HIM" command).
*/
namespace MutationOfJB {
@ -119,6 +122,9 @@ bool EndBlockCommandParser::parse(const Common::String &line, ScriptParseContext
const uint8 startupId = atoi(line.c_str() + 9);
IdAndCommand ic = {startupId, command};
_foundStartups.push_back(ic);
} else if (line.size() >= 7 && line.hasPrefix("#EXTRA")) {
NameAndCommand nc = {line.c_str() + 6, command};
_foundExtras.push_back(nc);
}
if (firstChar == '#') {
@ -183,6 +189,23 @@ void EndBlockCommandParser::transition(ScriptParseContext &parseCtx, Command *ol
}
}
}
if (!_foundExtras.empty()) {
if (newCommand) {
for (NameAndCommandArray::iterator it = _foundExtras.begin(); it != _foundExtras.end();) {
if (it->_command != oldCommand) {
it++;
continue;
}
if (!parseCtx._extras.contains(it->_name)) {
parseCtx._extras[it->_name] = newCommand;
} else {
warning(_("Extra '%s' already exists"), it->_name.c_str());
}
it = _foundExtras.erase(it);
}
}
}
if (newCommandParser != this) {
if (!_pendingActionInfos.empty()) {
@ -208,9 +231,13 @@ void EndBlockCommandParser::finish(ScriptParseContext &) {
if (!_foundStartups.empty()) {
debug("Problem: Found startups from end block parser is not empty!");
}
if (!_foundExtras.empty()) {
debug("Problem: Found extras from end block parser is not empty!");
}
_pendingActionInfos.clear();
_foundMacros.clear();
_foundStartups.clear();
_foundExtras.clear();
}
Command::ExecuteResult EndBlockCommand::execute(ScriptExecutionContext &scriptExecCtx) {

View File

@ -56,6 +56,7 @@ private:
typedef Common::Array<IdAndCommand> IdAndCommandArray;
NameAndCommandArray _foundMacros;
IdAndCommandArray _foundStartups;
NameAndCommandArray _foundExtras;
};
class EndBlockCommand : public Command {

View File

@ -56,8 +56,8 @@ bool ConversationLineList::parseFile(const Common::String &fileName) {
Common::String::iterator endIt = Common::find(lineStr.begin(), lineStr.end(), '|');
if (endIt != lineStr.end()) {
Common::String extra = lineStr + endIt;
if (*endIt == 'X') {
endIt++;
if (endIt != lineStr.end() && *endIt == 'X') {
line._extra = Common::String(endIt + 1, lineStr.end()); // Skip 'X' char.
}
}

View File

@ -202,6 +202,7 @@ Common::Error MutationOfJBEngine::run() {
_game->setCurrentAction(ActionInfo::PickUp);
break;
}
break;
}
default:
break;

View File

@ -189,6 +189,23 @@ Command *ScriptExecutionContext::getMacro(const Common::String &name) const {
return cmd;
}
Command *ScriptExecutionContext::getExtra(const Common::String &name) const {
Command *cmd = nullptr;
Script *const localScript = _localScriptOverride ? _localScriptOverride : _game.getLocalScript();
Script *const globalScript = _game.getGlobalScript();
if (localScript) {
cmd = localScript->getExtra(name);
}
if (!cmd && globalScript) {
cmd = globalScript->getExtra(name);
}
return cmd;
}
bool Script::loadFromStream(Common::SeekableReadStream &stream) {
destroy();
@ -236,6 +253,7 @@ bool Script::loadFromStream(Common::SeekableReadStream &stream) {
_macros = parseCtx._macros;
_startups = parseCtx._startups;
_extras = parseCtx._extras;
return true;
}
@ -285,4 +303,13 @@ Command *Script::getStartup(uint8 startupId) const {
return it->_value;
}
Command *Script::getExtra(const Common::String &name) const {
Extras::const_iterator it = _extras.find(name);
if (it == _extras.end()) {
return nullptr;
}
return it->_value;
}
}

View File

@ -67,6 +67,7 @@ typedef Common::Array<ActionInfo> ActionInfos;
typedef Common::Array<GotoCommand *> GotoCommands;
typedef Common::HashMap<Common::String, Command *> Macros;
typedef Common::HashMap<uint8, Command *> Startups;
typedef Common::HashMap<Common::String, Command *> Extras;
class ScriptParseContext {
public:
@ -98,6 +99,7 @@ public:
ActionInfos _actionInfos;
Macros _macros;
Startups _startups;
Extras _extras;
private:
};
@ -116,6 +118,7 @@ public:
Game &getGame();
GameData &getGameData();
Command *getMacro(const Common::String &name) const;
Command *getExtra(const Common::String &name) const;
private:
Game &_game;
@ -135,6 +138,7 @@ public:
const Startups &getStartups() const;
Command *getMacro(const Common::String &name) const;
Command *getStartup(uint8 startupId) const;
Command *getExtra(const Common::String &name) const;
private:
void destroy();
@ -142,6 +146,7 @@ private:
ActionInfos _actionInfos[5];
Macros _macros;
Startups _startups;
Extras _extras;
};
}

View File

@ -27,11 +27,14 @@
#include "mutationofjb/game.h"
#include "mutationofjb/gamedata.h"
#include "mutationofjb/gui.h"
#include "mutationofjb/script.h"
#include "mutationofjb/tasks/saytask.h"
#include "mutationofjb/tasks/taskmanager.h"
#include "mutationofjb/util.h"
#include "mutationofjb/widgets/conversationwidget.h"
#include "common/translation.h"
namespace MutationOfJB {
void ConversationTask::start() {
@ -69,11 +72,11 @@ void ConversationTask::update() {
break;
}
case SAYING_RESPONSE: {
if (_currentItem->_nextLineIndex == 0) {
finish();
} else {
_currentLineIndex = _currentItem->_nextLineIndex - 1;
showChoicesOrPick();
startExtra();
if (_substate != RUNNING_EXTRA)
{
gotoNextLine();
}
break;
}
@ -82,6 +85,16 @@ void ConversationTask::update() {
}
}
}
if (_innerExecCtx) {
Command::ExecuteResult res = _innerExecCtx->runActiveCommand();
if (res == Command::Finished) {
delete _innerExecCtx;
_innerExecCtx = nullptr;
gotoNextLine();
}
}
}
void ConversationTask::onChoiceClicked(ConversationWidget *convWidget, int, uint32 data) {
@ -203,4 +216,35 @@ void ConversationTask::finish() {
game.getGui().markDirty(); // TODO: Handle automatically when changing visibility.
}
void ConversationTask::startExtra() {
const ConversationLineList& responseList = getTaskManager()->getGame().getAssets().getResponseList();
const ConversationLineList::Line *const line = responseList.getLine(_currentItem->_response);
if (!line->_extra.empty()) {
_innerExecCtx = new ScriptExecutionContext(getTaskManager()->getGame());
Command *const extraCmd = _innerExecCtx->getExtra(line->_extra);
if (extraCmd) {
Command::ExecuteResult res = _innerExecCtx->startCommand(extraCmd);
if (res == Command::InProgress) {
_substate = RUNNING_EXTRA;
} else {
delete _innerExecCtx;
_innerExecCtx = nullptr;
}
} else {
warning(_("Extra '%s' not found"), line->_extra.c_str());
delete _innerExecCtx;
_innerExecCtx = nullptr;
}
}
}
void ConversationTask::gotoNextLine() {
if (_currentItem->_nextLineIndex == 0) {
finish();
} else {
_currentLineIndex = _currentItem->_nextLineIndex - 1;
showChoicesOrPick();
}
}
}

View File

@ -27,10 +27,11 @@
namespace MutationOfJB {
class SayTask;
class ScriptExecutionContext;
class ConversationTask : public Task, public ConversationWidgetCallback {
public:
ConversationTask(uint8 sceneId, const ConversationInfo& convInfo) : _sceneId(sceneId), _convInfo(convInfo), _currentLineIndex(0), _currentItem(nullptr), _sayTask(nullptr), _substate(IDLE), _haveChoices(false) {}
ConversationTask(uint8 sceneId, const ConversationInfo& convInfo) : _sceneId(sceneId), _convInfo(convInfo), _currentLineIndex(0), _currentItem(nullptr), _sayTask(nullptr), _substate(IDLE), _haveChoices(false), _innerExecCtx(nullptr) {}
virtual ~ConversationTask() {}
virtual void start() override;
@ -41,6 +42,8 @@ private:
void showChoicesOrPick();
const ConversationInfo::Line *getCurrentLine() const;
void finish();
void startExtra();
void gotoNextLine();
uint8 _sceneId;
const ConversationInfo &_convInfo;
@ -52,11 +55,13 @@ private:
IDLE,
SAYING_CHOICE,
SAYING_RESPONSE,
SAYING_NO_CHOICES
SAYING_NO_CHOICES,
RUNNING_EXTRA
};
Substate _substate;
bool _haveChoices;
ScriptExecutionContext *_innerExecCtx;
};
}