aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/engine/kyra_v1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/engine/kyra_v1.cpp')
-rw-r--r--engines/kyra/engine/kyra_v1.cpp698
1 files changed, 698 insertions, 0 deletions
diff --git a/engines/kyra/engine/kyra_v1.cpp b/engines/kyra/engine/kyra_v1.cpp
new file mode 100644
index 0000000000..e2896eb1a5
--- /dev/null
+++ b/engines/kyra/engine/kyra_v1.cpp
@@ -0,0 +1,698 @@
+/* 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 "kyra/kyra_v1.h"
+#include "kyra/sound/sound_intern.h"
+#include "kyra/resource/resource.h"
+#include "kyra/engine/timer.h"
+#include "kyra/gui/debugger.h"
+
+#include "common/error.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+
+namespace Kyra {
+
+KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags)
+ : Engine(system), _flags(flags), _rnd("kyra") {
+ _res = 0;
+ _sound = 0;
+ _text = 0;
+ _staticres = 0;
+ _timer = 0;
+ _emc = 0;
+ _debugger = 0;
+
+ _configRenderMode = Common::kRenderDefault;
+
+ if (_flags.platform == Common::kPlatformAmiga)
+ _gameSpeed = 50;
+ else
+ _gameSpeed = 60;
+ _tickLength = (uint8)(1000.0 / _gameSpeed);
+
+ _trackMap = 0;
+ _trackMapSize = 0;
+ _lastMusicCommand = -1;
+ _curSfxFile = _curMusicTheme = -1;
+
+ _gameToLoad = -1;
+
+ _mouseState = -1;
+ _deathHandler = -1;
+
+ memset(_flagsTable, 0, sizeof(_flagsTable));
+
+ _isSaveAllowed = false;
+
+ _mouseX = _mouseY = 0;
+
+ // sets up all engine specific debug levels
+ DebugMan.addDebugChannel(kDebugLevelScriptFuncs, "ScriptFuncs", "Script function debug level");
+ DebugMan.addDebugChannel(kDebugLevelScript, "Script", "Script interpreter debug level");
+ DebugMan.addDebugChannel(kDebugLevelSprites, "Sprites", "Sprite debug level");
+ DebugMan.addDebugChannel(kDebugLevelScreen, "Screen", "Screen debug level");
+ DebugMan.addDebugChannel(kDebugLevelSound, "Sound", "Sound debug level");
+ DebugMan.addDebugChannel(kDebugLevelAnimator, "Animator", "Animator debug level");
+ DebugMan.addDebugChannel(kDebugLevelMain, "Main", "Generic debug level");
+ DebugMan.addDebugChannel(kDebugLevelGUI, "GUI", "GUI debug level");
+ DebugMan.addDebugChannel(kDebugLevelSequence, "Sequence", "Sequence debug level");
+ DebugMan.addDebugChannel(kDebugLevelMovie, "Movie", "Movie debug level");
+ DebugMan.addDebugChannel(kDebugLevelTimer, "Timer", "Timer debug level");
+}
+
+::GUI::Debugger *KyraEngine_v1::getDebugger() {
+ return _debugger;
+}
+
+void KyraEngine_v1::pauseEngineIntern(bool pause) {
+ Engine::pauseEngineIntern(pause);
+ if (_sound)
+ _sound->pause(pause);
+ if (_timer)
+ _timer->pause(pause);
+}
+
+Common::Error KyraEngine_v1::init() {
+ // Setup mixer
+ syncSoundSettings();
+
+ if (!_flags.useDigSound) {
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ if (_flags.gameID == GI_KYRA1)
+ _sound = new SoundTowns(this, _mixer);
+ else
+ _sound = new SoundTownsPC98_v2(this, _mixer);
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ if (_flags.gameID == GI_KYRA1)
+ _sound = new SoundPC98(this, _mixer);
+ else
+ _sound = new SoundTownsPC98_v2(this, _mixer);
+ } else if (_flags.platform == Common::kPlatformAmiga) {
+ _sound = new SoundAmiga(this, _mixer);
+ } else {
+ // In Kyra 1 users who have specified a default MT-32 device in the launcher settings
+ // will get MT-32 music, otherwise AdLib. In Kyra 2 and LoL users who have specified a
+ // default GM device in the launcher will get GM music, otherwise AdLib. Users who want
+ // MT-32 music in Kyra2 or LoL have to select this individually (since we assume that
+ // most users rather have a GM device than a MT-32 device).
+ // Users who want PC speaker sound always have to select this individually for all
+ // Kyra games.
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_PCSPK | MDT_MIDI | MDT_ADLIB | ((_flags.gameID == GI_KYRA2 || _flags.gameID == GI_LOL) ? MDT_PREFER_GM : MDT_PREFER_MT32));
+ if (MidiDriver::getMusicType(dev) == MT_ADLIB) {
+ _sound = new SoundAdLibPC(this, _mixer);
+ } else {
+ Sound::kType type;
+ const MusicType midiType = MidiDriver::getMusicType(dev);
+
+ if (midiType == MT_PCSPK || midiType == MT_NULL)
+ type = Sound::kPCSpkr;
+ else if (midiType == MT_MT32 || ConfMan.getBool("native_mt32"))
+ type = Sound::kMidiMT32;
+ else
+ type = Sound::kMidiGM;
+
+ MidiDriver *driver = 0;
+
+ if (MidiDriver::getMusicType(dev) == MT_PCSPK) {
+ driver = new MidiDriver_PCSpeaker(_mixer);
+ } else {
+ driver = MidiDriver::createMidi(dev);
+ if (type == Sound::kMidiMT32)
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ }
+
+ assert(driver);
+
+ SoundMidiPC *soundMidiPc = new SoundMidiPC(this, _mixer, driver, type);
+ _sound = soundMidiPc;
+ assert(_sound);
+
+ // Unlike some SCUMM games, it's not that the MIDI sounds are
+ // missing. It's just that at least at the time of writing they
+ // are decidedly inferior to the AdLib ones.
+ if (ConfMan.getBool("multi_midi")) {
+ SoundAdLibPC *adlib = new SoundAdLibPC(this, _mixer);
+ assert(adlib);
+
+ _sound = new MixedSoundDriver(this, _mixer, soundMidiPc, adlib);
+ }
+ }
+ }
+
+ assert(_sound);
+ }
+
+ if (_sound)
+ _sound->updateVolumeSettings();
+
+ if (ConfMan.hasKey("render_mode"))
+ _configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+
+ _res = new Resource(this);
+ assert(_res);
+ _res->reset();
+
+ _staticres = new StaticResource(this);
+ assert(_staticres);
+ if (!_staticres->init())
+ error("_staticres->init() failed");
+ assert(screen());
+ if (!screen()->init())
+ error("screen()->init() failed");
+ _timer = new TimerManager(this, _system);
+ assert(_timer);
+ setupTimers();
+ _emc = new EMCInterpreter(this);
+ assert(_emc);
+
+ setupOpcodeTable();
+ readSettings();
+
+ if (ConfMan.hasKey("save_slot")) {
+ _gameToLoad = ConfMan.getInt("save_slot");
+ if (!saveFileLoadable(_gameToLoad))
+ _gameToLoad = -1;
+ }
+
+ setupKeyMap();
+
+ // Prevent autosave on game startup
+ _lastAutosave = _system->getMillis();
+
+ return Common::kNoError;
+}
+
+KyraEngine_v1::~KyraEngine_v1() {
+ for (Common::Array<const Opcode *>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ delete *i;
+ _opcodes.clear();
+ _keyMap.clear();
+
+ delete _res;
+ delete _staticres;
+ delete _sound;
+ delete _text;
+ delete _timer;
+ delete _emc;
+ delete _debugger;
+}
+
+Common::Point KyraEngine_v1::getMousePos() {
+ Common::Point mouse = _eventMan->getMousePos();
+
+ if (_flags.useHiRes) {
+ mouse.x >>= 1;
+ mouse.y >>= 1;
+ }
+
+ return mouse;
+}
+
+void KyraEngine_v1::setMousePos(int x, int y) {
+ if (_flags.useHiRes) {
+ x <<= 1;
+ y <<= 1;
+ }
+ _system->warpMouse(x, y);
+}
+
+int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag) {
+ _isSaveAllowed = mainLoop;
+ updateInput();
+ _isSaveAllowed = false;
+
+ if (mainLoop)
+ checkAutosave();
+
+ int keys = 0;
+ int8 mouseWheel = 0;
+
+ while (!_eventList.empty()) {
+ Common::Event event = *_eventList.begin();
+ bool breakLoop = false;
+
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode >= Common::KEYCODE_1 && event.kbd.keycode <= Common::KEYCODE_9 &&
+ (event.kbd.hasFlags(Common::KBD_CTRL) || event.kbd.hasFlags(Common::KBD_ALT)) && mainLoop) {
+ int saveLoadSlot = 9 - (event.kbd.keycode - Common::KEYCODE_0) + 990;
+
+ if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ if (saveFileLoadable(saveLoadSlot))
+ loadGameStateCheck(saveLoadSlot);
+ _eventList.clear();
+ breakLoop = true;
+ } else {
+ char savegameName[14];
+ sprintf(savegameName, "Quicksave %d", event.kbd.keycode - Common::KEYCODE_0);
+ saveGameStateIntern(saveLoadSlot, savegameName, 0);
+ }
+ } else if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ if (event.kbd.keycode == Common::KEYCODE_d) {
+ if (_debugger)
+ _debugger->attach();
+ breakLoop = true;
+ } else if (event.kbd.keycode == Common::KEYCODE_q) {
+ quitGame();
+ }
+ } else {
+ KeyMap::const_iterator keycode = _keyMap.find(event.kbd.keycode);
+ if (keycode != _keyMap.end()) {
+ keys = keycode->_value;
+ if (event.kbd.flags & Common::KBD_SHIFT)
+ keys |= 0x100;
+ } else {
+ keys = 0;
+ }
+
+ // When we got an keypress, which we might need to handle,
+ // break the event loop and pass it to GUI code.
+ if (keys)
+ breakLoop = true;
+ }
+ break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP: {
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ if (_flags.useHiRes) {
+ _mouseX >>= 1;
+ _mouseY >>= 1;
+ }
+ keys = (event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800));
+ breakLoop = true;
+ } break;
+
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP: {
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ if (_flags.useHiRes) {
+ _mouseX >>= 1;
+ _mouseY >>= 1;
+ }
+ keys = (event.type == Common::EVENT_RBUTTONDOWN ? 201 : (202 | 0x800));
+ breakLoop = true;
+ } break;
+
+ case Common::EVENT_WHEELUP:
+ mouseWheel = -1;
+ break;
+
+ case Common::EVENT_WHEELDOWN:
+ mouseWheel = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_debugger)
+ _debugger->onFrame();
+
+ if (breakLoop)
+ break;
+
+ _eventList.erase(_eventList.begin());
+ }
+
+ GUI *guiInstance = gui();
+ if (guiInstance) {
+ if (keys)
+ return guiInstance->processButtonList(buttonList, keys | eventFlag, mouseWheel);
+ else
+ return guiInstance->processButtonList(buttonList, 0, mouseWheel);
+ } else {
+ return keys;
+ }
+}
+
+void KyraEngine_v1::setupKeyMap() {
+ struct KeyCodeMapEntry {
+ Common::KeyCode kcScummVM;
+ int16 kcDOS;
+ int16 kcPC98;
+ int16 kcFMTowns;
+ };
+
+#define UNKNOWN_KEYCODE -1
+#define KC(x) Common::KEYCODE_##x
+ static const KeyCodeMapEntry keys[] = {
+ { KC(SPACE), 61, 53, 32 },
+ { KC(RETURN), 43, 29, 13 },
+ { KC(UP), 96, 68, 30 },
+ { KC(KP8), 96, 68, 30 },
+ { KC(RIGHT), 102, 73, 28 },
+ { KC(KP6), 102, 73, 28 },
+ { KC(DOWN), 98, 76, 31 },
+ { KC(KP2), 98, 76, 31 },
+ { KC(KP5), 97, 72, UNKNOWN_KEYCODE },
+ { KC(LEFT), 92, 71, 29 },
+ { KC(KP4), 92, 71, 29 },
+ { KC(HOME), 91, 67, 127 },
+ { KC(KP7), 91, 67, 127 },
+ { KC(PAGEUP), 101, 69, 18 },
+ { KC(KP9), 101, 69, 18 },
+ { KC(END), 93, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE },
+ { KC(KP1), 93, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE },
+ { KC(PAGEDOWN), 103, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE },
+ { KC(KP3), 103, UNKNOWN_KEYCODE, UNKNOWN_KEYCODE },
+ { KC(F1), 112, 99, 93 },
+ { KC(F2), 113, 100, 94 },
+ { KC(F3), 114, 101, 95 },
+ { KC(F4), 115, 102, 96 },
+ { KC(F5), 116, 103, 97 },
+ { KC(F6), 117, 104, 98 },
+ { KC(a), 31, 31, UNKNOWN_KEYCODE },
+ { KC(b), 50, 50, 66 },
+ { KC(c), 48, 48, 67 },
+ { KC(d), 33, 33, 68 },
+ { KC(e), 19, 19, UNKNOWN_KEYCODE },
+ { KC(f), 34, 34, 70 },
+ { KC(i), 24, 24, 24 },
+ { KC(k), 38, 38, 75 },
+ { KC(m), 52, 52, 77 },
+ { KC(n), 51, 51, UNKNOWN_KEYCODE },
+ { KC(o), 25, 25, 79 },
+ { KC(p), 26, 26, 80 },
+ { KC(r), 20, 20, 82 },
+ { KC(s), 32, 32, UNKNOWN_KEYCODE },
+ { KC(w), 18, 18, UNKNOWN_KEYCODE },
+ { KC(y), 22, 22, UNKNOWN_KEYCODE },
+ { KC(z), 46, 46, UNKNOWN_KEYCODE },
+ { KC(0), UNKNOWN_KEYCODE, UNKNOWN_KEYCODE, 48 },
+ { KC(1), 2, UNKNOWN_KEYCODE, 49 },
+ { KC(2), 3, UNKNOWN_KEYCODE, 50 },
+ { KC(3), 4, UNKNOWN_KEYCODE, 51 },
+ { KC(4), 5, UNKNOWN_KEYCODE, 52 },
+ { KC(5), 6, UNKNOWN_KEYCODE, 53 },
+ { KC(6), 7, UNKNOWN_KEYCODE, 54 },
+ { KC(7), 8, UNKNOWN_KEYCODE, 55 },
+ { KC(SLASH), 55, 55, 47 },
+ { KC(ESCAPE), 110, 1, 27 },
+ { KC(MINUS), 12, UNKNOWN_KEYCODE, 45 },
+ { KC(KP_MINUS), 105, UNKNOWN_KEYCODE, 45 },
+ { KC(PLUS), 13, UNKNOWN_KEYCODE, 43 },
+ { KC(KP_PLUS), 106, UNKNOWN_KEYCODE, 43 },
+
+ // Multiple mappings for the keys to the right of the 'M' key,
+ // since these are different for QWERTZ, QWERTY and AZERTY keyboards.
+ // QWERTZ
+ { KC(COMMA), 53, UNKNOWN_KEYCODE, 60 },
+ { KC(PERIOD), 54, UNKNOWN_KEYCODE, 62 },
+ // AZERTY
+ { KC(SEMICOLON), 53, UNKNOWN_KEYCODE, 60 },
+ { KC(COLON), 54, UNKNOWN_KEYCODE, 62 },
+ // QWERTY
+ { KC(LESS), 53, UNKNOWN_KEYCODE, 60 },
+ { KC(GREATER), 54, UNKNOWN_KEYCODE, 62 }
+ };
+#undef KC
+#undef UNKNOWN_KEYCODE
+
+ _keyMap.clear();
+
+ for (int i = 0; i < ARRAYSIZE(keys); i++)
+ _keyMap[keys[i].kcScummVM] = (_flags.platform == Common::kPlatformPC98) ? keys[i].kcPC98 : ((_flags.platform == Common::kPlatformFMTowns) ? keys[i].kcFMTowns : keys[i].kcDOS);
+}
+
+void KyraEngine_v1::updateInput() {
+ Common::Event event;
+
+ bool updateScreen = false;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode == Common::KEYCODE_PERIOD || event.kbd.keycode == Common::KEYCODE_ESCAPE ||
+ event.kbd.keycode == Common::KEYCODE_SPACE || event.kbd.keycode == Common::KEYCODE_RETURN ||
+ event.kbd.keycode == Common::KEYCODE_UP || event.kbd.keycode == Common::KEYCODE_RIGHT ||
+ event.kbd.keycode == Common::KEYCODE_DOWN || event.kbd.keycode == Common::KEYCODE_LEFT)
+ _eventList.push_back(Event(event, true));
+ else if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL))
+ quitGame();
+ else
+ _eventList.push_back(event);
+ break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_RBUTTONDOWN:
+ _eventList.push_back(Event(event, true));
+ break;
+
+ case Common::EVENT_MOUSEMOVE:
+ if (screen()->isMouseVisible())
+ updateScreen = true;
+ break;
+
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ _eventList.push_back(event);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (updateScreen)
+ _system->updateScreen();
+}
+
+void KyraEngine_v1::removeInputTop() {
+ if (!_eventList.empty())
+ _eventList.erase(_eventList.begin());
+}
+
+bool KyraEngine_v1::skipFlag() const {
+ for (Common::List<Event>::const_iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip)
+ return true;
+ }
+ return false;
+}
+
+void KyraEngine_v1::resetSkipFlag(bool removeEvent) {
+ for (Common::List<Event>::iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip) {
+ if (removeEvent)
+ _eventList.erase(i);
+ else
+ i->causedSkip = false;
+ return;
+ }
+ }
+}
+
+
+int KyraEngine_v1::setGameFlag(int flag) {
+ assert((flag >> 3) >= 0 && (flag >> 3) <= ARRAYSIZE(_flagsTable));
+ _flagsTable[flag >> 3] |= (1 << (flag & 7));
+ return 1;
+}
+
+int KyraEngine_v1::queryGameFlag(int flag) const {
+ assert((flag >> 3) >= 0 && (flag >> 3) <= ARRAYSIZE(_flagsTable));
+ return ((_flagsTable[flag >> 3] >> (flag & 7)) & 1);
+}
+
+int KyraEngine_v1::resetGameFlag(int flag) {
+ assert((flag >> 3) >= 0 && (flag >> 3) <= ARRAYSIZE(_flagsTable));
+ _flagsTable[flag >> 3] &= ~(1 << (flag & 7));
+ return 0;
+}
+
+void KyraEngine_v1::delayUntil(uint32 timestamp, bool updateTimers, bool update, bool isMainLoop) {
+ const uint32 curTime = _system->getMillis();
+ if (curTime > timestamp)
+ return;
+
+ uint32 del = timestamp - curTime;
+ while (del && !shouldQuit()) {
+ uint32 step = MIN<uint32>(del, _tickLength);
+ delay(step, update, isMainLoop);
+ del -= step;
+ }
+}
+
+void KyraEngine_v1::delay(uint32 amount, bool update, bool isMainLoop) {
+ _system->delayMillis(amount);
+}
+
+void KyraEngine_v1::delayWithTicks(int ticks) {
+ delay(ticks * _tickLength);
+}
+
+void KyraEngine_v1::registerDefaultSettings() {
+ if (_flags.platform == Common::kPlatformFMTowns)
+ ConfMan.registerDefault("cdaudio", true);
+ if (_flags.fanLang != Common::UNK_LANG) {
+ // HACK/WORKAROUND: Since we can't use registerDefault here to overwrite
+ // the global subtitles settings, we're using this hack to enable subtitles
+ // for fan translations
+ const Common::ConfigManager::Domain *cur = ConfMan.getActiveDomain();
+ if (!cur || (cur && cur->getVal("subtitles").empty()))
+ ConfMan.setBool("subtitles", true);
+ }
+}
+
+void KyraEngine_v1::readSettings() {
+ _configWalkspeed = ConfMan.getInt("walkspeed");
+ _configMusic = 0;
+
+ if (!ConfMan.getBool("music_mute")) {
+ if (_flags.platform == Common::kPlatformFMTowns)
+ _configMusic = ConfMan.getBool("cdaudio") ? 2 : 1;
+ else
+ _configMusic = 1;
+ }
+ _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1;
+
+ if (_sound) {
+ _sound->enableMusic(_configMusic);
+ _sound->enableSFX(_configSounds);
+ }
+
+ bool speechMute = ConfMan.getBool("speech_mute");
+ bool subtitles = ConfMan.getBool("subtitles");
+
+ if (!speechMute && subtitles)
+ _configVoice = 2; // Voice & Text
+ else if (!speechMute && !subtitles)
+ _configVoice = 1; // Voice only
+ else
+ _configVoice = 0; // Text only
+
+ setWalkspeed(_configWalkspeed);
+}
+
+void KyraEngine_v1::writeSettings() {
+ bool speechMute, subtitles;
+
+ ConfMan.setInt("walkspeed", _configWalkspeed);
+ ConfMan.setBool("music_mute", _configMusic == 0);
+ if (_flags.platform == Common::kPlatformFMTowns)
+ ConfMan.setBool("cdaudio", _configMusic == 2);
+ ConfMan.setBool("sfx_mute", _configSounds == 0);
+
+ switch (_configVoice) {
+ case 0: // Text only
+ speechMute = true;
+ subtitles = true;
+ break;
+ case 1: // Voice only
+ speechMute = false;
+ subtitles = false;
+ break;
+ default: // Voice & Text
+ speechMute = false;
+ subtitles = true;
+ }
+
+ if (_sound) {
+ if (!_configMusic)
+ _sound->beginFadeOut();
+ _sound->enableMusic(_configMusic);
+ _sound->enableSFX(_configSounds);
+ }
+
+ ConfMan.setBool("speech_mute", speechMute);
+ ConfMan.setBool("subtitles", subtitles);
+
+ ConfMan.flushToDisk();
+}
+
+bool KyraEngine_v1::speechEnabled() {
+ return _flags.isTalkie && (_configVoice == 1 || _configVoice == 2);
+}
+
+bool KyraEngine_v1::textEnabled() {
+ return !_flags.isTalkie || (_configVoice == 0 || _configVoice == 2);
+}
+
+int KyraEngine_v1::convertVolumeToMixer(int value) {
+ value -= 2;
+ return (value * Audio::Mixer::kMaxMixerVolume) / 95;
+}
+
+int KyraEngine_v1::convertVolumeFromMixer(int value) {
+ return (value * 95) / Audio::Mixer::kMaxMixerVolume + 2;
+}
+
+void KyraEngine_v1::setVolume(kVolumeEntry vol, uint8 value) {
+ switch (vol) {
+ case kVolumeMusic:
+ ConfMan.setInt("music_volume", convertVolumeToMixer(value));
+ break;
+
+ case kVolumeSfx:
+ ConfMan.setInt("sfx_volume", convertVolumeToMixer(value));
+ break;
+
+ case kVolumeSpeech:
+ ConfMan.setInt("speech_volume", convertVolumeToMixer(value));
+ break;
+ }
+
+ // Resetup mixer
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+ if (_sound)
+ _sound->updateVolumeSettings();
+}
+
+uint8 KyraEngine_v1::getVolume(kVolumeEntry vol) {
+ switch (vol) {
+ case kVolumeMusic:
+ return convertVolumeFromMixer(ConfMan.getInt("music_volume"));
+
+ case kVolumeSfx:
+ return convertVolumeFromMixer(ConfMan.getInt("sfx_volume"));
+
+ case kVolumeSpeech:
+ if (speechEnabled())
+ return convertVolumeFromMixer(ConfMan.getInt("speech_volume"));
+ else
+ return 2;
+ break;
+ }
+
+ return 2;
+}
+
+void KyraEngine_v1::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+ // We need to use this here to allow the subtitle options to be changed
+ // through the GMM's options dialog.
+ readSettings();
+
+ if (_sound)
+ _sound->updateVolumeSettings();
+}
+
+} // End of namespace Kyra