diff options
Diffstat (limited to 'engines/mads/dialogs.cpp')
-rw-r--r-- | engines/mads/dialogs.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp new file mode 100644 index 0000000000..e4c7682a38 --- /dev/null +++ b/engines/mads/dialogs.cpp @@ -0,0 +1,344 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "mads/mads.h" +#include "mads/graphics.h" +#include "mads/msurface.h" +#include "mads/nebular/dialogs_nebular.h" + +namespace MADS { + +Dialog::Dialog(MADSEngine *vm): _vm(vm), _savedSurface(nullptr), + _position(Common::Point(-1, -1)), _width(0), _height(0) { +} + +Dialog::~Dialog() { + restore(_vm->_screen); +} + + +void Dialog::save(MSurface *s) { + _savedSurface = new MSurface(_width, _height); + s->copyTo(_savedSurface, + Common::Rect(_position.x, _position.y, _position.x + _width, _position.y + _height), + Common::Point()); +} + +void Dialog::restore(MSurface *s) { + if (_savedSurface) { + _savedSurface->copyTo(s, _position); + delete _savedSurface; + _savedSurface = nullptr; + } +} + +void Dialog::draw() { + // Save the screen portion the dialog will overlap + save(_vm->_screen); + + // Draw the dialog + // Fill entire content of dialog + _vm->_screen->fillRect(Common::Rect(_position.x, _position.y, + _position.x + _width, _position.y + _height), TEXTDIALOG_BACKGROUND); + + // Draw the outer edge lines + _vm->_screen->hLine(_position.x + 1, _position.y + _height - 2, + _position.x + _width - 2, TEXTDIALOG_EDGE); + _vm->_screen->hLine(_position.x, _position.y + _height - 1, + _position.x + _width - 1, TEXTDIALOG_EDGE); + _vm->_screen->vLine(_position.x + _width - 2, _position.y + 2, + _position.y + _height - 2, TEXTDIALOG_EDGE); + _vm->_screen->vLine(_position.x + _width - 1, _position.y + 1, + _position.y + _height - 1, TEXTDIALOG_EDGE); + + // Draw the gravelly dialog content + drawContent(Common::Rect(_position.x + 2, _position.y + 2, + _position.x + _width - 2, _position.y + _height - 2), 0, + TEXTDIALOG_CONTENT1, TEXTDIALOG_CONTENT2); +} + +void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte color2) { + uint16 currSeed = seed ? seed : 0xB78E; + + for (int yp = 0; yp < r.height(); ++yp) { + byte *destP = _vm->_screen->getBasePtr(r.left, r.top + yp); + + for (int xp = 0; xp < r.width(); ++xp) { + uint16 seedAdjust = currSeed; + currSeed += 0x181D; + seedAdjust = (seedAdjust >> 9) | ((seedAdjust & 0x1ff) << 7); + currSeed ^= seedAdjust; + seedAdjust = (seedAdjust >> 3) | ((seedAdjust & 7) << 13); + currSeed += seedAdjust; + + *destP++ = (currSeed & 0x10) ? color2 : color1; + } + } +} + +/*------------------------------------------------------------------------*/ + +TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName, + const Common::Point &pos, int maxChars): + Dialog(vm) { + _vm = vm; + _fontName = fontName; + _position = pos; + + _vm->_font->setFont(FONT_INTERFACE); + _vm->_font->setColors(TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK); + + _innerWidth = (_vm->_font->maxWidth() + 1) * maxChars; + _width = _innerWidth + 10; + _lineSize = maxChars * 2; + _lineWidth = 0; + _currentX = 0; + _numLines = 0; + Common::fill(&_lineXp[0], &_lineXp[TEXT_DIALOG_MAX_LINES], 0); + _askLineNum = -1; + _askXp = 0; + + // Save the high end of the palette, and set up the entries for dialog display + Common::copy(&_vm->_palette->_mainPalette[TEXTDIALOG_CONTENT1 * 3], + &_vm->_palette->_mainPalette[TEXTDIALOG_CONTENT1 * 3 + 8 * 3], + &_savedPalette[0]); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_CONTENT1, 2, 0x90, 0x80); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_EDGE, 2, 0x9C, 0x70); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FC, 2, 0x90, 0x80); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FE, 1, 0xDC, 0xDC); + + _vm->_palette->setPalette(_vm->_palette->_mainPalette + (TEXTDIALOG_CONTENT1 * 3), + TEXTDIALOG_CONTENT1, 8); +} + +TextDialog::~TextDialog() { + restorePalette(); +} + +void TextDialog::addLine(const Common::String &line, bool underline) { + if (_lineWidth > 0 || _currentX > 0) + incNumLines(); + + int stringWidth = _vm->_font->getWidth(line, 1); + if (stringWidth >= _innerWidth || (int)line.size() >= _lineSize) { + wordWrap(line); + } else { + _lineXp[_numLines] = (_innerWidth / 2) - (stringWidth / 2); + _lines[_numLines] = line; + + if (underline) + underlineLine(); + } + + incNumLines(); +} + +void TextDialog::underlineLine() { + _lineXp[_numLines] |= 0x80; +} + +void TextDialog::incNumLines() { + _lineWidth = 0; + _currentX = 0; + if (++_numLines == TEXT_DIALOG_MAX_LINES) + error("Exceeded text dialog line max"); +} + +void TextDialog::wordWrap(const Common::String &line) { + Common::String tempLine; + + if (!line.empty()) { + const char *srcP = line.c_str(); + + do { + tempLine = ""; + bool endWord = false; + bool newLine = false; + bool continueFlag = true; + + do { + if (!*srcP) { + continueFlag = false; + } else { + tempLine += *srcP; + + if (*srcP == 10) { + continueFlag = false; + newLine = true; + ++srcP; + tempLine.deleteLastChar(); + } else if (*srcP == ' ') { + ++srcP; + endWord = true; + } else if (!endWord) { + ++srcP; + } else { + tempLine.deleteLastChar(); + continueFlag = false; + } + } + } while (continueFlag); + + if (tempLine.hasSuffix(" ")) + tempLine.deleteLastChar(); + + Common::String tempLine2; + if (_currentX > 0) + tempLine2 += ' '; + tempLine2 += tempLine; + + int lineWidth = _vm->_font->getWidth(tempLine2, 1); + if (((_currentX + (int)tempLine2.size()) > _lineSize) || + ((_lineWidth + lineWidth) > _innerWidth)) { + incNumLines(); + appendLine(tempLine); + } else { + appendLine(tempLine2); + } + + if (newLine) + incNumLines(); + } while (*srcP); + } +} + +void TextDialog::appendLine(const Common::String &line) { + _currentX += line.size(); + _lineWidth += _vm->_font->getWidth(line, 1); + _lines[_numLines] += line; +} + +void TextDialog::addInput() { + _askXp = _currentX + 1; + _askLineNum = _numLines; + incNumLines(); +} + +void TextDialog::draw() { + if (!_lineWidth) + --_numLines; + + // Figure out the size and position for the dialog + _height = (_vm->_font->getHeight() + 1) * (_numLines + 1) + 10; + if (_position.x == -1) + _position.x = 160 - (_width / 2); + if (_position.y == -1) + _position.y = 100 - (_height / 2); + + if ((_position.x + _width) > _vm->_screen->getWidth()) + _position.x = _vm->_screen->getWidth() - (_position.x + _width); + if ((_position.y + _height) > _vm->_screen->getHeight()) + _position.y = _vm->_screen->getHeight() - (_position.y + _height); + + // Draw the underlying dialog + Dialog::draw(); + + // Draw the text lines + int lineYp = _position.y + 5; + for (int lineNum = 0; lineNum < _numLines; ++lineNum) { + if (_lineXp[lineNum] == -1) { + // Draw a line across the entire dialog + _vm->_screen->hLine(_position.x + 2, + lineYp + (_vm->_font->getHeight() + 1) / 2, + _position.x + _width - 4, TEXTDIALOG_BLACK); + } else { + // Draw a text line + int xp = (_lineXp[lineNum] & 0x7F) + _position.x + 5; + int yp = lineYp; + if (_lineXp[lineNum] & 0x40) + ++yp; + + _vm->_font->writeString(_vm->_screen, _lines[lineNum], + Common::Point(xp, yp), 0, 1); + + if (_lineXp[lineNum] & 0x80) { + // Draw an underline under the text + int lineWidth = _vm->_font->getWidth(_lines[lineNum], 1); + _vm->_screen->hLine(xp, yp + _vm->_font->getHeight(), xp + lineWidth, + TEXTDIALOG_BLACK); + } + } + + lineYp += _vm->_font->getHeight() + 1; + } +} + +void TextDialog::drawWithInput() { + //int innerWidth = _innerWidth; + //int lineHeight = _vm->_font->getHeight() + 1; + //int xp = _position.x + 5; + + // Draw the content of the dialog + drawContent(Common::Rect(_position.x + 2, _position.y + 2, + _position.x + _width - 2, _position.y + _height - 2), 0, + TEXTDIALOG_CONTENT1, TEXTDIALOG_CONTENT2); + + error("TODO: drawWithInput"); +} + +void TextDialog::restorePalette() { + Common::copy(&_savedPalette[0], &_savedPalette[8 * 3], + &_vm->_palette->_mainPalette[248 * 3]); + _vm->_palette->setPalette(_vm->_palette->_mainPalette, 248, 8); +} + +/*------------------------------------------------------------------------*/ + +MessageDialog::MessageDialog(MADSEngine *vm, int maxChars, ...): + TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), maxChars) { + // Add in passed line list + va_list va; + va_start(va, maxChars); + + const char *line = va_arg(va, const char *); + while (line) { + addLine(line); + line = va_arg(va, const char *); + } + va_end(va); +} + +void MessageDialog::show() { + draw(); + _vm->_events->showCursor(); + + while (!_vm->shouldQuit() && !_vm->_events->_keyPressed && + !_vm->_events->_mouseClicked) { + _vm->_events->delay(1); + } +} + +/*------------------------------------------------------------------------*/ + +Dialogs *Dialogs::init(MADSEngine *vm) { + if (vm->getGameID() == GType_RexNebular) + return new Nebular::DialogsNebular(vm); + + error("Unknown game"); +} + +Dialogs::Dialogs(MADSEngine *vm): _vm(vm) { +} + +} // End of namespace MADS |