diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index b46eb67b50e..425c3212945 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -60,6 +60,7 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { _soundIsOn = &_soundPlaying; _curPriority = 0; _digiBuf = nullptr; + _soundVolume = 255; _soundOn = true; _speechOn = true; diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h index 414b1ef49b4..797547885aa 100644 --- a/engines/sherlock/sound.h +++ b/engines/sherlock/sound.h @@ -59,6 +59,7 @@ public: bool _soundPlaying; bool *_soundIsOn; byte *_digiBuf; + int _soundVolume; Common::String _talkSoundFile; public: diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp index aa8404f4daa..e7dd20ada4e 100644 --- a/engines/sherlock/tattoo/tattoo.cpp +++ b/engines/sherlock/tattoo/tattoo.cpp @@ -39,6 +39,7 @@ TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDes _fastMode = false; _allowFastMode = true; _transparentMenus = true; + _textWindowsOn = true; } TattooEngine::~TattooEngine() { diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h index 774e2437331..6885f51e2ea 100644 --- a/engines/sherlock/tattoo/tattoo.h +++ b/engines/sherlock/tattoo/tattoo.h @@ -82,6 +82,7 @@ public: bool _runningProlog; bool _fastMode, _allowFastMode; bool _transparentMenus; + bool _textWindowsOn; public: TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc); virtual ~TattooEngine(); diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.cpp b/engines/sherlock/tattoo/tattoo_fixed_text.cpp index 72c67570de5..a4c38c80649 100644 --- a/engines/sherlock/tattoo/tattoo_fixed_text.cpp +++ b/engines/sherlock/tattoo/tattoo_fixed_text.cpp @@ -87,7 +87,17 @@ static const char *const FIXED_TEXT_ENGLISH[] = { "Apply", "Water", - "Heat" + "Heat", + "Load Game", + "Save Game", + "Music", + "Sound Effects", + "Voices", + "Text Windows", + "Transparent Menus", + "Change Font Style", + "Off", + "On" }; TattooFixedText::TattooFixedText(SherlockEngine *vm) : FixedText(vm) { diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h index c26d7870957..e8fea93e864 100644 --- a/engines/sherlock/tattoo/tattoo_fixed_text.h +++ b/engines/sherlock/tattoo/tattoo_fixed_text.h @@ -87,7 +87,18 @@ enum FixedTextId { kFixedText_Apply, kFixedText_Water, - kFixedText_Heat + kFixedText_Heat, + kFixedText_LoadGame, + kFixedText_SaveGame, + kFixedText_Music, + kFixedText_SoundEffects, + kFixedText_Voices, + kFixedText_TextWindows, + kFixedText_TransparentMenus, + kFixedText_ChangeFont, + kFixedText_Off, + kFixedText_On, + kFixedText_Quit }; class TattooFixedText: public FixedText { diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp index 8352e2975c4..528be5f14ea 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.cpp +++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp @@ -561,6 +561,7 @@ void TattooUserInterface::doInventory(int mode) { } void TattooUserInterface::doControls() { + _menuMode = OPTION_MODE; _optionsWidget.load(); } diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp index 9d95fed9bf0..4f58125bb92 100644 --- a/engines/sherlock/tattoo/widget_base.cpp +++ b/engines/sherlock/tattoo/widget_base.cpp @@ -207,6 +207,10 @@ void WidgetBase::makeInfoArea() { makeInfoArea(_surface); } +void WidgetBase::drawDialogRect(const Common::Rect &r, bool raised) { + static_cast(_vm->_ui)->drawDialogRect(_surface, r, raised); +} + void WidgetBase::checkTabbingKeys(int numOptions) { } diff --git a/engines/sherlock/tattoo/widget_base.h b/engines/sherlock/tattoo/widget_base.h index fcf22cee8ef..149f80e7707 100644 --- a/engines/sherlock/tattoo/widget_base.h +++ b/engines/sherlock/tattoo/widget_base.h @@ -64,6 +64,11 @@ protected: */ void makeInfoArea(); + /** + * Draw a dialog rectangle + */ + void drawDialogRect(const Common::Rect &r, bool raised = true); + /** * Draw the scrollbar for the dialog */ diff --git a/engines/sherlock/tattoo/widget_options.cpp b/engines/sherlock/tattoo/widget_options.cpp index 5b4c706a5c6..16d1d1476ba 100644 --- a/engines/sherlock/tattoo/widget_options.cpp +++ b/engines/sherlock/tattoo/widget_options.cpp @@ -22,20 +22,174 @@ #include "sherlock/tattoo/widget_options.h" #include "sherlock/tattoo/tattoo.h" +#include "sherlock/tattoo/tattoo_fixed_text.h" +#include "sherlock/tattoo/tattoo_user_interface.h" namespace Sherlock { namespace Tattoo { WidgetOptions::WidgetOptions(SherlockEngine *vm) : WidgetBase(vm) { + _midiSliderX = _digiSliderX = 0; + _selector = _oldSelector = -1; } void WidgetOptions::load() { + Events &events = *_vm->_events; + Music &music = *_vm->_music; + Sound &sound = *_vm->_sound; + Common::Point mousePos = events.mousePos(); + // Set bounds for the dialog + Common::String widestString = Common::String::format("%s %s", FIXED(TransparentMenus), FIXED(Off)); + _bounds = Common::Rect(_surface.stringWidth(widestString) + _surface.widestChar() * 2 + 6, + (_surface.fontHeight() + 7) * 11 + 3); + _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2); + + // Get slider positions + _midiSliderX = music._musicVolume * (_bounds.width() - _surface.widestChar() * 2) / 255 + _surface.widestChar(); + _digiSliderX = sound._soundVolume * (_bounds.width() - _surface.widestChar() * 2) / 255 + _surface.widestChar(); + + // Setup the dialog + _surface.create(_bounds.width(), _bounds.height()); + render(); } void WidgetOptions::handleEvents() { Events &events = *_vm->_events; + // TODO +} + +void WidgetOptions::render(OptionRenderMode mode) { + TattooEngine &vm = *(TattooEngine *)_vm; + Music &music = *_vm->_music; + Sound &sound = *_vm->_sound; + TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; + ImageFile &images = *ui._interfaceImages; + const char *const OFF_ON[2] = { FIXED(Off), FIXED(On) }; + + // Draw the border if necessary + if (mode == OP_ALL) { + _surface.fill(TRANSPARENCY); + makeInfoArea(); + + int yp = _surface.fontHeight() + 7; + for (int idx = 0; idx < 7; ++idx) { + _surface.transBlitFrom(images[4], Common::Point(0, yp - 1)); + _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, yp - 1)); + _surface.hLine(3, yp, _surface.w() - 4, INFO_TOP); + _surface.hLine(3, yp + 1, _surface.w() - 4, INFO_MIDDLE); + _surface.hLine(3, yp + 2, _surface.w() - 4, INFO_BOTTOM); + + yp += _surface.fontHeight() + 7; + if (idx == 1) + yp += _surface.fontHeight() + 7; + else if (idx == 2) + yp += (_surface.fontHeight() + 7) * 2; + } + } + + // Now go through and display all the items that can be highlighted + for (int idx = 0, yp = 5; idx < 11; ++idx, yp += _surface.fontHeight() + 7) { + if (mode == OP_ALL || idx == _selector || idx == _oldSelector) { + if (mode == OP_NAMES) + _surface.fillRect(Common::Rect(4, yp, _surface.w() - 5, yp + _surface.fontHeight() - 1), TRANSPARENCY); + byte color = (idx == _selector) ? COMMAND_HIGHLIGHTED : INFO_TOP; + Common::String str; + + switch (idx) { + case 0: + str = FIXED(LoadGame); + break; + + case 1: + str = FIXED(SaveGame); + break; + + case 2: + str = Common::String::format("%s %s", FIXED(Music), OFF_ON[music._musicOn]); + break; + + case 3: { + int num = (_surface.fontHeight() + 4) & 0xfe; + int sliderY = yp + num / 2 - 8; + + _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5, + sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY); + _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, + _surface.w() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE); + drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar() * 2, 6)); + + _surface.fillRect(Common::Rect(_midiSliderX - 1, sliderY - (num - 6) / 2 + 2, + _midiSliderX + 1, sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE); + drawDialogRect(Common::Rect(_midiSliderX - 3, sliderY - (num - 6) / 2, 7, num)); + + if (_midiSliderX - 4 > _surface.widestChar()) + _surface.fillRect(Common::Rect(_midiSliderX - 4, sliderY, _midiSliderX - 4, sliderY + 4), INFO_BOTTOM); + if (_midiSliderX + 4 < _surface.w() - _surface.widestChar()) + _surface.fillRect(Common::Rect(_midiSliderX + 4, sliderY, _midiSliderX + 4, sliderY + 4), INFO_BOTTOM); + break; + } + + case 4: + str = Common::String::format("%s %s", FIXED(SoundEffects), OFF_ON[sound._digitized]); + break; + + case 5: + str = Common::String::format("%s %s", FIXED(Voices), OFF_ON[sound._voices]); + break; + + case 6: { + int num = (_surface.fontHeight() + 4) & 0xfe; + int sliderY = yp + num / 2 - 8; + + _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5, + sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY); + _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, _surface.w() - _surface.widestChar() - 1, + sliderY + 3), INFO_MIDDLE); + drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar() * 2, 6)); + _surface.fillRect(Common::Rect(_digiSliderX - 1, sliderY - (num - 6) / 2 + 2, _digiSliderX + 1, + sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE); + drawDialogRect(Common::Rect(_digiSliderX - 3, sliderY - (num - 6) / 2, 7, num)); + if (_digiSliderX - 4 > _surface.widestChar()) + _surface.fillRect(Common::Rect(_digiSliderX - 4, sliderY, _digiSliderX - 4, sliderY + 4), INFO_BOTTOM); + if (_digiSliderX + 4 < _surface.w() - _surface.widestChar()) + _surface.fillRect(Common::Rect(_digiSliderX + 4, sliderY, _digiSliderX + 4, sliderY + 4), INFO_BOTTOM); + break; + } + + case 7: + if (!sound._voices) { + color = INFO_BOTTOM; + str = Common::String::format("%s %s", FIXED(TextWindows), FIXED(On)); + } else { + str = Common::String::format("%s %s", FIXED(TextWindows), OFF_ON[vm._textWindowsOn]); + } + break; + + case 8: + str = FIXED(ChangeFont); + break; + + case 9: + str = Common::String::format("%s %s", FIXED(TransparentMenus), OFF_ON[vm._transparentMenus]); + break; + + case 10: + str = FIXED(Quit); + break; + + default: + break; + } + + // Unless we're doing one of the Slider Controls, print the text for the line + if (idx != 3 && idx != 6) { + int xp = (_surface.w() - _surface.stringWidth(str)) / 2; + _surface.writeString(str, Common::Point(xp, yp), color); + } + } + } } } // End of namespace Tattoo diff --git a/engines/sherlock/tattoo/widget_options.h b/engines/sherlock/tattoo/widget_options.h index 2edb47cb79c..b76aed9bc86 100644 --- a/engines/sherlock/tattoo/widget_options.h +++ b/engines/sherlock/tattoo/widget_options.h @@ -32,11 +32,20 @@ class SherlockEngine; namespace Tattoo { +enum OptionRenderMode { OP_ALL = 0, OP_CONTENTS = 1, OP_NAMES = 2}; + /** * Handles displaying the options dialog */ class WidgetOptions : public WidgetBase { private: + int _midiSliderX, _digiSliderX; + int _selector, _oldSelector; + + /** + * Render the contents of the dialog onto the widget's surface + */ + void render(OptionRenderMode mode = OP_ALL); public: WidgetOptions(SherlockEngine *vm); virtual ~WidgetOptions() {} diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h index 9af5ad5ae65..75e005cb050 100644 --- a/engines/sherlock/user_interface.h +++ b/engines/sherlock/user_interface.h @@ -53,7 +53,8 @@ enum MenuMode { // Rose Tattoo specific LAB_MODE = 20, MESSAGE_MODE = 21, - VERB_MODE = 22 + VERB_MODE = 22, + OPTION_MODE = 23 }; class UserInterface {