SCUMM: COMI: Implement the original main menu

Every functionality has been implemented (audio options, text options, saving and loading).
The only thing currently missing from the menu is the thumbnail handling.
This commit is contained in:
AndywinXp 2022-06-18 20:38:48 +02:00 committed by Lothar Serra Mari
parent 89580f2f9c
commit 1e9d51c28a
9 changed files with 224 additions and 40 deletions

View file

@ -49,8 +49,7 @@ int IMuseDigital::cmdsHandleCmd(int cmd, uint8 *ptr, int a, int b, int c, int d,
case 4:
return cmdsResume();
case 7:
_groupsHandler->setGroupVol(a, b);
break;
return _groupsHandler->setGroupVol(a, b);
case 8:
cmdsStartSound(a, b);
break;

View file

@ -315,6 +315,12 @@ void IMuseDigital::saveLoadEarly(Common::Serializer &s) {
_curMusicCue = 0;
} else {
diMUSESaveLoad(s);
if (s.isLoading() && _vm->isUsingOriginalGUI()) {
diMUSESetMusicGroupVol(diMUSEGetMusicGroupVol());
diMUSESetVoiceGroupVol(diMUSEGetVoiceGroupVol());
diMUSESetSFXGroupVol(diMUSEGetSFXGroupVol());
}
}
}
@ -359,6 +365,7 @@ void IMuseDigital::diMUSEHeartbeat() {
waveOutCallback();
if (!_vm->isUsingOriginalGUI()) {
// Update volumes
if (_curMixerMusicVolume != _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)) {
@ -375,6 +382,7 @@ void IMuseDigital::diMUSEHeartbeat() {
_curMixerSFXVolume = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
diMUSESetSFXGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127));
}
}
// Handle fades and triggers
@ -659,6 +667,7 @@ void IMuseDigital::parseScriptCmds(int cmd, int soundId, int sub_cmd, int d, int
int b = soundId;
int c = sub_cmd;
int id;
int volume = b;
switch (cmd) {
case 0x1000:
// SetState
@ -678,15 +687,27 @@ void IMuseDigital::parseScriptCmds(int cmd, int soundId, int sub_cmd, int d, int
break;
case 0x2000:
// SetGroupSfxVolume
diMUSESetSFXGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127));
if (!_vm->isUsingOriginalGUI()) {
volume = CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127);
}
diMUSESetSFXGroupVol(volume);
break;
case 0x2001:
// SetGroupVoiceVolume
diMUSESetVoiceGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2, 0, 127));
if (!_vm->isUsingOriginalGUI()) {
volume = CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2, 0, 127);
}
diMUSESetVoiceGroupVol(volume);
break;
case 0x2002:
// SetGroupMusicVolume
diMUSESetMusicGroupVol(CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2, 0, 127));
if (!_vm->isUsingOriginalGUI()) {
volume = CLIP(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2, 0, 127);
}
diMUSESetMusicGroupVol(volume);
break;
case 10: // StopAllSounds
case 12: // SetParam
@ -813,6 +834,30 @@ int IMuseDigital::diMUSELipSync(int soundId, int syncId, int msPos, int32 &width
return waveLipSync(soundId, syncId, msPos, width, height);
}
int IMuseDigital::diMUSEGetMusicGroupVol() {
if (_vm->isUsingOriginalGUI()) {
return diMUSESetGroupVol(DIMUSE_GROUP_MUSIC, -1);
}
return _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2;
}
int IMuseDigital::diMUSEGetSFXGroupVol() {
if (_vm->isUsingOriginalGUI()) {
return diMUSESetGroupVol(DIMUSE_GROUP_SFX, -1);
}
return _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2;
}
int IMuseDigital::diMUSEGetVoiceGroupVol() {
if (_vm->isUsingOriginalGUI()) {
return diMUSESetGroupVol(DIMUSE_GROUP_SPEECH, -1);
}
return _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2;
}
int IMuseDigital::diMUSESetMusicGroupVol(int volume) {
debug(5, "IMuseDigital::diMUSESetMusicGroupVol(): %d", volume);
if (_isEarlyDiMUSE)

View file

@ -373,6 +373,9 @@ public:
void diMUSEQueryStream(int soundId, int32 &bufSize, int32 &criticalSize, int32 &freeSpace, int &paused);
int diMUSEFeedStream(int soundId, uint8 *srcBuf, int32 sizeToFeed, int paused);
int diMUSELipSync(int soundId, int syncId, int msPos, int32 &width, int32 &height);
int diMUSEGetMusicGroupVol();
int diMUSEGetSFXGroupVol();
int diMUSEGetVoiceGroupVol();
int diMUSESetMusicGroupVol(int volume);
int diMUSESetSFXGroupVol(int volume);
int diMUSESetVoiceGroupVol(int volume);

View file

@ -377,13 +377,25 @@ void ScummEngine::processInput() {
#ifdef ENABLE_SCUMM_7_8
void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
// F1 (the trigger for the original save/load dialog) is mapped to F5
// F1 (the trigger for the original save/load dialog) is mapped to F5,
// unless we chose to use the original GUI
if (!(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F1 && lastKeyHit.hasFlags(0)) {
if (isUsingOriginalGUI()) {
lastKeyHit = Common::KeyState(Common::KEYCODE_F1, 315);
} else {
lastKeyHit = Common::KeyState(Common::KEYCODE_F5, 319);
}
// Alt-F5 should bring up the original save/load dialog, so map it to F1.
if (!(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
}
// If we are using the original GUI, remap F5 to F1
if (isUsingOriginalGUI() && !(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(0)) {
lastKeyHit = Common::KeyState(Common::KEYCODE_F1, 315);
}
// Alt-F5 should bring up the original save/load dialog, so map it to F1,
// again, unless we chose to use the original GUI
if (!isUsingOriginalGUI() && !(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
lastKeyHit = Common::KeyState(Common::KEYCODE_F1, 315);
}
@ -668,9 +680,8 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
// Map arrow keys to number keys in the SEGA version of MI to support
// scrolling to conversation choices. See bug report #2013 for details.
_mouseAndKeyboardStat = lastKeyHit.keycode - Common::KEYCODE_UP + 54;
} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine) {
// Map arrow keys to number keys in the PCEngine version of Loom to support
// the menu screen.
} else if (isUsingOriginalGUI() || (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine)) {
// Map arrow keys to number keys in games which use the original menu screen.
switch (lastKeyHit.keycode) {
case Common::KEYCODE_UP:
_mouseAndKeyboardStat = 328;
@ -697,6 +708,10 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
}
} else {
// Map the DEL key when using the original GUI; used when writing the savegame name.
if (isUsingOriginalGUI() && lastKeyHit.keycode == Common::KEYCODE_DELETE)
_mouseAndKeyboardStat = 339;
else
_mouseAndKeyboardStat = lastKeyHit.ascii;
}
}

View file

@ -156,6 +156,54 @@ void ScummEngine::requestLoad(int slot) {
_saveLoadFlag = 2; // 2 for load
}
void ScummEngine::copyHeapSaveGameToFile(int slot, const char *saveName) {
Common::String fileName;
SaveGameHeader hdr;
bool saveFailed = false;
uint32 heapFileSize;
Common::SeekableReadStream *heapSaveFile = openSaveFileForReading(1, true, fileName);
hdr.type = heapSaveFile->readUint32BE();
hdr.size = heapSaveFile->readUint32LE();
hdr.ver = heapSaveFile->readUint32LE();
heapSaveFile->read(hdr.name, sizeof(hdr.name));
Common::strlcpy(hdr.name, saveName, sizeof(hdr.name));
heapFileSize = (uint32)heapSaveFile->size();
if (heapSaveFile->err() || hdr.type != MKTAG('S','C','V','M')) {
saveFailed = true;
} else {
Common::WriteStream *saveFile = openSaveFileForWriting(slot, false, fileName);
if (!saveFile) {
saveFailed = true;
} else {
saveFile->writeUint32BE(hdr.type);
saveFile->writeUint32LE(hdr.size);
saveFile->writeUint32LE(hdr.ver);
saveFile->write(hdr.name, sizeof(hdr.name));
heapSaveFile->seek(sizeof(hdr), SEEK_SET);
while (!heapSaveFile->eos()) {
byte b = heapSaveFile->readByte();
saveFile->writeByte(b);
}
saveFile->finalize();
if (saveFile->err())
saveFailed = true;
delete saveFile;
}
}
if (saveFailed)
debug(1, "State save as '%s' FAILED", fileName.c_str());
else
debug(1, "State saved as '%s'", fileName.c_str());
}
Common::SeekableReadStream *ScummEngine::openSaveFileForReading(int slot, bool compat, Common::String &fileName) {
fileName = makeSavegameName(slot, compat);
return _saveFileMan->openForLoading(fileName);
@ -1653,6 +1701,19 @@ void ScummEngine_v7::saveLoadWithSerializer(Common::Serializer &s) {
// WORKAROUND bug #3483: Reset the default charset color to a sane value.
_string[0]._default.charset = 1;
}
// The original Save/Load screen for COMI saves a heap savegame when it is entered
// and the same heap savegame is restored when it is exited, so let's refresh these
// variables so that they are not lost. The original doesn't do this as it appears
// to handle these temporary heap savegames a little differently, but this should
// suffice...
if (isUsingOriginalGUI() && _game.version == 8) {
if (ConfMan.hasKey("original_gui_saveload_page", _targetName))
VAR(VAR_SAVELOAD_PAGE) = ConfMan.getInt("original_gui_saveload_page");
if (ConfMan.hasKey("original_gui_object_labels", _targetName))
VAR(VAR_OBJECT_LABEL_FLAG) = ConfMan.getInt("original_gui_object_labels");
}
}
#endif

View file

@ -289,7 +289,7 @@ void ScummEngine_v8::writeVar(uint var, int value) {
if (!(var & 0xF0000000)) {
assertRange(0, var, _numVariables - 1, "variable (writing)");
if (var == VAR_CHARINC) {
if (!isUsingOriginalGUI() && var == VAR_CHARINC) {
// Did the user override the talkspeed manually? Then use that.
// Otherwise, use the value specified by the game script.
// Note: To determine whether there was a user override, we only
@ -1120,9 +1120,11 @@ void ScummEngine_v8::o8_kernelSetFunctions() {
break;
}
case 26: { // saveGameWrite
// FIXME: This doesn't work
char *address = (char *)getStringAddress(args[2]);
debug(0, "o8_kernelSetFunctions: saveGame(%d, %s)", args[1], address);
char *saveName = (char *)getStringAddress(args[2]);
debug(0, "o8_kernelSetFunctions: saveGame(%d, %s)", args[1], saveName);
if (isUsingOriginalGUI()) {
copyHeapSaveGameToFile(args[1], saveName);
}
break;
}
case 27: // saveGameRead
@ -1148,6 +1150,24 @@ void ScummEngine_v8::o8_kernelSetFunctions() {
int idx = args[1];
int value = args[2];
const char *str = (const char *)getStringAddress(idx);
if (isUsingOriginalGUI()) {
if (!strcmp(str, "SFX Volume"))
ConfMan.setInt("sfx_volume", value * 2);
else if (!strcmp(str, "Voice Volume"))
ConfMan.setInt("speech_volume", value * 2);
else if (!strcmp(str, "Music Volume"))
ConfMan.setInt("music_volume", value * 2);
else if (!strcmp(str, "Text Status"))
ConfMan.setInt("original_gui_text_status", value);
else if (!strcmp(str, "Text Speed"))
ConfMan.setInt("original_gui_text_speed", value);
else if (!strcmp(str, "Object Names"))
ConfMan.setInt("original_gui_object_labels", value);
else if (!strcmp(str, "Saveload Page"))
ConfMan.setInt("original_gui_saveload_page", value);
ConfMan.flushToDisk();
}
debugC(DEBUG_GENERAL,"o8_kernelSetFunctions: writeRegistryValue(%s, %d)", str, value);
}
@ -1156,10 +1176,14 @@ void ScummEngine_v8::o8_kernelSetFunctions() {
debug(0, "o8_kernelSetFunctions: paletteSetIntensity(%d, %d)", args[1], args[2]);
break;
case 34: // queryQuit
if (isUsingOriginalGUI()) {
confirmExitDialog();
} else {
if (ConfMan.getBool("confirm_exit"))
confirmExitDialog();
else
quitGame();
}
break;
case 108: // buildPaletteShadow
setShadowPalette(args[1], args[2], args[3], args[4], args[5], args[6]);
@ -1234,13 +1258,13 @@ void ScummEngine_v8::o8_kernelGetFunctions() {
}
break;
case 0xDD: // getGroupSfxVol
push(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2);
push(_imuseDigital->diMUSEGetSFXGroupVol());
break;
case 0xDE: // getGroupVoiceVol
push(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2);
push(_imuseDigital->diMUSEGetVoiceGroupVol());
break;
case 0xDF: // getGroupMusicVol
push(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2);
push(_imuseDigital->diMUSEGetMusicGroupVol());
break;
case 0xE0: // readRegistryValue
{
@ -1253,13 +1277,16 @@ void ScummEngine_v8::o8_kernelGetFunctions() {
else if (!strcmp(str, "Music Volume"))
push(ConfMan.getInt("music_volume") / 2);
else if (!strcmp(str, "Text Status"))
push(ConfMan.getBool("subtitles"));
push(isUsingOriginalGUI() ? ConfMan.getInt("original_gui_text_status") : ConfMan.getBool("subtitles"));
else if (!strcmp(str, "Text Speed"))
push(ConfMan.getInt("original_gui_text_speed"));
else if (!strcmp(str, "Object Names"))
push(ConfMan.getBool("object_labels"));
push(isUsingOriginalGUI() ? ConfMan.getInt("original_gui_object_labels") : ConfMan.getBool("object_labels"));
else if (!strcmp(str, "Saveload Page"))
push(14);
push(ConfMan.getInt("original_gui_saveload_page"));
else // Use defaults
push(-1);
debugC(DEBUG_GENERAL,"o8_kernelGetFunctions: readRegistryValue(%s)", str);
}
break;

View file

@ -2059,6 +2059,25 @@ void ScummEngine::setupMusic(int midi, const Common::String &macInstrumentFile)
}
void ScummEngine::syncSoundSettings() {
if (isUsingOriginalGUI() && _game.version == 8) {
_voiceMode = ConfMan.getInt("original_gui_text_status");
if (VAR_VOICE_MODE != 0xFF)
VAR(VAR_VOICE_MODE) = _voiceMode;
if (ConfMan.hasKey("original_gui_text_speed", _targetName)) {
_defaultTalkDelay = ConfMan.getInt("original_gui_text_speed");
// In the original GUI the talk delay is represented as text speed,
// so we have to invert the value:
// - 9 is the highest text speed possible;
// - 0 is the lowest text speed possible.
if (VAR_CHARINC != 0xFF)
VAR(VAR_CHARINC) = 9 - _defaultTalkDelay;
}
return;
}
Engine::syncSoundSettings();
// Sync the engine with the config manager
@ -2534,7 +2553,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
bool success;
Common::U32String errMsg;
if (_game.version == 8 && _saveTemporaryState)
if (_game.version == 8 && (_saveTemporaryState || isUsingOriginalGUI()))
VAR(VAR_GAME_LOADED) = 0;
Common::String filename;
@ -2553,7 +2572,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
if (!success)
errMsg = _("Failed to load saved game from file:\n\n%s");
if (success && _saveTemporaryState && VAR_GAME_LOADED != 0xFF)
if (success && (_saveTemporaryState || isUsingOriginalGUI()) && VAR_GAME_LOADED != 0xFF)
VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : 203;
}
@ -2945,6 +2964,13 @@ void ScummEngine::restart() {
runBootscript();
}
bool ScummEngine::isUsingOriginalGUI() {
if (_game.version == 8)
return _useOriginalGUI;
return false;
}
void ScummEngine::runBootscript() {
int args[NUM_SCRIPT_LOCAL];
memset(args, 0, sizeof(args));

View file

@ -386,6 +386,7 @@ public:
ResourceManager *_res = nullptr;
bool _enableEnhancements = false;
bool _useOriginalGUI = true;
bool _enableAudioOverride = false;
protected:
@ -482,6 +483,7 @@ protected:
public:
void pauseGame();
void restart();
bool isUsingOriginalGUI();
protected:
Dialog *_pauseDialog = nullptr;
@ -619,6 +621,7 @@ protected:
void loadResource(Common::Serializer &ser, ResType type, ResId idx);
void loadResourceOLD(Common::Serializer &ser, ResType type, ResId idx); // "Obsolete"
void copyHeapSaveGameToFile(int slot, const char *saveName);
virtual Common::SeekableReadStream *openSaveFileForReading(int slot, bool compat, Common::String &fileName);
virtual Common::WriteStream *openSaveFileForWriting(int slot, bool compat, Common::String &fileName);
@ -1443,6 +1446,8 @@ public:
byte VAR_RIGHTBTN_HOLD = 0xFF; // V6/V72HE/V7/V8
byte VAR_SAVELOAD_SCRIPT = 0xFF; // V6/V7 (not HE)
byte VAR_SAVELOAD_SCRIPT2 = 0xFF; // V6/V7 (not HE)
byte VAR_SAVELOAD_PAGE = 0xFF; // V8
byte VAR_OBJECT_LABEL_FLAG = 0xFF; // V8
// V6/V7 specific variables (FT & Sam & Max specific)
byte VAR_CHARSET_MASK = 0xFF;

View file

@ -558,6 +558,9 @@ void ScummEngine_v8::setupScummVars() {
VAR_KEYPRESS = 132;
VAR_BLAST_ABOVE_TEXT = 133;
VAR_SYNC = 134;
VAR_SAVELOAD_PAGE = 175;
VAR_OBJECT_LABEL_FLAG = 176;
}
#endif