diff options
-rw-r--r-- | sword2/anims.cpp | 3 | ||||
-rw-r--r-- | sword2/controls.cpp | 1226 | ||||
-rw-r--r-- | sword2/controls.h | 149 | ||||
-rw-r--r-- | sword2/defs.h | 15 | ||||
-rw-r--r-- | sword2/function.cpp | 5 | ||||
-rw-r--r-- | sword2/mouse.cpp | 27 | ||||
-rw-r--r-- | sword2/mouse.h | 5 | ||||
-rw-r--r-- | sword2/save_rest.cpp | 47 | ||||
-rw-r--r-- | sword2/speech.cpp | 1 | ||||
-rw-r--r-- | sword2/sword2.cpp | 125 | ||||
-rw-r--r-- | sword2/sword2.h | 11 |
11 files changed, 832 insertions, 782 deletions
diff --git a/sword2/anims.cpp b/sword2/anims.cpp index f8db3c57eb..7f4a78b152 100644 --- a/sword2/anims.cpp +++ b/sword2/anims.cpp @@ -30,7 +30,6 @@ #include "sword2/sword2.h" #include "sword2/defs.h" #include "sword2/build_display.h" -#include "sword2/controls.h" #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" @@ -246,7 +245,7 @@ void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) { // if we want subtitles, or speech failed to load - if (_vm->_gui->_subtitles || !speechRunning) { + if (_vm->getSubtitles() || !speechRunning) { // open text resource & get the line text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); // make the sprite diff --git a/sword2/controls.cpp b/sword2/controls.cpp index 5ff77f8008..ece196e6c8 100644 --- a/sword2/controls.cpp +++ b/sword2/controls.cpp @@ -24,52 +24,23 @@ #include "common/system.h" #include "sword2/sword2.h" -#include "sword2/controls.h" #include "sword2/defs.h" -#include "sword2/logic.h" +#include "sword2/controls.h" #include "sword2/mouse.h" #include "sword2/resman.h" -#include "sword2/router.h" #include "sword2/sound.h" -#define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;) -#define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels +#define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;) +#define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels // our fonts start on SPACE character (32) -#define SIZE_OF_CHAR_SET (256 - 32) - -#define MAX_WIDGETS 25 +#define SIZE_OF_CHAR_SET (256 - 32) namespace Sword2 { -class Widget; - -/** - * Base class for all dialogs. - */ - -class Dialog { -private: - int _numWidgets; - Widget *_widgets[MAX_WIDGETS]; - bool _finish; - int _result; - -public: - Gui *_gui; - - Dialog(Gui *gui); - virtual ~Dialog(); - - void registerWidget(Widget *widget); - - virtual void paint(); - virtual void setResult(int result); - - int run(); +static int baseSlot = 0; - virtual void onAction(Widget *widget, int result = 0) {} -}; +class Widget; /** * Base class for all widgets. @@ -77,6 +48,7 @@ public: class Widget { protected: + Sword2Engine *_vm; Dialog *_parent; SpriteInfo *_sprites; @@ -130,7 +102,7 @@ public: class FontRendererGui { private: - Gui *_gui; + Sword2Engine *_vm; struct Glyph { byte *_data; @@ -149,7 +121,7 @@ public: kAlignCenter }; - FontRendererGui(Gui *gui, int fontId); + FontRendererGui(Sword2Engine *vm, int fontId); ~FontRendererGui(); void fetchText(uint32 textId, byte *buf); @@ -164,34 +136,34 @@ public: void drawText(uint32 textId, int x, int y, int alignment = kAlignLeft); }; -FontRendererGui::FontRendererGui(Gui *gui, int fontId) - : _gui(gui), _fontId(fontId) { - byte *font = _gui->_vm->_resman->openResource(fontId); +FontRendererGui::FontRendererGui(Sword2Engine *vm, int fontId) + : _vm(vm), _fontId(fontId) { + byte *font = _vm->_resman->openResource(fontId); FrameHeader *head; SpriteInfo sprite; sprite.type = RDSPR_NOCOMPRESSION | RDSPR_TRANS; for (int i = 0; i < SIZE_OF_CHAR_SET; i++) { - head = (FrameHeader *) _gui->_vm->fetchFrameHeader(font, i); + head = (FrameHeader *) _vm->fetchFrameHeader(font, i); sprite.data = (byte *) (head + 1); sprite.w = head->width; sprite.h = head->height; - _gui->_vm->_screen->createSurface(&sprite, &_glyph[i]._data); + _vm->_screen->createSurface(&sprite, &_glyph[i]._data); _glyph[i]._width = head->width; _glyph[i]._height = head->height; } - _gui->_vm->_resman->closeResource(fontId); + _vm->_resman->closeResource(fontId); } FontRendererGui::~FontRendererGui() { for (int i = 0; i < SIZE_OF_CHAR_SET; i++) - _gui->_vm->_screen->deleteSurface(_glyph[i]._data); + _vm->_screen->deleteSurface(_glyph[i]._data); } void FontRendererGui::fetchText(uint32 textId, byte *buf) { - byte *data = _gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff); + byte *data = _vm->fetchTextLine(_vm->_resman->openResource(textId / SIZE), textId & 0xffff); int i; for (i = 0; data[i + 2]; i++) { @@ -200,7 +172,7 @@ void FontRendererGui::fetchText(uint32 textId, byte *buf) { } buf[i] = 0; - _gui->_vm->_resman->closeResource(textId / SIZE); + _vm->_resman->closeResource(textId / SIZE); } int FontRendererGui::getCharWidth(byte c) { @@ -256,7 +228,7 @@ void FontRendererGui::drawText(byte *text, int x, int y, int alignment) { sprite.w = getCharWidth(text[i]); sprite.h = getCharHeight(text[i]); - _gui->_vm->_screen->drawSurface(&sprite, _glyph[text[i] - 32]._data); + _vm->_screen->drawSurface(&sprite, _glyph[text[i] - 32]._data); sprite.x += (getCharWidth(text[i]) - CHARACTER_OVERLAP); } @@ -274,16 +246,16 @@ void FontRendererGui::drawText(uint32 textId, int x, int y, int alignment) { // Dialog class functions // -Dialog::Dialog(Gui *gui) - : _numWidgets(0), _finish(false), _result(0), _gui(gui) { - _gui->_vm->_screen->setFullPalette(CONTROL_PANEL_PALETTE); - _gui->_vm->_screen->clearScene(); +Dialog::Dialog(Sword2Engine *vm) + : _numWidgets(0), _finish(false), _result(0), _vm(vm) { + _vm->_screen->setFullPalette(CONTROL_PANEL_PALETTE); + _vm->_screen->clearScene(); // HACK: Since the dialogs don't do normal scene updates we need to // trigger a full redraw manually. - _gui->_vm->_screen->setNeedFullRedraw(); - _gui->_vm->_screen->updateDisplay(); + _vm->_screen->setNeedFullRedraw(); + _vm->_screen->updateDisplay(); } Dialog::~Dialog() { @@ -297,7 +269,7 @@ void Dialog::registerWidget(Widget *widget) { } void Dialog::paint() { - _gui->_vm->_screen->clearScene(); + _vm->_screen->clearScene(); for (int i = 0; i < _numWidgets; i++) _widgets[i]->paint(); } @@ -307,8 +279,8 @@ void Dialog::setResult(int result) { _finish = true; } -int Dialog::run() { - uint32 oldFilter = _gui->_vm->setEventFilter(0); +int Dialog::runModal() { + uint32 oldFilter = _vm->setEventFilter(0); int i; @@ -319,17 +291,17 @@ int Dialog::run() { while (!_finish) { // So that the menu icons will reach their full size - _gui->_vm->_mouse->processMenu(); - _gui->_vm->_screen->updateDisplay(false); + _vm->_mouse->processMenu(); + _vm->_screen->updateDisplay(false); int newMouseX, newMouseY; - _gui->_vm->_mouse->getPos(newMouseX, newMouseY); + _vm->_mouse->getPos(newMouseX, newMouseY); newMouseY += 40; - MouseEvent *me = _gui->_vm->mouseEvent(); - KeyboardEvent *ke = _gui->_vm->keyboardEvent(); + MouseEvent *me = _vm->mouseEvent(); + KeyboardEvent *ke = _vm->keyboardEvent(); if (ke) { if (ke->keycode == 27) @@ -408,13 +380,13 @@ int Dialog::run() { oldMouseX = newMouseX; oldMouseY = newMouseY; - _gui->_vm->_system->delayMillis(20); + _vm->_system->delayMillis(20); - if (_gui->_vm->_quit) + if (_vm->_quit) setResult(0); } - _gui->_vm->setEventFilter(oldFilter); + _vm->setEventFilter(oldFilter); return _result; } @@ -423,7 +395,7 @@ int Dialog::run() { // Widget::Widget(Dialog *parent, int states) - : _parent(parent), _numStates(states), _state(0) { + : _vm(parent->_vm), _parent(parent), _numStates(states), _state(0) { _sprites = (SpriteInfo *) calloc(states, sizeof(SpriteInfo)); _surfaces = (WidgetSurface *) calloc(states, sizeof(WidgetSurface)); @@ -433,7 +405,7 @@ Widget::Widget(Dialog *parent, int states) Widget::~Widget() { for (int i = 0; i < _numStates; i++) { if (_surfaces[i]._original) - _parent->_gui->_vm->_screen->deleteSurface(_surfaces[i]._surface); + _vm->_screen->deleteSurface(_surfaces[i]._surface); } free(_sprites); free(_surfaces); @@ -447,11 +419,11 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) uint32 spriteType = RDSPR_TRANS; // open anim resource file, point to base - file = _parent->_gui->_vm->_resman->openResource(res); + file = _vm->_resman->openResource(res); - anim_head = _parent->_gui->_vm->fetchAnimHeader(file); - cdt_entry = _parent->_gui->_vm->fetchCdtEntry(file, pc); - frame_head = _parent->_gui->_vm->fetchFrameHeader(file, pc); + anim_head = _vm->fetchAnimHeader(file); + cdt_entry = _vm->fetchCdtEntry(file, pc); + frame_head = _vm->fetchFrameHeader(file, pc); // If the frame is flipped. (Only really applicable to frames using // offsets.) @@ -488,11 +460,11 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) // Points to just after frame header, ie. start of sprite data _sprites[state].data = (byte *) (frame_head + 1); - _parent->_gui->_vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); + _vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); _surfaces[state]._original = true; // Release the anim resource - _parent->_gui->_vm->_resman->closeResource(res); + _vm->_resman->closeResource(res); } void Widget::linkSurfaceImage(Widget *from, int state, int x, int y) { @@ -541,7 +513,7 @@ int Widget::getState() { } void Widget::paint(Common::Rect *clipRect) { - _parent->_gui->_vm->_screen->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); + _vm->_screen->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); } /** @@ -801,257 +773,258 @@ public: }; /** - * A "mini" dialog is usually a yes/no question, but also used for the - * restart/restore dialog at the beginning of the game. + * The "mini" dialog. */ -class MiniDialog : public Dialog { -private: - uint32 _headerTextId; - uint32 _okTextId; - uint32 _cancelTextId; - FontRendererGui *_fr; - Widget *_panel; - Button *_okButton; - Button *_cancelButton; +MiniDialog::MiniDialog(Sword2Engine *vm, uint32 headerTextId, uint32 okTextId, uint32 cancelTextId) : Dialog(vm) { + _headerTextId = headerTextId; + _okTextId = okTextId; + _cancelTextId = cancelTextId; -public: - MiniDialog(Gui *gui, uint32 headerTextId, uint32 okTextId = 149618688, uint32 cancelTextId = 149618689) - : Dialog(gui), _headerTextId(headerTextId), _okTextId(okTextId), _cancelTextId(cancelTextId) { - _fr = new FontRendererGui(_gui, _gui->_vm->_controlsFontId); + _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - _panel = new Widget(this, 1); - _panel->createSurfaceImages(1996, 203, 104); + _panel = new Widget(this, 1); + _panel->createSurfaceImages(1996, 203, 104); - _okButton = new Button(this, 243, 214, 24, 24); - _okButton->createSurfaceImages(2002, 243, 214); + _okButton = new Button(this, 243, 214, 24, 24); + _okButton->createSurfaceImages(2002, 243, 214); - _cancelButton = new Button(this, 243, 276, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 243, 276); + _cancelButton = new Button(this, 243, 276, 24, 24); + _cancelButton->linkSurfaceImages(_okButton, 243, 276); - registerWidget(_panel); - registerWidget(_okButton); - registerWidget(_cancelButton); - } + registerWidget(_panel); + registerWidget(_okButton); + registerWidget(_cancelButton); +} - ~MiniDialog() { - delete _fr; - } +MiniDialog::~MiniDialog() { + delete _fr; +} - virtual void paint() { - Dialog::paint(); +void MiniDialog::paint() { + Dialog::paint(); - if (_headerTextId) - _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); - _fr->drawText(_okTextId, 270, 214); - _fr->drawText(_cancelTextId, 270, 276); - } + if (_headerTextId) + _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); + _fr->drawText(_okTextId, 270, 214); + _fr->drawText(_cancelTextId, 270, 276); +} - virtual void onAction(Widget *widget, int result = 0) { - if (widget == _okButton) - setResult(1); - else if (widget == _cancelButton) - setResult(0); +void MiniDialog::onAction(Widget *widget, int result) { + if (widget == _okButton) + setResult(1); + else if (widget == _cancelButton) + setResult(0); +} + +StartDialog::StartDialog(Sword2Engine *vm) : MiniDialog(vm, 0) {} + +int StartDialog::runModal() { + while (1) { + MiniDialog startDialog(_vm, 0, TEXT_RESTART, TEXT_RESTORE); + + if (startDialog.runModal()) + return 1; + + if (_vm->_quit) + return 0; + + SaveLoadDialog loadDialog(_vm, kLoadDialog); + + if (loadDialog.runModal()) + return 0; + + if (_vm->_quit) + return 0; } -}; + + return 1; +} /** - * The game settings dialog. + * The restart dialog. */ -class OptionsDialog : public Dialog { -private: - FontRendererGui *_fr; - Widget *_panel; - Switch *_objectLabelsSwitch; - Switch *_subtitlesSwitch; - Switch *_reverseStereoSwitch; - Switch *_musicSwitch; - Switch *_speechSwitch; - Switch *_fxSwitch; - Slider *_musicSlider; - Slider *_speechSlider; - Slider *_fxSlider; - Slider *_gfxSlider; - Widget *_gfxPreview; - Button *_okButton; - Button *_cancelButton; - - SoundMixer *_mixer; +RestartDialog::RestartDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_RESTART) {} -public: - OptionsDialog(Gui *gui) : Dialog(gui) { - _fr = new FontRendererGui(gui, gui->_vm->_controlsFontId); +int RestartDialog::runModal() { + int result = MiniDialog::runModal(); + + if (result) + _vm->restartGame(); + + return result; +} + +/** + * The quit dialog. + */ + +QuitDialog::QuitDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_QUIT) {} + +int QuitDialog::runModal() { + int result = MiniDialog::runModal(); + + if (result) + _vm->closeGame(); + + return result; +} + +/** + * The game settings dialog. + */ + +OptionsDialog::OptionsDialog(Sword2Engine *vm) : Dialog(vm) { + _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - _mixer = _gui->_vm->_mixer; - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(3405, 0, 40); - - _objectLabelsSwitch = new Switch(this, 304, 100, 53, 32); - _objectLabelsSwitch->createSurfaceImages(3687, 304, 100); - - _subtitlesSwitch = new Switch(this, 510, 100, 53, 32); - _subtitlesSwitch->linkSurfaceImages(_objectLabelsSwitch, 510, 100); - - _reverseStereoSwitch = new Switch(this, 304, 293, 53, 32); - _reverseStereoSwitch->linkSurfaceImages(_objectLabelsSwitch, 304, 293); - - _musicSwitch = new Switch(this, 516, 157, 40, 32); - _musicSwitch->createSurfaceImages(3315, 516, 157); - _musicSwitch->reverseStates(); - - _speechSwitch = new Switch(this, 516, 205, 40, 32); - _speechSwitch->linkSurfaceImages(_musicSwitch, 516, 205); - _speechSwitch->reverseStates(); - - _fxSwitch = new Switch(this, 516, 250, 40, 32); - _fxSwitch->linkSurfaceImages(_musicSwitch, 516, 250); - _fxSwitch->reverseStates(); - - int volStep = SoundMixer::kMaxMixerVolume / 10; - - _musicSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 161, 170, 27, volStep); - _speechSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 208, 170, 27, volStep, _musicSlider); - _fxSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 254, 170, 27, volStep, _musicSlider); - _gfxSlider = new Slider(this, _panel, 3, 309, 341, 170, 27, 1, _musicSlider); - - _gfxPreview = new Widget(this, 4); - _gfxPreview->createSurfaceImages(256, 495, 310); - - _okButton = new Button(this, 203, 382, 53, 32); - _okButton->createSurfaceImages(901, 203, 382); - - _cancelButton = new Button(this, 395, 382, 53, 32); - _cancelButton->linkSurfaceImages(_okButton, 395, 382); - - registerWidget(_panel); - registerWidget(_objectLabelsSwitch); - registerWidget(_subtitlesSwitch); - registerWidget(_reverseStereoSwitch); - registerWidget(_musicSwitch); - registerWidget(_speechSwitch); - registerWidget(_fxSwitch); - registerWidget(_musicSlider); - registerWidget(_speechSlider); - registerWidget(_fxSlider); - registerWidget(_gfxSlider); - registerWidget(_gfxPreview); - registerWidget(_okButton); - registerWidget(_cancelButton); - - _gui->readOptionSettings(); - - _objectLabelsSwitch->setValue(_gui->_pointerTextSelected); - _subtitlesSwitch->setValue(_gui->_subtitles); - _reverseStereoSwitch->setValue(_gui->_vm->_sound->isReverseStereo()); - _musicSwitch->setValue(!_gui->_vm->_sound->isMusicMute()); - _speechSwitch->setValue(!_gui->_vm->_sound->isSpeechMute()); - _fxSwitch->setValue(!_gui->_vm->_sound->isFxMute()); - - _musicSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kMusicAudioDataType)); - _speechSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSpeechAudioDataType)); - _fxSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSFXAudioDataType)); - - _gfxSlider->setValue(_gui->_vm->_screen->getRenderLevel()); - _gfxPreview->setState(_gui->_vm->_screen->getRenderLevel()); - } + _mixer = _vm->_mixer; + + _panel = new Widget(this, 1); + _panel->createSurfaceImages(3405, 0, 40); + + _objectLabelsSwitch = new Switch(this, 304, 100, 53, 32); + _objectLabelsSwitch->createSurfaceImages(3687, 304, 100); + + _subtitlesSwitch = new Switch(this, 510, 100, 53, 32); + _subtitlesSwitch->linkSurfaceImages(_objectLabelsSwitch, 510, 100); + + _reverseStereoSwitch = new Switch(this, 304, 293, 53, 32); + _reverseStereoSwitch->linkSurfaceImages(_objectLabelsSwitch, 304, 293); + + _musicSwitch = new Switch(this, 516, 157, 40, 32); + _musicSwitch->createSurfaceImages(3315, 516, 157); + _musicSwitch->reverseStates(); + + _speechSwitch = new Switch(this, 516, 205, 40, 32); + _speechSwitch->linkSurfaceImages(_musicSwitch, 516, 205); + _speechSwitch->reverseStates(); + + _fxSwitch = new Switch(this, 516, 250, 40, 32); + _fxSwitch->linkSurfaceImages(_musicSwitch, 516, 250); + _fxSwitch->reverseStates(); + + int volStep = SoundMixer::kMaxMixerVolume / 10; + + _musicSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 161, 170, 27, volStep); + _speechSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 208, 170, 27, volStep, _musicSlider); + _fxSlider = new Slider(this, _panel, SoundMixer::kMaxMixerVolume, 309, 254, 170, 27, volStep, _musicSlider); + _gfxSlider = new Slider(this, _panel, 3, 309, 341, 170, 27, 1, _musicSlider); + + _gfxPreview = new Widget(this, 4); + _gfxPreview->createSurfaceImages(256, 495, 310); + + _okButton = new Button(this, 203, 382, 53, 32); + _okButton->createSurfaceImages(901, 203, 382); + + _cancelButton = new Button(this, 395, 382, 53, 32); + _cancelButton->linkSurfaceImages(_okButton, 395, 382); + + registerWidget(_panel); + registerWidget(_objectLabelsSwitch); + registerWidget(_subtitlesSwitch); + registerWidget(_reverseStereoSwitch); + registerWidget(_musicSwitch); + registerWidget(_speechSwitch); + registerWidget(_fxSwitch); + registerWidget(_musicSlider); + registerWidget(_speechSlider); + registerWidget(_fxSlider); + registerWidget(_gfxSlider); + registerWidget(_gfxPreview); + registerWidget(_okButton); + registerWidget(_cancelButton); + + _objectLabelsSwitch->setValue(_vm->_mouse->getObjectLabels()); + _subtitlesSwitch->setValue(_vm->getSubtitles()); + _reverseStereoSwitch->setValue(_vm->_sound->isReverseStereo()); + _musicSwitch->setValue(!_vm->_sound->isMusicMute()); + _speechSwitch->setValue(!_vm->_sound->isSpeechMute()); + _fxSwitch->setValue(!_vm->_sound->isFxMute()); + + _musicSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kMusicAudioDataType)); + _speechSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSpeechAudioDataType)); + _fxSlider->setValue(_mixer->getVolumeForSoundType(SoundMixer::kSFXAudioDataType)); + + _gfxSlider->setValue(_vm->_screen->getRenderLevel()); + _gfxPreview->setState(_vm->_screen->getRenderLevel()); +} - ~OptionsDialog() { - delete _fr; - } +OptionsDialog::~OptionsDialog() { + delete _fr; +} - virtual void paint() { - Dialog::paint(); - - int maxWidth = 0; - int width; - - uint32 alignTextIds[] = { - 149618700, // object labels - 149618702, // music volume - 149618703, // speech volume - 149618704, // fx volume - 149618705, // graphics quality - 149618709, // reverse stereo - }; - - for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) { - width = _fr->getTextWidth(alignTextIds[i]); - if (width > maxWidth) - maxWidth = width; - } +void OptionsDialog::paint() { + Dialog::paint(); - // Options - _fr->drawText(149618698, 321, 55, FontRendererGui::kAlignCenter); - // Subtitles - _fr->drawText(149618699, 500, 103, FontRendererGui::kAlignRight); - // Object labels - _fr->drawText(149618700, 299 - maxWidth, 103); - // Music volume - _fr->drawText(149618702, 299 - maxWidth, 161); - // Speech volume - _fr->drawText(149618703, 299 - maxWidth, 208); - // FX volume - _fr->drawText(149618704, 299 - maxWidth, 254); - // Reverse stereo - _fr->drawText(149618709, 299 - maxWidth, 296); - // Graphics quality - _fr->drawText(149618705, 299 - maxWidth, 341); - // Ok - _fr->drawText(149618688, 193, 382, FontRendererGui::kAlignRight); - // Cancel - _fr->drawText(149618689, 385, 382, FontRendererGui::kAlignRight); - } + int maxWidth = 0; + int width; - virtual void onAction(Widget *widget, int result = 0) { - // Since there is music playing while the dialog is displayed - // we need to update music volume immediately. - - if (widget == _musicSwitch) { - _gui->_vm->_sound->muteMusic(result != 0); - } else if (widget == _musicSlider) { - _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, result); - _gui->_vm->_sound->muteMusic(result == 0); - _musicSwitch->setValue(result != 0); - } else if (widget == _speechSlider) { - _speechSwitch->setValue(result != 0); - } else if (widget == _fxSlider) { - _fxSwitch->setValue(result != 0); - } else if (widget == _gfxSlider) { - _gfxPreview->setState(result); - _gui->updateGraphicsLevel(result); - } else if (widget == _okButton) { - _gui->_subtitles = _subtitlesSwitch->getValue(); - _gui->_pointerTextSelected = _objectLabelsSwitch->getValue(); - - // Apply the changes - _gui->_vm->_sound->muteMusic(!_musicSwitch->getValue()); - _gui->_vm->_sound->muteSpeech(!_speechSwitch->getValue()); - _gui->_vm->_sound->muteFx(!_fxSwitch->getValue()); - _gui->_vm->_sound->setReverseStereo(_reverseStereoSwitch->getValue()); - _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, _musicSlider->getValue()); - _mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, _speechSlider->getValue()); - _mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, _fxSlider->getValue()); - - _gui->updateGraphicsLevel(_gfxSlider->getValue()); - - _gui->writeOptionSettings(); - setResult(1); - } else if (widget == _cancelButton) { - // Revert the changes - _gui->readOptionSettings(); - setResult(0); - } - } -}; + uint32 alignTextIds[] = { + TEXT_OBJECT_LABELS, + TEXT_MUSIC_VOLUME, + TEXT_SPEECH_VOLUME, + TEXT_FX_VOLUME, + TEXT_GFX_QUALITY, + TEXT_REVERSE_STEREO + }; -// FIXME: Move these into some class + for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) { + width = _fr->getTextWidth(alignTextIds[i]); + if (width > maxWidth) + maxWidth = width; + } + + _fr->drawText(TEXT_OPTIONS, 321, 55, FontRendererGui::kAlignCenter); + _fr->drawText(TEXT_SUBTITLES, 500, 103, FontRendererGui::kAlignRight); + _fr->drawText(TEXT_OBJECT_LABELS, 299 - maxWidth, 103); + _fr->drawText(TEXT_MUSIC_VOLUME, 299 - maxWidth, 161); + _fr->drawText(TEXT_SPEECH_VOLUME, 299 - maxWidth, 208); + _fr->drawText(TEXT_FX_VOLUME, 299 - maxWidth, 254); + _fr->drawText(TEXT_REVERSE_STEREO, 299 - maxWidth, 296); + _fr->drawText(TEXT_GFX_QUALITY, 299 - maxWidth, 341); + _fr->drawText(TEXT_OK, 193, 382, FontRendererGui::kAlignRight); + _fr->drawText(TEXT_CANCEL, 385, 382, FontRendererGui::kAlignRight); +} -enum { - kSaveDialog, - kLoadDialog -}; +void OptionsDialog::onAction(Widget *widget, int result) { + // Since there is music playing while the dialog is displayed we need + // to update music volume immediately. + + if (widget == _musicSwitch) { + _vm->_sound->muteMusic(result != 0); + } else if (widget == _musicSlider) { + _vm->_mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, result); + _vm->_sound->muteMusic(result == 0); + _musicSwitch->setValue(result != 0); + } else if (widget == _speechSlider) { + _speechSwitch->setValue(result != 0); + } else if (widget == _fxSlider) { + _fxSwitch->setValue(result != 0); + } else if (widget == _gfxSlider) { + _gfxPreview->setState(result); + _vm->_screen->setRenderLevel(result); + } else if (widget == _okButton) { + // Apply the changes + _vm->setSubtitles(_subtitlesSwitch->getValue()); + _vm->_mouse->setObjectLabels(_objectLabelsSwitch->getValue()); + _vm->_sound->muteMusic(!_musicSwitch->getValue()); + _vm->_sound->muteSpeech(!_speechSwitch->getValue()); + _vm->_sound->muteFx(!_fxSwitch->getValue()); + _vm->_sound->setReverseStereo(_reverseStereoSwitch->getValue()); + _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, _musicSlider->getValue()); + _mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, _speechSlider->getValue()); + _mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, _fxSlider->getValue()); + _vm->_screen->setRenderLevel(_gfxSlider->getValue()); + + _vm->writeSettings(); + setResult(1); + } else if (widget == _cancelButton) { + // Revert the changes + _vm->readSettings(); + setResult(0); + } +} // Slot button actions. Note that keyboard input generates positive actions @@ -1168,498 +1141,273 @@ public: } }; -class SaveLoadDialog : public Dialog { -private: - int _mode, _selectedSlot; - byte _editBuffer[SAVE_DESCRIPTION_LEN]; - int _editPos, _firstPos; - int _cursorTick; - - FontRendererGui *_fr1; - FontRendererGui *_fr2; - Widget *_panel; - Slot *_slotButton[8]; - ScrollButton *_zupButton; - ScrollButton *_upButton; - ScrollButton *_downButton; - ScrollButton *_zdownButton; - Button *_okButton; - Button *_cancelButton; +SaveLoadDialog::SaveLoadDialog(Sword2Engine *vm, int mode) : Dialog(vm) { + int i; -public: - SaveLoadDialog(Gui *gui, int mode) - : Dialog(gui), _mode(mode), _selectedSlot(-1) { - int i; + _mode = mode; + _selectedSlot = -1; - // FIXME: The "control font" and the "red font" are currently - // always the same font, so one should be eliminated. + // FIXME: The "control font" and the "red font" are currently always + // the same font, so one should be eliminated. - _fr1 = new FontRendererGui(_gui, _gui->_vm->_controlsFontId); - _fr2 = new FontRendererGui(_gui, _gui->_vm->_redFontId); + _fr1 = new FontRendererGui(_vm, _vm->_controlsFontId); + _fr2 = new FontRendererGui(_vm, _vm->_redFontId); - _panel = new Widget(this, 1); - _panel->createSurfaceImages(2016, 0, 40); + _panel = new Widget(this, 1); + _panel->createSurfaceImages(2016, 0, 40); - for (i = 0; i < 4; i++) { - _slotButton[i] = new Slot(this, 114, 0, 384, 36); - _slotButton[i]->createSurfaceImages(2006 + i, 114, 0); - _slotButton[i]->setMode(mode); - _slotButton[i + 4] = new Slot(this, 114, 0, 384, 36); - _slotButton[i + 4]->linkSurfaceImages(_slotButton[i], 114, 0); - _slotButton[i + 4]->setMode(mode); - } + for (i = 0; i < 4; i++) { + _slotButton[i] = new Slot(this, 114, 0, 384, 36); + _slotButton[i]->createSurfaceImages(2006 + i, 114, 0); + _slotButton[i]->setMode(mode); + _slotButton[i + 4] = new Slot(this, 114, 0, 384, 36); + _slotButton[i + 4]->linkSurfaceImages(_slotButton[i], 114, 0); + _slotButton[i + 4]->setMode(mode); + } - updateSlots(); + updateSlots(); - _zupButton = new ScrollButton(this, 516, 65, 17, 17); - _zupButton->createSurfaceImages(1982, 516, 65); + _zupButton = new ScrollButton(this, 516, 65, 17, 17); + _zupButton->createSurfaceImages(1982, 516, 65); - _upButton = new ScrollButton(this, 516, 85, 17, 17); - _upButton->createSurfaceImages(2067, 516, 85); + _upButton = new ScrollButton(this, 516, 85, 17, 17); + _upButton->createSurfaceImages(2067, 516, 85); - _downButton = new ScrollButton(this, 516, 329, 17, 17); - _downButton->createSurfaceImages(1986, 516, 329); + _downButton = new ScrollButton(this, 516, 329, 17, 17); + _downButton->createSurfaceImages(1986, 516, 329); - _zdownButton = new ScrollButton(this, 516, 350, 17, 17); - _zdownButton->createSurfaceImages(1988, 516, 350); + _zdownButton = new ScrollButton(this, 516, 350, 17, 17); + _zdownButton->createSurfaceImages(1988, 516, 350); - _okButton = new Button(this, 130, 377, 24, 24); - _okButton->createSurfaceImages(2002, 130, 377); + _okButton = new Button(this, 130, 377, 24, 24); + _okButton->createSurfaceImages(2002, 130, 377); - _cancelButton = new Button(this, 350, 377, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 350, 377); + _cancelButton = new Button(this, 350, 377, 24, 24); + _cancelButton->linkSurfaceImages(_okButton, 350, 377); - registerWidget(_panel); + registerWidget(_panel); - for (i = 0; i < 8; i++) - registerWidget(_slotButton[i]); + for (i = 0; i < 8; i++) + registerWidget(_slotButton[i]); - registerWidget(_zupButton); - registerWidget(_upButton); - registerWidget(_downButton); - registerWidget(_zdownButton); - registerWidget(_okButton); - registerWidget(_cancelButton); - } + registerWidget(_zupButton); + registerWidget(_upButton); + registerWidget(_downButton); + registerWidget(_zdownButton); + registerWidget(_okButton); + registerWidget(_cancelButton); +} - ~SaveLoadDialog() { - delete _fr1; - delete _fr2; - } +SaveLoadDialog::~SaveLoadDialog() { + delete _fr1; + delete _fr2; +} - // There aren't really a hundred different button objects of course, - // there are only eight. Re-arrange them to simulate scrolling. - - void updateSlots() { - for (int i = 0; i < 8; i++) { - Slot *slot = _slotButton[(_gui->_baseSlot + i) % 8]; - FontRendererGui *fr; - byte description[SAVE_DESCRIPTION_LEN]; - - slot->setY(72 + i * 36); - - if (_gui->_baseSlot + i == _selectedSlot) { - slot->setEditable(_mode == kSaveDialog); - slot->setState(1); - fr = _fr2; - } else { - slot->setEditable(false); - slot->setState(0); - fr = _fr1; - } +// There aren't really a hundred different button objects of course, there are +// only eight. Re-arrange them to simulate scrolling. - if (_gui->_vm->getSaveDescription(_gui->_baseSlot + i, description) == SR_OK) { - slot->setText(fr, _gui->_baseSlot + i, description); - slot->setClickable(true); - } else { - slot->setText(fr, _gui->_baseSlot + i, NULL); - slot->setClickable(_mode == kSaveDialog); - } +void SaveLoadDialog::updateSlots() { + for (int i = 0; i < 8; i++) { + Slot *slot = _slotButton[(baseSlot + i) % 8]; + FontRendererGui *fr; + byte description[SAVE_DESCRIPTION_LEN]; - if (slot->isEditable()) - drawEditBuffer(slot); - else - slot->paint(); - } - } + slot->setY(72 + i * 36); - virtual void onAction(Widget *widget, int result = 0) { - if (widget == _zupButton) { - if (_gui->_baseSlot > 0) { - if (_gui->_baseSlot >= 8) - _gui->_baseSlot -= 8; - else - _gui->_baseSlot = 0; - updateSlots(); - } - } else if (widget == _upButton) { - if (_gui->_baseSlot > 0) { - _gui->_baseSlot--; - updateSlots(); - } - } else if (widget == _downButton) { - if (_gui->_baseSlot < 92) { - _gui->_baseSlot++; - updateSlots(); - } - } else if (widget == _zdownButton) { - if (_gui->_baseSlot < 92) { - if (_gui->_baseSlot <= 84) - _gui->_baseSlot += 8; - else - _gui->_baseSlot = 92; - updateSlots(); - } - } else if (widget == _okButton) { - setResult(1); - } else if (widget == _cancelButton) { - setResult(0); + if (baseSlot + i == _selectedSlot) { + slot->setEditable(_mode == kSaveDialog); + slot->setState(1); + fr = _fr2; } else { - Slot *slot = (Slot *) widget; - int textWidth; - byte tmp; - int i; - int j; - - switch (result) { - case kWheelUp: - onAction(_upButton); - break; - case kWheelDown: - onAction(_downButton); - break; - case kSelectSlot: - case kDeselectSlot: - if (result == kSelectSlot) - _selectedSlot = _gui->_baseSlot + (slot->getY() - 72) / 35; - else if (result == kDeselectSlot) - _selectedSlot = -1; - - for (i = 0; i < 8; i++) - if (widget == _slotButton[i]) - break; - - for (j = 0; j < 8; j++) { - if (j != i) { - _slotButton[j]->setEditable(false); - _slotButton[j]->setState(0); - } - } - break; - case kStartEditing: - if (_selectedSlot >= 10) - _firstPos = 5; - else - _firstPos = 4; - - strcpy((char *) _editBuffer, (char *) slot->getText()); - _editPos = strlen((char *) _editBuffer); - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - _editBuffer[_editPos + 1] = 0; - slot->setEditable(true); - drawEditBuffer(slot); - break; - case kCursorTick: - _cursorTick++; - if (_cursorTick == 7) { - _editBuffer[_editPos] = ' '; - drawEditBuffer(slot); - } else if (_cursorTick == 14) { - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - drawEditBuffer(slot); - } - break; - case 8: - if (_editPos > _firstPos) { - _editBuffer[_editPos - 1] = _editBuffer[_editPos]; - _editBuffer[_editPos--] = 0; - drawEditBuffer(slot); - } - break; - default: - tmp = _editBuffer[_editPos]; - _editBuffer[_editPos] = 0; - textWidth = _fr2->getTextWidth(_editBuffer); - _editBuffer[_editPos] = tmp; - - if (textWidth < 340 && _editPos < SAVE_DESCRIPTION_LEN - 2) { - _editBuffer[_editPos + 1] = _editBuffer[_editPos]; - _editBuffer[_editPos + 2] = 0; - _editBuffer[_editPos++] = result; - drawEditBuffer(slot); - } - break; - } + slot->setEditable(false); + slot->setState(0); + fr = _fr1; } - } - - void drawEditBuffer(Slot *slot) { - if (_selectedSlot == -1) - return; - - // This will redraw a bit more than is strictly necessary, - // but I doubt that will make any noticeable difference. - slot->paint(); - _fr2->drawText(_editBuffer, 130, 78 + (_selectedSlot - _gui->_baseSlot) * 36); - } - - virtual void paint() { - Dialog::paint(); - - if (_mode == kLoadDialog) { - // Restore - _fr1->drawText(149618690, 165, 377); + if (_vm->getSaveDescription(baseSlot + i, description) == SR_OK) { + slot->setText(fr, baseSlot + i, description); + slot->setClickable(true); } else { - // Save - _fr1->drawText(149618691, 165, 377); - } - // Cancel - _fr1->drawText(149618689, 382, 377); - } - - virtual void setResult(int result) { - // Cancel - - if (result == 0) { - Dialog::setResult(result); - return; + slot->setText(fr, baseSlot + i, NULL); + slot->setClickable(_mode == kSaveDialog); } - // Save / Restore - - if (_selectedSlot == -1) - return; + if (slot->isEditable()) + drawEditBuffer(slot); + else + slot->paint(); + } +} - if (_mode == kSaveDialog) { - if (_editPos <= _firstPos) - return; +void SaveLoadDialog::drawEditBuffer(Slot *slot) { + if (_selectedSlot == -1) + return; - _editBuffer[_editPos] = 0; + // This will redraw a bit more than is strictly necessary, but I doubt + // that will make any noticeable difference. - uint32 rv = _gui->_vm->saveGame(_selectedSlot, (byte *) &_editBuffer[_firstPos]); + slot->paint(); + _fr2->drawText(_editBuffer, 130, 78 + (_selectedSlot - baseSlot) * 36); +} - if (rv != SR_OK) { - uint32 textId; +void SaveLoadDialog::onAction(Widget *widget, int result) { + if (widget == _zupButton) { + if (baseSlot > 0) { + if (baseSlot >= 8) + baseSlot -= 8; + else + baseSlot = 0; + updateSlots(); + } + } else if (widget == _upButton) { + if (baseSlot > 0) { + baseSlot--; + updateSlots(); + } + } else if (widget == _downButton) { + if (baseSlot < 92) { + baseSlot++; + updateSlots(); + } + } else if (widget == _zdownButton) { + if (baseSlot < 92) { + if (baseSlot <= 84) + baseSlot += 8; + else + baseSlot = 92; + updateSlots(); + } + } else if (widget == _okButton) { + setResult(1); + } else if (widget == _cancelButton) { + setResult(0); + } else { + Slot *slot = (Slot *) widget; + int textWidth; + byte tmp; + int i; + int j; - switch (rv) { - case SR_ERR_FILEOPEN: - textId = 213516674; - break; - default: // SR_ERR_WRITEFAIL - textId = 213516676; + switch (result) { + case kWheelUp: + onAction(_upButton); + break; + case kWheelDown: + onAction(_downButton); + break; + case kSelectSlot: + case kDeselectSlot: + if (result == kSelectSlot) + _selectedSlot = baseSlot + (slot->getY() - 72) / 35; + else if (result == kDeselectSlot) + _selectedSlot = -1; + + for (i = 0; i < 8; i++) + if (widget == _slotButton[i]) break; - } - - _gui->_vm->_screen->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); - result = 0; - } - } else { - uint32 rv = _gui->_vm->restoreGame(_selectedSlot); - if (rv != SR_OK) { - uint32 textId; - - switch (rv) { - case SR_ERR_FILEOPEN: - textId = 213516670; - break; - case SR_ERR_INCOMPATIBLE: - textId = 213516671; - break; - default: // SR_ERR_READFAIL - textId = 213516673; - break; + for (j = 0; j < 8; j++) { + if (j != i) { + _slotButton[j]->setEditable(false); + _slotButton[j]->setState(0); } + } + break; + case kStartEditing: + if (_selectedSlot >= 10) + _firstPos = 5; + else + _firstPos = 4; + + strcpy((char *) _editBuffer, (char *) slot->getText()); + _editPos = strlen((char *) _editBuffer); + _cursorTick = 0; + _editBuffer[_editPos] = '_'; + _editBuffer[_editPos + 1] = 0; + slot->setEditable(true); + drawEditBuffer(slot); + break; + case kCursorTick: + _cursorTick++; + if (_cursorTick == 7) { + _editBuffer[_editPos] = ' '; + drawEditBuffer(slot); + } else if (_cursorTick == 14) { + _cursorTick = 0; + _editBuffer[_editPos] = '_'; + drawEditBuffer(slot); + } + break; + case 8: + if (_editPos > _firstPos) { + _editBuffer[_editPos - 1] = _editBuffer[_editPos]; + _editBuffer[_editPos--] = 0; + drawEditBuffer(slot); + } + break; + default: + tmp = _editBuffer[_editPos]; + _editBuffer[_editPos] = 0; + textWidth = _fr2->getTextWidth(_editBuffer); + _editBuffer[_editPos] = tmp; - _gui->_vm->_screen->displayMsg(_gui->_vm->fetchTextLine(_gui->_vm->_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); - result = 0; - } else { - // Prime system with a game cycle - - // Reset the graphic 'BuildUnit' list before a - // new logic list (see fnRegisterFrame) - _gui->_vm->_screen->resetRenderLists(); - - // Reset the mouse hot-spot list (see - // fnRegisterMouse and fnRegisterFrame) - _gui->_vm->_mouse->resetMouseList(); - - if (_gui->_vm->_logic->processSession()) - error("restore 1st cycle failed??"); + if (textWidth < 340 && _editPos < SAVE_DESCRIPTION_LEN - 2) { + _editBuffer[_editPos + 1] = _editBuffer[_editPos]; + _editBuffer[_editPos + 2] = 0; + _editBuffer[_editPos++] = result; + drawEditBuffer(slot); } + break; } - - Dialog::setResult(result); } -}; - -Gui::Gui(Sword2Engine *vm) : _vm(vm), _baseSlot(0) { - ConfMan.registerDefault("music_mute", false); - ConfMan.registerDefault("speech_mute", false); - ConfMan.registerDefault("sfx_mute", false); - ConfMan.registerDefault("gfx_details", 2); - ConfMan.registerDefault("subtitles", false); - ConfMan.registerDefault("reverse_stereo", false); } -void Gui::readOptionSettings(void) { - _subtitles = ConfMan.getBool("subtitles"); - _pointerTextSelected = ConfMan.getBool("object_labels"); +void SaveLoadDialog::paint() { + Dialog::paint(); - updateGraphicsLevel((uint8) ConfMan.getInt("gfx_details")); - - _vm->_mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, ConfMan.getInt("music_volume")); - _vm->_mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, ConfMan.getInt("speech_volume")); - _vm->_mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, ConfMan.getInt("sfx_volume")); - _vm->_sound->muteMusic(ConfMan.getBool("music_mute")); - _vm->_sound->muteSpeech(ConfMan.getBool("speech_mute")); - _vm->_sound->muteFx(ConfMan.getBool("sfx_mute")); - _vm->_sound->setReverseStereo(ConfMan.getBool("reverse_stereo")); -} - -void Gui::writeOptionSettings(void) { - ConfMan.set("music_volume", _vm->_mixer->getVolumeForSoundType(SoundMixer::kMusicAudioDataType)); - ConfMan.set("speech_volume", _vm->_mixer->getVolumeForSoundType(SoundMixer::kSpeechAudioDataType)); - ConfMan.set("sfx_volume", _vm->_mixer->getVolumeForSoundType(SoundMixer::kSFXAudioDataType)); - ConfMan.set("music_mute", _vm->_sound->isMusicMute()); - ConfMan.set("speech_mute", _vm->_sound->isSpeechMute()); - ConfMan.set("sfx_mute", _vm->_sound->isFxMute()); - ConfMan.set("gfx_details", _vm->_screen->getRenderLevel()); - ConfMan.set("subtitles", _subtitles); - ConfMan.set("object_labels", _pointerTextSelected); - ConfMan.set("reverse_stereo", _vm->_sound->isReverseStereo()); - - ConfMan.flushToDisk(); + _fr1->drawText((_mode == kLoadDialog) ? TEXT_RESTORE : TEXT_SAVE, 165, 377); + _fr1->drawText(TEXT_CANCEL, 382, 377); } -uint32 Gui::restoreControl(void) { - // returns 0 for no restore - // 1 for restored ok - - SaveLoadDialog loadDialog(this, kLoadDialog); - return loadDialog.run(); -} - -void Gui::saveControl(void) { - SaveLoadDialog saveDialog(this, kSaveDialog); - _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); - saveDialog.run(); - _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); -} - -bool Gui::startControl(void) { - while (1) { - MiniDialog startDialog(this, 0, 149618693, 149618690); - - if (startDialog.run()) - return true; - - if (_vm->_quit) - return false; +void SaveLoadDialog::setResult(int result) { + if (result) { + if (_selectedSlot == -1) + return; - if (restoreControl()) - return false; + if (_mode == kSaveDialog) { + if (_editPos <= _firstPos) + return; - if (_vm->_quit) - return false; + _editBuffer[_editPos] = 0; + } } - return true; -} - -void Gui::quitControl(void) { - MiniDialog quitDialog(this, 149618692); - - if (quitDialog.run()) - _vm->closeGame(); -} - -void Gui::restartControl(void) { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - uint32 temp_demo_flag; - - MiniDialog restartDialog(this, 149618693); - - if (!restartDialog.run()) - return; - - _vm->_mouse->closeMenuImmediately(); - - // Restart the game. To do this, we must... - - // Stop music instantly! - _vm->_sound->stopMusic(true); - - // In case we were dead - well we're not anymore! - Logic::_scriptVars[DEAD] = 0; - - // Restart the game. Clear all memory and reset the globals - temp_demo_flag = Logic::_scriptVars[DEMO]; - - // Remove all resources from memory, including player object and - // global variables - _vm->_resman->removeAll(); - - // Reopen global variables resource and player object - _vm->setupPersistentResources(); - - Logic::_scriptVars[DEMO] = temp_demo_flag; - - // Free all the route memory blocks from previous game - _vm->_logic->_router->freeAllRouteMem(); - - // Call the same function that first started us up - _vm->startGame(); - - // Prime system with a game cycle - - // Reset the graphic 'BuildUnit' list before a new logic list - // (see fnRegisterFrame) - _vm->_screen->resetRenderLists(); - - // Reset the mouse hot-spot list (see fnRegisterMouse and - // fnRegisterFrame) - _vm->_mouse->resetMouseList(); - - _vm->_mouse->closeMenuImmediately(); - - // FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! - // - this is taken from fnInitBackground - // switch on scrolling (2 means first time on screen) - screenInfo->scroll_flag = 2; - - if (_vm->_logic->processSession()) - error("restart 1st cycle failed??"); - - // So palette not restored immediately after control panel - we want - // to fade up instead! - screenInfo->new_palette = 99; + Dialog::setResult(result); } -void Gui::optionControl(void) { - OptionsDialog optionsDialog(this); - - optionsDialog.run(); - return; -} +int SaveLoadDialog::runModal() { + if (_mode == kSaveDialog) + _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); -void Gui::updateGraphicsLevel(int newLevel) { - if (newLevel < 0) - newLevel = 0; - else if (newLevel > 3) - newLevel = 3; + int result = Dialog::runModal(); - _vm->_screen->setRenderLevel(newLevel); + if (_mode == kSaveDialog) + _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); - // update our global variable - which needs to be checked when dimming - // the palette in PauseGame() in sword2.cpp (since palette-matching - // cannot be done with dimmed palette so we turn down one notch while - // dimmed, if at top level) + if (result) { + switch (_mode) { + case kSaveDialog: + if (_vm->saveGame(_selectedSlot, (byte *) &_editBuffer[_firstPos]) != SR_OK) + result = 0; + break; + case kLoadDialog: + if (_vm->restoreGame(_selectedSlot) != SR_OK) + result = 0; + break; + } + } - _currentGraphicsLevel = newLevel; + return result; } } // End of namespace Sword2 diff --git a/sword2/controls.h b/sword2/controls.h index 27cf07f9f5..9fa95a6b85 100644 --- a/sword2/controls.h +++ b/sword2/controls.h @@ -21,33 +21,152 @@ #ifndef _CONTROL_S #define _CONTROL_S +#include "sword2/defs.h" + +#define MAX_WIDGETS 25 + namespace Sword2 { class Sword2Engine; +class FontRendererGui; +class Widget; +class Switch; +class Slider; +class Button; +class ScrollButton; +class Slot; + +enum { + kSaveDialog, + kLoadDialog +}; + +/** + * Base class for all dialogs. + */ + +class Dialog { +private: + int _numWidgets; + Widget *_widgets[MAX_WIDGETS]; + bool _finish; + int _result; -class Gui { public: Sword2Engine *_vm; - int _baseSlot; - uint8 _currentGraphicsLevel; + Dialog(Sword2Engine *vm); + virtual ~Dialog(); + + void registerWidget(Widget *widget); + + virtual void paint(); + virtual void setResult(int result); + + virtual int runModal(); + + virtual void onAction(Widget *widget, int result = 0) {} +}; + +class OptionsDialog : public Dialog { +private: + FontRendererGui *_fr; + Widget *_panel; + Switch *_objectLabelsSwitch; + Switch *_subtitlesSwitch; + Switch *_reverseStereoSwitch; + Switch *_musicSwitch; + Switch *_speechSwitch; + Switch *_fxSwitch; + Slider *_musicSlider; + Slider *_speechSlider; + Slider *_fxSlider; + Slider *_gfxSlider; + Widget *_gfxPreview; + Button *_okButton; + Button *_cancelButton; + + SoundMixer *_mixer; + +public: + OptionsDialog(Sword2Engine *vm); + ~OptionsDialog(); + + virtual void paint(); + virtual void onAction(Widget *widget, int result = 0); +}; + +class SaveLoadDialog : public Dialog { +private: + int _mode, _selectedSlot; + byte _editBuffer[SAVE_DESCRIPTION_LEN]; + int _editPos, _firstPos; + int _cursorTick; + + FontRendererGui *_fr1; + FontRendererGui *_fr2; + Widget *_panel; + Slot *_slotButton[8]; + ScrollButton *_zupButton; + ScrollButton *_upButton; + ScrollButton *_downButton; + ScrollButton *_zdownButton; + Button *_okButton; + Button *_cancelButton; - bool _subtitles; - bool _pointerTextSelected; +public: + SaveLoadDialog(Sword2Engine *vm, int mode); + ~SaveLoadDialog(); - Gui(Sword2Engine *vm); + void updateSlots(); + void drawEditBuffer(Slot *slot); + + virtual void onAction(Widget *widget, int result = 0); + virtual void paint(); + virtual void setResult(int result); + virtual int runModal(); +}; - uint32 restoreControl(void); - void saveControl(void); - bool startControl(void); - void quitControl(void); - void restartControl(void); - void optionControl(void); - void readOptionSettings(void); - void writeOptionSettings(void); - void updateGraphicsLevel(int newLevel); +/** + * A "mini" dialog is usually a yes/no question, but also used for the + * restart/restore dialog at the beginning of the game. + */ + +class MiniDialog : public Dialog { +private: + uint32 _headerTextId; + uint32 _okTextId; + uint32 _cancelTextId; + FontRendererGui *_fr; + Widget *_panel; + Button *_okButton; + Button *_cancelButton; + +public: + MiniDialog(Sword2Engine *vm, uint32 headerTextId, uint32 okTextId = TEXT_OK, uint32 cancelTextId = TEXT_CANCEL); + virtual ~MiniDialog(); + virtual void paint(); + virtual void onAction(Widget *widget, int result = 0); }; +class StartDialog : public MiniDialog { +public: + StartDialog(Sword2Engine *vm); + virtual int runModal(); +}; + +class RestartDialog : public MiniDialog { +public: + RestartDialog(Sword2Engine *vm); + virtual int runModal(); +}; + +class QuitDialog : public MiniDialog { +public: + QuitDialog(Sword2Engine *vm); + virtual int runModal(); +}; + } // End of namespace Sword2 #endif diff --git a/sword2/defs.h b/sword2/defs.h index 9c17517455..e6f8639516 100644 --- a/sword2/defs.h +++ b/sword2/defs.h @@ -24,6 +24,21 @@ #define SIZE 0x10000 // 65536 items per section #define NuSIZE 0xffff // & with this +#define TEXT_OK 0x08EB0000 +#define TEXT_CANCEL 0x08EB0001 +#define TEXT_RESTORE 0x08EB0002 +#define TEXT_SAVE 0x08EB0003 +#define TEXT_QUIT 0x08EB0004 +#define TEXT_RESTART 0x08EB0005 +#define TEXT_OPTIONS 0x08EB000A +#define TEXT_SUBTITLES 0x08EB000B +#define TEXT_OBJECT_LABELS 0x08EB000C +#define TEXT_MUSIC_VOLUME 0x08EB000E +#define TEXT_SPEECH_VOLUME 0x08EB000F +#define TEXT_FX_VOLUME 0x08EB0010 +#define TEXT_GFX_QUALITY 0x08EB0011 +#define TEXT_REVERSE_STEREO 0x08EB0015 + // always 8 (George object used for Nico player character as well) #define CUR_PLAYER_ID 8 diff --git a/sword2/function.cpp b/sword2/function.cpp index 51931417b2..b20335b57a 100644 --- a/sword2/function.cpp +++ b/sword2/function.cpp @@ -26,7 +26,6 @@ #include "sword2/defs.h" #include "sword2/build_display.h" #include "sword2/console.h" -#include "sword2/controls.h" #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/maketext.h" @@ -1246,7 +1245,7 @@ int32 Logic::fnISpeak(int32 *params) { // we don't want to use a wav for this line either, then just // quit back to script right now! - if (!_vm->_gui->_subtitles && !wantSpeechForLine(params[S_WAV])) + if (!_vm->getSubtitles() && !wantSpeechForLine(params[S_WAV])) return IR_CONT; // Drop out for 1st cycle to allow walks/anims to end and @@ -1411,7 +1410,7 @@ int32 Logic::fnISpeak(int32 *params) { } } - if (_vm->_gui->_subtitles || !speechRunning) { + if (_vm->getSubtitles() || !speechRunning) { // We want subtitles, or the speech failed to load. // Either way, we're going to show the text so create // the text sprite. diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp index be8953c254..a0ee7361ac 100644 --- a/sword2/mouse.cpp +++ b/sword2/mouse.cpp @@ -326,19 +326,34 @@ void Mouse::systemMenuMouse(void) { switch (hit) { case 0: - _vm->_gui->optionControl(); + { + OptionsDialog dialog(_vm); + dialog.runModal(); + } break; case 1: - _vm->_gui->quitControl(); + { + QuitDialog dialog(_vm); + dialog.runModal(); + } break; case 2: - _vm->_gui->saveControl(); + { + SaveLoadDialog dialog(_vm, kSaveDialog); + dialog.runModal(); + } break; case 3: - _vm->_gui->restoreControl(); + { + SaveLoadDialog dialog(_vm, kLoadDialog); + dialog.runModal(); + } break; case 4: - _vm->_gui->restartControl(); + { + RestartDialog dialog(_vm); + dialog.runModal(); + } break; } @@ -993,7 +1008,7 @@ void Mouse::createPointerText(uint32 text_id, uint32 pointer_res) { int16 xOffset, yOffset; uint8 justification; - if (!_vm->_gui->_pointerTextSelected || !text_id) + if (!_objectLabels || !text_id) return; // Check what the pointer is, to set offsets correctly for text diff --git a/sword2/mouse.h b/sword2/mouse.h index e304db086b..1f277c9a9f 100644 --- a/sword2/mouse.h +++ b/sword2/mouse.h @@ -135,6 +135,8 @@ private: uint32 _mouseTouching; uint32 _oldMouseTouching; + bool _objectLabels; + uint32 _menuSelectedPos; void decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff = 0, int yOff = 0); @@ -151,6 +153,9 @@ public: void getPos(int &x, int &y); void setPos(int x, int y); + bool getObjectLabels() { return _objectLabels; } + void setObjectLabels(bool b) { _objectLabels = b; } + bool getMouseStatus() { return _mouseStatus; } uint32 getMouseTouching() { return _mouseTouching; } void setMouseTouching(uint32 touching) { _mouseTouching = touching; } diff --git a/sword2/save_rest.cpp b/sword2/save_rest.cpp index ea1b34f5c0..8fbe6e98b5 100644 --- a/sword2/save_rest.cpp +++ b/sword2/save_rest.cpp @@ -102,6 +102,22 @@ uint32 Sword2Engine::saveGame(uint16 slotNo, byte *desc) { uint32 errorCode = saveData(slotNo, saveBufferMem, bufferSize); free(saveBufferMem); + + if (errorCode != SR_OK) { + uint32 textId; + + switch (errorCode) { + case SR_ERR_FILEOPEN: + textId = 213516674; + break; + default: // SR_ERR_WRITEFAIL + textId = 213516676; + break; + } + + _screen->displayMsg(fetchTextLine(_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); + } + return errorCode; } @@ -205,6 +221,37 @@ uint32 Sword2Engine::restoreGame(uint16 slotNo) { else free(saveBufferMem); + if (errorCode != SR_OK) { + uint32 textId; + + switch (errorCode) { + case SR_ERR_FILEOPEN: + textId = 213516670; + break; + case SR_ERR_INCOMPATIBLE: + textId = 213516671; + break; + default: // SR_ERR_READFAIL + textId = 213516673; + break; + } + + _screen->displayMsg(fetchTextLine(_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); + } else { + // Prime system with a game cycle + + // Reset the graphic 'BuildUnit' list before a new logic list + // (see fnRegisterFrame) + _screen->resetRenderLists(); + + // Reset the mouse hot-spot list. See fnRegisterMouse() + // and fnRegisterFrame() + _mouse->resetMouseList(); + + if (_logic->processSession()) + error("restore 1st cycle failed??"); + } + // Force the game engine to pick a cursor. This appears to be needed // when using the -x command-line option to restore a game. _mouse->setMouseTouching(1); diff --git a/sword2/speech.cpp b/sword2/speech.cpp index abf0e67d85..232526c949 100644 --- a/sword2/speech.cpp +++ b/sword2/speech.cpp @@ -23,7 +23,6 @@ #include "sword2/sword2.h" #include "sword2/console.h" -#include "sword2/controls.h" #include "sword2/defs.h" #include "sword2/interpreter.h" #include "sword2/logic.h" diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 461401b8a7..2c1c861969 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -38,6 +38,7 @@ #include "sword2/memory.h" #include "sword2/mouse.h" #include "sword2/resman.h" +#include "sword2/router.h" #include "sword2/sound.h" #ifdef _WIN32_WCE @@ -128,7 +129,6 @@ Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) : Engine(syst) _mouse = NULL; _logic = NULL; _fontRenderer = NULL; - _gui = NULL; _debugger = NULL; _keyboardEvent.pending = false; @@ -152,7 +152,6 @@ Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) : Engine(syst) Sword2Engine::~Sword2Engine() { delete _debugger; delete _sound; - delete _gui; delete _fontRenderer; delete _screen; delete _mouse; @@ -179,6 +178,43 @@ void Sword2Engine::errorString(const char *buf1, char *buf2) { } } +void Sword2Engine::registerDefaultSettings() { + ConfMan.registerDefault("music_mute", false); + ConfMan.registerDefault("speech_mute", false); + ConfMan.registerDefault("sfx_mute", false); + ConfMan.registerDefault("gfx_details", 2); + ConfMan.registerDefault("subtitles", false); + ConfMan.registerDefault("reverse_stereo", false); +} + +void Sword2Engine::readSettings() { + _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, ConfMan.getInt("music_volume")); + _mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, ConfMan.getInt("speech_volume")); + _mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, ConfMan.getInt("sfx_volume")); + setSubtitles(ConfMan.getBool("subtitles")); + _sound->muteMusic(ConfMan.getBool("music_mute")); + _sound->muteSpeech(ConfMan.getBool("speech_mute")); + _sound->muteFx(ConfMan.getBool("sfx_mute")); + _sound->setReverseStereo(ConfMan.getBool("reverse_stereo")); + _mouse->setObjectLabels(ConfMan.getBool("object_labels")); + _screen->setRenderLevel(ConfMan.getInt("gfx_details")); +} + +void Sword2Engine::writeSettings() { + ConfMan.set("music_volume", _mixer->getVolumeForSoundType(SoundMixer::kMusicAudioDataType)); + ConfMan.set("speech_volume", _mixer->getVolumeForSoundType(SoundMixer::kSpeechAudioDataType)); + ConfMan.set("sfx_volume", _mixer->getVolumeForSoundType(SoundMixer::kSFXAudioDataType)); + ConfMan.set("music_mute", _sound->isMusicMute()); + ConfMan.set("speech_mute", _sound->isSpeechMute()); + ConfMan.set("sfx_mute", _sound->isFxMute()); + ConfMan.set("gfx_details", _screen->getRenderLevel()); + ConfMan.set("subtitles", getSubtitles()); + ConfMan.set("object_labels", _mouse->getObjectLabels()); + ConfMan.set("reverse_stereo", _sound->isReverseStereo()); + + ConfMan.flushToDisk(); +} + /** * The global script variables and player object should be kept open throughout * the game, so that they are never expelled by the resource manager. @@ -209,7 +245,6 @@ int Sword2Engine::init(GameDetector &detector) { _resman = new ResourceManager(this); _logic = new Logic(this); _fontRenderer = new FontRenderer(this); - _gui = new Gui(this); _sound = new Sound(this); _mouse = new Mouse(this); @@ -217,9 +252,8 @@ int Sword2Engine::init(GameDetector &detector) { if (!_mixer->isReady()) warning("Sound initialization failed"); - _mixer->setVolumeForSoundType(SoundMixer::kMusicAudioDataType, ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(SoundMixer::kSpeechAudioDataType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(SoundMixer::kSFXAudioDataType, ConfMan.getInt("sfx_volume")); + registerDefaultSettings(); + readSettings(); initStartMenu(); @@ -235,14 +269,15 @@ int Sword2Engine::init(GameDetector &detector) { else Logic::_scriptVars[DEMO] = 0; - _gui->readOptionSettings(); - if (_saveSlot != -1) { if (saveExists(_saveSlot)) restoreGame(_saveSlot); else { + SaveLoadDialog dialog(this, kLoadDialog); + _mouse->setMouse(NORMAL_MOUSE_ID); - if (!_gui->restoreControl()) + + if (!dialog.runModal()) startGame(); } } else if (!_bootParam && saveExists()) { @@ -251,7 +286,10 @@ int Sword2Engine::init(GameDetector &detector) { _mouse->setMouse(NORMAL_MOUSE_ID); _logic->fnPlayMusic(pars); - result = _gui->startControl(); + + StartDialog dialog(this); + + result = dialog.runModal(); // If the game is started from the beginning, the cutscene // player will kill the music for us. Otherwise, the restore @@ -350,6 +388,63 @@ void Sword2Engine::closeGame() { _quit = true; } +void Sword2Engine::restartGame() { + ScreenInfo *screenInfo = _screen->getScreenInfo(); + uint32 temp_demo_flag; + + _mouse->closeMenuImmediately(); + + // Restart the game. To do this, we must... + + // Stop music instantly! + _sound->stopMusic(true); + + // In case we were dead - well we're not anymore! + Logic::_scriptVars[DEAD] = 0; + + // Restart the game. Clear all memory and reset the globals + temp_demo_flag = Logic::_scriptVars[DEMO]; + + // Remove all resources from memory, including player object and + // global variables + _resman->removeAll(); + + // Reopen global variables resource and player object + setupPersistentResources(); + + Logic::_scriptVars[DEMO] = temp_demo_flag; + + // Free all the route memory blocks from previous game + _logic->_router->freeAllRouteMem(); + + // Call the same function that first started us up + startGame(); + + // Prime system with a game cycle + + // Reset the graphic 'BuildUnit' list before a new logic list + // (see fnRegisterFrame) + _screen->resetRenderLists(); + + // Reset the mouse hot-spot list (see fnRegisterMouse and + // fnRegisterFrame) + _mouse->resetMouseList(); + + _mouse->closeMenuImmediately(); + + // FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! + // - this is taken from fnInitBackground + // switch on scrolling (2 means first time on screen) + screenInfo->scroll_flag = 2; + + if (_logic->processSession()) + error("restart 1st cycle failed??"); + + // So palette not restored immediately after control panel - we want + // to fade up instead! + screenInfo->new_palette = 99; +} + bool Sword2Engine::checkForMouseEvents() { return _mouseEvent.pending; } @@ -529,11 +624,11 @@ void Sword2Engine::pauseGame() { _sound->pauseAllSound(); _mouse->pauseGame(); - // If level at max, turn down because palette-matching won't work - // when dimmed + // If render level is at max, turn it down because palette-matching + // won't work when the palette is dimmed. - if (_gui->_currentGraphicsLevel == 3) { - _gui->updateGraphicsLevel(2); + if (_screen->getRenderLevel() == 3) { + _screen->setRenderLevel(2); _graphicsLevelFudged = true; } @@ -559,7 +654,7 @@ void Sword2Engine::unpauseGame() { // If graphics level at max, turn up again if (_graphicsLevelFudged) { - _gui->updateGraphicsLevel(3); + _screen->setRenderLevel(3); _graphicsLevelFudged = false; } diff --git a/sword2/sword2.h b/sword2/sword2.h index 8de53d64e4..8a30dad63e 100644 --- a/sword2/sword2.h +++ b/sword2/sword2.h @@ -111,6 +111,8 @@ private: uint32 _totalScreenManagers; uint32 _startRes; + bool _useSubtitles; + struct StartUp { char description[MAX_description]; @@ -131,8 +133,15 @@ public: int go(); int init(GameDetector &detector); + void registerDefaultSettings(); + void readSettings(); + void writeSettings(); + void setupPersistentResources(); + bool getSubtitles() { return _useSubtitles; } + void setSubtitles(bool b) { _useSubtitles = b; } + bool _quit; uint32 _features; @@ -145,7 +154,6 @@ public: Mouse *_mouse; Logic *_logic; FontRenderer *_fontRenderer; - Gui *_gui; Debugger *_debugger; @@ -238,6 +246,7 @@ public: void startGame(); void gameCycle(); void closeGame(); + void restartGame(); void sleepUntil(uint32 time); |