aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/font.cpp160
-rw-r--r--engines/mads/font.h31
-rw-r--r--engines/mads/mads.cpp4
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp167
-rw-r--r--engines/mads/nebular/dialogs_nebular.h75
-rw-r--r--engines/mads/palette.cpp43
-rw-r--r--engines/mads/palette.h42
7 files changed, 330 insertions, 192 deletions
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 */