Initial commit
This commit is contained in:
251
engines/agds/dialog.cpp
Normal file
251
engines/agds/dialog.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* 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 "agds/dialog.h"
|
||||
#include "agds/agds.h"
|
||||
#include "agds/object.h"
|
||||
#include "agds/systemVariable.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace AGDS {
|
||||
|
||||
void Dialog::parseDialogDefs(const Common::String &defs) {
|
||||
_dialogDefs.clear();
|
||||
Common::String name, value;
|
||||
bool readName = true;
|
||||
for (uint32 p = 0, size = defs.size(); p < size; ++p) {
|
||||
char ch = defs[p];
|
||||
if (ch == ' ') {
|
||||
continue;
|
||||
} else if (ch == '\n' || ch == '\r' || p + 1 == size) {
|
||||
if (p + 1 == size)
|
||||
value += ch;
|
||||
// debug("dialog definition: '%s' = '%s'", name.c_str(), value.c_str());
|
||||
if (!name.empty() && !value.empty()) {
|
||||
_dialogDefs[name] = atoi(value.c_str());
|
||||
}
|
||||
readName = true;
|
||||
name.clear();
|
||||
value.clear();
|
||||
continue;
|
||||
} else if (ch == '=') {
|
||||
if (readName) {
|
||||
readName = false;
|
||||
} else {
|
||||
warning("equal sign in value, skipping");
|
||||
}
|
||||
} else {
|
||||
if (readName)
|
||||
name += ch;
|
||||
else
|
||||
value += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::load(const Common::String &processName, const Common::String &dialogScript, const Common::String &defs) {
|
||||
_currentDef.clear();
|
||||
_sounds.clear();
|
||||
parseDialogDefs(defs);
|
||||
_dialogProcessName = processName;
|
||||
_dialogScript = dialogScript;
|
||||
_dialogScriptPos = 0;
|
||||
_engine->getSystemVariable("dialog_var")->setInteger(-1);
|
||||
}
|
||||
|
||||
int Dialog::textDelay(const Common::String &str) {
|
||||
int speed = _engine->getSystemVariable("text_speed")->getInteger();
|
||||
if (speed < 0)
|
||||
speed = 0;
|
||||
else if (speed > 100)
|
||||
speed = 100;
|
||||
speed /= 10;
|
||||
|
||||
int delay = str.size();
|
||||
if (delay < 20)
|
||||
delay = 20;
|
||||
|
||||
// this looks like an error in original code
|
||||
// original first value in this table is 0x0FFFFFEB4 (-332)
|
||||
// 0x0FFFFFEB4 * 20 and then 16-to-32 conversion gives 0xffffe610
|
||||
// 0xe610 / 20 = 2944
|
||||
static const int delays[] = {
|
||||
2944, 631, 398, 251, 158,
|
||||
100, 63, 40, 25, 16, 10};
|
||||
return delays[speed] * delay / 41 + 1;
|
||||
}
|
||||
|
||||
bool Dialog::tick() {
|
||||
if (_dialogProcessName.empty())
|
||||
return false;
|
||||
|
||||
auto dialog_var = _engine->getSystemVariable("dialog_var");
|
||||
int dialog_var_value = dialog_var->getInteger();
|
||||
if (dialog_var_value != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint n = _dialogScript.size();
|
||||
if (_dialogScriptPos >= n) {
|
||||
|
||||
if (!_dialogProcessName.empty()) {
|
||||
debug("end of dialog, running %s", _dialogProcessName.c_str());
|
||||
dialog_var->setInteger(-2);
|
||||
_engine->reactivate(_dialogProcessName, "end of dialog");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String &line = _dialogLine;
|
||||
line.clear();
|
||||
|
||||
bool command = _dialogScript[_dialogScriptPos] == '@';
|
||||
while (_dialogScriptPos < n) {
|
||||
if (!command && _dialogScript[_dialogScriptPos] == '@')
|
||||
break;
|
||||
|
||||
while (_dialogScriptPos < n && _dialogScript[_dialogScriptPos] != '\n' && _dialogScript[_dialogScriptPos] != '\r') {
|
||||
line += _dialogScript[_dialogScriptPos++];
|
||||
}
|
||||
if (!command)
|
||||
line += '\n';
|
||||
|
||||
while (_dialogScriptPos < n && (_dialogScript[_dialogScriptPos] == '\n' || _dialogScript[_dialogScriptPos] == '\r'))
|
||||
++_dialogScriptPos;
|
||||
|
||||
if (command)
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.empty())
|
||||
return true;
|
||||
|
||||
debug("dialog line: %s", line.c_str());
|
||||
if (line[0] == '@') {
|
||||
processDirective(line);
|
||||
} else {
|
||||
debug("text: %s", line.c_str() + 1);
|
||||
dialog_var->setInteger(-3);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dialog::processSoundDirective(const Common::String &line) {
|
||||
debug("sound: %s", line.c_str());
|
||||
auto arg1 = line.find('(');
|
||||
if (arg1 == line.npos) {
|
||||
warning("invalid sound directive");
|
||||
return;
|
||||
}
|
||||
++arg1;
|
||||
|
||||
auto comma1 = line.find(',', arg1);
|
||||
if (comma1 == line.npos) {
|
||||
warning("invalid sound directive, missing arg2");
|
||||
return;
|
||||
}
|
||||
++comma1;
|
||||
auto comma2 = line.find(',', comma1);
|
||||
if (comma2 == line.npos) {
|
||||
warning("invalid sound directive, missing arg3");
|
||||
return;
|
||||
}
|
||||
auto end = line.find(')', comma2 + 1);
|
||||
if (end == line.npos) {
|
||||
warning("invalid sound directive");
|
||||
return;
|
||||
}
|
||||
--end;
|
||||
Common::String name = line.substr(arg1, comma1 - arg1 - 1);
|
||||
while (line[comma1] == ' ')
|
||||
++comma1;
|
||||
Common::String sample = line.substr(comma1, comma2 - comma1);
|
||||
while (line[comma2] == ' ')
|
||||
++comma2;
|
||||
Common::String step = line.substr(comma2 + 1, end - comma2);
|
||||
debug("sound args = %s,%s,%s", name.c_str(), sample.c_str(), step.c_str());
|
||||
_sounds.push_back(Sound(name, sample, atoi(step.c_str())));
|
||||
}
|
||||
|
||||
void Dialog::processDirective(Common::String line) {
|
||||
if (line.size() < 2 || line[1] == '@') {
|
||||
debug("comment, bailing out");
|
||||
return;
|
||||
}
|
||||
|
||||
line.erase(0, 1);
|
||||
|
||||
if (line.hasPrefix("sound")) {
|
||||
processSoundDirective(line);
|
||||
} else {
|
||||
DialogDefsType::const_iterator it = _dialogDefs.find(line);
|
||||
if (it != _dialogDefs.end()) {
|
||||
int value = it->_value;
|
||||
_currentDef = line;
|
||||
if (!_currentDef.hasPrefix("vybervarianty") && !_currentDef.hasPrefix("varianta")) {
|
||||
_currentSoundIndex = -1;
|
||||
|
||||
for (uint s = 0; s < _sounds.size(); ++s) {
|
||||
auto &sound = _sounds[s];
|
||||
if (_currentDef.hasPrefixIgnoreCase(sound.Name)) {
|
||||
_currentSoundIndex = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug("dialog value %s = %d (0x%04x), sample index: %d", line.c_str(), value, value, _currentSoundIndex);
|
||||
_engine->getSystemVariable("dialog_var")->setInteger(value);
|
||||
} else
|
||||
warning("invalid dialog directive: %s", line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Common::String Dialog::getNextDialogSound() {
|
||||
if (_currentDef.empty())
|
||||
return Common::String();
|
||||
|
||||
debug("getNextDialogSound %s %d", _currentDef.c_str(), _currentSoundIndex);
|
||||
if (_currentSoundIndex < 0)
|
||||
return Common::String();
|
||||
|
||||
auto &sound = _sounds[_currentSoundIndex];
|
||||
auto &sample = sound.Sample;
|
||||
auto currentSample = sample;
|
||||
|
||||
int carry = sound.Step;
|
||||
for (auto pos = sample.size() - 1; pos > 0 && sample[pos] >= '0' && sample[pos] <= '9'; --pos) {
|
||||
int d = sample[pos] - '0';
|
||||
d += carry;
|
||||
carry = d / 10;
|
||||
sample.setChar('0' + (d % 10), pos);
|
||||
if (carry == 0)
|
||||
break;
|
||||
}
|
||||
if (carry != 0)
|
||||
warning("sample index overflow, %s", sample.c_str());
|
||||
|
||||
debug("returning sample name %s", currentSample.c_str());
|
||||
return currentSample + ".ogg";
|
||||
}
|
||||
|
||||
} // namespace AGDS
|
||||
Reference in New Issue
Block a user