From 9f1416c6a358eb1dc860ff1176ae89721d82fc50 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 22 Feb 2014 00:24:39 -0500 Subject: MADS: Implemented constructor for copy protection dialog, and support methods --- engines/mads/font.cpp | 160 ++++++++--------------------- engines/mads/font.h | 31 +----- engines/mads/mads.cpp | 4 +- engines/mads/nebular/dialogs_nebular.cpp | 167 ++++++++++++++++++++++++++++++- engines/mads/nebular/dialogs_nebular.h | 75 +++++++++++++- engines/mads/palette.cpp | 43 +++++--- engines/mads/palette.h | 42 +++----- 7 files changed, 330 insertions(+), 192 deletions(-) (limited to 'engines/mads') diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp index 076eca92c6..52541500c9 100644 --- a/engines/mads/font.cpp +++ b/engines/mads/font.cpp @@ -28,14 +28,6 @@ namespace MADS { -Font *Font::init(MADSEngine *vm) { - if (vm->getGameFeatures() & GF_MADS) { - return new FontMADS(vm); - } else { - return new FontM4(vm); - } -} - Font::Font(MADSEngine *vm) : _vm(vm) { _sysFont = true; @@ -53,6 +45,43 @@ Font::~Font() { } } +void Font::setFont(const Common::String &filename) { + if (!_filename.empty() && (filename == _filename)) + // Already using specified font, so don't bother reloading + return; + + _sysFont = false; + _filename = filename; + + MadsPack fontData(filename, _vm); + Common::SeekableReadStream *fontFile = fontData.getItemStream(0); + + _maxHeight = fontFile->readByte(); + _maxWidth = fontFile->readByte(); + + _charWidths = new uint8[128]; + // Char data is shifted by 1 + _charWidths[0] = 0; + fontFile->read(_charWidths + 1, 127); + fontFile->readByte(); // remainder + + _charOffs = new uint16[128]; + + uint startOffs = 2 + 128 + 256; + uint fontSize = fontFile->size() - startOffs; + + // Char data is shifted by 1 + _charOffs[0] = 0; + for (int i = 1; i < 128; i++) + _charOffs[i] = fontFile->readUint16LE() - startOffs; + fontFile->readUint16LE(); // remainder + + _charData = new uint8[fontSize]; + fontFile->read(_charData, fontSize); + + delete fontFile; +} + void Font::setColor(uint8 color) { if (_sysFont) _fontColors[1] = color; @@ -60,14 +89,11 @@ void Font::setColor(uint8 color) { _fontColors[3] = color; } -void Font::setColors(uint8 alt1, uint8 alt2, uint8 foreground) { - if (_sysFont) - _fontColors[1] = foreground; - else { - _fontColors[1] = alt1; - _fontColors[2] = alt2; - _fontColors[3] = foreground; - } +void Font::setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4) { + _fontColors[0] = v1; + _fontColors[1] = v2; + _fontColors[2] = v3; + _fontColors[3] = v4; } int Font::write(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width, int spaceWidth, uint8 colors[]) { @@ -160,11 +186,6 @@ int Font::write(MSurface *surface, const Common::String &msg, const Common::Poin } int Font::getWidth(const Common::String &msg, int spaceWidth) { - /* - if (custom_ascii_converter) { // if there is a function to convert the extended ASCII characters - custom_ascii_converter(out_string); // call it with the string - } - */ int width = 0; const char *text = msg.c_str(); @@ -173,46 +194,7 @@ int Font::getWidth(const Common::String &msg, int spaceWidth) { return width; } -/*------------------------------------------------------------------------*/ - -void FontMADS::setFont(const Common::String &filename) { - if (!_filename.empty() && (filename == _filename)) - // Already using specified font, so don't bother reloading - return; - - _sysFont = false; - _filename = filename; - - MadsPack fontData(filename, _vm); - Common::SeekableReadStream *fontFile = fontData.getItemStream(0); - - _maxHeight = fontFile->readByte(); - _maxWidth = fontFile->readByte(); - - _charWidths = new uint8[128]; - // Char data is shifted by 1 - _charWidths[0] = 0; - fontFile->read(_charWidths + 1, 127); - fontFile->readByte(); // remainder - - _charOffs = new uint16[128]; - - uint startOffs = 2 + 128 + 256; - uint fontSize = fontFile->size() - startOffs; - - // Char data is shifted by 1 - _charOffs[0] = 0; - for (int i = 1; i < 128; i++) - _charOffs[i] = fontFile->readUint16LE() - startOffs; - fontFile->readUint16LE(); // remainder - - _charData = new uint8[fontSize]; - fontFile->read(_charData, fontSize); - - delete fontFile; -} - -int FontMADS::getBpp(int charWidth) { +int Font::getBpp(int charWidth) { if (charWidth > 12) return 4; else if (charWidth > 8) @@ -223,60 +205,4 @@ int FontMADS::getBpp(int charWidth) { return 1; } -/*------------------------------------------------------------------------*/ - -void FontM4::setFont(const Common::String &filename) { - if (!_filename.empty() && (filename == _filename)) - // Already using specified font, so don't bother reloading - return; - - _sysFont = false; - _filename = filename; - - Common::SeekableReadStream *fontFile = nullptr; //_vm->_resources->openFile(filename); - - if (fontFile->readUint32LE() != MKTAG('F', 'O', 'N', 'T')) { - warning("Font: FONT tag expected"); - return; - } - - _maxHeight = fontFile->readByte(); - _maxWidth = fontFile->readByte(); - uint fontSize = fontFile->readUint32LE(); - - //printf("Font::Font: _maxWidth = %d, _maxHeight = %d, fontSize = %d\n", _maxWidth, _maxHeight, fontSize); - - if (fontFile->readUint32LE() != MKTAG('W', 'I', 'D', 'T')) { - warning("Font: WIDT tag expected"); - return; - } - - _charWidths = new uint8[256]; - fontFile->read(_charWidths, 256); - - if (fontFile->readUint32LE() != MKTAG('O', 'F', 'F', 'S')) { - warning("Font: OFFS tag expected\n"); - return; - } - - _charOffs = new uint16[256]; - - for (int i = 0; i < 256; i++) - _charOffs[i] = fontFile->readUint16LE(); - - if (fontFile->readUint32LE() != MKTAG('P', 'I', 'X', 'S')) { - warning("Font: PIXS tag expected\n"); - return; - } - - _charData = new uint8[fontSize]; - fontFile->read(_charData, fontSize); - -// _vm->_resources->toss(filename); -} - -int FontM4::getBpp(int charWidth) { - return charWidth / 4 + 1; -} - } // End of namespace MADS diff --git a/engines/mads/font.h b/engines/mads/font.h index d36be80830..3f01260fbd 100644 --- a/engines/mads/font.h +++ b/engines/mads/font.h @@ -62,19 +62,16 @@ protected: Common::String _filename; uint8 _fontColors[4]; -protected: - Font(MADSEngine *vm); - - virtual void setFont(const Common::String &filename) = 0; - virtual int getBpp(int charWidth) = 0; -public: - static Font *init(MADSEngine *vm); + int getBpp(int charWidth); public: + Font(MADSEngine *vm); virtual ~Font(); + void setFont(const Common::String &filename); void setColor(uint8 color); - void setColors(uint8 alt1, uint8 alt2, uint8 foreground); + void setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4); + int maxWidth() const { return _maxWidth; } int getWidth(const Common::String &msg, int spaceWidth = -1); int getHeight() const { return _maxHeight; } int write(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width, int spaceWidth, uint8 colors[]); @@ -83,24 +80,6 @@ public: } }; -class FontMADS: public Font { - friend class Font; -protected: - virtual void setFont(const Common::String &filename); - virtual int getBpp(int charWidth); - - FontMADS(MADSEngine *vm): Font(vm) {} -}; - -class FontM4: public Font { - friend class Font; -protected: - virtual void setFont(const Common::String &filename); - virtual int getBpp(int charWidth); - - FontM4(MADSEngine *vm): Font(vm) {} -}; - } // End of namespace MADS #endif /* MADS_FONT_H */ diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index ec99b314a7..827c62ac61 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -74,8 +74,8 @@ void MADSEngine::initialise() { ResourcesManager::init(this); _events = new EventsManager(this); - _palette = Palette::init(this); - _font = Font::init(this); + _palette = new Palette(this); + _font = new Font(this); _screen = MSurface::init(true); _sound = new SoundManager(this, _mixer); _userInterface = UserInterface::init(this); diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index cd7ab86590..85b06ce592 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -31,15 +31,178 @@ namespace MADS { namespace Nebular { +TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName, + const Common::Point &pos, int maxChars) { + _vm = vm; + _fontName = fontName; + _position = pos; + + _vm->_font->setFont(FONT_INTERFACE); + _vm->_font->setColors(TEXTDIALOG_FONT, TEXTDIALOG_FONT, TEXTDIALOG_FONT, TEXTDIALOG_FONT); + + _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); + + Common::copy(&_vm->_palette->_mainPalette[TEXTDIALOG_F8 * 3], + &_vm->_palette->_mainPalette[TEXTDIALOG_F8 * 3 + 8 * 3], + &_savedPalette[0]); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_F8, 2, 0x24, 0x20); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FA, 2, 0x27, 0x1C); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FC, 2, 0x24, 0x20); + Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FE, 1, 0x37, 0x37); + + _vm->_palette->setPalette(_vm->_palette->_mainPalette + (TEXTDIALOG_F8 * 3), + TEXTDIALOG_F8, 8); +} + +TextDialog::~TextDialog() { +} + +void TextDialog::addLine(const Common::String &line, bool underline) { + if (_lineWidth > 0 || _currentX > 0) + incNumLines(); + + int stringWidth = _vm->_font->getWidth(line); + 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; +} + +/*------------------------------------------------------------------------*/ + bool CopyProtectionDialog::show(MADSEngine *vm) { - CopyProtectionDialog *dlg = new CopyProtectionDialog(vm); + CopyProtectionDialog *dlg = new CopyProtectionDialog(vm, false); delete dlg; return true; } -CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm): _vm(vm) { +CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong): + TextDialog(vm, FONT_INTERFACE_MADS, Common::Point(-1, -1), 32) { getHogAnusEntry(_hogEntry); + + if (priorAnswerWrong) { + addLine("ANSWER INCORRECT!", true); + wordWrap("\n"); + addLine("(But we'll give you another chance!)"); + } else { + addLine("REX NEBULAR version 8.43", true); + wordWrap("\n"); + addLine("(Copy Protection, for your convenience)"); + } + wordWrap("\n"); + + wordWrap("Now comes the part that everybody hates. But if we don't"); + wordWrap("do this, nasty rodent-like people will pirate this game"); + wordWrap("and a whole generation of talented designers, programmers,"); + wordWrap("artists, and playtesters will go hungry, and will wander"); + wordWrap("aimlessly through the land at night searching for peace."); + wordWrap("So let's grit our teeth and get it over with. Just get"); + + Common::String line = "out your copy of "; + line += _hogEntry._bookId == 103 ? "the GAME MANUAL" : "REX'S LOGBOOK"; + line += ". See! That was easy. "; + wordWrap(line); + + line = Common::String::format("Next, just turn to page %d. On line %d, find word number %d, ", + _hogEntry._pageNum, _hogEntry._lineNum, _hogEntry._wordNum); + wordWrap(line); + + wordWrap("and type it on the line below (we',27h,'ve even given you"); + wordWrap("first letter as a hint). As soon as you do that, we can get"); + wordWrap("right into this really COOL adventure game!\n"); + wordWrap("\n"); + wordWrap(" "); + wordWrap("\n"); + } bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) { diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index 6417c2cdc3..3e28ee39b3 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -30,6 +30,76 @@ namespace MADS { namespace Nebular { +enum { + TEXTDIALOG_F8 = 0XF8, + TEXTDIALOG_F9 = 0XF8, + TEXTDIALOG_FA = 0XF8, + TEXTDIALOG_FB = 0XF8, + TEXTDIALOG_FC = 0XF8, + TEXTDIALOG_FD = 0XF8, + TEXTDIALOG_FE = 0XF8, + TEXTDIALOG_FONT = 0 +}; + +#define TEXT_DIALOG_MAX_LINES 20 + +class TextDialog { +private: + /** + * Increments the number of text lines the text dialog uses + */ + void incNumLines(); + + /** + * Flags the previously added line to be underlined + */ + void underlineLine(); + + /** + * Append text to the currently end line. + */ + void appendLine(const Common::String &line); +protected: + MADSEngine *_vm; + Common::Point _position; + Common::String _fontName; + int _width; + int _innerWidth; + int _lineWidth; + int _currentX; + int _numLines; + int _lineSize; + Common::String _lines[TEXT_DIALOG_MAX_LINES]; + int _lineXp[TEXT_DIALOG_MAX_LINES]; + byte _savedPalette[8 * 3]; + + /** + * Add a new line to the dialog + */ + void addLine(const Common::String &line, bool underline = false); + + /** + * Adds one or more lines, word wrapping the passed text + */ + void wordWrap(const Common::String &line); +public: + /** + * Constructor + * @param vm Engine reference + * @param fontName Font to use for display + * @param pos Position for window top-left + * @param maxChars Horizontal width of window in characters + */ + TextDialog(MADSEngine *vm, const Common::String &fontName, const Common::Point &pos, + int maxChars); + + /** + * Destructor + */ + ~TextDialog(); + +}; + struct HOGANUS { int _bookId; int _pageNum; @@ -38,15 +108,14 @@ struct HOGANUS { Common::String _word; }; -class CopyProtectionDialog { +class CopyProtectionDialog: public TextDialog { private: - MADSEngine *_vm; HOGANUS _hogEntry; /** * Constructor */ - CopyProtectionDialog(MADSEngine *vm); + CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong); /** * Get a random copy protection entry from the HOGANUS resource diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp index 6a5d507c13..c858984a52 100644 --- a/engines/mads/palette.cpp +++ b/engines/mads/palette.cpp @@ -54,18 +54,11 @@ RGBList::~RGBList() { #define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2) -Palette *Palette::init(MADSEngine *vm) { - if (vm->getGameFeatures() & GF_MADS) { - return new PaletteMADS(vm); - } else { - return new PaletteM4(vm); - } -} - Palette::Palette(MADSEngine *vm) : _vm(vm) { reset(); _fading_in_progress = false; Common::fill(&_usageCount[0], &_usageCount[PALETTE_COUNT], 0); + Common::fill(&_mainPalette[0], &_mainPalette[PALETTE_SIZE], 0); } void Palette::setPalette(const byte *colors, uint start, uint num) { @@ -245,9 +238,35 @@ void Palette::fadeRange(byte *srcPal, byte *destPal, int startIndex, int endInd _vm->_palette->setPalette(&destPal[startIndex * 3], startIndex, endIndex - startIndex + 1); } -/*------------------------------------------------------------------------*/ +void Palette::setGradient(byte *palette, int start, int count, int rgbValue1, int rgbValue2) { + int rgbCtr = 0; + int rgbDiff = -(rgbValue2 - rgbValue1); + int rgbCurrent = rgbValue2; + + if (count > 0) { + byte *pDest = palette + start * 3; + int endVal = count - 1; + int numLeft = count; + + do { + pDest[0] = pDest[1] = pDest[2] = rgbCurrent; + + if (count > 1) { + rgbCtr += rgbDiff; + if (rgbCtr >= endVal) { + do { + ++rgbCurrent; + rgbCtr += 1 - numLeft; + } while (rgbCtr >= endVal); + } + } + + pDest += 3; + } while (--numLeft > 0); + } +} -byte *PaletteMADS::decodePalette(Common::SeekableReadStream *palStream, int *numColors) { +byte *Palette::decodePalette(Common::SeekableReadStream *palStream, int *numColors) { *numColors = palStream->readUint16LE(); assert(*numColors <= 252); @@ -269,7 +288,7 @@ byte *PaletteMADS::decodePalette(Common::SeekableReadStream *palStream, int *num return palData; } -int PaletteMADS::loadPalette(Common::SeekableReadStream *palStream, int indexStart) { +int Palette::loadPalette(Common::SeekableReadStream *palStream, int indexStart) { int colorCount; byte *palData = decodePalette(palStream, &colorCount); _vm->_palette->setPalette(palData, indexStart, colorCount); @@ -278,7 +297,7 @@ int PaletteMADS::loadPalette(Common::SeekableReadStream *palStream, int indexSta return colorCount; } -void PaletteMADS::setSystemPalette() { +void Palette::setSystemPalette() { resetColorCounts(); byte palData[4 * 3]; diff --git a/engines/mads/palette.h b/engines/mads/palette.h index a97d5de20f..0ef8693a1f 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -84,13 +84,14 @@ protected: byte _fadedPalette[PALETTE_COUNT * 4]; int _usageCount[PALETTE_COUNT]; - Palette(MADSEngine *vm); void reset(); +public: + byte _mainPalette[PALETTE_SIZE]; public: /** - * Creates a new palette instance + * Constructor */ - static Palette *init(MADSEngine *vm); + Palette(MADSEngine *vm); /** * Destructor @@ -153,17 +154,22 @@ public: /** * Decode a palette and return it, without affecting the Palette itself */ - virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors) = 0; + byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors); /** * Loads a palette from a stream */ - virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0) = 0; + int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0); /** * Sets a small set of system/core colors needed by the game */ - virtual void setSystemPalette() = 0; + void setSystemPalette(); + + /** + * Update a range of an arbitrary palette + */ + static void setGradient(byte *palette, int start, int count, int rgbValue1, int rgbValue2); // Color indexes uint8 BLACK; @@ -184,30 +190,6 @@ public: uint8 WHITE; }; -class PaletteMADS: protected Palette { - friend class Palette; -protected: - PaletteMADS(MADSEngine *vm): Palette(vm) {} -public: - virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors); - virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0); - virtual void setSystemPalette(); -}; - -class PaletteM4: protected Palette { - friend class Palette; -protected: - PaletteM4(MADSEngine *vm): Palette(vm) {} -public: - virtual byte *decodePalette(Common::SeekableReadStream *palStream, int *numColors) { - return nullptr; - } - virtual int loadPalette(Common::SeekableReadStream *palStream, int indexStart = 0) { - return 0; - } - virtual void setSystemPalette() {} -}; - } // End of namespace MADS #endif /* MADS_PALETTE_H */ -- cgit v1.2.3