1142 lines
37 KiB
C++
1142 lines
37 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/debug.h"
|
|
#include "common/endian.h"
|
|
#include "common/file.h"
|
|
#include "common/rect.h"
|
|
|
|
#include "audio/mixer.h"
|
|
|
|
#include "graphics/surface.h"
|
|
|
|
#include "dgds/dgds.h"
|
|
#include "dgds/font.h"
|
|
#include "dgds/image.h"
|
|
#include "dgds/includes.h"
|
|
#include "dgds/request.h"
|
|
#include "dgds/resource.h"
|
|
|
|
namespace Dgds {
|
|
|
|
static const byte DragonButtonColors[] = {
|
|
0x73, 0xF0, 0x7B, 0xDF, 0x5F, 0x5F, 0x7E, 0x27, 0x16, 0x73, 0x27, 0x16, 0xDF
|
|
};
|
|
|
|
static const byte DragonSliderColors[] = {
|
|
0x7B, 0x4D, 0xF4, 0x54, 0xDF, 0x74, 0x58
|
|
};
|
|
|
|
static const byte DragonEGAButtonColors[] = {
|
|
0x7, 0x8, 0x7, 0x0, 0xF, 0x7, 0xC, 0x4, 0x0, 0xF, 0xF, 0xC, 0x4
|
|
};
|
|
|
|
static const byte DragonEGASliderColors[] {
|
|
0x7, 0xF, 0x8, 0x7, 0x0, 0x7, 0x7
|
|
};
|
|
|
|
static const byte DragonHeaderTxtColor = 0;
|
|
static const byte DragonHeaderTopColor = 0;
|
|
static const byte DragonHeaderBottomColor = 15;
|
|
static const byte DragonBackgroundColor = 7;
|
|
|
|
static const byte ChinaBackgroundColor = 23;
|
|
static const byte ChinaHeaderTxtColor = 25;
|
|
static const byte ChinaHeaderTopColor = 16;
|
|
static const byte ChinaHeaderBottomColor = 20;
|
|
static const byte ChinaButtonColorsOn[] = {
|
|
0x10, 0x11, 0x10, 0x10, 0x10, 0x06, 0x14, 0x1A
|
|
};
|
|
static const byte ChinaButtonColorsOff[] = {
|
|
0x10, 0x14, 0x06, 0x18, 0x10, 0x11, 0x14, 0x13
|
|
};
|
|
|
|
static const byte ChinaEGAButtonColorsOn[] = {
|
|
8, 15, 14, 14, 14, 6, 0, 8
|
|
};
|
|
|
|
static const byte ChinaEGAButtonColorsOff[] = {
|
|
6, 0, 8, 6, 14, 7, 0, 0
|
|
};
|
|
|
|
static const byte ChinaSliderColors[] = {
|
|
0x1A, 0x15, 0x10, 0x06, 0x18
|
|
};
|
|
|
|
static const byte WillyBackgroundColor = 16;
|
|
static const byte WillyButtonColor = 20;
|
|
static const byte WillyHeaderTxtColor = 0;
|
|
|
|
static const byte MenuBackgroundColors[] {
|
|
0x71, 0x71, 0x71, 0x71, 0x71, 0x7B, 0x71, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B,
|
|
0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A,
|
|
0x7A, 0x7A, 0x7A, 0x46, 0x7A, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
|
|
0x46, 0x46, 0x58, 0x46, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
|
0x58, 0x52, 0x58, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,
|
|
0x59, 0x52, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5C,
|
|
0x59, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x0F, 0x5C,
|
|
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x5C, 0x0F, 0x5C, 0x5C, 0x5C,
|
|
0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x59, 0x5C, 0x59, 0x59, 0x59, 0x59,
|
|
0x59, 0x59, 0x59, 0x59, 0x59, 0x52, 0x59, 0x52, 0x52, 0x52, 0x52, 0x52,
|
|
0x52, 0x52, 0x52, 0x52, 0x58, 0x52, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
|
|
0x58, 0x58, 0x58, 0x46, 0x58, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
|
|
0x46, 0x46, 0x7A, 0x46, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A,
|
|
0x7A, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B,
|
|
0x71, 0x7B, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71
|
|
};
|
|
|
|
|
|
RequestParser::RequestParser(ResourceManager *resman, Decompressor *decompressor) : DgdsParser(resman, decompressor) {
|
|
}
|
|
|
|
|
|
bool RequestParser::parseGADChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
|
|
Common::SeekableReadStream *str = chunk.getContent();
|
|
|
|
uint16 numGadgets = str->readUint16LE();
|
|
data._gadgets.resize(numGadgets);
|
|
|
|
// Note: The original has some logic about loading single gadgets
|
|
// here, is only ever called with "num" of -1 (load all gadgets),
|
|
// so maybe just skip it?
|
|
if (num != -1)
|
|
error("Request::parseGADChunk: Implement handling of num other than -1");
|
|
|
|
for (Common::SharedPtr<Gadget> &gptr : data._gadgets) {
|
|
uint16 vals[12];
|
|
for (int i = 0; i < 12; i++)
|
|
vals[i] = str->readUint16LE();
|
|
|
|
GadgetType gadgetType = static_cast<GadgetType>(vals[5]);
|
|
if (num == -1 || num == vals[0]) {
|
|
if (gadgetType == kGadgetText)
|
|
gptr.reset(new TextAreaGadget());
|
|
else if (gadgetType == kGadgetSlider)
|
|
gptr.reset(new SliderGadget());
|
|
else if (gadgetType == kGadgetImage)
|
|
gptr.reset(new ImageGadget());
|
|
else if (gadgetType == kGadgetButton)
|
|
gptr.reset(new ButtonGadget());
|
|
else
|
|
gptr.reset(new Gadget());
|
|
}
|
|
|
|
if (gptr) {
|
|
gptr->_gadgetNo = vals[0];
|
|
gptr->_x = vals[1];
|
|
gptr->_y = vals[2];
|
|
gptr->_width = vals[3];
|
|
gptr->_height = vals[4];
|
|
gptr->_gadgetType = gadgetType;
|
|
gptr->_flags2 = vals[6];
|
|
gptr->_flags3 = vals[7];
|
|
gptr->_fontNo = vals[8];
|
|
gptr->_col1 = vals[9];
|
|
gptr->_col2 = vals[10];
|
|
gptr->_col3 = vals[11];
|
|
gptr->_parentX = data._rect.x;
|
|
gptr->_parentY = data._rect.y;
|
|
}
|
|
|
|
uint16 type1 = str->readUint16LE();
|
|
if (type1 == 1) {
|
|
Common::String s = str->readString();
|
|
if (gptr)
|
|
gptr->_sval1S = s;
|
|
} else {
|
|
uint16 i = str->readUint16LE();
|
|
if (gptr)
|
|
gptr->_sval1I = i;
|
|
}
|
|
if (gptr)
|
|
gptr->_sval1Type = type1;
|
|
|
|
uint16 type2 = str->readUint16LE();
|
|
if (type2 == 1) {
|
|
Common::String s = str->readString();
|
|
if (gptr)
|
|
gptr->_sval2S = s;
|
|
} else {
|
|
uint16 i = str->readUint16LE();
|
|
if (gptr)
|
|
gptr->_sval2I = i;
|
|
}
|
|
if (gptr)
|
|
gptr->_sval2Type = type2;
|
|
|
|
uint16 val = str->readUint16LE();
|
|
if (gptr) {
|
|
gptr->_field20_0x28 = val;
|
|
gptr->_field21_0x2a = val >> 0xf;
|
|
}
|
|
|
|
switch (gadgetType) {
|
|
case kGadgetText: {
|
|
uint16 i1 = str->readUint16LE();
|
|
uint16 i2 = str->readUint16LE();
|
|
if (gptr) {
|
|
TextAreaGadget *g1 = static_cast<TextAreaGadget *>(gptr.get());
|
|
g1->_textGadget_i1 = i1;
|
|
g1->_bufLen = i2;
|
|
}
|
|
break;
|
|
}
|
|
case kGadgetSlider: {
|
|
uint16 i1 = str->readUint16LE();
|
|
uint16 i2 = str->readUint16LE();
|
|
uint16 i3 = str->readUint16LE();
|
|
uint16 i4 = str->readUint16LE();
|
|
if (gptr) {
|
|
SliderGadget *g2 = static_cast<SliderGadget *>(gptr.get());
|
|
g2->_gadget2_i1 = i1;
|
|
g2->_gadget2_i2 = i2;
|
|
g2->_gadget2_i3 = i3;
|
|
g2->_gadget2_i4 = i4;
|
|
}
|
|
break;
|
|
}
|
|
case kGadgetButton: {
|
|
Common::String s = str->readString();
|
|
if (gptr)
|
|
gptr->_buttonName = s;
|
|
break;
|
|
}
|
|
case kGadgetImage: {
|
|
uint16 i1 = str->readUint16LE();
|
|
uint16 i2 = str->readUint16LE();
|
|
if (gptr) {
|
|
ImageGadget *g8 = static_cast<ImageGadget *>(gptr.get());
|
|
g8->_xStep = i1;
|
|
g8->_yStep = i2;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return str->err();
|
|
}
|
|
|
|
|
|
bool RequestParser::parseREQChunk(RequestData &data, DgdsChunkReader &chunk, int num) {
|
|
Common::SeekableReadStream *str = chunk.getContent();
|
|
|
|
uint16 chunkNum = str->readUint16LE();
|
|
|
|
// Slight HACK - only Willy Beamish has a different number for the main menu
|
|
if (chunkNum == kMenuMainBeamish)
|
|
chunkNum = kMenuMain;
|
|
|
|
// Note: The original has some logic about loading single request blocks
|
|
// here, is only ever called with "num" of -1 (load all),
|
|
// so maybe just skip it?
|
|
if (num != -1)
|
|
error("Request::parseGADChunk: Implement handling of num other than -1");
|
|
|
|
data._fileNum = chunkNum;
|
|
data._rect.x = str->readUint16LE();
|
|
data._rect.y = str->readUint16LE();
|
|
data._rect.width = str->readUint16LE();
|
|
data._rect.height = str->readUint16LE();
|
|
data._col1 = str->readUint16LE();
|
|
data._col2 = str->readUint16LE();
|
|
data._flags = str->readUint16LE();
|
|
|
|
uint16 numTextItems = str->readUint16LE();
|
|
data._textItemList.resize(numTextItems);
|
|
for (int i = 0; i < numTextItems; i++) {
|
|
TextItem &dst = data._textItemList[i];
|
|
dst._x = str->readUint16LE();
|
|
dst._y = str->readUint16LE();
|
|
for (int j = 0; j < 2; j++) {
|
|
dst._vals[j] = str->readUint16LE();
|
|
}
|
|
dst._txt = str->readString();
|
|
}
|
|
|
|
uint16 numFillAreas = str->readUint16LE();
|
|
data._fillAreaList.resize(numFillAreas);
|
|
for (int i = 0; i < numFillAreas; i++) {
|
|
RequestFillArea &dst = data._fillAreaList[i];
|
|
dst._x = str->readUint16LE();
|
|
dst._y = str->readUint16LE();
|
|
dst._width = str->readUint16LE();
|
|
dst._height = str->readUint16LE();
|
|
dst._col1 = str->readUint16LE();
|
|
dst._col2 = str->readUint16LE();
|
|
}
|
|
|
|
return str->err();
|
|
}
|
|
|
|
|
|
bool RequestParser::handleChunk(DgdsChunkReader &chunk, ParserData *data) {
|
|
REQFileData &rfdata = *static_cast<REQFileData *>(data);
|
|
|
|
// The game supports loading a particular item, but always passes -1?
|
|
int num = -1;
|
|
|
|
if (chunk.isContainer()) {
|
|
// TAG: contains tags for the request data, all content
|
|
if (chunk.getId() == ID_TAG)
|
|
chunk.skipContent();
|
|
|
|
return false; // continue parsing
|
|
}
|
|
|
|
if (chunk.getId() == ID_REQ) {
|
|
rfdata._requests.resize(rfdata._requests.size() + 1);
|
|
parseREQChunk(rfdata._requests.back(), chunk, num);
|
|
} else if (chunk.getId() == ID_GAD) {
|
|
if (rfdata._requests.empty())
|
|
error("GAD chunk before any REQ chunks in Request file %s", _filename.c_str());
|
|
parseGADChunk(rfdata._requests.back(), chunk, num);
|
|
}
|
|
|
|
return chunk.getContent()->err();
|
|
}
|
|
|
|
|
|
Common::String Gadget::dump() const {
|
|
char buf1[6], buf2[6];
|
|
const char *sval1 = _sval1S.c_str();
|
|
const char *sval2 = _sval2S.c_str();
|
|
if (_sval1Type != 1) {
|
|
sval1 = buf1;
|
|
snprintf(buf1, 6, "%d", _sval1I);
|
|
}
|
|
if (_sval2Type != 1) {
|
|
sval2 = buf2;
|
|
snprintf(buf2, 6, "%d", _sval2I);
|
|
}
|
|
|
|
return Common::String::format(
|
|
"%s<num %d pos (%d,%d) sz (%d,%d), typ %d, flgs %04x %04x svals %s, %s, '%s', parent (%d,%d)>",
|
|
_gadgetType == kGadgetButton ? "ButtonGadget" : "Gadget",
|
|
_gadgetNo, _x, _y, _width, _height, _gadgetType, _flags2, _flags3, sval1, sval2,
|
|
_buttonName.c_str(), _parentX, _parentY);
|
|
}
|
|
|
|
void Gadget::draw(Graphics::ManagedSurface *dst) const {}
|
|
|
|
Common::Point Gadget::topLeft() const {
|
|
return Common::Point(_x + _parentX, _y + _parentY);
|
|
}
|
|
|
|
Common::Point Gadget::midPoint() const {
|
|
return topLeft() + Common::Point(_width / 2, _height / 2);
|
|
}
|
|
|
|
bool Gadget::containsPoint(const Common::Point &pt) {
|
|
Common::Point tl = topLeft();
|
|
Common::Rect gadgetRect(tl, _width, _height - 1);
|
|
return gadgetRect.contains(pt);
|
|
}
|
|
|
|
void Gadget::setVisible(bool visible) {
|
|
if (visible)
|
|
_flags3 &= ~0x40;
|
|
else
|
|
_flags3 |= 0x40;
|
|
}
|
|
|
|
byte ButtonGadget::drawDragonBg(Graphics::ManagedSurface *dst, bool enabled) const {
|
|
Common::Point pt = topLeft();
|
|
int16 x = pt.x;
|
|
int16 y = pt.y;
|
|
|
|
int16 right = x + _width;
|
|
int16 x2 = right - 1;
|
|
int16 bottom = (y + _height) - 1;
|
|
|
|
const byte *colors = DgdsEngine::getInstance()->isEGA() ? DragonEGAButtonColors : DragonButtonColors;
|
|
|
|
byte fill = colors[0];
|
|
dst->hLine(x, y, x2, fill);
|
|
dst->hLine(x + 2, y + 2, right - 3, fill);
|
|
dst->hLine(x + 1, bottom - 2, x + 1, fill);
|
|
dst->hLine(right - 2, bottom - 2, right - 2, fill);
|
|
dst->hLine(x + 1, bottom - 1, right - 2, fill);
|
|
|
|
fill = colors[1];
|
|
dst->vLine(x, y + 1, bottom, fill);
|
|
dst->vLine(x2, y + 1, bottom, fill);
|
|
dst->vLine(x + 2, y + 3, bottom - 2, fill);
|
|
dst->vLine(right - 3, y + 3, bottom - 2, fill);
|
|
dst->hLine(x + 3,bottom - 2, right - 4, fill);
|
|
|
|
fill = colors[2];
|
|
dst->vLine(x + 1, y + 2, bottom - 3, fill);
|
|
dst->vLine(right - 2, y + 2, bottom - 3, fill);
|
|
dst->hLine(x + 1, bottom, right - 2, colors[3]);
|
|
dst->hLine(x + 1, y + 1, right - 2, colors[4]);
|
|
|
|
int colOffset;
|
|
if (enabled) {
|
|
colOffset = 5;
|
|
} else {
|
|
colOffset = 9;
|
|
}
|
|
|
|
dst->hLine(x + 3, y + 3, right - 4, colors[colOffset + 1]);
|
|
|
|
// TODO: This is done with a different call in the game.. is there some reason for that?
|
|
dst->fillRect(Common::Rect(x + 3, y + 4, x + 3 + _width - 6, y + 4 + _height - 8), colors[colOffset + 2]);
|
|
|
|
dst->hLine(x + 3, bottom - 3, right - 4, colors[colOffset + 3]);
|
|
|
|
return colors[colOffset];
|
|
}
|
|
|
|
byte ButtonGadget::drawChinaBg(Graphics::ManagedSurface *dst, bool enabled) const {
|
|
Common::Point pt = topLeft();
|
|
int16 x = pt.x;
|
|
int16 x2 = x + _width - 1;
|
|
int16 y = pt.y;
|
|
int16 y2 = y + _height - 1;
|
|
int cnum = 0;
|
|
const byte *colors = DgdsEngine::getInstance()->isEGA() ?
|
|
(enabled ? ChinaEGAButtonColorsOn : ChinaEGAButtonColorsOff) :
|
|
(enabled ? ChinaButtonColorsOn : ChinaButtonColorsOff);
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
byte drawCol = colors[cnum];
|
|
cnum++;
|
|
if (i < 3) {
|
|
dst->hLine(x + i + 1, y + i, x2 - i, drawCol);
|
|
dst->vLine(x2 - i, y + i + 1, y2 - i, drawCol);
|
|
} else if (i < 4) {
|
|
int16 rheight, rwidth;
|
|
if (_height + -6 < 3)
|
|
rheight = 2;
|
|
else
|
|
rheight = _height + -6;
|
|
|
|
if (_width + -6 < 3)
|
|
rwidth = 2;
|
|
else
|
|
rwidth = _width + -6;
|
|
|
|
dst->fillRect(Common::Rect(Common::Point(x + 3, y + 3), rwidth, rheight), drawCol);
|
|
} else {
|
|
int16 x2_ = 6 - i;
|
|
dst->vLine(x + x2_, y + x2_, y2 - x2_, drawCol);
|
|
dst->hLine(x + x2_, y2 - x2_, (x2 - x2_) + -1, drawCol);
|
|
}
|
|
}
|
|
return colors[7];
|
|
}
|
|
|
|
byte ButtonGadget::drawWillyBg(Graphics::ManagedSurface *dst, bool enabled) const {
|
|
Common::Point pt = topLeft();
|
|
uint16 cornerFrame = enabled ? 8 : 16;
|
|
RequestData::drawCorners(dst, cornerFrame, pt.x, pt.y, _width, _height);
|
|
int16 fillHeight = enabled ? _height - 8 : _height - 6;
|
|
if (_width > 16 && fillHeight > 0)
|
|
dst->fillRect(Common::Rect(Common::Point(pt.x + 8, pt.y + 3), _width - 16, fillHeight), WillyButtonColor);
|
|
return 0;
|
|
}
|
|
|
|
void ButtonGadget::draw(Graphics::ManagedSurface *dst) const {
|
|
DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
|
|
bool enabled = !(_flags3 & 9);
|
|
|
|
byte textCol;
|
|
if (gameId == GID_DRAGON)
|
|
textCol = drawDragonBg(dst, enabled);
|
|
else if (gameId == GID_HOC)
|
|
textCol = drawChinaBg(dst, enabled);
|
|
else
|
|
textCol = drawWillyBg(dst, enabled);
|
|
|
|
Common::Point pt = topLeft();
|
|
int16 x = pt.x;
|
|
int16 y = pt.y;
|
|
|
|
if (!_buttonName.empty()) {
|
|
const DgdsFont *font = RequestData::getMenuFont();
|
|
Common::String name = _buttonName;
|
|
int fontHeight = font->getFontHeight();
|
|
//bool twoline;
|
|
int yoffset;
|
|
uint32 linebreak = name.find('&');
|
|
|
|
Common::String line1, line2;
|
|
if (linebreak != Common::String::npos) {
|
|
//twoline = true;
|
|
name.setChar(' ', linebreak);
|
|
yoffset = _height + 1 - fontHeight * 2;
|
|
line1 = _buttonName.substr(0, linebreak);
|
|
line2 = _buttonName.substr(linebreak + 1);
|
|
} else {
|
|
//twoline = false;
|
|
yoffset = _height - fontHeight;
|
|
line1 = _buttonName;
|
|
}
|
|
|
|
yoffset = y + yoffset / 2;
|
|
if (gameId == GID_WILLY)
|
|
yoffset -= 2;
|
|
|
|
int lineWidth = font->getStringWidth(line1);
|
|
font->drawString(dst, line1, x + (_width - lineWidth) / 2 + 1, yoffset + 2, lineWidth, textCol);
|
|
|
|
if (linebreak != Common::String::npos) {
|
|
lineWidth = font->getStringWidth(line2);
|
|
font->drawString(dst, line2, x + (_width - lineWidth) / 2 + 1, yoffset + fontHeight, lineWidth, textCol);
|
|
}
|
|
} else if (gameId == GID_WILLY && _height == 32) {
|
|
drawWillyBmpButtons(dst);
|
|
}
|
|
}
|
|
|
|
enum WillyMenuIcons {
|
|
kWillyArrowRight = 33,
|
|
kWillyCD = 34,
|
|
kWillyRewind = 35,
|
|
kWillyStop = 36,
|
|
kWillyQuestionMark = 37,
|
|
kWillyBam = 38,
|
|
kWillyMusicNote = 39,
|
|
kWillyHelpText = 40,
|
|
kWillySwoosh = 42,
|
|
kWillyPlay = 43,
|
|
kWillyNoBam = 44,
|
|
kWillyNoMusicNote = 45,
|
|
};
|
|
|
|
void ButtonGadget::drawCenteredBmpIcon(Graphics::ManagedSurface *dst, int16 cornerNum) const {
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
const Common::Rect screen(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
const Common::Point tl = topLeft();
|
|
int16 x = tl.x + (_width - uiCorners->width(cornerNum)) / 2;
|
|
int16 y = tl.y + (_height - uiCorners->height(cornerNum)) / 2;
|
|
uiCorners->drawBitmap(cornerNum, x, y, screen, *dst);
|
|
}
|
|
|
|
void ButtonGadget::drawWillyLoadSaveIcon(Graphics::ManagedSurface *dst, bool isLoad) const {
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
const Common::Rect screen(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
const Common::Point tl = topLeft();
|
|
int16 cdIconWidth = uiCorners->width(kWillyCD);
|
|
int16 arrowIconWidth = uiCorners->width(kWillyArrowRight);
|
|
int16 x = tl.x + (_width - cdIconWidth - arrowIconWidth) / 2;
|
|
int16 cdy = tl.y + (_height - uiCorners->height(kWillyCD)) / 2;
|
|
int16 arrowy = tl.y + (_height - uiCorners->height(kWillyArrowRight)) / 2;
|
|
uiCorners->drawBitmap(kWillyCD, x, cdy, screen, *dst);
|
|
uiCorners->drawBitmap(kWillyArrowRight, x + cdIconWidth, arrowy, screen, *dst, isLoad ? kImageFlipNone : kImageFlipH);
|
|
}
|
|
|
|
void ButtonGadget::drawWillyBmpButtons(Graphics::ManagedSurface *dst) const {
|
|
|
|
switch (_gadgetNo) {
|
|
case 110: // SAVE (CD icon, arrow flipped)
|
|
drawWillyLoadSaveIcon(dst, false);
|
|
break;
|
|
case 111: // LOAD (CD icon, arrow)
|
|
drawWillyLoadSaveIcon(dst, true);
|
|
break;
|
|
case 112: // RESTART (rewind icon)
|
|
drawCenteredBmpIcon(dst, kWillyRewind);
|
|
break;
|
|
case 113: // QUIT (stop icon)
|
|
drawCenteredBmpIcon(dst, kWillyStop);
|
|
break;
|
|
case 114: // HELP (questionmark icon)
|
|
drawCenteredBmpIcon(dst, kWillyQuestionMark);
|
|
break;
|
|
case 115: { // SFX (bam icon)
|
|
bool sfxOff = DgdsEngine::getInstance()->_mixer->isSoundTypeMuted(Audio::Mixer::kSFXSoundType);
|
|
drawCenteredBmpIcon(dst, sfxOff ? kWillyNoBam : kWillyBam);
|
|
break;
|
|
}
|
|
case 116: { // MUSIC (musical note icon)
|
|
bool musicOff = DgdsEngine::getInstance()->_mixer->isSoundTypeMuted(Audio::Mixer::kMusicSoundType);
|
|
drawCenteredBmpIcon(dst, musicOff ? kWillyNoMusicNote : kWillyMusicNote);
|
|
break;
|
|
}
|
|
case 120: // HELP (questionmark and text icon)
|
|
drawCenteredBmpIcon(dst, kWillyHelpText);
|
|
break;
|
|
case 118: // CREDITS (swoosh icon)
|
|
drawCenteredBmpIcon(dst, kWillySwoosh);
|
|
break;
|
|
case 119: // PLAY (play icon)
|
|
drawCenteredBmpIcon(dst, kWillyPlay);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ButtonGadget::toggle(bool enable) {
|
|
if (!enable)
|
|
_flags3 |= 9; // 0x1001
|
|
else
|
|
_flags3 &= 6; // 0x0110
|
|
}
|
|
|
|
Common::String TextAreaGadget::dump() const {
|
|
const Common::String base = Gadget::dump();
|
|
return Common::String::format("TextArea<%s, %d buflen %d>", base.c_str(), _textGadget_i1, _bufLen);
|
|
}
|
|
|
|
void TextAreaGadget::draw(Graphics::ManagedSurface *dst) const {
|
|
const DgdsFont *font = RequestData::getMenuFont();
|
|
font->drawString(dst, _buttonName, _x + _parentX, _y + _parentY, 0, 0);
|
|
}
|
|
|
|
Common::String SliderGadget::dump() const {
|
|
const Common::String base = Gadget::dump();
|
|
return Common::String::format("Slider<%s, %d %d %d %d>", base.c_str(), _gadget2_i1, _gadget2_i2, _gadget2_i3, _gadget2_i4);
|
|
}
|
|
|
|
// Slider labels and title are hard-coded in game, not part of data files.
|
|
static const char *_sliderTitleForGadget(uint16 num, Common::Language language) {
|
|
if (language == Common::EN_ANY) {
|
|
switch (num) {
|
|
case 0x7B: return "DIFFICULTY";
|
|
case 0x7D: return "TEXT SPEED";
|
|
case 0x83: return "DETAIL LEVEL";
|
|
case 0x98: return "MOUSE SPEED";
|
|
case 0x9C: return "BUTTON THRESHOLD";
|
|
default: return "SLIDER";
|
|
}
|
|
} else if (language == Common::DE_DEU) {
|
|
switch (num) {
|
|
case 0x7B: return "SCHWIERIGKEITSGRAD";
|
|
case 0x7D: return "TEXT-VERWEILDAUER";
|
|
case 0x83: return "DETAILS";
|
|
case 0x98: return "GESCHWINDIGKEIT";
|
|
case 0x9C: return "TASTENEMPFINDLICHKEIT";
|
|
default: return "REGLER";
|
|
}
|
|
} else {
|
|
error("Unsupported language %d", language);
|
|
}
|
|
}
|
|
|
|
static const char *_sliderLabelsForGadget(uint16 num, Common::Language language) {
|
|
if (language == Common::EN_ANY) {
|
|
switch (num) {
|
|
case 0x7B: return "EASY HARD";
|
|
case 0x7D: return "SLOW FAST";
|
|
case 0x83: return "LOW HIGH";
|
|
case 0x98: return "SLOW FAST";
|
|
case 0x9C: return "LONG SHORT";
|
|
default: return "MIN MAX";
|
|
}
|
|
} else if (language == Common::DE_DEU) {
|
|
return "- +";
|
|
} else {
|
|
error("Unsupported language %d", language);
|
|
}
|
|
}
|
|
|
|
static const int SLIDER_HANDLE_FRAME = 28;
|
|
|
|
void SliderGadget::drawDragonBg(Graphics::ManagedSurface *dst) const {
|
|
int16 x = _x + _parentX;
|
|
int16 y = _y + _parentY;
|
|
int16 x2 = x + _width;
|
|
int16 y2 = (y + _height) - 1;
|
|
|
|
int16 y1 = y - 1;
|
|
|
|
static const byte *colors = DgdsEngine::getInstance()->isEGA() ? DragonEGASliderColors : DragonSliderColors;
|
|
|
|
dst->vLine(x - 2, y - 1, y2, colors[0]);
|
|
dst->vLine(x - 1, y1, y2, colors[1]);
|
|
dst->hLine(x, y2, x2 - 1, colors[1]);
|
|
dst->hLine(x, y1, x2, colors[2]);
|
|
dst->vLine(x2, y1, y2, colors[2]);
|
|
dst->vLine(x2 + 1, y1, y2, colors[3]);
|
|
dst->hLine(x, y, x2 - 1, colors[4]);
|
|
dst->vLine(x2 - 1, y + 1, (y + _height) - 2, colors[4]);
|
|
// This is not exactly what happens in the original, but gets the same result
|
|
Common::Rect fillrect = Common::Rect(x, y + 1, x + _width - 1, y + _height - 1);
|
|
dst->fillRect(fillrect, colors[5]);
|
|
fillrect.grow(-1);
|
|
dst->fillRect(fillrect, colors[6]);
|
|
}
|
|
|
|
void SliderGadget::drawChinaBg(Graphics::ManagedSurface *dst) const {
|
|
int16 x = _x + _parentX;
|
|
int16 y = _y + _parentY;
|
|
int16 y2 = y + 8;
|
|
int16 x2 = x + _width + 2;
|
|
|
|
// left 1st
|
|
dst->vLine(x - 2, y - 1, y2 + 1, ChinaSliderColors[0]);
|
|
// left 2nd
|
|
dst->vLine(x - 1, y, y2, ChinaSliderColors[1]);
|
|
// left 3rd
|
|
dst->vLine(x, y + 1, y2 - 1, ChinaSliderColors[2]);
|
|
|
|
// top 1st
|
|
dst->hLine(x - 1, y - 1, x2,ChinaSliderColors[2]);
|
|
// top 2nd
|
|
dst->hLine(x, y, x2 - 1, ChinaSliderColors[0]);
|
|
// top 3rd
|
|
dst->hLine(x + 1, y + 1, x2 - 2, ChinaSliderColors[3]);
|
|
|
|
// right 1st
|
|
dst->vLine(x2 - 1, y + 1, y2 - 1, ChinaSliderColors[3]);
|
|
// right 2nd
|
|
dst->vLine(x2, y, y2, ChinaSliderColors[0]);
|
|
// right 3rd
|
|
dst->vLine(x2 + 1, y - 1, y2 + 1, ChinaSliderColors[2]);
|
|
|
|
// bottom 1st
|
|
dst->hLine(x + 1, y2 - 1, x2 - 2, ChinaSliderColors[2]);
|
|
// bottom 2nd
|
|
dst->hLine(x, y2, x2 - 1, ChinaSliderColors[1]);
|
|
// bottom 3rd
|
|
dst->hLine(x - 1, y2 + 1, x2, ChinaSliderColors[0]);
|
|
|
|
Common::Rect fillrect = Common::Rect(x + 1, y + 2, x2 - 1, y2 - 1);
|
|
dst->fillRect(fillrect, ChinaSliderColors[4]);
|
|
}
|
|
|
|
|
|
void SliderGadget::draw(Graphics::ManagedSurface *dst) const {
|
|
const DgdsFont *font = RequestData::getMenuFont();
|
|
Common::Language language = DgdsEngine::getInstance()->getGameLang();
|
|
|
|
int16 x = _x + _parentX;
|
|
int16 y = _y + _parentY;
|
|
|
|
int16 titley = (y - font->getFontHeight()) + 1;
|
|
const char *title = _sliderTitleForGadget(_gadgetNo, language);
|
|
const char *labels = _sliderLabelsForGadget(_gadgetNo, language);
|
|
int16 titleWidth = font->getStringWidth(title);
|
|
DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
|
|
|
|
byte textCol = (gameId == GID_DRAGON) ? 0 : 0x13;
|
|
int16 labelYOff = (gameId == GID_DRAGON) ? 7 : 11;
|
|
|
|
font->drawString(dst, title, x + (_width - titleWidth) / 2, titley, titleWidth, textCol);
|
|
int16 labelWidth = font->getStringWidth(labels);
|
|
font->drawString(dst, labels, x + (_width - labelWidth) / 2, y + labelYOff, labelWidth, textCol);
|
|
|
|
if (gameId == GID_DRAGON)
|
|
drawDragonBg(dst);
|
|
else
|
|
drawChinaBg(dst);
|
|
|
|
// Draw the slider control in the right spot
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
uiCorners->drawBitmap(SLIDER_HANDLE_FRAME, x + _handleX, y, Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), *dst);
|
|
}
|
|
|
|
SliderGadget::SliderGadget() : _lock(false), _steps(0), _gadget2_i1(0),
|
|
_gadget2_i2(0), _gadget2_i3(0), _gadget2_i4(0), _handleX(0) {
|
|
}
|
|
|
|
int16 SliderGadget::getHandleWidth() const {
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
int16 handleWidth = uiCorners->width(SLIDER_HANDLE_FRAME);
|
|
return handleWidth - 2;
|
|
}
|
|
|
|
int16 SliderGadget::getUsableWidth() const {
|
|
return _width + 4 - getHandleWidth();
|
|
}
|
|
|
|
void SliderGadget::onDrag(const Common::Point &mousePt) {
|
|
const Common::Point topLeftPt = topLeft();
|
|
const Common::Point relMouse = mousePt - topLeftPt;
|
|
// match middle of handle to mouse point
|
|
int16 handleWidth = getHandleWidth();
|
|
_handleX = CLIP(relMouse.x - handleWidth / 2, 0, (int)getUsableWidth());
|
|
}
|
|
|
|
int16 SliderGadget::onDragFinish(const Common::Point &mousePt) {
|
|
onDrag(mousePt);
|
|
int16 newVal = getValue();
|
|
if (_lock)
|
|
setValue(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
int16 SliderGadget::getValue() {
|
|
int16 stepSize = getUsableWidth() / (_steps - 1);
|
|
// Find the closest step point to the left end of the handle
|
|
int16 closestStep = (_handleX + stepSize / 2) / stepSize;
|
|
return CLIP(closestStep, (int16)0, _steps);
|
|
}
|
|
|
|
void SliderGadget::setValue(int16 val) {
|
|
// if val is steps-1, slider x should be at..
|
|
int16 usableWidth = getUsableWidth();
|
|
if (val == _steps - 1)
|
|
_handleX = usableWidth;
|
|
else
|
|
_handleX = (usableWidth * val) / (_steps - 1);
|
|
}
|
|
|
|
int16 SliderGadget::onClick(const Common::Point &mousePt) {
|
|
const Common::Point topLeftPt = topLeft();
|
|
const Common::Point relMouse = mousePt - topLeftPt;
|
|
|
|
// A click should move the slider to the next step in the direction of the click.
|
|
int16 handleMiddle = _handleX + getHandleWidth() / 2;
|
|
// round up step size to ensure we move far enough..
|
|
|
|
int16 val = getValue();
|
|
int16 newVal = val;
|
|
if (relMouse.x > handleMiddle)
|
|
newVal++;
|
|
else
|
|
newVal--;
|
|
|
|
debug(1, "clicked on slider %d, move val from %d -> %d", _gadgetNo, val, newVal);
|
|
|
|
newVal = CLIP((int)newVal, 0, _steps - 1);
|
|
setValue(newVal);
|
|
return newVal;
|
|
}
|
|
|
|
Common::String ImageGadget::dump() const {
|
|
const Common::String base = Gadget::dump();
|
|
return Common::String::format("Image<%s, xStep %d yStep %d>", base.c_str(), _xStep, _yStep);
|
|
}
|
|
|
|
static void _drawFrame(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 w, int16 h, byte col1, byte col2) {
|
|
const int xmax = x + w - 1;
|
|
const int ymax = y + h - 1;
|
|
bool filled = true;
|
|
if (filled) {
|
|
for (int yy = y; yy < ymax; yy++) {
|
|
for (int xx = x; xx < xmax; xx = xx + 1) {
|
|
dst->setPixel(xx, yy, (byte)dst->getPixel(xx, yy) ^ col2);
|
|
}
|
|
}
|
|
}
|
|
for (int yy = y; yy <= ymax; yy++) {
|
|
dst->setPixel(x, yy, (byte)dst->getPixel(x, yy) ^ col1);
|
|
dst->setPixel(xmax, yy, (byte)dst->getPixel(xmax, yy) ^ col1);
|
|
}
|
|
for (int xx = x; xx < xmax; xx++) {
|
|
dst->setPixel(xx, y, (byte)dst->getPixel(xx, y) ^ col1);
|
|
dst->setPixel(xx, ymax, (byte)dst->getPixel(xx, ymax) ^ col1);
|
|
}
|
|
}
|
|
|
|
void ImageGadget::draw(Graphics::ManagedSurface *dst) const {
|
|
int xstep = _xStep;
|
|
int ystep = _yStep;
|
|
|
|
if (!xstep || !ystep)
|
|
return;
|
|
|
|
const DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
|
|
|
|
int xoff = _x + _parentX;
|
|
int yoff = _y + _parentY;
|
|
int fillHeight = _height;
|
|
if (gameId == GID_WILLY)
|
|
fillHeight++;
|
|
|
|
Common::Rect drawRect(Common::Point(xoff, yoff), _width, fillHeight);
|
|
dst->fillRect(drawRect, _col1);
|
|
// Note: not quite the same as the original logic here, but gets the same result.
|
|
_drawFrame(dst, xoff, yoff, _width, _height, _sval1I, _sval1I);
|
|
|
|
// NOTE: This only done in inventory in originals, but no other
|
|
// Request uses the ImageGadget.
|
|
if (gameId == GID_DRAGON)
|
|
RequestData::drawCorners(dst, 19, xoff - 2, yoff - 2, _width + 4, _height + 4);
|
|
else if (gameId == GID_HOC)
|
|
RequestData::drawCorners(dst, 19, xoff - 4, yoff - 4, _width + 8, _height + 8);
|
|
else if (gameId == GID_WILLY)
|
|
RequestData::drawCorners(dst, 25, xoff - 4, yoff - 4, _width + 8, _height + 8);
|
|
}
|
|
|
|
Common::String RequestData::dump() const {
|
|
Common::String ret = Common::String::format("RequestData<file %d %s c1 %d c2 %d flg %d\n",
|
|
_fileNum, _rect.dump("").c_str(), _col1, _col2, _flags);
|
|
for (const auto &t : _textItemList)
|
|
ret += Common::String::format(" TextItem<'%s' pos (%d,%d) %d %d>\n", t._txt.c_str(),
|
|
t._x, t._y, t._vals[0], t._vals[1]);
|
|
for (const auto &f : _fillAreaList)
|
|
ret += Common::String::format(" FillArea<x %d y %d w %d h %d c1 %d c2 %d>\n", f._x, f._y,
|
|
f._width, f._height, f._col1, f._col2);
|
|
for (const auto &g : _gadgets)
|
|
ret += Common::String::format(" %s\n", g->dump().c_str());
|
|
ret += ">";
|
|
|
|
return ret;
|
|
}
|
|
|
|
void RequestData::drawBg(Graphics::ManagedSurface *dst) const {
|
|
int slidery = 0;
|
|
for (const auto &gadget : _gadgets) {
|
|
const SliderGadget *slider = dynamic_cast<const SliderGadget *>(gadget.get());
|
|
if (slider) {
|
|
slidery = MAX(slidery, slider->_y + slider->_height);
|
|
}
|
|
}
|
|
|
|
Common::String header;
|
|
if (!_textItemList.empty())
|
|
header = _textItemList[0]._txt.substr(1);
|
|
|
|
bool isDragon = DgdsEngine::getInstance()->getGameId() == GID_DRAGON;
|
|
if (slidery && isDragon)
|
|
drawBackgroundWithSliderArea(dst, slidery, header);
|
|
else
|
|
drawBackgroundNoSliders(dst, header);
|
|
}
|
|
|
|
void RequestData::drawInvType(Graphics::ManagedSurface *dst) {
|
|
if (_flags & 0x40)
|
|
return;
|
|
|
|
drawBackgroundNoSliders(dst, "");
|
|
for (const auto &fillArea : _fillAreaList) {
|
|
Common::Rect r(Common::Point(_rect.x + fillArea._x, _rect.y + fillArea._y), fillArea._width, fillArea._height);
|
|
dst->fillRect(r, fillArea._col1);
|
|
}
|
|
|
|
for (const auto &textItem : _textItemList) {
|
|
if (!textItem._txt.empty() && textItem._txt != " ")
|
|
error("TODO: RequestData::drawInvType: Implement support for drawing text item.");
|
|
}
|
|
|
|
for (auto &gadget : _gadgets)
|
|
gadget->_flags3 |= 0x100;
|
|
|
|
for (auto &gadget : _gadgets) {
|
|
if (!(gadget->_flags3 & 0x40)) {
|
|
gadget->draw(dst);
|
|
}
|
|
}
|
|
|
|
_flags |= 4;
|
|
}
|
|
|
|
/*static*/
|
|
const DgdsFont *RequestData::getMenuFont() {
|
|
return DgdsEngine::getInstance()->getFontMan()->getFont(FontManager::kGameFont);
|
|
}
|
|
|
|
/*static*/
|
|
const Image *RequestData::getCorners() {
|
|
return DgdsEngine::getInstance()->getUICorners().get();
|
|
}
|
|
|
|
/*static*/
|
|
void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height) {
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
assert(uiCorners->loadedFrameCount() > startNum + 7);
|
|
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &cframes = uiCorners->getFrames();
|
|
const Common::SharedPtr<Graphics::ManagedSurface> *corners = cframes.data() + startNum;
|
|
|
|
//
|
|
// Corners images are:
|
|
// 0 1 2 3 4 5 6 7
|
|
// TL T TR L R BL B BR
|
|
//
|
|
|
|
//
|
|
// The T, L, R, and B blocks are repeated as many times as is needed to make the
|
|
// size of menu/button we need.
|
|
//
|
|
// The last repeated one is bottom/right-aligned so that it doesn't overlap with
|
|
// the corner (this is visible eg in Willy Beamish menu buttons)
|
|
//
|
|
|
|
for (int xoff = x + corners[0]->w; xoff < (x + width) - corners[2]->w; xoff += corners[1]->w) {
|
|
int xdraw = MIN(xoff, (x + width) - corners[2]->w - corners[1]->w);
|
|
dst->transBlitFrom(*corners[1], Common::Point(xdraw, y));
|
|
}
|
|
|
|
for (int xoff = x + corners[5]->w; xoff < (x + width) - corners[7]->w; xoff += corners[6]->w) {
|
|
int xdraw = MIN(xoff, (x + width) - corners[7]->w - corners[6]->w);
|
|
dst->transBlitFrom(*corners[6], Common::Point(xdraw, (y + height) - corners[6]->h));
|
|
}
|
|
|
|
for (int yoff = y + corners[0]->h; yoff < (y + height) - corners[5]->h; yoff += corners[3]->h) {
|
|
int ydraw = MIN(yoff, (y + height) - corners[5]->h - corners[3]->h);
|
|
dst->transBlitFrom(*corners[3], Common::Point(x, ydraw));
|
|
}
|
|
|
|
for (int yoff = y + corners[2]->h; yoff < (y + height) - corners[7]->h; yoff += corners[4]->h) {
|
|
int ydraw = MIN(yoff, (y + height) - corners[7]->h - corners[4]->h);
|
|
dst->transBlitFrom(*corners[4], Common::Point((x + width) - corners[4]->w, ydraw));
|
|
}
|
|
|
|
dst->transBlitFrom(*corners[0], Common::Point(x, y));
|
|
dst->transBlitFrom(*corners[2], Common::Point((x + width) - corners[2]->w, y));
|
|
dst->transBlitFrom(*corners[5], Common::Point(x, (y + height) - corners[5]->h));
|
|
dst->transBlitFrom(*corners[7], Common::Point((x + width) - corners[7]->w, (y + height) - corners[7]->h));
|
|
}
|
|
|
|
/*static*/
|
|
void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header, byte fontCol, bool drawBox, byte boxTopColor, byte boxBottomColor) {
|
|
if (!header.empty()) {
|
|
const DgdsFont *font = getMenuFont();
|
|
int hwidth = font->getStringWidth(header);
|
|
int hheight = font->getFontHeight();
|
|
int hleft = x + (width - hwidth) / 2;
|
|
int hright = hleft + hwidth + 3;
|
|
int htop = y + yoffset;
|
|
int hbottom = htop + hheight;
|
|
|
|
font->drawString(dst, header, hleft + 1, htop + 2, hwidth, fontCol);
|
|
if (drawBox) {
|
|
dst->hLine(hleft - 3, htop, hright, boxTopColor);
|
|
dst->vLine(hright, htop + 1, hbottom, boxTopColor);
|
|
dst->vLine(hleft - 3, htop + 1, hbottom, boxBottomColor);
|
|
dst->hLine(hleft - 2, hbottom, hleft + hwidth + 2, boxBottomColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, int16 sliderHeight, const Common::String &header) const {
|
|
int16 x = _rect.x;
|
|
int16 y = _rect.y;
|
|
int16 width = _rect.width;
|
|
int16 height = _rect.height;
|
|
uint16 sliderBgHeight = sliderHeight + 18;
|
|
fillBackground(dst, x, y, width, sliderBgHeight, 0);
|
|
fillBackground(dst, x + 8, y + sliderBgHeight, width - 16, height - sliderBgHeight, 8 - sliderBgHeight);
|
|
fillBackground(dst, x + 9, y + 8, width - 18, sliderHeight + 2, 8);
|
|
fillBackground(dst, x + 17, y + 8 + sliderHeight + 2, width - 34, height - sliderBgHeight, 32 - sliderBgHeight);
|
|
|
|
const Image *uiCorners = RequestData::getCorners();
|
|
assert(uiCorners->loadedFrameCount() >= 11);
|
|
const Common::Array<Common::SharedPtr<Graphics::ManagedSurface>> &corners = uiCorners->getFrames();
|
|
|
|
for (int xoff = x + corners[0]->w; xoff < (x + width) - corners[3]->w; xoff += corners[2]->w) {
|
|
dst->transBlitFrom(*corners[2], Common::Point(xoff, y));
|
|
}
|
|
for (int xoff = x + 8 + corners[6]->w; xoff < (x + 8 + width - 16) - corners[8]->w; xoff += corners[7]->w) {
|
|
dst->transBlitFrom(*corners[7], Common::Point(xoff, (y + height) - corners[7]->h));
|
|
}
|
|
for (int yoff = y + corners[3]->h; yoff < (y + sliderBgHeight) - corners[10]->h; yoff += corners[5]->h) {
|
|
dst->transBlitFrom(*corners[5], Common::Point((x + width) - corners[5]->w, yoff));
|
|
}
|
|
for (int yoff = y + corners[1]->h; yoff < (y + sliderBgHeight) - corners[9]->h; yoff += corners[4]->h) {
|
|
dst->transBlitFrom(*corners[4], Common::Point(x, yoff));
|
|
}
|
|
for (int yoff = y + sliderBgHeight; yoff < (y + height) - corners[6]->h; yoff += corners[4]->h) {
|
|
dst->transBlitFrom(*corners[4], Common::Point(x + 8, yoff));
|
|
}
|
|
for (int yoff = y + sliderBgHeight; yoff < (y + height) - corners[8]->h; yoff += corners[5]->h) {
|
|
dst->transBlitFrom(*corners[5], Common::Point((x + 8 + width - 16) - corners[5]->w, yoff));
|
|
}
|
|
dst->transBlitFrom(*corners[1], Common::Point(x, y));
|
|
dst->transBlitFrom(*corners[3], Common::Point((x + width) - corners[3]->w, y));
|
|
dst->transBlitFrom(*corners[6], Common::Point(x + 8, (y + height) - corners[6]->h));
|
|
dst->transBlitFrom(*corners[8], Common::Point((x + width - 8) - corners[8]->w, (y + height) - corners[8]->h));
|
|
dst->transBlitFrom(*corners[9], Common::Point(x, (y + sliderBgHeight) - corners[9]->h));
|
|
dst->transBlitFrom(*corners[10], Common::Point((x + width) - corners[10]->w, (y + sliderBgHeight) - corners[10]->h));
|
|
|
|
if (DgdsEngine::getInstance()->getGameId() == GID_DRAGON)
|
|
drawHeader(dst, x, y, width, 9, header, DragonHeaderTxtColor, true, DragonHeaderTopColor, DragonHeaderBottomColor);
|
|
else
|
|
drawHeader(dst, x, y + 4, width, 9, header, ChinaHeaderTxtColor, true, ChinaHeaderTopColor, ChinaHeaderBottomColor);
|
|
}
|
|
|
|
|
|
void RequestData::drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const Common::String &header) const {
|
|
DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
|
|
|
|
if (_rect.width == 0 || _rect.height == 0) {
|
|
warning("drawBackgroundNoSliders: empty rect");
|
|
return;
|
|
}
|
|
|
|
if (gameId != GID_WILLY)
|
|
fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
|
|
else
|
|
fillBackground(dst, _rect.x + 5, _rect.y + 5, _rect.width - 10, _rect.height - 10, 0);
|
|
uint16 cornerOffset = (gameId == GID_DRAGON ? 11 : (gameId == GID_HOC ? 1 : 0));
|
|
drawCorners(dst, cornerOffset, _rect.x, _rect.y, _rect.width, _rect.height);
|
|
if (gameId == GID_DRAGON)
|
|
drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, header, DragonHeaderTxtColor, true, DragonHeaderTopColor, DragonHeaderBottomColor);
|
|
else if (gameId == GID_HOC)
|
|
drawHeader(dst, _rect.x, _rect.y + 4, _rect.width, 4, header, ChinaHeaderTxtColor, true, ChinaHeaderTopColor, ChinaHeaderBottomColor);
|
|
else { // WILLY
|
|
drawHeader(dst, _rect.x, _rect.y + 4, _rect.width, 4, header, WillyHeaderTxtColor, false, 0, 0);
|
|
}
|
|
}
|
|
|
|
/*static*/
|
|
void RequestData::fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset) {
|
|
DgdsEngine *engine = DgdsEngine::getInstance();
|
|
|
|
if (engine->getGameId() == GID_DRAGON && engine->getDetailLevel() == kDgdsDetailHigh && !engine->isEGA()) {
|
|
Graphics::Surface area = dst->getSubArea(Common::Rect(Common::Point(x, y), width, height));
|
|
while (startoffset < 0)
|
|
startoffset += ARRAYSIZE(MenuBackgroundColors);
|
|
startoffset = startoffset % ARRAYSIZE(MenuBackgroundColors);
|
|
|
|
int coloffset = startoffset;
|
|
for (int xoff = 0; xoff < width; xoff++) {
|
|
area.drawLine(xoff, 0, xoff + height, height, MenuBackgroundColors[coloffset]);
|
|
coloffset++;
|
|
if (coloffset >= ARRAYSIZE(MenuBackgroundColors))
|
|
coloffset = 0;
|
|
}
|
|
// TODO: Game positions mouse in middle of menu here?
|
|
coloffset = startoffset;
|
|
for (int yoff = 0; yoff < height; yoff++) {
|
|
area.drawLine(0, yoff, height, yoff + height, MenuBackgroundColors[coloffset]);
|
|
coloffset--;
|
|
if (coloffset < 0)
|
|
coloffset = ARRAYSIZE(MenuBackgroundColors) - 1;
|
|
}
|
|
} else {
|
|
byte bgCol = DragonBackgroundColor;
|
|
if (engine->getGameId() == GID_HOC)
|
|
bgCol = ChinaBackgroundColor;
|
|
else if (engine->getGameId() == GID_WILLY)
|
|
bgCol = WillyBackgroundColor;
|
|
dst->fillRect(Common::Rect(Common::Point(x, y), width, height), bgCol);
|
|
}
|
|
}
|
|
|
|
Gadget *RequestData::findGadgetByNumWithFlags3Not0x40(int16 num) {
|
|
for (auto &gadget : _gadgets) {
|
|
if (gadget->_gadgetNo == num && (gadget->_flags3 & 0x40) == 0)
|
|
return gadget.get();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
Common::String REQFileData::dump() const {
|
|
Common::String ret("REQFileData<\n");
|
|
for (const auto &req : _requests) {
|
|
ret += req.dump().c_str();
|
|
ret += "\n";
|
|
}
|
|
ret += ">";
|
|
|
|
return ret;
|
|
}
|
|
|
|
} // End of namespace Dgds
|