2014-02-18 23:43:06 -05:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/scummsys.h"
|
|
|
|
#include "mads/mads.h"
|
2014-03-15 18:43:39 -04:00
|
|
|
#include "mads/compression.h"
|
2014-02-18 23:43:06 -05:00
|
|
|
#include "mads/user_interface.h"
|
|
|
|
|
|
|
|
namespace MADS {
|
|
|
|
|
2014-03-15 18:43:39 -04:00
|
|
|
void SceneNode::load(Common::SeekableReadStream *f) {
|
|
|
|
_walkPos.x = f->readSint16LE();
|
|
|
|
_walkPos.y = f->readSint16LE();
|
|
|
|
for (int i = 0; i < MAX_ROUTE_NODES; ++i)
|
|
|
|
_indexes[i] = f->readUint16LE();
|
2014-02-18 23:43:06 -05:00
|
|
|
}
|
|
|
|
|
2014-03-15 18:43:39 -04:00
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
UserInterface::UserInterface(MADSEngine *vm) : _vm(vm) {
|
|
|
|
_category = CAT_NONE;
|
|
|
|
_screenObjectsCount = 0;
|
2014-03-15 20:19:01 -04:00
|
|
|
_inventoryTopIndex = 0;
|
|
|
|
_objectY = 0;
|
2014-03-16 23:40:21 -04:00
|
|
|
_selectedInvIndex = -1;
|
|
|
|
_selectedActionIndex = -1;
|
|
|
|
_selectedItemVocabIdx = -1;
|
|
|
|
_scrollerY = 0;
|
|
|
|
_v1A = -1;
|
|
|
|
_v1C = -1;
|
|
|
|
_v1E = -1;
|
2014-03-15 18:52:44 -04:00
|
|
|
|
2014-03-16 14:53:10 -04:00
|
|
|
byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
|
2014-03-15 18:52:44 -04:00
|
|
|
setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
|
2014-03-15 18:43:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void UserInterface::load(const Common::String &resName) {
|
|
|
|
File f(resName);
|
|
|
|
MadsPack madsPack(&f);
|
|
|
|
|
|
|
|
// Load in the palette
|
|
|
|
Common::SeekableReadStream *palStream = madsPack.getItemStream(0);
|
|
|
|
|
|
|
|
uint32 *gamePalP = &_vm->_palette->_palFlags[0];
|
|
|
|
byte *palP = &_vm->_palette->_mainPalette[0];
|
|
|
|
|
|
|
|
for (int i = 0; i < 16; ++i, gamePalP++, palP += 3) {
|
|
|
|
palP[0] = VGA_COLOR_TRANS(palStream->readByte());
|
|
|
|
palP[1] = VGA_COLOR_TRANS(palStream->readByte());
|
|
|
|
palP[2] = VGA_COLOR_TRANS(palStream->readByte());
|
|
|
|
*gamePalP |= 1;
|
|
|
|
palStream->skip(3);
|
|
|
|
}
|
|
|
|
delete palStream;
|
|
|
|
|
|
|
|
// set the size for the interface
|
|
|
|
Common::SeekableReadStream *pixelsStream = madsPack.getItemStream(1);
|
|
|
|
pixelsStream->read(getData(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT);
|
|
|
|
delete pixelsStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserInterface::setup(int id) {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
if (scene._screenObjects._v832EC != id) {
|
|
|
|
Common::String resName = _vm->_game->_aaName;
|
|
|
|
|
|
|
|
// Strip off any extension
|
|
|
|
const char *p = strchr(resName.c_str(), '.');
|
|
|
|
if (p) {
|
|
|
|
resName = Common::String(resName.c_str(), p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add on suffix if necessary
|
|
|
|
if (id)
|
|
|
|
resName += "A";
|
|
|
|
|
|
|
|
resName += ".INT";
|
|
|
|
load(resName);
|
|
|
|
}
|
|
|
|
scene._screenObjects._v832EC = id;
|
|
|
|
|
|
|
|
scene._imageInterEntries.clear();
|
|
|
|
scene._imageInterEntries.add(-2, 0xff);
|
|
|
|
_vm->_game->_ticksExpiry = _vm->_events->getFrameCounter();
|
2014-03-16 23:40:21 -04:00
|
|
|
_v1A = -1;
|
|
|
|
_v1E = -1;
|
|
|
|
_v1C = -1;
|
2014-03-15 18:43:39 -04:00
|
|
|
|
|
|
|
// Make a copy of the surface
|
|
|
|
copyTo(&_surface);
|
|
|
|
|
|
|
|
if (_vm->_game->_v1 == 5)
|
|
|
|
scene._imageInterEntries.call(0, 0);
|
|
|
|
|
|
|
|
scene._action.clear();
|
2014-03-16 17:50:47 -04:00
|
|
|
drawTextElements();
|
2014-03-15 18:43:39 -04:00
|
|
|
loadElements();
|
|
|
|
scene._dynamicHotspots.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserInterface::elementHighlighted() {
|
|
|
|
warning("TODO: UserInterface::elementHighlighted");
|
|
|
|
}
|
|
|
|
|
2014-03-16 17:50:47 -04:00
|
|
|
void UserInterface::drawTextElements() {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
if (scene._screenObjects._v832EC) {
|
|
|
|
drawTalkList();
|
|
|
|
} else {
|
|
|
|
// Draw the actions
|
|
|
|
drawActions();
|
2014-03-16 23:40:21 -04:00
|
|
|
// drawInventoryList();
|
|
|
|
// drawItemVocabList();
|
2014-03-16 17:50:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserInterface::drawActions() {
|
|
|
|
for (int idx = 0; idx < 10; ++idx) {
|
2014-03-16 23:40:21 -04:00
|
|
|
writeVocab(CAT_ACTION, idx);
|
2014-03-16 17:50:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UserInterface::drawInventoryList() {
|
|
|
|
int endIndex = MIN((int)_vm->_game->_objects._inventoryList.size(), _inventoryTopIndex + 5);
|
|
|
|
for (int idx = _inventoryTopIndex; idx < endIndex; ++idx) {
|
2014-03-16 23:40:21 -04:00
|
|
|
writeVocab(CAT_INV_LIST, idx);
|
2014-03-16 17:50:47 -04:00
|
|
|
}
|
2014-03-15 18:43:39 -04:00
|
|
|
}
|
|
|
|
|
2014-03-16 17:50:47 -04:00
|
|
|
void UserInterface::drawItemVocabList() {
|
2014-03-16 23:40:21 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-16 17:50:47 -04:00
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
void UserInterface::drawScrolller() {
|
|
|
|
if (_scrollerY > 0)
|
|
|
|
writeVocab(CAT_INV_SCROLLER, _scrollerY);
|
|
|
|
writeVocab(CAT_INV_SCROLLER, 4);
|
2014-03-16 17:50:47 -04:00
|
|
|
}
|
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
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);
|
2014-03-16 17:50:47 -04:00
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
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;
|
|
|
|
}
|
2014-03-16 17:50:47 -04:00
|
|
|
}
|
2014-03-15 18:43:39 -04:00
|
|
|
|
|
|
|
void UserInterface::setBounds(const Common::Rect &r) {
|
|
|
|
_bounds = r;
|
2014-02-18 23:43:06 -05:00
|
|
|
}
|
|
|
|
|
2014-03-15 18:43:39 -04:00
|
|
|
void UserInterface::loadElements() {
|
2014-03-15 20:19:01 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
Common::Rect bounds;
|
|
|
|
scene._screenObjects.clear();
|
|
|
|
|
|
|
|
if (!scene._screenObjects._v832EC) {
|
2014-03-15 21:33:15 -04:00
|
|
|
// Set up screen objects for the inventory scroller
|
2014-03-15 20:19:01 -04:00
|
|
|
for (int idx = 1; idx <= 3; ++idx) {
|
|
|
|
getBounds(CAT_INV_SCROLLER, idx, bounds);
|
2014-03-15 21:33:15 -04:00
|
|
|
moveRect(bounds);
|
|
|
|
|
|
|
|
scene._screenObjects.add(bounds, LAYER_GUI, CAT_INV_SCROLLER, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up actions
|
|
|
|
for (int idx = 0; idx < 10; ++idx) {
|
|
|
|
getBounds(CAT_ACTION, idx, bounds);
|
|
|
|
moveRect(bounds);
|
|
|
|
|
|
|
|
scene._screenObjects.add(bounds, LAYER_GUI, CAT_ACTION, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up inventory list
|
|
|
|
for (int idx = 0; idx < 5; ++idx) {
|
|
|
|
getBounds(CAT_INV_LIST, idx, bounds);
|
|
|
|
moveRect(bounds);
|
|
|
|
|
|
|
|
scene._screenObjects.add(bounds, LAYER_GUI, CAT_INV_LIST, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up the inventory vocab list
|
|
|
|
for (int idx = 0; idx < 5; ++idx) {
|
|
|
|
getBounds(CAT_INV_VOCAB, idx, bounds);
|
|
|
|
moveRect(bounds);
|
|
|
|
|
|
|
|
scene._screenObjects.add(bounds, LAYER_GUI, CAT_INV_VOCAB, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up the inventory item picture
|
|
|
|
scene._screenObjects.add(Common::Rect(160, 159, 231, 194), LAYER_GUI,
|
|
|
|
CAT_INV_ANIM, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!scene._screenObjects._v832EC || scene._screenObjects._v832EC == 2) {
|
|
|
|
for (int hotspotIdx = scene._hotspots.size() - 1; hotspotIdx >= 0; --hotspotIdx) {
|
|
|
|
Hotspot &hs = scene._hotspots[hotspotIdx];
|
|
|
|
scene._screenObjects.add(hs._bounds, LAYER_GUI, CAT_HOTSPOT, hotspotIdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scene._screenObjects._v832EC == 1) {
|
2014-03-16 23:40:21 -04:00
|
|
|
// setup areas for talk entries
|
2014-03-15 21:33:15 -04:00
|
|
|
for (int idx = 0; idx < 5; ++idx) {
|
2014-03-16 23:40:21 -04:00
|
|
|
getBounds(CAT_TALK_ENTRY, idx, bounds);
|
2014-03-15 21:33:15 -04:00
|
|
|
moveRect(bounds);
|
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
scene._screenObjects.add(bounds, LAYER_GUI, CAT_TALK_ENTRY, idx);
|
2014-03-15 20:19:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds) {
|
|
|
|
int heightMultiplier, widthMultiplier;
|
|
|
|
int leftStart, yOffset, widthAmt;
|
|
|
|
|
|
|
|
switch (category) {
|
|
|
|
case CAT_ACTION:
|
2014-03-16 23:40:21 -04:00
|
|
|
heightMultiplier = v % 5;
|
2014-03-15 20:19:01 -04:00
|
|
|
widthMultiplier = v / 5;
|
|
|
|
leftStart = 2;
|
|
|
|
yOffset = 3;
|
|
|
|
widthAmt = 32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAT_INV_LIST:
|
|
|
|
if (v < _inventoryTopIndex || v > (_inventoryTopIndex + 5))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
heightMultiplier = v - _inventoryTopIndex;
|
|
|
|
widthMultiplier = 0;
|
|
|
|
leftStart = 90;
|
|
|
|
yOffset = 3;
|
|
|
|
widthAmt = 69;
|
|
|
|
break;
|
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
case CAT_TALK_ENTRY:
|
2014-03-15 20:19:01 -04:00
|
|
|
heightMultiplier = v;
|
|
|
|
widthMultiplier = 0;
|
|
|
|
leftStart = 2;
|
|
|
|
yOffset = 3;
|
|
|
|
widthAmt = 310;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAT_INV_SCROLLER:
|
|
|
|
heightMultiplier = 0;
|
|
|
|
widthMultiplier = 73;
|
|
|
|
yOffset = 0;
|
|
|
|
widthAmt = 9;
|
|
|
|
leftStart = (v != 73) ? 73 : 75;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
heightMultiplier = v;
|
|
|
|
widthMultiplier = 0;
|
|
|
|
leftStart = 240;
|
|
|
|
yOffset = 3;
|
|
|
|
widthAmt = 80;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-16 23:40:21 -04:00
|
|
|
bounds.left = (widthMultiplier > 0) ? widthMultiplier * widthAmt + leftStart : leftStart;
|
|
|
|
bounds.setWidth(widthAmt);
|
|
|
|
bounds.top = heightMultiplier * 8 + yOffset;
|
|
|
|
bounds.setHeight(8);
|
2014-03-15 20:19:01 -04:00
|
|
|
|
|
|
|
if (category == CAT_INV_SCROLLER) {
|
|
|
|
switch (v) {
|
|
|
|
case 1:
|
|
|
|
// Arrow up
|
2014-03-16 23:40:21 -04:00
|
|
|
bounds.top = 4;
|
|
|
|
bounds.setHeight(7);
|
2014-03-15 20:19:01 -04:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// Arrow down
|
2014-03-16 23:40:21 -04:00
|
|
|
bounds.top = 35;
|
|
|
|
bounds.setHeight(7);
|
2014-03-15 20:19:01 -04:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// Scroller
|
2014-03-16 23:40:21 -04:00
|
|
|
bounds.top = 12;
|
|
|
|
bounds.setHeight(22);
|
2014-03-15 20:19:01 -04:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
// Thumb
|
2014-03-16 23:40:21 -04:00
|
|
|
bounds.top = _objectY + 14;
|
|
|
|
bounds.setHeight(1);
|
2014-03-15 20:19:01 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-15 21:33:15 -04:00
|
|
|
void UserInterface::moveRect(Common::Rect &bounds) {
|
2014-03-16 14:53:10 -04:00
|
|
|
bounds.translate(0, MADS_SCENE_HEIGHT);
|
2014-02-18 23:43:06 -05:00
|
|
|
}
|
|
|
|
|
2014-03-16 17:50:47 -04:00
|
|
|
void UserInterface::drawTalkList() {
|
|
|
|
warning("TODO: drawTalkList");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-18 23:43:06 -05:00
|
|
|
} // End of namespace MADS
|