From 807b33ec29797006dd13e4627102166344cc8901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Sun, 20 Feb 2005 15:38:48 +0000 Subject: [PATCH] More BS2 restructuring. The various game settings are no longer stored in the Gui class. They are stored in the class that use them. Code that doesn't belong in the Gui class, e.g. the "restart" code, has been moved out of it. Afterwards, the Gui class had been reduced to nothing more than a handful of trivial methods for invoking the in-game dialogs. So the entire Gui class has been removed. svn-id: r16827 --- sword2/anims.cpp | 3 +- sword2/controls.cpp | 1212 +++++++++++++++++------------------------- sword2/controls.h | 149 +++++- sword2/defs.h | 15 + sword2/function.cpp | 5 +- sword2/mouse.cpp | 27 +- sword2/mouse.h | 5 + sword2/save_rest.cpp | 47 ++ sword2/speech.cpp | 1 - sword2/sword2.cpp | 125 ++++- sword2/sword2.h | 11 +- 11 files changed, 825 insertions(+), 775 deletions(-) diff --git a/sword2/anims.cpp b/sword2/anims.cpp index f8db3c57eb4..7f4a78b152c 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 5ff77f80086..ece196e6c8f 100644 --- a/sword2/controls.cpp +++ b/sword2/controls.cpp @@ -24,59 +24,31 @@ #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 { +static int baseSlot = 0; + 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(); - - virtual void onAction(Widget *widget, int result = 0) {} -}; - /** * Base class for all widgets. */ 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::~MiniDialog() { + delete _fr; +} + +void MiniDialog::paint() { + Dialog::paint(); + + if (_headerTextId) + _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); + _fr->drawText(_okTextId, 270, 214); + _fr->drawText(_cancelTextId, 270, 276); +} + +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; } - ~MiniDialog() { - delete _fr; - } + return 1; +} - virtual void paint() { - Dialog::paint(); +/** + * The restart dialog. + */ - if (_headerTextId) - _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); - _fr->drawText(_okTextId, 270, 214); - _fr->drawText(_cancelTextId, 270, 276); - } +RestartDialog::RestartDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_RESTART) {} - virtual void onAction(Widget *widget, int result = 0) { - if (widget == _okButton) - setResult(1); - else if (widget == _cancelButton) - setResult(0); - } -}; +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. */ -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(Gui *gui) : Dialog(gui) { - _fr = new FontRendererGui(gui, gui->_vm->_controlsFontId); +OptionsDialog::OptionsDialog(Sword2Engine *vm) : Dialog(vm) { + _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - _mixer = _gui->_vm->_mixer; + _mixer = _vm->_mixer; - _panel = new Widget(this, 1); - _panel->createSurfaceImages(3405, 0, 40); + _panel = new Widget(this, 1); + _panel->createSurfaceImages(3405, 0, 40); - _objectLabelsSwitch = new Switch(this, 304, 100, 53, 32); - _objectLabelsSwitch->createSurfaceImages(3687, 304, 100); + _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); + _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); + _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(); + _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(); + _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(); + _fxSwitch = new Switch(this, 516, 250, 40, 32); + _fxSwitch->linkSurfaceImages(_musicSwitch, 516, 250); + _fxSwitch->reverseStates(); - int volStep = SoundMixer::kMaxMixerVolume / 10; + 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); + _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); + _gfxPreview = new Widget(this, 4); + _gfxPreview->createSurfaceImages(256, 495, 310); - _okButton = new Button(this, 203, 382, 53, 32); - _okButton->createSurfaceImages(901, 203, 382); + _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); + _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); + 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(_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()); - _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)); - _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()); +} - _gfxSlider->setValue(_gui->_vm->_screen->getRenderLevel()); - _gfxPreview->setState(_gui->_vm->_screen->getRenderLevel()); +OptionsDialog::~OptionsDialog() { + delete _fr; +} + +void OptionsDialog::paint() { + Dialog::paint(); + + int maxWidth = 0; + int width; + + uint32 alignTextIds[] = { + TEXT_OBJECT_LABELS, + TEXT_MUSIC_VOLUME, + TEXT_SPEECH_VOLUME, + TEXT_FX_VOLUME, + TEXT_GFX_QUALITY, + TEXT_REVERSE_STEREO + }; + + for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) { + width = _fr->getTextWidth(alignTextIds[i]); + if (width > maxWidth) + maxWidth = width; } - ~OptionsDialog() { - delete _fr; + _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); +} + +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); } - - 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; - } - - // 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); - } - - 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); - } - } -}; - -// FIXME: Move these into some class - -enum { - kSaveDialog, - kLoadDialog -}; +} // Slot button actions. Note that keyboard input generates positive actions @@ -1168,268 +1141,236 @@ public: } }; -class SaveLoadDialog : public Dialog { -private: - int _mode, _selectedSlot; - byte _editBuffer[SAVE_DESCRIPTION_LEN]; - int _editPos, _firstPos; - int _cursorTick; +SaveLoadDialog::SaveLoadDialog(Sword2Engine *vm, int mode) : Dialog(vm) { + int i; - FontRendererGui *_fr1; - FontRendererGui *_fr2; - Widget *_panel; - Slot *_slotButton[8]; - ScrollButton *_zupButton; - ScrollButton *_upButton; - ScrollButton *_downButton; - ScrollButton *_zdownButton; - Button *_okButton; - Button *_cancelButton; + _mode = mode; + _selectedSlot = -1; -public: - SaveLoadDialog(Gui *gui, int mode) - : Dialog(gui), _mode(mode), _selectedSlot(-1) { - int i; + // 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(_vm, _vm->_controlsFontId); + _fr2 = new FontRendererGui(_vm, _vm->_redFontId); - _fr1 = new FontRendererGui(_gui, _gui->_vm->_controlsFontId); - _fr2 = new FontRendererGui(_gui, _gui->_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); - } - - updateSlots(); - - _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); - - _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); - - _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); - - registerWidget(_panel); - - for (i = 0; i < 8; i++) - registerWidget(_slotButton[i]); - - registerWidget(_zupButton); - registerWidget(_upButton); - registerWidget(_downButton); - registerWidget(_zdownButton); - registerWidget(_okButton); - registerWidget(_cancelButton); + 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); } - ~SaveLoadDialog() { - delete _fr1; - delete _fr2; - } + updateSlots(); - // There aren't really a hundred different button objects of course, - // there are only eight. Re-arrange them to simulate scrolling. + _zupButton = new ScrollButton(this, 516, 65, 17, 17); + _zupButton->createSurfaceImages(1982, 516, 65); - void updateSlots() { - for (int i = 0; i < 8; i++) { - Slot *slot = _slotButton[(_gui->_baseSlot + i) % 8]; - FontRendererGui *fr; - byte description[SAVE_DESCRIPTION_LEN]; + _upButton = new ScrollButton(this, 516, 85, 17, 17); + _upButton->createSurfaceImages(2067, 516, 85); - slot->setY(72 + i * 36); + _downButton = new ScrollButton(this, 516, 329, 17, 17); + _downButton->createSurfaceImages(1986, 516, 329); - if (_gui->_baseSlot + i == _selectedSlot) { - slot->setEditable(_mode == kSaveDialog); - slot->setState(1); - fr = _fr2; - } else { - slot->setEditable(false); - slot->setState(0); - fr = _fr1; - } + _zdownButton = new ScrollButton(this, 516, 350, 17, 17); + _zdownButton->createSurfaceImages(1988, 516, 350); - 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); - } + _okButton = new Button(this, 130, 377, 24, 24); + _okButton->createSurfaceImages(2002, 130, 377); - if (slot->isEditable()) - drawEditBuffer(slot); - else - slot->paint(); - } - } + _cancelButton = new Button(this, 350, 377, 24, 24); + _cancelButton->linkSurfaceImages(_okButton, 350, 377); - 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); + registerWidget(_panel); + + for (i = 0; i < 8; i++) + registerWidget(_slotButton[i]); + + registerWidget(_zupButton); + registerWidget(_upButton); + registerWidget(_downButton); + registerWidget(_zdownButton); + registerWidget(_okButton); + registerWidget(_cancelButton); +} + +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 SaveLoadDialog::updateSlots() { + for (int i = 0; i < 8; i++) { + Slot *slot = _slotButton[(baseSlot + i) % 8]; + FontRendererGui *fr; + byte description[SAVE_DESCRIPTION_LEN]; + + slot->setY(72 + i * 36); + + 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; + slot->setEditable(false); + slot->setState(0); + fr = _fr1; + } - 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; + if (_vm->getSaveDescription(baseSlot + i, description) == SR_OK) { + slot->setText(fr, baseSlot + i, description); + slot->setClickable(true); + } else { + slot->setText(fr, baseSlot + i, NULL); + slot->setClickable(_mode == kSaveDialog); + } - for (i = 0; i < 8; i++) - if (widget == _slotButton[i]) - break; + if (slot->isEditable()) + drawEditBuffer(slot); + else + slot->paint(); + } +} - for (j = 0; j < 8; j++) { - if (j != i) { - _slotButton[j]->setEditable(false); - _slotButton[j]->setState(0); - } +void SaveLoadDialog::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 - baseSlot) * 36); +} + +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 (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; + + 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; + } + break; + case kStartEditing: + if (_selectedSlot >= 10) + _firstPos = 5; + else + _firstPos = 4; - strcpy((char *) _editBuffer, (char *) slot->getText()); - _editPos = strlen((char *) _editBuffer); + 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] = '_'; - _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; } + 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; } } +} - void drawEditBuffer(Slot *slot) { - if (_selectedSlot == -1) - return; +void SaveLoadDialog::paint() { + Dialog::paint(); - // 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); - } 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; - } - - // Save / Restore + _fr1->drawText((_mode == kLoadDialog) ? TEXT_RESTORE : TEXT_SAVE, 165, 377); + _fr1->drawText(TEXT_CANCEL, 382, 377); +} +void SaveLoadDialog::setResult(int result) { + if (result) { if (_selectedSlot == -1) return; @@ -1438,228 +1379,35 @@ public: return; _editBuffer[_editPos] = 0; - - uint32 rv = _gui->_vm->saveGame(_selectedSlot, (byte *) &_editBuffer[_firstPos]); - - if (rv != SR_OK) { - uint32 textId; - - switch (rv) { - case SR_ERR_FILEOPEN: - textId = 213516674; - break; - default: // SR_ERR_WRITEFAIL - textId = 213516676; - 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; - } - - _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??"); - } } - - 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"); - - 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(); -} - -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; - - if (restoreControl()) - return false; - - if (_vm->_quit) - return false; } - return true; + Dialog::setResult(result); } -void Gui::quitControl(void) { - MiniDialog quitDialog(this, 149618692); +int SaveLoadDialog::runModal() { + if (_mode == kSaveDialog) + _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); - if (quitDialog.run()) - _vm->closeGame(); -} + int result = Dialog::runModal(); -void Gui::restartControl(void) { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - uint32 temp_demo_flag; + if (_mode == kSaveDialog) + _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); - MiniDialog restartDialog(this, 149618693); + 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; + } + } - 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; -} - -void Gui::optionControl(void) { - OptionsDialog optionsDialog(this); - - optionsDialog.run(); - return; -} - -void Gui::updateGraphicsLevel(int newLevel) { - if (newLevel < 0) - newLevel = 0; - else if (newLevel > 3) - newLevel = 3; - - _vm->_screen->setRenderLevel(newLevel); - - // 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) - - _currentGraphicsLevel = newLevel; + return result; } } // End of namespace Sword2 diff --git a/sword2/controls.h b/sword2/controls.h index 27cf07f9f57..9fa95a6b852 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(); - bool _subtitles; - bool _pointerTextSelected; + void registerWidget(Widget *widget); - Gui(Sword2Engine *vm); + virtual void paint(); + virtual void setResult(int result); - 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); + 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; + +public: + SaveLoadDialog(Sword2Engine *vm, int mode); + ~SaveLoadDialog(); + + 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(); +}; + +/** + * 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 9c17517455d..e6f86395166 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 51931417b2e..b20335b57a8 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 be8953c2544..a0ee7361acf 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 e304db086b4..1f277c9a9fd 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 ea1b34f5c0a..8fbe6e98b58 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 abf0e67d856..232526c9492 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 461401b8a77..2c1c8619695 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 8de53d64e4c..8a30dad63ef 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);