scummvm/engines/nancy/action/soundrecords.cpp
Kaloyan Chehlarski f5311cfe87 NANCY: Expand TableData struct
From nancy8 on, a new method of writing and evaluating
data started being used. This commit expands the existing
TableData struct to accommodate it.
2024-02-07 23:15:23 +01:00

324 lines
8.5 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 "common/random.h"
#include "common/config-manager.h"
#include "engines/nancy/nancy.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/util.h"
#include "engines/nancy/action/soundrecords.h"
#include "engines/nancy/state/scene.h"
namespace Nancy {
namespace Action {
void SetVolume::readData(Common::SeekableReadStream &stream) {
channel = stream.readUint16LE();
volume = stream.readByte();
}
void SetVolume::execute() {
g_nancy->_sound->setVolume(channel, volume);
_isDone = true;
}
void PlaySound::readData(Common::SeekableReadStream &stream) {
_sound.readDIGI(stream);
if (g_nancy->getGameType() >= kGameTypeNancy3) {
_soundEffect = new SoundEffectDescription;
_soundEffect->readData(stream);
if (g_nancy->getGameType() >= kGameTypeNancy6) {
_changeSceneImmediately = stream.readByte();
}
}
_sceneChange.readData(stream, g_nancy->getGameType() == kGameTypeVampire);
_flag.label = stream.readSint16LE();
_flag.flag = stream.readByte();
stream.skip(2); // VIDEO_STOP_RENDERING, VIDEO_CONTINUE_RENDERING
}
void PlaySound::execute() {
switch (_state) {
case kBegin:
g_nancy->_sound->loadSound(_sound, &_soundEffect);
g_nancy->_sound->playSound(_sound);
if (g_nancy->getGameType() >= kGameTypeNancy8) {
NancySceneState.setEventFlag(_flag);
}
if (_changeSceneImmediately) {
NancySceneState.changeScene(_sceneChange);
finishExecution();
break;
}
_state = kRun;
break;
case kRun:
if (!g_nancy->_sound->isSoundPlaying(_sound)) {
_state = kActionTrigger;
}
break;
case kActionTrigger:
NancySceneState.changeScene(_sceneChange);
if (g_nancy->getGameType() <= kGameTypeNancy7) {
NancySceneState.setEventFlag(_flag);
}
g_nancy->_sound->stopSound(_sound);
finishExecution();
break;
}
}
Common::String PlaySound::getRecordTypeName() const {
if (g_nancy->getGameType() <= kGameTypeNancy2) {
return "PlayDigiSoundAndDie";
} else if (g_nancy->getGameType() <= kGameTypeNancy5) {
return "PlayDigiSound";
} else {
return "PlaySound";
}
}
void PlaySoundCC::readData(Common::SeekableReadStream &stream) {
PlaySound::readData(stream);
readCCText(stream, _ccText);
}
void PlaySoundCC::execute() {
if (_state == kBegin && _ccText.size() && ConfMan.getBool("subtitles", ConfMan.getActiveDomainName())) {
NancySceneState.getTextbox().clear();
NancySceneState.getTextbox().addTextLine(_ccText);
}
PlaySound::execute();
}
void PlaySoundCC::readCCText(Common::SeekableReadStream &stream, Common::String &out) {
int16 textSize = stream.readUint16LE();
if (textSize > 0) {
char *strBuf = new char[textSize];
stream.read(strBuf, textSize);
assembleTextLine(strBuf, out, textSize);
delete[] strBuf;
} else if (textSize == -1) {
// Text is in Autotext chunk
Common::String key;
readFilename(stream, key);
const CVTX *autotext = (const CVTX *)g_nancy->getEngineData("AUTOTEXT");
assert(autotext);
out = autotext->texts[key];
}
}
Common::String PlaySoundCC::getRecordTypeName() const {
if (g_nancy->getGameType() <= kGameTypeNancy5) {
return "PlayDigiSoundCC";
} else {
return "PlaySoundCC";
}
}
void PlaySoundTerse::readData(Common::SeekableReadStream &stream) {
_sound.readTerse(stream);
_changeSceneImmediately = stream.readByte();
_sceneChange.sceneID = stream.readUint16LE();
_sceneChange.continueSceneSound = kContinueSceneSound;
_soundEffect = new SoundEffectDescription;
readCCText(stream, _ccText);
}
void PlaySoundEventFlagTerse::readData(Common::SeekableReadStream &stream) {
_sound.readTerse(stream);
_changeSceneImmediately = stream.readByte();
_sceneChange.sceneID = stream.readUint16LE();
_flag.label = stream.readUint16LE();
_flag.flag = stream.readByte();
_sceneChange.continueSceneSound = kContinueSceneSound;
_soundEffect = new SoundEffectDescription;
readCCText(stream, _ccText);
}
void PlaySoundFrameAnchor::readData(Common::SeekableReadStream &stream) {
_sound.readDIGI(stream);
stream.skip(2);
_sound.isPanning = true;
}
void PlaySoundFrameAnchor::execute() {
g_nancy->_sound->loadSound(_sound);
g_nancy->_sound->playSound(_sound);
_isDone = true;
}
Common::String PlaySoundFrameAnchor::getRecordTypeName() const {
if (g_nancy->getGameType() <= kGameTypeNancy2) {
return "PlaySoundPanFrameAnchorAndDie";
} else {
return "PlaySoundFrameAnchor";
}
}
void PlaySoundMultiHS::readData(Common::SeekableReadStream &stream) {
_sound.readNormal(stream);
if (g_nancy->getGameType() != kGameTypeVampire) {
_sceneChange.readData(stream);
_flag.label = stream.readSint16LE();
_flag.flag = stream.readByte();
stream.skip(2);
} else {
_flag.label = kEvNoEvent;
_sceneChange.sceneID = kNoScene;
}
uint16 numHotspots = stream.readUint16LE();
_hotspots.reserve(numHotspots);
for (uint i = 0; i < numHotspots; ++i) {
_hotspots.push_back(HotspotDescription());
_hotspots.back().frameID = stream.readUint16LE();
readRect(stream, _hotspots.back().coords);
}
}
void PlaySoundMultiHS::execute() {
switch (_state) {
case kBegin:
_state = kRun;
// fall through
case kRun: {
_hasHotspot = false;
uint currentFrame = NancySceneState.getSceneInfo().frameID;
for (uint i = 0; i < _hotspots.size(); ++i) {
if (_hotspots[i].frameID == currentFrame) {
_hotspot = _hotspots[i].coords;
_hasHotspot = true;
break;
}
}
break;
}
case kActionTrigger:
g_nancy->_sound->loadSound(_sound);
g_nancy->_sound->playSound(_sound);
NancySceneState.changeScene(_sceneChange);
NancySceneState.setEventFlag(_flag);
finishExecution();
break;
}
}
void StopSound::readData(Common::SeekableReadStream &stream) {
_channelID = stream.readUint16LE();
_sceneChange.readData(stream);
}
void StopSound::execute() {
g_nancy->_sound->stopSound(_channelID);
_sceneChange.execute();
}
void PlayRandomSound::readData(Common::SeekableReadStream &stream) {
uint16 numSounds = stream.readUint16LE();
readFilenameArray(stream, _soundNames, numSounds - 1);
PlaySound::readData(stream);
_soundNames.push_back(_sound.name);
}
void PlayRandomSound::execute() {
if (_state == kBegin) {
_sound.name = _soundNames[g_nancy->_randomSource->getRandomNumber(_soundNames.size() - 1)];
}
PlaySound::execute();
}
void PlayRandomSoundTerse::readData(Common::SeekableReadStream &stream) {
uint16 numSounds = stream.readUint16LE();
readFilenameArray(stream, _soundNames, numSounds - 1);
PlaySoundTerse::readData(stream);
// The call above will have read the last sound name and the first cc text
_soundNames.push_back(_sound.name);
_ccTexts.push_back(_ccText);
for (int i = 0; i < numSounds - 1; ++i) {
_ccTexts.push_back(Common::String());
readCCText(stream, _ccTexts.back());
}
}
void PlayRandomSoundTerse::execute() {
if (_state == kBegin) {
uint16 randomID = g_nancy->_randomSource->getRandomNumber(_soundNames.size() - 1);
_sound.name = _soundNames[randomID];
_ccText = _ccTexts[randomID];
}
PlaySoundCC::execute();
}
void TableIndexPlaySound::readData(Common::SeekableReadStream &stream) {
_tableIndex = stream.readUint16LE();
PlaySound::readData(stream); // Data does NOT contain captions, so we call the PlaySound version
}
void TableIndexPlaySound::execute() {
TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
assert(playerTable);
auto *tabl = GetEngineData(TABL);
assert(tabl);
if (_lastIndexVal != playerTable->singleValues[_tableIndex - 1]) {
g_nancy->_sound->stopSound(_sound);
NancySceneState.getTextbox().clear();
_lastIndexVal = playerTable->singleValues[_tableIndex - 1];
_sound.name = Common::String::format("%s%u", tabl->soundBaseName.c_str(), playerTable->singleValues[_tableIndex - 1]);
_ccText = tabl->strings[playerTable->singleValues[_tableIndex - 1] - 1];
}
PlaySoundCC::execute();
}
} // End of namespace Action
} // End of namespace Nancy