169 lines
4.6 KiB
C++
169 lines
4.6 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "mutationofjb/commands/saycommand.h"
|
|
|
|
#include "mutationofjb/game.h"
|
|
#include "mutationofjb/gamedata.h"
|
|
#include "mutationofjb/script.h"
|
|
#include "mutationofjb/tasks/saytask.h"
|
|
#include "mutationofjb/tasks/taskmanager.h"
|
|
|
|
#include "common/str.h"
|
|
#include "common/debug.h"
|
|
#include "common/debug-channels.h"
|
|
|
|
/** @file
|
|
* <firstLine> { <CRLF> <additionalLine> }
|
|
*
|
|
* firstLine ::= ("SM" | "SLM" | "NM" | "NLM") " " <lineToSay> [ "<" <voiceFile> | "<!" ]
|
|
* additionalLine ::= <skipped> " " <lineToSay> ( "<" <voiceFile> | "<!" )
|
|
*
|
|
* Say command comes in four variants: SM, SLM, NM and NLM.
|
|
* Note: In script files, they are usually written as *SM.
|
|
* The asterisk is ignored by the readLine function.
|
|
*
|
|
* Each of them plays a voice file (if present) and/or shows a message
|
|
* (if voice file not present or subtitles are enabled).
|
|
*
|
|
* The difference between versions starting with "S" and "N" is that
|
|
* the "N" version does not show talking animation.
|
|
*
|
|
* The "L" versions are "blocking", i.e. they wait for the previous say command to finish.
|
|
*
|
|
* If the line ends with "<!", it means the message continues to the next line.
|
|
* Next line usually has "SM" (or other variant) repeated, but it does not have to.
|
|
* Then we have the rest of the string to say (which is concatenated with the previous line)
|
|
* and possibly the voice file or "<!" again.
|
|
*/
|
|
|
|
namespace MutationOfJB {
|
|
|
|
bool SayCommandParser::parse(const Common::String &line, ScriptParseContext &parseCtx, Command *&command) {
|
|
bool waitForPrevious = false;
|
|
bool talkingAnimation = false;
|
|
|
|
if (line.hasPrefix("SM")) {
|
|
waitForPrevious = false;
|
|
talkingAnimation = true;
|
|
} else if (line.hasPrefix("SLM")) {
|
|
waitForPrevious = true;
|
|
talkingAnimation = true;
|
|
} else if (line.hasPrefix("NM")) {
|
|
waitForPrevious = false;
|
|
talkingAnimation = false;
|
|
} else if (line.hasPrefix("NLM")) {
|
|
waitForPrevious = true;
|
|
talkingAnimation = false;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
Common::String currentLine = line;
|
|
|
|
Common::String lineToSay;
|
|
Common::String voiceFile;
|
|
|
|
bool cont = false;
|
|
bool firstPass = true;
|
|
|
|
do {
|
|
cont = false;
|
|
|
|
uint startPos;
|
|
for (startPos = 0; startPos < currentLine.size(); ++startPos) {
|
|
if (currentLine[startPos] == ' ') {
|
|
break;
|
|
}
|
|
}
|
|
if (startPos == currentLine.size()) {
|
|
if (!firstPass) {
|
|
warning("Unable to parse line '%s'", currentLine.c_str());
|
|
break;
|
|
}
|
|
}
|
|
if (startPos != currentLine.size()) {
|
|
startPos++;
|
|
}
|
|
|
|
uint endPos;
|
|
for (endPos = startPos; endPos < currentLine.size(); ++endPos) {
|
|
if (currentLine[endPos] == '<') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Common::String talkStr(currentLine.c_str() + startPos, endPos - startPos);
|
|
|
|
if (endPos != currentLine.size()) {
|
|
const char *end = currentLine.c_str() + endPos + 1;
|
|
if (end[0] == '!') {
|
|
cont = true;
|
|
} else {
|
|
voiceFile = end;
|
|
}
|
|
}
|
|
|
|
if (talkStr.lastChar() == '~') {
|
|
debug("Found say command ending with '~'. Please take a look.");
|
|
}
|
|
|
|
if (lineToSay.empty()) {
|
|
lineToSay = talkStr;
|
|
} else {
|
|
lineToSay += " " + talkStr;
|
|
}
|
|
|
|
if (cont) {
|
|
if (!parseCtx.readLine(currentLine)) {
|
|
cont = false;
|
|
}
|
|
}
|
|
|
|
firstPass = false;
|
|
} while (cont);
|
|
|
|
command = new SayCommand(lineToSay, voiceFile, waitForPrevious, talkingAnimation);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
Command::ExecuteResult SayCommand::execute(ScriptExecutionContext &scriptExecCtx) {
|
|
Game &game = scriptExecCtx.getGame();
|
|
|
|
if (_waitForPrevious) {
|
|
if (game.getActiveSayTask()) {
|
|
return InProgress;
|
|
}
|
|
}
|
|
|
|
TaskPtr task(new SayTask(_lineToSay, game.getGameData()._color));
|
|
game.getTaskManager().startTask(task);
|
|
|
|
return Finished;
|
|
}
|
|
|
|
Common::String SayCommand::debugString() const {
|
|
return Common::String::format("SHOWMSG%s%s '%s' '%s'", _waitForPrevious ? "+WAIT" : "", _talkingAnimation ? "+TALKANIM" : "", _lineToSay.c_str(), _voiceFile.c_str());
|
|
}
|
|
|
|
}
|