MADS: Implementing user interface text display methods

This commit is contained in:
Paul Gilbert 2014-03-16 23:40:21 -04:00
parent e24a4b7b16
commit acba8f9254
15 changed files with 235 additions and 117 deletions

View File

@ -270,7 +270,7 @@ void TextDialog::draw() {
++yp;
_vm->_font->writeString(&_vm->_screen, _lines[lineNum],
Common::Point(xp, yp), 0, 1);
Common::Point(xp, yp), 1);
if (_lineXp[lineNum] & 0x80) {
// Draw an underline under the text

View File

@ -28,14 +28,26 @@
namespace MADS {
Font::Font(MADSEngine *vm) : _vm(vm) {
MADSEngine *Font::_vm = nullptr;
uint8 Font::_fontColors[4];
void Font::init(MADSEngine *vm) {
_vm = vm;
_fontColors[0] = 0xFF;
_fontColors[1] = 0xF;
_fontColors[2] = 7;
_fontColors[3] = 8;
}
Font *Font::getFont(const Common::String &fontName) {
Font *font = new Font();
font->setFont(fontName);
return font;
}
Font::Font() {
_sysFont = true;
/*
_fontColors[0] = _vm->_palette->BLACK;
_fontColors[1] = _vm->_palette->WHITE;
_fontColors[2] = _vm->_palette->BLACK;
_fontColors[3] = _vm->_palette->DARK_GRAY;
*/
}
Font::~Font() {
@ -96,18 +108,28 @@ void Font::setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4) {
_fontColors[2] = v3;
}
int Font::write(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width, int spaceWidth, uint8 colors[]) {
/*TODO
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
void Font::setColorMode(int mode) {
switch (mode) {
case 0:
setColors(0xFF, 4, 4, 0);
break;
case 1:
setColors(0xFF, 5, 5, 0);
break;
case 2:
setColors(0xFF, 6, 6, 0);
break;
default:
break;
}
*/
}
int Font::writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth, int width) {
if (width > 0)
width = MIN(surface->getWidth(), pt.x + width);
width = MIN((int)surface->w, pt.x + width);
else
width = surface->getWidth();
width = surface->w - pt.x;
int x = pt.x + 1;
int y = pt.y + 1;
@ -154,16 +176,16 @@ int Font::write(MSurface *surface, const Common::String &msg, const Common::Poin
for (int i = 0; i < height; i++) {
for (int j = 0; j < bpp; j++) {
if (*charData & 0xc0)
*destPtr = colors[(*charData & 0xc0) >> 6];
*destPtr = _fontColors[(*charData & 0xc0) >> 6];
destPtr++;
if (*charData & 0x30)
*destPtr = colors[(*charData & 0x30) >> 4];
*destPtr = _fontColors[(*charData & 0x30) >> 4];
destPtr++;
if (*charData & 0x0C)
*destPtr = colors[(*charData & 0x0C) >> 2];
*destPtr = _fontColors[(*charData & 0x0C) >> 2];
destPtr++;
if (*charData & 0x03)
*destPtr = colors[*charData & 0x03];
*destPtr = _fontColors[*charData & 0x03];
destPtr++;
charData++;
}
@ -205,10 +227,4 @@ int Font::getBpp(int charWidth) {
return 1;
}
Font *Font::getFont(const Common::String &fontName) {
Font *font = new Font(_vm);
font->setFont(fontName);
return font;
}
} // End of namespace MADS

View File

@ -41,38 +41,42 @@ namespace MADS {
class MADSEngine;
class Font {
protected:
MADSEngine *_vm;
private:
static uint8 _fontColors[4];
static MADSEngine *_vm;
public:
/**
* Initialise the font system
*/
static void init(MADSEngine *vm);
/**
* Returns a new Font instance using the specified font name
*/
static Font *getFont(const Common::String &fontName);
protected:
uint8 _maxWidth, _maxHeight;
uint8 *_charWidths;
uint16 *_charOffs;
uint8 *_charData;
bool _sysFont;
Common::String _filename;
uint8 _fontColors[4];
int getBpp(int charWidth);
public:
Font(MADSEngine *vm);
Font();
virtual ~Font();
void setFont(const Common::String &filename);
void setColor(uint8 color);
void setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4);
void setColorMode(int mode);
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[]);
int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width = 0, int spaceWidth = -1) {
return write(surface, msg, pt, width, spaceWidth, _fontColors);
}
/**
* Returns a new Font instance using the specified font name
*/
Font *getFont(const Common::String &fontName);
int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth = 0, int width = 0);
};
} // End of namespace MADS

View File

@ -165,7 +165,7 @@ void Game::sectionLoop() {
_scene._screenObjects._v8333C = true;
_scene._screenObjects._v832EC = 0;
_scene._screenObjects._yp = 0;
_scene._userInterface._scrollerY = 0;
_v3 = -1;
_scene._sceneLogic->setup();
@ -196,9 +196,9 @@ void Game::sectionLoop() {
}
_vm->_events->initVars();
_scene._v1A = true;
_scene._v1C = -1;
_objectHiliteVocabIdx = -1;
_scene._userInterface._v1A = -1;
_scene._userInterface._v1C = -1;
_scene._userInterface._v1E = -1;
_scene._action.clear();
_player.turnToDestFacing();
@ -297,7 +297,6 @@ void Game::loadResourceSequence(const Common::String prefix, int v) {
void Game::loadQuotes() {
File f("*QUOTES.DAT");
int curPos = 0;
Common::String msg;
while (true) {

View File

@ -129,7 +129,6 @@ public:
uint32 _priorFrameTimer;
Common::String _aaName;
uint32 _ticksExpiry;
int _objectHiliteVocabIdx;
int _exitFlag;
public:
virtual ~Game();

View File

@ -66,6 +66,13 @@ public:
*/
void load();
/**
* Returns the inventory item from the player's inventory
*/
InventoryObject &getItem(int itemIndex) {
return (*this)[_inventoryList[itemIndex]];
}
/**
* Set the associated data? pointer with an inventory object
*/

View File

@ -80,7 +80,8 @@ void MADSEngine::initialise() {
_dialogs = Dialogs::init(this);
_events = new EventsManager(this);
_palette = new Palette(this);
_font = new Font(this);
Font::init(this);
_font = new Font();
_screen.init();
_sound = new SoundManager(this, _mixer);
_game = Game::init(this);

View File

@ -391,7 +391,7 @@ void TextDisplayList::draw(MSurface *s) {
td._font->setColors(0xFF, td._color1, td._color2, 0);
td._font->writeString(s, td._msg,
Common::Point(td._bounds.left, td._bounds.top),
td._bounds.width(), td._spacing);
td._spacing, td._bounds.width());
}
}
}

View File

@ -58,8 +58,9 @@ void MSurface::setSize(int width, int height) {
void MSurface::setPixels(byte *pData, int horizSize, int vertSize) {
_freeFlag = false;
pixels = pData;
w = horizSize;
w = pitch = horizSize;
h = vertSize;
format.bytesPerPixel = 1;
}
int MSurface::scaleValue(int value, int scale, int err) {

View File

@ -35,14 +35,11 @@ Scene::Scene(MADSEngine *vm): _vm(vm), _action(_vm), _depthSurface(vm),
_priorSceneId = 0;
_nextSceneId = 0;
_currentSceneId = 0;
_vocabBuffer = nullptr;
_sceneLogic = nullptr;
_sceneInfo = nullptr;
_animFlag = false;
_animVal1 = 0;
_depthStyle = 0;
_v1A = 0;
_v1C = 0;
_roomChanged = false;
_reloadSceneFlag = false;
_destFacing = 0;
@ -66,21 +63,14 @@ Scene::Scene(MADSEngine *vm): _vm(vm), _action(_vm), _depthSurface(vm),
}
Scene::~Scene() {
delete[] _vocabBuffer;
delete _sceneLogic;
delete _sceneInfo;
}
void Scene::clearVocab() {
freeVocab();
_activeVocabs.clear();
}
void Scene::freeVocab() {
delete[] _vocabBuffer;
_vocabBuffer = nullptr;
}
void Scene::addActiveVocab(int vocabId) {
if (activeVocabIndexOf(vocabId) == -1) {
assert(_activeVocabs.size() < 200);
@ -222,21 +212,22 @@ void Scene::loadVocab() {
}
void Scene::loadVocabStrings() {
freeVocab();
_vocabStrings.clear();
File f("*VOCAB.DAT");
Common::String msg;
char *textStrings = new char[f.size()];
f.read(textStrings, f.size());
for (;;) {
char c = (char)f.readByte();
if (f.eos()) break;
for (uint strIndex = 0; strIndex < _activeVocabs.size(); ++strIndex) {
const char *s = textStrings;
for (int vocabIndex = 0; vocabIndex < _activeVocabs[strIndex]; ++vocabIndex)
s += strlen(s) + 1;
_vocabStrings.push_back(s);
if (c == '\0') {
_vocabStrings.push_back(msg);
msg = "";
} else {
msg += c;
}
}
delete[] textStrings;
f.close();
}

View File

@ -41,11 +41,6 @@ namespace MADS {
class Scene {
private:
/**
* Free the voculary list buffer
*/
void freeVocab();
/**
* Return the index of a given Vocab in the active vocab list
*/
@ -88,7 +83,6 @@ public:
SpriteSets _sprites;
int _spritesIndex;
DynamicHotspots _dynamicHotspots;
byte *_vocabBuffer;
Common::Array<int> _activeVocabs;
SequenceList _sequences;
KernelMessages _kernelMessages;
@ -118,8 +112,6 @@ public:
int _scaleRange;
int _interfaceY;
int _spritesCount;
bool _v1A;
int _v1C;
MADSAction _action;
bool _roomChanged;
bool _reloadSceneFlag;
@ -204,6 +196,11 @@ public:
*/
void loadAnimation(const Common::String &resName, int abortTimers = 0);
/**
* Returns a vocab entry
*/
Common::String getVocab(int vocabId) { return _vocabStrings[vocabId]; }
/**
* Clear the data for the scene
*/

View File

@ -41,7 +41,6 @@ ScreenObject::ScreenObject() {
ScreenObjects::ScreenObjects(MADSEngine *vm): _vm(vm) {
_v8333C = false;
_v832EC = 0;
_yp = 0;
_v7FECA = 0;
_v7FED6 = 0;
_v8332A = 0;
@ -68,11 +67,11 @@ void ScreenObjects::check(bool scanFlag) {
if (!_vm->_events->_mouseButtons || _v832EC)
_v7FECA = false;
if ((_vm->_events->_vD6 || _v8332A || _yp || _v8333C) && scanFlag) {
scene._userInterface._selectedObject = scanBackwards(_vm->_events->currentPos(), LAYER_GUI);
if (scene._userInterface._selectedObject > 0) {
_category = (ScrCategory)((*this)[scene._userInterface._selectedObject - 1]._category & 7);
_objectIndex = (*this)[scene._userInterface._selectedObject - 1]._descId;
if ((_vm->_events->_vD6 || _v8332A || _vm->_game->_scene._userInterface._scrollerY || _v8333C) && scanFlag) {
scene._userInterface._selectedInvIndex = scanBackwards(_vm->_events->currentPos(), LAYER_GUI);
if (scene._userInterface._selectedInvIndex > 0) {
_category = (ScrCategory)((*this)[scene._userInterface._selectedInvIndex - 1]._category & 7);
_objectIndex = (*this)[scene._userInterface._selectedInvIndex - 1]._descId;
}
// Handling for easy mouse
@ -80,7 +79,7 @@ void ScreenObjects::check(bool scanFlag) {
if (_vm->_easyMouse && !_vm->_events->_vD4 && category != _category
&& scene._userInterface._category != CAT_NONE) {
_released = true;
if (category >= CAT_ACTION && category <= CAT_6) {
if (category >= CAT_ACTION && category <= CAT_TALK_ENTRY) {
scene._userInterface.elementHighlighted();
}
}
@ -90,7 +89,7 @@ void ScreenObjects::check(bool scanFlag) {
scene._userInterface._category = _category;
if (!_vm->_events->_mouseButtons || _vm->_easyMouse) {
if (category >= CAT_ACTION && category <= CAT_6) {
if (category >= CAT_ACTION && category <= CAT_TALK_ENTRY) {
scene._userInterface.elementHighlighted();
}
}
@ -106,7 +105,7 @@ void ScreenObjects::check(bool scanFlag) {
scene._userInterface._category = CAT_NONE;
}
if (_vm->_events->_mouseButtons || _vm->_easyMouse || _yp)
if (_vm->_events->_mouseButtons || _vm->_easyMouse || scene._userInterface._scrollerY)
proc1();
if (_vm->_events->_mouseButtons || _vm->_easyMouse)

View File

@ -87,7 +87,6 @@ public:
int _v7FECA;
int _v7FED6;
int _v8332A;
int _yp;
int _v8333C;
int _selectedObject;
ScrCategory _category;

View File

@ -41,7 +41,13 @@ UserInterface::UserInterface(MADSEngine *vm) : _vm(vm) {
_screenObjectsCount = 0;
_inventoryTopIndex = 0;
_objectY = 0;
_selectedObject = -1;
_selectedInvIndex = -1;
_selectedActionIndex = -1;
_selectedItemVocabIdx = -1;
_scrollerY = 0;
_v1A = -1;
_v1C = -1;
_v1E = -1;
byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
@ -96,9 +102,9 @@ void UserInterface::setup(int id) {
scene._imageInterEntries.clear();
scene._imageInterEntries.add(-2, 0xff);
_vm->_game->_ticksExpiry = _vm->_events->getFrameCounter();
scene._v1A = true;
_vm->_game->_objectHiliteVocabIdx = -1;
scene._v1C = -1;
_v1A = -1;
_v1E = -1;
_v1C = -1;
// Make a copy of the surface
copyTo(&_surface);
@ -123,30 +129,118 @@ void UserInterface::drawTextElements() {
} else {
// Draw the actions
drawActions();
drawInventoryList();
drawItemVocabList();
// drawInventoryList();
// drawItemVocabList();
}
}
void UserInterface::drawActions() {
for (int idx = 0; idx < 10; ++idx) {
drawVocab(CAT_ACTION, idx);
writeVocab(CAT_ACTION, idx);
}
}
void UserInterface::drawInventoryList() {
int endIndex = MIN((int)_vm->_game->_objects._inventoryList.size(), _inventoryTopIndex + 5);
for (int idx = _inventoryTopIndex; idx < endIndex; ++idx) {
drawVocab(CAT_INV_LIST, idx);
writeVocab(CAT_INV_LIST, idx);
}
}
void UserInterface::drawItemVocabList() {
if (_selectedInvIndex >= 0) {
InventoryObject &io = _vm->_game->_objects[
_vm->_game->_objects._inventoryList[_selectedInvIndex]];
for (int idx = 0; idx < io._vocabCount; ++idx) {
writeVocab(CAT_INV_VOCAB, idx);
}
}
}
void UserInterface::drawVocab(ScrCategory category, int id) {
void UserInterface::drawScrolller() {
if (_scrollerY > 0)
writeVocab(CAT_INV_SCROLLER, _scrollerY);
writeVocab(CAT_INV_SCROLLER, 4);
}
void UserInterface::writeVocab(ScrCategory category, int id) {
Common::Rect bounds;
if (!getBounds(category, id, bounds))
return;
Scene &scene = _vm->_game->_scene;
Font *font = nullptr;
int vocabId;
Common::String vocabStr;
switch (category) {
case CAT_ACTION:
font = _vm->_font->getFont(FONT_INTERFACE);
vocabId = scene._verbList[id]._id;
if (_v1A) {
_vm->_font->setColorMode(1);
} else {
_vm->_font->setColorMode(id == _selectedActionIndex ? 2 : 0);
}
vocabStr = scene.getVocab(vocabId);
vocabStr.toUppercase();
font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
break;
case CAT_INV_LIST:
font = _vm->_font->getFont(FONT_INTERFACE);
vocabId = _vm->_game->_objects.getItem(id)._descId;
if (_v1C == id) {
_vm->_font->setColorMode(1);
} else {
_vm->_font->setColorMode(id == _selectedInvIndex ? 2 : 0);
vocabStr = scene.getVocab(vocabId);
vocabStr.toUppercase();
font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
break;
}
break;
case CAT_TALK_ENTRY:
error("TODO: CAT_TALK_ENTRY");
case CAT_INV_SCROLLER:
font = _vm->_font->getFont(FONT_MISC);
switch (id) {
case 1:
vocabStr = "a";
break;
case 2:
vocabStr = "b";
break;
case 3:
vocabStr = "d";
break;
case 4:
vocabStr = "c";
break;
default:
break;
}
font->setColorMode((id == 4) || (_scrollerY == 3) ? 1 : 0);
font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
break;
default:
font = _vm->_font->getFont(FONT_INTERFACE);
vocabId = _vm->_game->_objects.getItem(_selectedInvIndex)._vocabList[id]._vocabId;
if (_v1E == id) {
_vm->_font->setColorMode(1);
} else {
_vm->_font->setColorMode(id == _selectedInvIndex ? 2 : 0);
vocabStr = scene.getVocab(vocabId);
vocabStr.toUppercase();
font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
break;
}
break;
}
}
void UserInterface::setBounds(const Common::Rect &r) {
@ -204,23 +298,23 @@ void UserInterface::loadElements() {
}
if (scene._screenObjects._v832EC == 1) {
// setup areas for talk entries
for (int idx = 0; idx < 5; ++idx) {
getBounds(CAT_6, idx, bounds);
getBounds(CAT_TALK_ENTRY, idx, bounds);
moveRect(bounds);
scene._screenObjects.add(bounds, LAYER_GUI, CAT_6, idx);
scene._screenObjects.add(bounds, LAYER_GUI, CAT_TALK_ENTRY, idx);
}
}
}
bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds) {
Common::Rect result;
int heightMultiplier, widthMultiplier;
int leftStart, yOffset, widthAmt;
switch (category) {
case CAT_ACTION:
heightMultiplier = v / 5;
heightMultiplier = v % 5;
widthMultiplier = v / 5;
leftStart = 2;
yOffset = 3;
@ -238,7 +332,7 @@ bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds)
widthAmt = 69;
break;
case CAT_6:
case CAT_TALK_ENTRY:
heightMultiplier = v;
widthMultiplier = 0;
leftStart = 2;
@ -263,32 +357,32 @@ bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds)
break;
}
result.left = (widthMultiplier > 0) ? widthMultiplier * widthAmt + leftStart : leftStart;
result.setWidth(widthAmt);
result.top = heightMultiplier * 3 + yOffset;
result.setHeight(8);
bounds.left = (widthMultiplier > 0) ? widthMultiplier * widthAmt + leftStart : leftStart;
bounds.setWidth(widthAmt);
bounds.top = heightMultiplier * 8 + yOffset;
bounds.setHeight(8);
if (category == CAT_INV_SCROLLER) {
switch (v) {
case 1:
// Arrow up
result.top = 4;
result.setHeight(7);
bounds.top = 4;
bounds.setHeight(7);
break;
case 2:
// Arrow down
result.top = 35;
result.setHeight(7);
bounds.top = 35;
bounds.setHeight(7);
break;
case 3:
// Scroller
result.top = 12;
result.setHeight(22);
bounds.top = 12;
bounds.setHeight(22);
break;
case 4:
// Thumb
result.top = _objectY + 14;
result.setHeight(1);
bounds.top = _objectY + 14;
bounds.setHeight(1);
break;
default:
break;

View File

@ -32,7 +32,7 @@ namespace MADS {
enum ScrCategory {
CAT_NONE = 0, CAT_ACTION = 1, CAT_INV_LIST = 2, CAT_INV_VOCAB = 3,
CAT_HOTSPOT = 4, CAT_INV_ANIM = 5, CAT_6 = 6, CAT_INV_SCROLLER = 7,
CAT_HOTSPOT = 4, CAT_INV_ANIM = 5, CAT_TALK_ENTRY = 6, CAT_INV_SCROLLER = 7,
CAT_12 = 12
};
@ -76,9 +76,14 @@ private:
void drawItemVocabList();
/**
* Draw a vocab text entry
* Draw the inventory scroller
*/
void drawVocab(ScrCategory category, int id);
void drawScrolller();
/**
* Draw a UI textual element
*/
void writeVocab(ScrCategory category, int id);
public:
ScrCategory _category;
int _screenObjectsCount;
@ -87,7 +92,13 @@ public:
MSurface _surface;
int _inventoryTopIndex;
int _objectY;
int _selectedObject;
int _selectedInvIndex;
int _selectedActionIndex;
int _selectedItemVocabIdx;
int _scrollerY;
int _v1A;
int _v1C;
int _v1E;
public:
/**
* Constructor