mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 01:38:36 +00:00
NANCY: Render text in The Vampire Diaries
Text in TVD is now rendered in the textbox, and should be pixel-accurate to the original engine.
This commit is contained in:
parent
6efcbebef5
commit
6abc61edf7
@ -75,6 +75,11 @@ void Font::read(Common::SeekableReadStream &stream) {
|
||||
Common::Rect &cur = _symbolRects[i];
|
||||
readRect(stream, cur);
|
||||
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
++cur.bottom;
|
||||
++cur.right;
|
||||
}
|
||||
|
||||
_maxCharWidth = MAX<int>(cur.width(), _maxCharWidth);
|
||||
_fontHeight = MAX<int>(cur.height(), _maxCharWidth);
|
||||
}
|
||||
@ -90,16 +95,29 @@ void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 col
|
||||
srcRect.translate(_colorCoordsOffset.x, _colorCoordsOffset.y);
|
||||
}
|
||||
|
||||
uint width = srcRect.width();
|
||||
uint vampireAdjust = g_nancy->getGameType() == kGameTypeVampire ? 1 : 0;
|
||||
uint width = MAX<int>(srcRect.width() - vampireAdjust, 0);
|
||||
uint height = srcRect.height();
|
||||
uint yOffset = getFontHeight() - height;
|
||||
height = MAX<int>(height - vampireAdjust, 0);
|
||||
|
||||
for (uint curY = 0; curY < height; ++curY) {
|
||||
for (uint curX = 0; curX < width; ++curX) {
|
||||
switch (g_nancy->_graphicsManager->getInputPixelFormat().bytesPerPixel) {
|
||||
case 1:
|
||||
// TODO
|
||||
case 1: {
|
||||
byte colorID = *(const byte *)_image.getBasePtr(srcRect.left + curX, srcRect.top + curY);
|
||||
|
||||
if (colorID != _transColor) {
|
||||
uint8 r, g, b;
|
||||
uint curColor = _image.getPalette()[colorID];
|
||||
r = curColor & 0xFF;
|
||||
g = (curColor & 0xFF00) >> 8;
|
||||
b = (curColor & 0xFF0000) >> 16;
|
||||
*(uint16 *)dst->getBasePtr(x + curX, y + yOffset + curY) = dst->format.RGBToColor(r, g, b);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint16 curColor = *(const uint16 *)_image.getBasePtr(srcRect.left + curX, srcRect.top + curY);
|
||||
|
||||
@ -121,6 +139,12 @@ void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 col
|
||||
void Font::wordWrap(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines, int initWidth) const {
|
||||
Common::String temp;
|
||||
for (const char *c = str.begin(); c != str.end(); ++c) {
|
||||
if (*c == '\n') {
|
||||
lines.push_back(temp);
|
||||
temp.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
temp += *c;
|
||||
int size = getStringWidth(temp) + (lines.size() == 0 ? initWidth : 0);
|
||||
if (size >= maxWidth) {
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "common/array.h"
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
@ -82,7 +82,7 @@ private:
|
||||
|
||||
Common::Array<Common::Rect> _symbolRects; // 0x62
|
||||
|
||||
Graphics::Surface _image;
|
||||
Graphics::ManagedSurface _image;
|
||||
|
||||
int _fontHeight;
|
||||
int _maxCharWidth;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "engines/nancy/dialogs.h"
|
||||
#include "engines/nancy/console.h"
|
||||
#include "engines/nancy/constants.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/action/primaryvideo.h"
|
||||
|
||||
@ -467,8 +468,12 @@ void NancyEngine::readBootSummary(const IFF &boot) {
|
||||
readChunkList(boot, ser, "OB");
|
||||
}
|
||||
|
||||
ser.skip(0x96, kGameTypeVampire, kGameTypeVampire);
|
||||
ser.skip(0x79, kGameTypeNancy1, kGameTypeNancy1);
|
||||
ser.skip(0x28, kGameTypeVampire, kGameTypeVampire);
|
||||
ser.skip(0x10, kGameTypeNancy1, kGameTypeNancy1);
|
||||
readRect(*bsum, _textboxScreenPosition);
|
||||
|
||||
ser.skip(0x5E, kGameTypeVampire, kGameTypeVampire);
|
||||
ser.skip(0x59, kGameTypeNancy1, kGameTypeNancy1);
|
||||
ser.syncAsUint16LE(_horizontalEdgesSize, kGameTypeVampire, kGameTypeNancy1);
|
||||
ser.syncAsUint16LE(_verticalEdgesSize, kGameTypeVampire, kGameTypeNancy1);
|
||||
ser.skip(0x1C, kGameTypeVampire, kGameTypeNancy1);
|
||||
|
@ -122,6 +122,7 @@ public:
|
||||
|
||||
Common::RandomSource *_randomSource;
|
||||
|
||||
// BSUM data
|
||||
uint16 _firstSceneID;
|
||||
uint16 _startTimeHours;
|
||||
|
||||
@ -133,6 +134,8 @@ public:
|
||||
uint _horizontalEdgesSize;
|
||||
uint _verticalEdgesSize;
|
||||
|
||||
Common::Rect _textboxScreenPosition;
|
||||
|
||||
private:
|
||||
struct GameFlow {
|
||||
NancyState::NancyState curState = NancyState::kNone;
|
||||
|
@ -81,9 +81,7 @@ void Textbox::init() {
|
||||
chunk->seek(0x1FE, SEEK_SET);
|
||||
_fontID = chunk->readUint16LE();
|
||||
|
||||
chunk = g_nancy->getBootChunkStream("BSUM");
|
||||
chunk->seek(0x164);
|
||||
readRect(*chunk, _screenPosition);
|
||||
_screenPosition = g_nancy->_textboxScreenPosition;
|
||||
|
||||
Common::Rect outerBoundingBox = _screenPosition;
|
||||
outerBoundingBox.moveTo(0, 0);
|
||||
@ -142,11 +140,10 @@ void Textbox::drawTextbox() {
|
||||
const Font *font = g_nancy->_graphicsManager->getFont(_fontID);
|
||||
|
||||
uint maxWidth = _fullSurface.w - _maxWidthDifference - _borderWidth - 2;
|
||||
uint lineDist = _lineHeight + _lineHeight / 4;
|
||||
uint lineDist = _lineHeight + _lineHeight / 4 + (g_nancy->getGameType() == kGameTypeVampire ? 1 : 0);
|
||||
|
||||
for (uint lineID = 0; lineID < _textLines.size(); ++lineID) {
|
||||
Common::String currentLine = _textLines[lineID];
|
||||
currentLine.trim();
|
||||
|
||||
uint horizontalOffset = 0;
|
||||
bool hasHotspot = false;
|
||||
@ -168,12 +165,21 @@ void Textbox::drawTextbox() {
|
||||
currentLine = currentLine.substr(0, currentLine.size() - ARRAYSIZE(_telephoneEndToken) + 1);
|
||||
}
|
||||
|
||||
// Remove hotspot token and mark that we need to calculate the bounds
|
||||
// Assumes a single text line has a single hotspot
|
||||
uint32 hotspotPos = currentLine.find(_hotspotToken);
|
||||
if (hotspotPos != String::npos) {
|
||||
// Remove hotspot tokens and mark that we need to calculate the bounds
|
||||
// A single text line should only have one hotspot, but there's at least
|
||||
// one malformed line in TVD that breaks this
|
||||
uint32 hotspotPos, lastHotspotPos;
|
||||
while (hotspotPos = currentLine.find(_hotspotToken), hotspotPos != String::npos) {
|
||||
currentLine.erase(hotspotPos, ARRAYSIZE(_hotspotToken) - 1);
|
||||
|
||||
if (hasHotspot) {
|
||||
// Replace the second hotspot token with a newline to copy the original behavior
|
||||
// Maybe consider fixing the glitch instead of replicating it??
|
||||
currentLine.insertChar('\n', lastHotspotPos);
|
||||
}
|
||||
|
||||
hasHotspot = true;
|
||||
lastHotspotPos = hotspotPos;
|
||||
}
|
||||
|
||||
// Subdivide current line into sublines for proper handling of the tab and color tokens
|
||||
@ -280,6 +286,14 @@ void Textbox::assembleTextLine(char *rawCaption, Common::String &output, uint si
|
||||
i += newBit.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Fix spaces at the end of the string in nancy1
|
||||
output.trim();
|
||||
|
||||
// Fix at least one broken string in TVD
|
||||
if (output.hasSuffix(">>")) {
|
||||
output.deleteLastChar();
|
||||
}
|
||||
}
|
||||
|
||||
void Textbox::onScrollbarMove() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user