scummvm/engines/cryomni3d/versailles/dialogs_manager.cpp
Le Philousophe b45197642e BUILD/CRYOMNI3D: Reduce the number of bogus GCC warnings
As the warning is emitted on parsing the class constructor, just move it
out of the class definition.
2019-08-31 19:40:33 +02:00

380 lines
11 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 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 "audio/decoders/wave.h"
#include "common/file.h"
#include "common/system.h"
#include "cryomni3d/video/hnm_decoder.h"
#include "cryomni3d/versailles/dialogs_manager.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
Versailles_DialogsManager::Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine,
bool padAudioFileName) :
_engine(engine), _padAudioFileName(padAudioFileName) {
}
bool Versailles_DialogsManager::play(const Common::String &sequence) {
// Prepare with specific Versailles stuff
if (!_engine->preprocessDialog(sequence)) {
return false;
}
_engine->musicSetQuiet(true);
_engine->setCursor(181);
// No need to adjust hide cursor counter, there isn't any in ScummVM
bool cursorWasVisible = _engine->showMouse(true);
bool slowStop = false;
bool didSth = DialogsManager::play(sequence, slowStop);
_engine->showMouse(cursorWasVisible);
if (didSth && slowStop) {
if (_engine->showSubtitles()) {
bool skip = false;
uint end = g_system->getMillis() + 2000;
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skip) {
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents() &&
(_engine->checkKeysPressed(1, Common::KEYCODE_SPACE) ||
_engine->getCurrentMouseButton() == 1)) {
skip = true;
}
}
}
}
_engine->postprocessDialog(sequence);
_engine->musicSetQuiet(false);
_lastImage.free();
_engine->waitMouseRelease();
return didSth;
}
void Versailles_DialogsManager::executeShow(const Common::String &show) {
Common::HashMap<Common::String, ShowCallback>::iterator showIt = _shows.find(show);
if (showIt == _shows.end()) {
error("Missing show %s", show.c_str());
}
_lastImage.free();
ShowCallback cb = showIt->_value;
(_engine->*cb)();
}
void Versailles_DialogsManager::playDialog(const Common::String &video, const Common::String &sound,
const Common::String &text, const SubtitlesSettings &settings) {
// Don't look for HNS file here
Common::String videoFName(_engine->prepareFileName(video, "hnm"));
Common::String soundFName(sound);
if (_padAudioFileName) {
while (soundFName.size() < 8) {
soundFName += '_';
}
}
soundFName = _engine->prepareFileName(soundFName, "wav");
Video::HNMDecoder *videoDecoder = new Video::HNMDecoder(true);
if (!videoDecoder->loadFile(videoFName)) {
warning("Failed to open movie file %s/%s", video.c_str(), videoFName.c_str());
delete videoDecoder;
return;
}
Common::File *audioFile = new Common::File();
if (!audioFile->open(soundFName)) {
warning("Failed to open sound file %s/%s", sound.c_str(), soundFName.c_str());
delete videoDecoder;
delete audioFile;
return;
}
Audio::SeekableAudioStream *audioDecoder = Audio::makeWAVStream(audioFile, DisposeAfterUse::YES);
// We lost ownership of the audioFile just set it to nullptr and don't use it
audioFile = nullptr;
if (!audioDecoder) {
delete videoDecoder;
return;
}
_engine->showMouse(false);
uint16 width = videoDecoder->getWidth();
uint16 height = videoDecoder->getHeight();
// Preload first frame to draw subtitles from it
const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
assert(firstFrame != nullptr);
if (videoDecoder->hasDirtyPalette()) {
const byte *palette = videoDecoder->getPalette();
_engine->setupPalette(palette, 0, 256);
}
FontManager &fontManager = _engine->_fontManager;
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
_lastImage.blitFrom(*firstFrame);
fontManager.setCurrentFont(7);
fontManager.setTransparentBackground(true);
fontManager.setForeColor(241);
fontManager.setLineHeight(22);
fontManager.setSpaceWidth(2);
fontManager.setCharSpacing(1);
if (_engine->showSubtitles()) {
Common::Rect block = settings.textRect;
uint lines = fontManager.getLinesCount(text, block.width() - 8);
if (lines == 0) {
lines = 5;
}
uint blockHeight = fontManager.lineHeight() * lines + 6;
block.setHeight(blockHeight);
if (block.bottom >= 480) {
block.bottom = 470;
warning("Dialog text is really too long");
}
// Make only the block area translucent inplace
Graphics::Surface blockSurface = _lastImage.getSubArea(block);
_engine->makeTranslucent(blockSurface, blockSurface);
fontManager.setSurface(&_lastImage);
block.grow(-4);
fontManager.setupBlock(block);
fontManager.displayBlockText(text);
}
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, width, height);
g_system->updateScreen();
const Common::Rect &drawRect = settings.drawRect;
if (audioDecoder->getLength() == 0) {
// Empty wave file
delete audioDecoder;
uint duration = 100 * text.size();
if (duration < 1000) {
duration = 1000;
}
bool skipWait = false;
uint end = g_system->getMillis() + duration;
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skipWait) {
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
skipWait = true;
}
}
} else {
// Let start the show!
videoDecoder->start();
Audio::SoundHandle audioHandle;
_engine->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &audioHandle, audioDecoder);
// We lost ownership of the audioDecoder just set it to nullptr and don't use it
audioDecoder = nullptr;
bool skipVideo = false;
while (!_engine->shouldAbort() && _engine->_mixer->isSoundHandleActive(audioHandle) && !skipVideo) {
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
skipVideo = true;
}
if (videoDecoder->needsUpdate()) {
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
if (videoDecoder->hasDirtyPalette()) {
const byte *palette = videoDecoder->getPalette();
_engine->setupPalette(palette, 0, 256);
}
// Only refresh the moving part of the animation
const Graphics::Surface subFrame = frame->getSubArea(drawRect);
g_system->copyRectToScreen(subFrame.getPixels(), subFrame.pitch, drawRect.left, drawRect.top,
subFrame.w, subFrame.h);
}
}
g_system->updateScreen();
g_system->delayMillis(10);
}
_engine->_mixer->stopHandle(audioHandle);
}
// It's intentional that _lastImage is set with the first video image
delete videoDecoder;
_engine->showMouse(true);
}
void Versailles_DialogsManager::displayMessage(const Common::String &text) {
_engine->displayMessageBoxWarp(text);
}
uint Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
const Common::StringArray &questions) {
if (_lastImage.empty()) {
loadFrame(video);
}
if (questions.size() == 0 || questions.size() > 5) {
return uint(-1);
}
FontManager &fontManager = _engine->_fontManager;
fontManager.setCurrentFont(7);
fontManager.setTransparentBackground(true);
fontManager.setLineHeight(18);
fontManager.setSpaceWidth(2);
fontManager.setSurface(&_lastImage);
int16 tops[5];
int16 bottoms[5];
int16 currentHeight = 0;
uint questionId = 0;
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
it++, questionId++) {
tops[questionId] = currentHeight;
uint lines = fontManager.getLinesCount(*it, 598);
if (lines == 0) {
lines = 1;
}
currentHeight += 18 * lines;
bottoms[questionId] = currentHeight;
}
int offsetY = 480 - (bottoms[questions.size() - 1] - tops[0]);
if (offsetY > 402) {
offsetY = 402;
} else if (offsetY < 2) {
offsetY = 2;
}
for (questionId = 0; questionId < questions.size(); questionId++) {
tops[questionId] += offsetY;
bottoms[questionId] += offsetY;
}
_engine->setCursor(181);
Graphics::Surface alphaSurface = _lastImage.getSubArea(Common::Rect(0, offsetY - 2, 640, 480));
_engine->makeTranslucent(alphaSurface, alphaSurface);
bool finished = false;
bool update = true;
uint selectedQuestion = uint(-1);
while (!finished) {
if (update) {
update = false;
questionId = 0;
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
it++, questionId++) {
fontManager.setForeColor(selectedQuestion == questionId ? 241 : 245);
fontManager.setupBlock(Common::Rect(10, tops[questionId], 608, bottoms[questionId]));
fontManager.displayBlockText(*it);
}
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, _lastImage.w,
_lastImage.h);
}
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents()) {
_engine->clearKeys();
if (_engine->shouldAbort()) {
finished = true;
selectedQuestion = uint(-1);
break;
}
Common::Point mousePos = _engine->getMousePos();
if (_engine->getDragStatus() == kDragStatus_Finished && selectedQuestion != uint(-1)) {
finished = true;
} else if (mousePos.x >= 608 || mousePos.y < offsetY) {
if (selectedQuestion != uint(-1)) {
selectedQuestion = uint(-1);
update = true;
}
} else {
for (questionId = 0; questionId < questions.size(); questionId++) {
if (mousePos.y > tops[questionId] && mousePos.y < bottoms[questionId]) {
break;
}
}
if (questionId < questions.size()) {
if (selectedQuestion != questionId) {
selectedQuestion = questionId;
update = true;
}
} else {
selectedQuestion = uint(-1);
update = true;
}
}
}
}
return selectedQuestion;
}
void Versailles_DialogsManager::loadFrame(const Common::String &video) {
Common::String videoFName(_engine->prepareFileName(video, "hnm"));
Video::HNMDecoder *videoDecoder = new Video::HNMDecoder();
if (!videoDecoder->loadFile(videoFName)) {
warning("Failed to open movie file %s/%s", video.c_str(), videoFName.c_str());
delete videoDecoder;
return;
}
// Preload first frame to draw questions on it
const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
_lastImage.blitFrom(*firstFrame);
if (videoDecoder->hasDirtyPalette()) {
const byte *palette = videoDecoder->getPalette();
_engine->setupPalette(palette, 0, 256);
}
}
} // End of namespace Versailles
} // End of namespace CryOmni3D