scummvm/engines/scumm/imuse_digi/dimuse_scripts.cpp

925 lines
27 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 "scumm/imuse_digi/dimuse_engine.h"
namespace Scumm {
#define DIG_STATE_OFFSET 11
#define DIG_SEQ_OFFSET (DIG_STATE_OFFSET + 65)
#define COMI_STATE_OFFSET 3
int IMuseDigital::scriptParse(int cmd, int a, int b) {
if (_scriptInitializedFlag || !cmd) {
switch (cmd) {
case DIMUSE_C_SCRIPT_INIT:
if (_scriptInitializedFlag) {
debug(5, "IMuseDigital::scriptParse(): script module already initialized");
return -1;
} else {
_scriptInitializedFlag = 1;
return scriptInit();
}
case DIMUSE_C_SCRIPT_TERMINATE:
_scriptInitializedFlag = 0;
return scriptTerminate();
case DIMUSE_C_SCRIPT_SAVE:
case DIMUSE_C_SCRIPT_RESTORE:
break;
case DIMUSE_C_SCRIPT_REFRESH:
scriptRefresh();
return 0;
case DIMUSE_C_SCRIPT_SET_STATE:
scriptSetState(a);
return 0;
case DIMUSE_C_SCRIPT_SET_SEQUENCE:
scriptSetSequence(a);
return 0;
case DIMUSE_C_SCRIPT_CUE_POINT:
scriptSetCuePoint(a);
return 0;
case DIMUSE_C_SCRIPT_SET_ATTRIBUTE:
return scriptSetAttribute(a, b);
default:
debug(5, "IMuseDigital::scriptParse(): unrecognized opcode (%d)", cmd);
return -1;
}
} else {
debug(5, "IMuseDigital::scriptParse(): script module not initialized");
return -1;
}
return -1;
}
int IMuseDigital::scriptInit() {
_curMusicState = 0;
_curMusicSeq = 0;
_nextSeqToPlay = 0;
_curMusicCue = 0;
memset(_attributes, 0, sizeof(_attributes));
return 0;
}
int IMuseDigital::scriptTerminate() {
diMUSETerminate();
_curMusicState = 0;
_curMusicSeq = 0;
_nextSeqToPlay = 0;
_curMusicCue = 0;
memset(_attributes, 0, sizeof(_attributes));
return 0;
}
void IMuseDigital::scriptRefresh() {
int soundId;
int nextSound;
if (_stopSequenceFlag) {
scriptSetSequence(0);
_stopSequenceFlag = 0;
}
soundId = 0;
while (1) {
nextSound = diMUSEGetNextSound(soundId);
soundId = nextSound;
if (!nextSound)
break;
if (diMUSEGetParam(nextSound, DIMUSE_P_SND_HAS_STREAM) && diMUSEGetParam(soundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC) {
if (soundId)
return;
break;
}
}
if (_curMusicSeq)
scriptSetSequence(0);
flushTracks();
}
void IMuseDigital::scriptSetState(int soundId) {
if (_vm->_game.id == GID_DIG && !_isEarlyDiMUSE) {
setDigMusicState(soundId);
} else if (_vm->_game.id == GID_CMI) {
setComiMusicState(soundId);
} else {
setFtMusicState(soundId);
}
}
void IMuseDigital::scriptSetSequence(int soundId) {
if (_vm->_game.id == GID_DIG && !_isEarlyDiMUSE) {
setDigMusicSequence(soundId);
} else if (_vm->_game.id == GID_CMI) {
setComiMusicSequence(soundId);
} else {
setFtMusicSequence(soundId);
}
}
void IMuseDigital::scriptSetCuePoint(int cueId) {
if (!_isEarlyDiMUSE)
return;
if (cueId > 3)
return;
debug(5, "IMuseDigital::scriptSetCuePoint(): Cue point sequence: %d", cueId);
if (_curMusicSeq && _curMusicCue != cueId) {
if (cueId == 0)
playFtMusic(nullptr, 0, 0);
else {
int seq = ((_curMusicSeq - 1) * 4) + cueId;
playFtMusic(_ftSeqMusicTable[seq].audioName, _ftSeqMusicTable[seq].transitionType, _ftSeqMusicTable[seq].volume);
}
}
_curMusicCue = cueId;
}
int IMuseDigital::scriptSetAttribute(int attrIndex, int attrVal) {
// FT appears to set a single attribute to 1 at start-up and
// never use it again, so we currently ignore that behavior
if (_vm->_game.id == GID_DIG) {
_attributes[attrIndex] = attrVal;
}
return 0;
}
int IMuseDigital::scriptTriggerCallback(char *marker) {
if (marker[0] != '_') {
debug(5, "IMuseDigital::scriptTriggerCallback(): got marker != '_end', callback ignored");
return -1;
}
_stopSequenceFlag = 1;
return 0;
}
void Scumm::IMuseDigital::setFtMusicState(int stateId) {
if (stateId > 48)
return;
debug(5, "IMuseDigital::setFtMusicState(): State music: %s, %s", _ftStateMusicTable[stateId].name, _ftStateMusicTable[stateId].audioName);
if (_curMusicState == stateId)
return;
if (_curMusicSeq == 0) {
if (stateId == 0) {
playFtMusic(nullptr, 0, 0);
} else {
playFtMusic(_ftStateMusicTable[stateId].audioName, _ftStateMusicTable[stateId].transitionType, _ftStateMusicTable[stateId].volume);
}
}
_curMusicState = stateId;
}
void IMuseDigital::setFtMusicSequence(int seqId) {
if (seqId > 52)
return;
debug(5, "IMuseDigital::setFtMusicSequence(): Sequence music: %s", _ftSeqNames[seqId].name);
if (_curMusicSeq != seqId) {
if (seqId == 0) {
if (_curMusicState == 0) {
playFtMusic(nullptr, 0, 0);
} else {
playFtMusic(_ftStateMusicTable[_curMusicState].audioName, _ftStateMusicTable[_curMusicState].transitionType, _ftStateMusicTable[_curMusicState].volume);
}
} else {
int seq = (seqId - 1) * 4;
playFtMusic(_ftSeqMusicTable[seq].audioName, _ftSeqMusicTable[seq].transitionType, _ftSeqMusicTable[seq].volume);
}
}
_curMusicSeq = seqId;
_curMusicCue = 0;
}
void IMuseDigital::setDigMusicState(int stateId) {
int l, num = -1;
for (l = 0; _digStateMusicTable[l].soundId != -1; l++) {
if ((_digStateMusicTable[l].soundId == stateId)) {
debug(5, "IMuseDigital::setDigMusicState(): Set music state: %s, %s", _digStateMusicTable[l].name, _digStateMusicTable[l].filename);
num = l;
break;
}
}
if (num == -1) {
for (l = 0; _digStateMusicMap[l].roomId != -1; l++) {
if ((_digStateMusicMap[l].roomId == stateId)) {
break;
}
}
num = l;
int offset = _attributes[_digStateMusicMap[num].offset];
if (offset == 0) {
if (_attributes[_digStateMusicMap[num].attribPos] != 0) {
num = _digStateMusicMap[num].stateIndex3;
} else {
num = _digStateMusicMap[num].stateIndex1;
}
} else {
int stateIndex2 = _digStateMusicMap[num].stateIndex2;
if (stateIndex2 == 0) {
num = _digStateMusicMap[num].stateIndex1 + offset;
} else {
num = stateIndex2;
}
}
}
debug(5, "IMuseDigital::setDigMusicState(): Set music state: %s, %s", _digStateMusicTable[num].name, _digStateMusicTable[num].filename);
if (_curMusicState == num)
return;
if (_curMusicSeq == 0) {
if (num == 0)
playDigMusic(nullptr, &_digStateMusicTable[0], num, false);
else
playDigMusic(_digStateMusicTable[num].name, &_digStateMusicTable[num], num, false);
}
_curMusicState = num;
}
void IMuseDigital::setDigMusicSequence(int seqId) {
int l, num = -1;
if (seqId == 0)
seqId = 2000;
for (l = 0; _digSeqMusicTable[l].soundId != -1; l++) {
if ((_digSeqMusicTable[l].soundId == seqId)) {
debug(5, "IMuseDigital::setDigMusicSequence(): Set music sequence: %s, %s", _digSeqMusicTable[l].name, _digSeqMusicTable[l].filename);
num = l;
break;
}
}
if (num == -1)
return;
if (_curMusicSeq == num)
return;
if (num != 0) {
if (_curMusicSeq && ((_digSeqMusicTable[_curMusicSeq].transitionType == 4)
|| (_digSeqMusicTable[_curMusicSeq].transitionType == 6))) {
_nextSeqToPlay = num;
return;
} else {
playDigMusic(_digSeqMusicTable[num].name, &_digSeqMusicTable[num], 0, true);
_nextSeqToPlay = 0;
_attributes[DIG_SEQ_OFFSET + num] = 1;
}
} else {
if (_nextSeqToPlay != 0) {
playDigMusic(_digSeqMusicTable[_nextSeqToPlay].name, &_digSeqMusicTable[_nextSeqToPlay], 0, true);
_attributes[DIG_SEQ_OFFSET + _nextSeqToPlay] = 1;
num = _nextSeqToPlay;
_nextSeqToPlay = 0;
} else {
if (_curMusicState != 0) {
playDigMusic(_digStateMusicTable[_curMusicState].name, &_digStateMusicTable[_curMusicState], _curMusicState, true);
} else {
playDigMusic(nullptr, &_digStateMusicTable[0], _curMusicState, true);
}
num = 0;
}
}
_curMusicSeq = num;
}
void IMuseDigital::setComiMusicState(int stateId) {
int l, num = -1;
if (stateId == 0)
stateId = 1000;
if ((_vm->_game.features & GF_DEMO) && stateId == 1000)
stateId = 0;
if (!(_vm->_game.features & GF_DEMO)) {
for (l = 0; _comiStateMusicTable[l].soundId != -1; l++) {
if ((_comiStateMusicTable[l].soundId == stateId)) {
debug(5, "IMuseDigital::setComiMusicState(): Set music state: %s, %s", _comiStateMusicTable[l].name, _comiStateMusicTable[l].filename);
num = l;
break;
}
}
}
if (num == -1 && !(_vm->_game.features & GF_DEMO))
return;
if (!(_vm->_game.features & GF_DEMO) && _curMusicState == num) {
return;
} else if ((_vm->_game.features & GF_DEMO) && _curMusicState == stateId) {
return;
}
if (_curMusicSeq == 0) {
if (_vm->_game.features & GF_DEMO) {
if (_curMusicSeq == 0) {
if (stateId == 0)
playComiDemoMusic(nullptr, &_comiDemoStateMusicTable[0], stateId, false);
else
playComiDemoMusic(_comiDemoStateMusicTable[stateId].name, &_comiDemoStateMusicTable[stateId], stateId, false);
}
} else {
if (num == 0)
playComiMusic(nullptr, &_comiStateMusicTable[0], num, false);
else
playComiMusic(_comiStateMusicTable[num].name, &_comiStateMusicTable[num], num, false);
}
}
if (!(_vm->_game.features & GF_DEMO)) {
_curMusicState = num;
} else {
_curMusicState = stateId;
}
}
void IMuseDigital::setComiMusicSequence(int seqId) {
int l, num = -1;
if (seqId == 0)
seqId = 2000;
for (l = 0; _comiSeqMusicTable[l].soundId != -1; l++) {
if ((_comiSeqMusicTable[l].soundId == seqId)) {
debug(5, "IMuseDigital::setComiMusicSequence(): Set music sequence: %s, %s", _comiSeqMusicTable[l].name, _comiSeqMusicTable[l].filename);
num = l;
break;
}
}
if (num == -1)
return;
if (_curMusicSeq == num)
return;
if (num != 0) {
if (_curMusicSeq && ((_comiSeqMusicTable[_curMusicSeq].transitionType == 4)
|| (_comiSeqMusicTable[_curMusicSeq].transitionType == 6))) {
_nextSeqToPlay = num;
return;
} else {
playComiMusic(_comiSeqMusicTable[num].name, &_comiSeqMusicTable[num], 0, true);
_nextSeqToPlay = 0;
}
} else {
if (_nextSeqToPlay != 0) {
playComiMusic(_comiSeqMusicTable[_nextSeqToPlay].name, &_comiSeqMusicTable[_nextSeqToPlay], 0, true);
num = _nextSeqToPlay;
_nextSeqToPlay = 0;
} else {
if (_curMusicState != 0) {
playComiMusic(_comiStateMusicTable[_curMusicState].name, &_comiStateMusicTable[_curMusicState], _curMusicState, true);
} else {
playComiMusic(nullptr, &_comiStateMusicTable[0], _curMusicState, true);
}
num = 0;
}
}
_curMusicSeq = num;
}
void IMuseDigital::playFtMusic(const char *songName, int transitionType, int volume) {
int oldSoundId = 0;
int soundId;
if (!_spooledMusicEnabled)
return;
// Check for any music piece which is played as a SFX (without an associated stream)
// and fade it out
for (int i = diMUSEGetNextSound(0); i; i = diMUSEGetNextSound(i)) {
if (diMUSEGetParam(i, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(i, DIMUSE_P_SND_HAS_STREAM))
diMUSEFadeParam(i, DIMUSE_P_VOLUME, 0, 200);
}
// Now grab the current standard music soundId: it will either be crossfaded by SwitchStream,
// or faded out
for (int j = diMUSEGetNextSound(0); j; j = diMUSEGetNextSound(j)) {
if (diMUSEGetParam(j, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && diMUSEGetParam(j, DIMUSE_P_SND_HAS_STREAM))
oldSoundId = j;
}
if (songName) {
switch (transitionType) {
case 0:
debug(5, "IMuseDigital::playFtMusic(): NULL transition, ignored");
return;
case 1:
soundId = getSoundIdByName(songName);
if (_filesHandler->openSound(soundId))
return;
if (!soundId) {
debug(5, "IMuseDigital::playFtMusic(): failed to retrieve soundId for sound \"%s\"", songName);
break;
}
if (diMUSEStartSound(soundId, 126))
debug(5, "IMuseDigital::playFtMusic(): transition 1, failed to start sound \"%s\"(%d)", songName, soundId);
_filesHandler->closeSound(soundId);
diMUSESetParam(soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetParam(soundId, DIMUSE_P_VOLUME, volume);
break;
case 2:
case 3:
soundId = getSoundIdByName(songName);
if (soundId)
if (_filesHandler->openSound(soundId))
return;
if (soundId) {
if (oldSoundId) {
if (oldSoundId != soundId || transitionType == 2) {
diMUSESwitchStream(oldSoundId, soundId, _ftCrossfadeBuffer, sizeof(_ftCrossfadeBuffer), 0);
}
// WORKAROUND for bug in the original: at the beginning of the game, going in
// and out of the bar a couple of times breaks and temporarily stops the music
// Here, we override the fade out, just like the remastered does
if (oldSoundId == soundId && soundId == 622 && _vm->enhancementEnabled(kEnhAudioChanges)) {
diMUSEFadeParam(soundId, DIMUSE_P_VOLUME, volume, 200);
}
} else if (diMUSEStartStream(soundId, 126, DIMUSE_BUFFER_MUSIC)) {
debug(5, "IMuseDigital::playFtMusic(): failed to start the stream for \"%s\" (%d)", songName, soundId);
}
_filesHandler->closeSound(soundId);
diMUSESetParam(soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetParam(soundId, DIMUSE_P_VOLUME, volume);
} else {
debug(5, "IMuseDigital::playFtMusic(): failed to retrieve soundId for sound \"%s\" (%d)", songName, soundId);
}
break;
case 4:
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 200);
return;
default:
debug(5, "IMuseDigital::playFtMusic(): bogus transition type, ignored");
return;
}
} else {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 200);
}
}
void IMuseDigital::playDigMusic(const char *songName, const imuseDigTable *table, int attribPos, bool sequence) {
int hookId = 0;
if (songName != nullptr) {
if ((_attributes[DIG_SEQ_OFFSET + 38]) && (!_attributes[DIG_SEQ_OFFSET + 41])) {
if ((attribPos == 43) || (attribPos == 44))
hookId = 3;
}
if ((_attributes[DIG_SEQ_OFFSET + 46] != 0) && (_attributes[DIG_SEQ_OFFSET + 48] == 0)) {
if ((attribPos == 38) || (attribPos == 39))
hookId = 3;
}
if ((_attributes[DIG_SEQ_OFFSET + 53] != 0)) {
if ((attribPos == 50) || (attribPos == 51))
hookId = 3;
}
if ((attribPos != 0) && (hookId == 0)) {
if (table->attribPos != 0)
attribPos = table->attribPos;
hookId = _attributes[DIG_STATE_OFFSET + attribPos];
if (table->hookId != 0) {
if ((hookId != 0) && (table->hookId > 1)) {
_attributes[DIG_STATE_OFFSET + attribPos] = 2;
} else {
_attributes[DIG_STATE_OFFSET + attribPos] = hookId + 1;
if (table->hookId < hookId + 1)
_attributes[DIG_STATE_OFFSET + attribPos] = 1;
}
}
}
}
int nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
// If a sound is found (and its stream is active), fade it out if it's a music track
if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM))
diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120);
}
int oldSoundId = 0;
nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) {
oldSoundId = nextSoundId;
break;
}
}
if (!songName) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120);
return;
}
switch (table->transitionType) {
case 0:
debug(5, "IMuseDigital::playDigMusic(): NULL transition, ignored");
break;
case 1:
if (_filesHandler->openSound(table->soundId))
return;
if (table->soundId) {
if (diMUSEStartSound(table->soundId, 126))
debug(5, "IMuseDigital::playDigMusic(): transition 1, failed to start the sound (%d)", table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 1);
diMUSEFadeParam(table->soundId, DIMUSE_P_VOLUME, 127, 120);
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
} else {
debug(5, "IMuseDigital::playDigMusic(): transition 1, empty soundId, ignored");
}
break;
case 2:
case 3:
case 4:
if (_filesHandler->openSound(table->soundId))
return;
if (table->filename[0] == 0 || table->soundId == 0) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60);
return;
}
if (table->transitionType == 4) {
_stopSequenceFlag = 0;
diMUSESetTrigger(table->soundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK);
}
if (oldSoundId) {
if (table->transitionType == 2) {
diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
diMUSEProcessStreams();
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally
return;
}
if (oldSoundId != table->soundId) {
if ((!sequence) && (table->attribPos != 0) &&
(table->attribPos == _digStateMusicTable[_curMusicState].attribPos)) {
diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 1);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSEProcessStreams();
} else {
diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
diMUSEProcessStreams();
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally
}
}
} else {
if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC))
debug(5, "IMuseDigital::playDigMusic(): failed to start the stream for sound %d", table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
}
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally
break;
case 5:
debug(5, "IMuseDigital::playDigMusic(): no-op transition type (5), ignored");
break;
case 6:
_stopSequenceFlag = 0;
diMUSESetTrigger(DIMUSE_SMUSH_SOUNDID + DIMUSE_BUFFER_MUSIC, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK);
break;
case 7:
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60);
break;
default:
debug(5, "IMuseDigital::playDigMusic(): bogus transition type, ignored");
break;
}
}
void IMuseDigital::playComiDemoMusic(const char *songName, const imuseComiTable *table, int attribPos, bool sequence) {
// This is a stripped down version of playDigMusic
int hookId = 0;
if (songName != nullptr) {
if (attribPos != 0) {
if (table->attribPos != 0)
attribPos = table->attribPos;
}
}
int nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
// If a sound is found (and its stream is active), fade it out if it's a music track
if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM))
diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120);
}
int oldSoundId = 0;
nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) {
oldSoundId = nextSoundId;
break;
}
}
if (!songName) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120);
return;
}
switch (table->transitionType) {
case 3:
if (_filesHandler->openSound(table->soundId))
return;
if (table->filename[0] == 0 || table->soundId == 0) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60);
return;
}
if (oldSoundId) {
if (oldSoundId != table->soundId) {
if ((!sequence) && (table->attribPos != 0) &&
(table->attribPos == _comiDemoStateMusicTable[_curMusicState].attribPos)) {
diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 1);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSEProcessStreams();
} else {
diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
diMUSEProcessStreams();
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally
}
}
} else {
if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC))
debug(5, "IMuseDigital::playComiDemoMusic(): failed to start the stream for sound %d", table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
}
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally
break;
default:
debug(5, "IMuseDigital::playComiDemoMusic(): bogus or unused transition type, ignored");
break;
}
}
void IMuseDigital::playComiMusic(const char *songName, const imuseComiTable *table, int attribPos, bool sequence) {
int hookId = 0;
int fadeDelay = 0;
if ((songName != nullptr) && (attribPos != 0)) {
if (table->attribPos != 0)
attribPos = table->attribPos;
hookId = _attributes[COMI_STATE_OFFSET + attribPos];
if (table->hookId != 0) {
if ((hookId != 0) && (table->hookId > 1)) {
_attributes[COMI_STATE_OFFSET + attribPos] = 2;
} else {
_attributes[COMI_STATE_OFFSET + attribPos] = hookId + 1;
if (table->hookId < hookId + 1)
_attributes[COMI_STATE_OFFSET + attribPos] = 1;
}
}
}
int nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
// If a sound is found (and its stream is active), fade it out if it's a music track
if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM))
diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120);
}
int oldSoundId = 0;
nextSoundId = 0;
while (1) {
nextSoundId = diMUSEGetNextSound(nextSoundId);
if (!nextSoundId)
break;
if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) {
oldSoundId = nextSoundId;
break;
}
}
if (!songName) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120);
return;
}
switch (table->transitionType) {
case 0:
debug(5, "IMuseDigital::playComiMusic(): NULL transition, ignored");
break;
case 1:
if (_filesHandler->openSound(table->soundId))
return;
if (table->soundId) {
if (diMUSEStartSound(table->soundId, 126))
debug(5, "IMuseDigital::playComiMusic(): transition 1, failed to start the sound (%d)", table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 1);
diMUSEFadeParam(table->soundId, DIMUSE_P_VOLUME, 127, 120);
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
} else {
debug(5, "IMuseDigital::playComiMusic(): transition 1, empty soundId, ignored");
}
break;
case 2:
case 3:
case 4:
case 12:
if (_filesHandler->openSound(table->soundId))
return;
if (table->filename[0] == 0 || table->soundId == 0) {
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60);
break;
}
if (table->transitionType == 4) {
_stopSequenceFlag = 0;
diMUSESetTrigger(table->soundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK);
}
if (oldSoundId) {
fadeDelay = table->fadeOutDelay;
if (!fadeDelay)
fadeDelay = 1000;
else
fadeDelay = (fadeDelay * 100) / 6; // Set dimuse_table fade out time to millisecond scale
if (table->transitionType == 2) {
diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 0);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, table->hookId);
diMUSEProcessStreams();
} else if (oldSoundId != table->soundId) {
if ((!sequence) && (table->attribPos != 0) &&
(table->attribPos == _comiStateMusicTable[_curMusicState].attribPos)) {
debug(5, "IMuseDigital::playComiMusic(): Starting new sound (%s) with same attribute as old sound (%s)",
table->name, _comiStateMusicTable[_curMusicState].name);
diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 1);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSEProcessStreams();
} else {
switch (table->transitionType) {
case 12:
diMUSESetHook(oldSoundId, table->hookId);
diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SWITCH_STREAM, oldSoundId, table->soundId, fadeDelay, 1, 0);
diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_PARAM, table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_PARAM, table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_HOOK, table->soundId, hookId);
diMUSEProcessStreams();
break;
default:
diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 0);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
diMUSEProcessStreams();
break;
}
}
}
} else {
if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC))
debug(5, "IMuseDigital::playComiMusic(): failed to start the stream for sound %d", table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
diMUSESetHook(table->soundId, hookId);
}
_filesHandler->closeSound(table->soundId);
diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF);
break;
case 5:
debug(5, "IMuseDigital::playComiMusic(): no-op transition type (5), ignored");
break;
case 6:
_stopSequenceFlag = 0;
diMUSESetTrigger(DIMUSE_SMUSH_SOUNDID + DIMUSE_BUFFER_MUSIC, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK);
break;
case 7:
if (oldSoundId)
diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60);
break;
case 8:
if (oldSoundId)
diMUSESetHook(oldSoundId, table->hookId);
break;
case 9:
if (oldSoundId)
diMUSESetHook(oldSoundId, table->hookId);
_stopSequenceFlag = 0;
diMUSESetTrigger(oldSoundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK);
break;
default:
debug(5, "IMuseDigital::playComiMusic(): bogus transition type, ignored");
break;
}
}
} // End of namespace Scumm