SHERLOCK: Implemented more support methods for RT map
This commit is contained in:
parent
dd1781a3f2
commit
6780c63e53
5 changed files with 305 additions and 14 deletions
|
@ -82,7 +82,7 @@ public:
|
||||||
*/
|
*/
|
||||||
int fontHeight() const { return _fontHeight; }
|
int fontHeight() const { return _fontHeight; }
|
||||||
|
|
||||||
|
int fontNumber() const { return _fontNumber; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace Sherlock {
|
||||||
#define BG_GREYSCALE_RANGE_END 229
|
#define BG_GREYSCALE_RANGE_END 229
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
BLACK = 0,
|
||||||
INFO_BLACK = 1,
|
INFO_BLACK = 1,
|
||||||
INFO_FOREGROUND = 11,
|
INFO_FOREGROUND = 11,
|
||||||
INFO_BACKGROUND = 1,
|
INFO_BACKGROUND = 1,
|
||||||
|
@ -52,7 +53,8 @@ enum {
|
||||||
BUTTON_BOTTOM = 248,
|
BUTTON_BOTTOM = 248,
|
||||||
TALK_FOREGROUND = 12,
|
TALK_FOREGROUND = 12,
|
||||||
TALK_NULL = 16,
|
TALK_NULL = 16,
|
||||||
PEN_COLOR = 250
|
PEN_COLOR = 250,
|
||||||
|
MAP_NAME_COLOR = 131
|
||||||
};
|
};
|
||||||
|
|
||||||
class SherlockEngine;
|
class SherlockEngine;
|
||||||
|
@ -77,11 +79,6 @@ private:
|
||||||
* Returns the union of two dirty area rectangles
|
* Returns the union of two dirty area rectangles
|
||||||
*/
|
*/
|
||||||
bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
|
bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws the given string into the back buffer using the images stored in _font
|
|
||||||
*/
|
|
||||||
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Adds a rectangle to the list of modified areas of the screen during the
|
* Adds a rectangle to the list of modified areas of the screen during the
|
||||||
|
@ -244,13 +241,17 @@ public:
|
||||||
*/
|
*/
|
||||||
Common::Rect getDisplayBounds();
|
Common::Rect getDisplayBounds();
|
||||||
|
|
||||||
int fontNumber() const { return _fontNumber; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronize the data for a savegame
|
* Synchronize the data for a savegame
|
||||||
*/
|
*/
|
||||||
void synchronize(Serializer &s);
|
void synchronize(Serializer &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the given string into the back buffer using the images stored in _font
|
||||||
|
*/
|
||||||
|
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
|
||||||
|
|
||||||
|
|
||||||
// Rose Tattoo specific methods
|
// Rose Tattoo specific methods
|
||||||
void initPaletteFade(int bytesToRead);
|
void initPaletteFade(int bytesToRead);
|
||||||
|
|
||||||
|
|
|
@ -71,11 +71,6 @@ protected:
|
||||||
Graphics::Surface _surface;
|
Graphics::Surface _surface;
|
||||||
|
|
||||||
virtual void addDirtyRect(const Common::Rect &r) {}
|
virtual void addDirtyRect(const Common::Rect &r) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws the given string into the back buffer using the images stored in _font
|
|
||||||
*/
|
|
||||||
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
|
|
||||||
public:
|
public:
|
||||||
Surface(uint16 width, uint16 height, Common::Platform platform);
|
Surface(uint16 width, uint16 height, Common::Platform platform);
|
||||||
Surface();
|
Surface();
|
||||||
|
@ -164,6 +159,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void setPixels(byte *pixels, int width, int height);
|
void setPixels(byte *pixels, int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the given string into the back buffer using the images stored in _font
|
||||||
|
*/
|
||||||
|
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
|
||||||
|
|
||||||
inline uint16 w() const { return _surface.w; }
|
inline uint16 w() const { return _surface.w; }
|
||||||
inline uint16 h() const { return _surface.h; }
|
inline uint16 h() const { return _surface.h; }
|
||||||
inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); }
|
inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); }
|
||||||
|
|
|
@ -35,6 +35,10 @@ void MapEntry::clear() {
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
TattooMap::TattooMap(SherlockEngine *vm) : Map(vm) {
|
TattooMap::TattooMap(SherlockEngine *vm) : Map(vm) {
|
||||||
|
_iconImages = nullptr;
|
||||||
|
_bgFound = _oldBgFound = 0;
|
||||||
|
_textBuffer = nullptr;
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +108,264 @@ void TattooMap::loadData() {
|
||||||
} while (stream->pos() < stream->size());
|
} while (stream->pos() < stream->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TattooMap::drwaMapIcons() {
|
||||||
|
Screen &screen = *_vm->_screen;
|
||||||
|
|
||||||
|
for (uint idx = 0; idx < _data.size(); ++idx) {
|
||||||
|
if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
|
||||||
|
MapEntry &mapEntry = _data[idx];
|
||||||
|
ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
|
||||||
|
screen._backBuffer1.transBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2,
|
||||||
|
mapEntry.y - img._height / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TattooMap::checkMapNames(bool slamIt) {
|
||||||
|
Events &events = *_vm->_events;
|
||||||
|
Screen &screen = *_vm->_screen;
|
||||||
|
Common::Point mousePos = events.mousePos();
|
||||||
|
int dif = 10000;
|
||||||
|
|
||||||
|
// See if the mouse is pointing at any of the map locations
|
||||||
|
_bgFound = -1;
|
||||||
|
|
||||||
|
for (uint idx = 0; idx < _data.size(); ++idx) {
|
||||||
|
if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
|
||||||
|
MapEntry &mapEntry = _data[idx];
|
||||||
|
ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
|
||||||
|
Common::Rect r(mapEntry.x - img._width / 2, mapEntry.y - img._height / 2,
|
||||||
|
mapEntry.x + img._width / 2, mapEntry.y + img._height / 2);
|
||||||
|
|
||||||
|
if (r.contains(mousePos)) {
|
||||||
|
_bgFound = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the previous bounds that were drawn
|
||||||
|
_oldTextBounds = _textBounds;
|
||||||
|
|
||||||
|
// See if thay are pointing at a different location and we need to change the display
|
||||||
|
if (_bgFound != _oldBgFound || (_bgFound != -1 && _textBuffer == nullptr)) {
|
||||||
|
// See if there is a new image to be displayed
|
||||||
|
if (_bgFound != -1 && (_bgFound != _oldBgFound || _textBuffer == nullptr)) {
|
||||||
|
const Common::String &desc = _data[_bgFound]._description;
|
||||||
|
const char *space = nullptr;
|
||||||
|
int width = screen.stringWidth(desc) + 2;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
// See if we need to split it into two lines
|
||||||
|
if (width > 150) {
|
||||||
|
const char *s = desc.c_str();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// Move to end of next word
|
||||||
|
s = strchr(s, ' ');
|
||||||
|
|
||||||
|
if (s == nullptr) {
|
||||||
|
// Reached end of description
|
||||||
|
if (space == nullptr) {
|
||||||
|
height = screen.stringHeight(desc) + 2;
|
||||||
|
} else {
|
||||||
|
Common::String line1(desc.c_str(), space);
|
||||||
|
Common::String line2(space + 1);
|
||||||
|
|
||||||
|
height = screen.stringHeight(line1) + screen.stringHeight(line2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Reached space separating words within the description
|
||||||
|
// Get width before and after word
|
||||||
|
int width1 = screen.stringWidth(Common::String(desc.c_str(), s));
|
||||||
|
int width2 = screen.stringWidth(Common::String(s + 1));
|
||||||
|
|
||||||
|
if (ABS(width1 - width2) < dif) {
|
||||||
|
space = s;
|
||||||
|
dif = ABS(width1 - width2);
|
||||||
|
width = MAX(width1, width) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
height = screen.stringHeight(desc) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete any previous saved area
|
||||||
|
delete _textBuffer;
|
||||||
|
|
||||||
|
// Allocate a new surface
|
||||||
|
_textBuffer = new Surface(width, height, _vm->getPlatform());
|
||||||
|
|
||||||
|
_textBuffer->fillRect(Common::Rect(0, 0, width, height), 255);
|
||||||
|
if (space == nullptr) {
|
||||||
|
// The whole text can be drawn on a single line
|
||||||
|
_textBuffer->writeString(desc, Common::Point(0, 0), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(1, 0), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(2, 0), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(0, 1), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(2, 1), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(0, 2), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(1, 2), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(2, 2), BLACK);
|
||||||
|
_textBuffer->writeString(desc, Common::Point(1, 1), MAP_NAME_COLOR);
|
||||||
|
} else {
|
||||||
|
// The text needs to be split up over two lines
|
||||||
|
Common::String line1(desc.c_str(), space);
|
||||||
|
Common::String line2(space + 1);
|
||||||
|
int xp, yp;
|
||||||
|
|
||||||
|
// Draw the first line
|
||||||
|
xp = (width - screen.stringWidth(desc)) / 2;
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 0, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 1, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 2, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 0, 1), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 2, 1), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 0, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 1, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 2, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line1, Common::Point(xp + 1, 1), MAP_NAME_COLOR);
|
||||||
|
|
||||||
|
yp = screen.stringHeight(line2);
|
||||||
|
xp = (width - screen.stringWidth(line2)) / 2;
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 0, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 1, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 2, 0), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 0, 1), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 2, 1), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 0, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 1, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 2, 2), BLACK);
|
||||||
|
_textBuffer->writeString(line2, Common::Point(xp + 1, 1), MAP_NAME_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the position of the Text Tag
|
||||||
|
// TODO: take current scroll into account
|
||||||
|
int xp = (mousePos.x - width / 2);
|
||||||
|
int yp = (mousePos.y - height / 2);
|
||||||
|
|
||||||
|
_textBounds = Common::Rect(xp, yp, xp + width, yp + height);
|
||||||
|
} else if (_bgFound == -1 && _oldBgFound != -1) {
|
||||||
|
// We need to clear a currently displayed name
|
||||||
|
delete _textBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
_oldBgFound = _bgFound;
|
||||||
|
} else {
|
||||||
|
// Set the new text position
|
||||||
|
// TODO: take current scroll into account
|
||||||
|
int xp = (mousePos.x - _textBounds.width() / 2);
|
||||||
|
int yp = (mousePos.y - _textBounds.height() / 2);
|
||||||
|
|
||||||
|
_textBounds.moveTo(xp, yp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text tag was displayed, restore the graphics underneath it
|
||||||
|
if (_oldTextBounds.width() > 0)
|
||||||
|
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTextBounds.left, _oldTextBounds.top), _oldTextBounds);
|
||||||
|
|
||||||
|
// See if we need to draw a Text Tag floating with the cursor
|
||||||
|
if (_textBuffer != nullptr)
|
||||||
|
screen.transBlitFrom(*_textBuffer, Common::Point(_textBounds.left, _textBounds.top));
|
||||||
|
|
||||||
|
// See if we need to flush the areas associated with the text
|
||||||
|
if (_oldTextBounds.width() > 0) {
|
||||||
|
if (slamIt)
|
||||||
|
// TODO: Take into account scroll
|
||||||
|
screen.slamRect(_oldTextBounds);
|
||||||
|
|
||||||
|
// If there's no text to display, reset the tag and old tag bounds
|
||||||
|
if (_textBuffer == nullptr) {
|
||||||
|
_textBounds.left = _textBounds.top = _textBounds.right = _textBounds.bottom = 0;
|
||||||
|
_oldTextBounds.left = _oldTextBounds.top = _oldTextBounds.right = _oldTextBounds.bottom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's a text to display, then copy the drawn area to the screen
|
||||||
|
if (_textBuffer != nullptr && slamIt)
|
||||||
|
// TODO: Handle scroll
|
||||||
|
screen.slamRect(_textBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TattooMap::restoreArea(const Common::Rect &bounds) {
|
||||||
|
Screen &screen = *_vm->_screen;
|
||||||
|
|
||||||
|
Common::Rect r = bounds;
|
||||||
|
r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h()));
|
||||||
|
|
||||||
|
if (!r.isEmpty())
|
||||||
|
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TattooMap::showCloseUp(int closeUpNum) {
|
||||||
|
Screen &screen = *_vm->_screen;
|
||||||
|
|
||||||
|
// Get the closeup images
|
||||||
|
Common::String fname = Common::String::format("res%02d.vgs", closeUpNum + 1);
|
||||||
|
ImageFile pic(fname);
|
||||||
|
|
||||||
|
Common::Point closeUp(_data[closeUpNum].x * 100, _data[closeUpNum].y * 100);
|
||||||
|
Common::Point delta((SHERLOCK_SCREEN_WIDTH / 2 - closeUp.x / 100) * 100 / CLOSEUP_STEPS,
|
||||||
|
(SHERLOCK_SCREEN_HEIGHT / 2 - closeUp.y / 100) * 100 / CLOSEUP_STEPS);
|
||||||
|
Common::Rect oldBounds(closeUp.x / 100, closeUp.y / 100, closeUp.x / 100 + 1, closeUp.y / 100 + 1);
|
||||||
|
int size = 64;
|
||||||
|
int n = 256;
|
||||||
|
int deltaVal = 512;
|
||||||
|
bool minimize = false;
|
||||||
|
int scaleVal, newSize;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
scaleVal = n;
|
||||||
|
newSize = pic[0].sDrawXSize(n);
|
||||||
|
|
||||||
|
if (newSize > size) {
|
||||||
|
if (minimize)
|
||||||
|
deltaVal /= 2;
|
||||||
|
n += deltaVal;
|
||||||
|
} else {
|
||||||
|
minimize = true;
|
||||||
|
deltaVal /= 2;
|
||||||
|
n -= deltaVal;
|
||||||
|
if (n < 1)
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
} while (deltaVal && size != newSize);
|
||||||
|
|
||||||
|
int deltaScale = (SCALE_THRESHOLD - scaleVal) / CLOSEUP_STEPS;
|
||||||
|
|
||||||
|
for (int step = 0; step < CLOSEUP_STEPS; ++step) {
|
||||||
|
Common::Point picSize(pic[0].sDrawXSize(scaleVal), pic[0].sDrawYSize(scaleVal));
|
||||||
|
Common::Point pt(closeUp.x / 100 - picSize.x, closeUp.y / 100 - picSize.y);
|
||||||
|
|
||||||
|
restoreArea(oldBounds);
|
||||||
|
screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal);
|
||||||
|
|
||||||
|
// TODO: handle scrolling
|
||||||
|
screen.slamRect(_oldTextBounds);
|
||||||
|
screen.slamArea(pt.x, pt.y, picSize.x, picSize.y);
|
||||||
|
|
||||||
|
oldBounds = Common::Rect(pt.x, pt.y, pt.x + picSize.x + 1, pt.y + picSize.y + 1);
|
||||||
|
closeUp += delta;
|
||||||
|
scaleVal += deltaScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle final drawing of closeup
|
||||||
|
// TODO: Handle scrolling
|
||||||
|
Common::Rect r(SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2, SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2,
|
||||||
|
SHERLOCK_SCREEN_WIDTH / 2 + pic[0]._width / 2 + pic[0]._width,
|
||||||
|
SHERLOCK_SCREEN_HEIGHT / 2 + pic[0]._height / 2 + pic[0]._height);
|
||||||
|
|
||||||
|
restoreArea(oldBounds);
|
||||||
|
screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top));
|
||||||
|
screen.slamRect(oldBounds);
|
||||||
|
screen.slamRect(r);
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Tattoo
|
} // End of namespace Tattoo
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
#include "sherlock/map.h"
|
#include "sherlock/map.h"
|
||||||
|
#include "sherlock/resources.h"
|
||||||
|
#include "sherlock/surface.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
|
@ -32,6 +34,8 @@ class SherlockEngine;
|
||||||
|
|
||||||
namespace Tattoo {
|
namespace Tattoo {
|
||||||
|
|
||||||
|
#define CLOSEUP_STEPS 30
|
||||||
|
|
||||||
struct MapEntry : Common::Point {
|
struct MapEntry : Common::Point {
|
||||||
int _iconNum;
|
int _iconNum;
|
||||||
Common::String _description;
|
Common::String _description;
|
||||||
|
@ -44,11 +48,35 @@ struct MapEntry : Common::Point {
|
||||||
class TattooMap : public Map {
|
class TattooMap : public Map {
|
||||||
private:
|
private:
|
||||||
Common::Array<MapEntry> _data;
|
Common::Array<MapEntry> _data;
|
||||||
|
ImageFile *_iconImages;
|
||||||
|
int _bgFound, _oldBgFound;
|
||||||
|
Surface *_textBuffer;
|
||||||
|
Common::Rect _textBounds, _oldTextBounds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load data needed for the map
|
* Load data needed for the map
|
||||||
*/
|
*/
|
||||||
void loadData();
|
void loadData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws all available location icons onto the back buffer
|
||||||
|
*/
|
||||||
|
void drwaMapIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the location names of whatever the mouse moves over on the map
|
||||||
|
*/
|
||||||
|
void checkMapNames(bool slamIt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores an area of the map background
|
||||||
|
*/
|
||||||
|
void restoreArea(const Common::Rect &bounds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will load a specified close up and zoom it up to the middle of the screen
|
||||||
|
*/
|
||||||
|
void showCloseUp(int closeUpNum);
|
||||||
public:
|
public:
|
||||||
TattooMap(SherlockEngine *vm);
|
TattooMap(SherlockEngine *vm);
|
||||||
virtual ~TattooMap() {}
|
virtual ~TattooMap() {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue