[Scummvm-git-logs] scummvm master -> eeecc8dc5bc6f97b39d76bb7025e23f2b8dfabc6
mduggan
noreply at scummvm.org
Sun Jul 7 06:16:40 UTC 2024
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
71bd37ece7 DGDS: Add detection for another willy beamish demo
eeecc8dc5b DGDS: Add various heart of china features
Commit: 71bd37ece78317c247166497dee3267d03df27a4
https://github.com/scummvm/scummvm/commit/71bd37ece78317c247166497dee3267d03df27a4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-07-07T16:12:51+10:00
Commit Message:
DGDS: Add detection for another willy beamish demo
Changed paths:
engines/dgds/detection_tables.h
diff --git a/engines/dgds/detection_tables.h b/engines/dgds/detection_tables.h
index a0f84432b41..174afc332ef 100644
--- a/engines/dgds/detection_tables.h
+++ b/engines/dgds/detection_tables.h
@@ -202,6 +202,22 @@ static const ADGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
+ // Adventures of Willy Beamish Demo from Joystick Magazine 1995 September disk
+ {
+ "beamish",
+ 0,
+ {
+ {"volume.001", 0, "84bb888d47b535512847d49549d7c289", 947579},
+ {"volume.rmf", 0, "924d02d0a767c3a3b91f9d32aa247669", 2492},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE | ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
+
// Heart of China (PC) GOG
{
"china",
Commit: eeecc8dc5bc6f97b39d76bb7025e23f2b8dfabc6
https://github.com/scummvm/scummvm/commit/eeecc8dc5bc6f97b39d76bb7025e23f2b8dfabc6
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-07-07T16:15:30+10:00
Commit Message:
DGDS: Add various heart of china features
Most dialogs now render correctly and the game is partly playable. Still a
bunch of work to do for inventory and menus to render correctly.
Added loading for TDS (talking head) data structures too, but they are not yet
used.
Changed paths:
engines/dgds/dgds.cpp
engines/dgds/dialog.cpp
engines/dgds/dialog.h
engines/dgds/font.cpp
engines/dgds/inventory.cpp
engines/dgds/menu.cpp
engines/dgds/request.cpp
engines/dgds/request.h
engines/dgds/resource.cpp
engines/dgds/scene.cpp
engines/dgds/scene.h
diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 7b994fc2149..d29f9982e6e 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -576,7 +576,9 @@ Common::Error DgdsEngine::run() {
checkDrawInventoryButton();
}
- _clock.draw(_compositionBuffer);
+ if (getGameId() == GID_DRAGON)
+ _clock.draw(_compositionBuffer);
+
bool haveActiveDialog = _scene->checkDialogActive();
_scene->drawAndUpdateDialogs(&_compositionBuffer);
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 4485cfa9247..251fc46ec65 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -58,7 +58,8 @@ Dialog *Dialog::_lastDialogSelectionChangedFor = nullptr;
Dialog::Dialog() : _num(0), _bgColor(0), _fontColor(0), _selectionBgCol(0), _selectonFontCol(0),
- _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogNum(0)
+ _fontSize(0), _flags(kDlgFlagNone), _frameType(kDlgFramePlain), _time(0), _nextDialogDlgNum(0),
+ _nextDialogFileNum(0)
{}
@@ -115,6 +116,45 @@ void Dialog::drawType1(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
}
}
+void Dialog::drawType2BackgroundDragon(Graphics::ManagedSurface *dst, const Common::String &title) {
+ _state->_loc = DgdsRect(_rect.x + 6, _rect.y + 6, _rect.width - 12, _rect.height - 12);
+ RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
+ RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
+ if (!title.empty()) {
+ // TODO: Maybe should measure the font?
+ _state->_loc.y += 10;
+ _state->_loc.height -= 10;
+ RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title, 0, true);
+ }
+
+ if (hasFlag(kDlgFlagFlatBg)) {
+ dst->fillRect(_state->_loc.toCommonRect(), 0);
+ } else {
+ RequestData::fillBackground(dst, _state->_loc.x, _state->_loc.y, _state->_loc.width, _state->_loc.height, 6);
+ }
+
+ RequestData::drawCorners(dst, 19, _state->_loc.x - 2, _state->_loc.y - 2,
+ _state->_loc.width + 4, _state->_loc.height + 4);
+
+ _state->_loc.x += 8;
+ _state->_loc.width -= 16;
+}
+
+void Dialog::drawType2BackgroundChina(Graphics::ManagedSurface *dst, const Common::String &title) {
+ _state->_loc = DgdsRect(_rect.x + 12, _rect.y + 10, _rect.width - 24, _rect.height - 20);
+ if (title.empty()) {
+ RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
+ RequestData::drawCorners(dst, 1, _rect.x, _rect.y, _rect.width, _rect.height);
+ } else {
+ dst->fillRect(Common::Rect(Common::Point(_rect.x, _rect.y), _rect.width, _rect.height), 0);
+ RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
+ // TODO: Maybe should measure the font?
+ _state->_loc.y += 11;
+ _state->_loc.height -= 11;
+ RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 2, title, _fontColor, false);
+ }
+}
+
// box with fancy frame and optional title (everything before ":")
void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
if (!_state)
@@ -134,29 +174,11 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
}
if (stage == kDlgDrawStageBackground) {
- _state->_loc = DgdsRect(_rect.x + 6, _rect.y + 6, _rect.width - 12, _rect.height - 12);
- Common::Rect drawRect(_rect.x, _rect.y, _rect.x + _rect.width, _rect.y + _rect.height);
- RequestData::fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
- RequestData::drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
- if (!title.empty()) {
- // TODO: Maybe should measure the font?
- _state->_loc.y += 10;
- _state->_loc.height -= 10;
- RequestData::drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, title);
- }
-
- if (hasFlag(kDlgFlagFlatBg)) {
- Common::Rect fr = _state->_loc.toCommonRect();
- dst->fillRect(fr, 0);
- } else {
- RequestData::fillBackground(dst, _state->_loc.x, _state->_loc.y, _state->_loc.width, _state->_loc.height, 6);
- }
-
- RequestData::drawCorners(dst, 19, _state->_loc.x - 2, _state->_loc.y - 2,
- _state->_loc.width + 4, _state->_loc.height + 4);
-
- _state->_loc.x += 8;
- _state->_loc.width -= 16;
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (engine->getGameId() == GID_DRAGON)
+ drawType2BackgroundDragon(dst, title);
+ else
+ drawType2BackgroundChina(dst, title);
} else if (stage == kDlgDrawFindSelectionPointXY) {
drawFindSelectionXY();
@@ -624,9 +646,9 @@ void Dialog::fixupStringAndActions() {
Common::String Dialog::dump(const Common::String &indent) const {
Common::String str = Common::String::format(
- "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d",
+ "%sDialog<num %d %s bgcol %d fcol %d selbgcol %d selfontcol %d fntsz %d flags 0x%02x frame %d delay %d next %d:%d",
indent.c_str(), _num, _rect.dump("").c_str(), _bgColor, _fontColor, _selectionBgCol, _selectonFontCol, _fontSize,
- _flags, _frameType, _time, _nextDialogNum);
+ _flags, _frameType, _time, _nextDialogFileNum, _nextDialogDlgNum);
str += indent + "state=" + (_state ? _state->dump("") : "null");
str += "\n";
str += _dumpStructList(indent, "actions", _action);
diff --git a/engines/dgds/dialog.h b/engines/dgds/dialog.h
index ae40dd71bc9..8c62cae335a 100644
--- a/engines/dgds/dialog.h
+++ b/engines/dgds/dialog.h
@@ -102,6 +102,7 @@ class Dialog {
public:
Dialog();
uint16 _num;
+ uint16 _fileNum; // HOC onward
DgdsRect _rect;
uint16 _bgColor;
uint16 _fontColor;
@@ -111,7 +112,8 @@ public:
DialogFlags _flags;
DialogFrameType _frameType;
uint16 _time;
- uint16 _nextDialogNum;
+ uint16 _nextDialogFileNum; // HOC onward, always set 0 in dragon.
+ uint16 _nextDialogDlgNum;
Common::Array<DialogAction> _action;
Common::String _str;
@@ -137,6 +139,9 @@ private:
void drawType3(Graphics::ManagedSurface *dst, DialogDrawStage stage);
void drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage);
+ void drawType2BackgroundDragon(Graphics::ManagedSurface *dst, const Common::String &title);
+ void drawType2BackgroundChina(Graphics::ManagedSurface *dst, const Common::String &title);
+
void drawFindSelectionXY();
void drawFindSelectionTxtOffset();
void drawForeground(Graphics::ManagedSurface *dst, uint16 fontcol, const Common::String &txt);
diff --git a/engines/dgds/font.cpp b/engines/dgds/font.cpp
index 7beb57644ac..53bdfc1571e 100644
--- a/engines/dgds/font.cpp
+++ b/engines/dgds/font.cpp
@@ -218,8 +218,8 @@ FontManager::FontType FontManager::fontTypeByName(const Common::String &filename
if (filename == "7X8.FNT") return k7x8Font;
if (filename == "P6X6.FNT") return kGameDlgFont;
if (filename == "HOC.FNT") return kGameFont;
- if (filename == "CHINA.FNT") return kChinaFont;
- if (filename == "CHINESE.FNT") return kGameDlgFont;
+ if (filename == "CHINA.FNT") return kGameDlgFont;
+ if (filename == "CHINESE.FNT") return kChinaFont;
if (filename == "WILLY.FNT") return kGameFont;
if (filename == "WVCR.FNT") return kVCRFont;
if (filename == "COMIX_16.FNT") return kGameDlgFont;
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index c82df45d4a4..e361ec24dba 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -70,6 +70,7 @@ void Inventory::setRequestData(const REQFileData &data) {
warning("No inventory request data to load");
return;
}
+
RequestData &req = _reqData._requests[0];
_prevPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(14));
_nextPageBtn = dynamic_cast<ButtonGadget *>(req.findGadgetByNumWithFlags3Not0x40(15));
@@ -104,12 +105,16 @@ void Inventory::drawHeader(Graphics::ManagedSurface &surf) {
int x1 = r._rect.x + 112;
font->drawString(&surf, title, x1 + 4, y1 + 2, titleWidth, 0);
- int x2 = x1 + titleWidth + 6;
- int y2 = y1 + font->getFontHeight();
- surf.drawLine(x1, y1, x2, y1, 0xdf);
- surf.drawLine(x2, y1 + 1, x2, y2, 0xdf);
- surf.drawLine(x1, y1 + 1, x1, y2, 0xff);
- surf.drawLine(x1 + 1, y2, x1 + titleWidth + 5, y2, 0xff);
+ // Only draw the box around the title in DRAGON
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (engine->getGameId() == GID_DRAGON) {
+ int x2 = x1 + titleWidth + 6;
+ int y2 = y1 + font->getFontHeight();
+ surf.drawLine(x1, y1, x2, y1, 0xdf);
+ surf.drawLine(x2, y1 + 1, x2, y2, 0xdf);
+ surf.drawLine(x1, y1 + 1, x1, y2, 0xff);
+ surf.drawLine(x1 + 1, y2, x1 + titleWidth + 5, y2, 0xff);
+ }
}
void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
@@ -145,10 +150,10 @@ void Inventory::draw(Graphics::ManagedSurface &surf, int itemCount) {
}
void Inventory::drawTime(Graphics::ManagedSurface &surf) {
- if (!_invClock) // no clock in Willy Beamish demo.
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ if (engine->getGameId() != GID_DRAGON)
return;
- DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
const DgdsFont *font = RequestData::getMenuFont();
const Common::String timeStr = engine->getClock().getTimeStr();
Common::Point clockpos = Common::Point(_invClock->_x + _invClock->_parentX, _invClock->_y + _invClock->_parentY);
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index d7c4a192451..0485320c4eb 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -317,8 +317,14 @@ void Menu::handleClick(const Common::Point &mouse) {
break;
case kMenuMainCalibrate:
case kMenuJoystickCalibrationOK:
- case kMenuMouseCalibrationCalibrate:
- drawMenu(kMenuCalibrate);
+ case kMenuMouseCalibrationCalibrate: // NOTE: same ID as kMenuJumpToGame (for HOC)
+ if (_curMenu == kMenuSkipPlayIntro) {
+ hideMenu();
+ engine->setShowClock(true);
+ engine->changeScene(24);
+ } else {
+ drawMenu(kMenuCalibrate);
+ }
break;
case kMenuMainFiles:
case kMenuSaveCancel:
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index a9011853149..018d8be38ac 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -45,12 +45,14 @@ static const byte SliderColors[] = {
0x7B, 0x4D, 0xF4, 0x54, 0xDF, 0x74, 0x58
};
-static const byte FallbackColors[] = {
+static const byte DragonFallbackColors[] = {
0x7, 0x7, 0x8, 0x7, 0x0, 0xF, 0x7, 0xC,
0x4, 0x0, 0xF, 0xF, 0xC, 0x4, 0x7, 0xF,
0x8, 0x7, 0x0, 0x7, 0x7
};
+static const byte ChinaBakgroundColor = 23;
+
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,
@@ -688,7 +690,7 @@ void RequestData::drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, ui
}
/*static*/
-void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header) {
+void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header, byte fontCol, bool addBox) {
if (!header.empty()) {
const DgdsFont *font = getMenuFont();
int hwidth = font->getStringWidth(header);
@@ -698,11 +700,13 @@ void RequestData::drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, in
int htop = y + yoffset;
int hbottom = htop + hheight;
- font->drawString(dst, header, hleft + 1, htop + 2, hwidth, 0);
- dst->drawLine(hleft - 3, htop, hright, htop, 0);
- dst->drawLine(hright, htop + 1, hright, hbottom, 0);
- dst->drawLine(hleft - 3, htop + 1, hleft - 3, hbottom, 15);
- dst->drawLine(hleft - 2, hbottom, hleft + hwidth, hbottom, 15);
+ font->drawString(dst, header, hleft + 1, htop + 2, hwidth, fontCol);
+ if (addBox) {
+ dst->drawLine(hleft - 3, htop, hright, htop, 0);
+ dst->drawLine(hright, htop + 1, hright, hbottom, 0);
+ dst->drawLine(hleft - 3, htop + 1, hleft - 3, hbottom, 15);
+ dst->drawLine(hleft - 2, hbottom, hleft + hwidth, hbottom, 15);
+ }
}
}
@@ -746,20 +750,25 @@ void RequestData::drawBackgroundWithSliderArea(Graphics::ManagedSurface *dst, in
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));
- drawHeader(dst, x, y, width, 9, header);
+ drawHeader(dst, x, y, width, 9, header, 0,
+ static_cast<DgdsEngine *>(g_engine)->getGameId() == GID_DRAGON);
}
void RequestData::drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const Common::String &header) const {
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
fillBackground(dst, _rect.x, _rect.y, _rect.width, _rect.height, 0);
- drawCorners(dst, 11, _rect.x, _rect.y, _rect.width, _rect.height);
- drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, header);
+ drawCorners(dst, engine->getGameId() == GID_DRAGON ? 11 : 1, _rect.x, _rect.y, _rect.width, _rect.height);
+ drawHeader(dst, _rect.x, _rect.y, _rect.width, 4, header, 0,
+ engine->getGameId() == GID_DRAGON);
}
/*static*/
void RequestData::fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset) {
- if (static_cast<DgdsEngine *>(g_engine)->getDetailLevel() == kDgdsDetailHigh) {
- Graphics::Surface area = dst->getSubArea(Common::Rect(x, y, x + width, y + height));
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+
+ if (engine->getGameId() == GID_DRAGON && engine->getDetailLevel() == kDgdsDetailHigh) {
+ Graphics::Surface area = dst->getSubArea(Common::Rect(Common::Point(x, y), width, height));
while (startoffset < 0)
startoffset += ARRAYSIZE(MenuBackgroundColors);
startoffset = startoffset % ARRAYSIZE(MenuBackgroundColors);
@@ -780,7 +789,10 @@ void RequestData::fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16
coloffset = ARRAYSIZE(MenuBackgroundColors) - 1;
}
} else {
- dst->fillRect(Common::Rect(x, y, width, height), FallbackColors[0]);
+ byte bgCol = DragonFallbackColors[0];
+ if (engine->getGameId() == GID_CHINA)
+ bgCol = ChinaBakgroundColor;
+ dst->fillRect(Common::Rect(Common::Point(x, y), width, height), bgCol);
}
}
diff --git a/engines/dgds/request.h b/engines/dgds/request.h
index aaaba3f7473..7a95ddf7a1d 100644
--- a/engines/dgds/request.h
+++ b/engines/dgds/request.h
@@ -197,7 +197,7 @@ public:
static void fillBackground(Graphics::ManagedSurface *dst, uint16 x, uint16 y, uint16 width, uint16 height, int16 startoffset);
static void drawCorners(Graphics::ManagedSurface *dst, uint16 startNum, uint16 x, uint16 y, uint16 width, uint16 height);
- static void drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header);
+ static void drawHeader(Graphics::ManagedSurface *dst, int16 x, int16 y, int16 width, int16 yoffset, const Common::String &header, byte fontCol, bool addBox);
Gadget *findGadgetByNumWithFlags3Not0x40(int16 num);
private:
diff --git a/engines/dgds/resource.cpp b/engines/dgds/resource.cpp
index 188100ee861..ee4d7e24409 100644
--- a/engines/dgds/resource.cpp
+++ b/engines/dgds/resource.cpp
@@ -178,6 +178,9 @@ bool DgdsChunkReader::isPacked() const {
case EX_TDS:
packed = (_id == ID_THD);
break;
+ case EX_DDS:
+ packed = (_id == ID_DDS);
+ break;
default:
break;
}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 2a655e52a33..cfa63e87bbf 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -128,6 +128,14 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
case kSceneOpHideClock: return "sceneOpHideClock";
case kSceneOpShowMouse: return "sceneOpShowMouse";
case kSceneOpHideMouse: return "sceneOpHideMouse";
+ case kSceneOpLoadTalkDataAndSetFlags: return "sceneOpLoadTalkDataAndSetFlags";
+ case kSceneOpDrawVisibleTalkHeads: return "sceneOpDrawVisibleTalksHeads";
+ case kSceneOpLoadTalkData: return "sceneOpLoadTalkData";
+ case kSceneOpLoadDDSData: return "sceneOpLoadDDSData";
+ case kSceneOpFreeDDSData: return "sceneOpFreeDDSData";
+ case kSceneOpFreeTalkData: return "sceneOpFreeTalkData";
+
+ // Dragon-specific
case kSceneOpPasscode: return "passcode";
case kSceneOpMeanwhile: return "meanwhile";
case kSceneOpOpenGameOverMenu: return "openGameOverMenu";
@@ -365,15 +373,18 @@ bool Scene::readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &li
}
-bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const {
+bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list, int16 filenum /* = 0 */) const {
// Some data on this format here https://www.oldgamesitalia.net/forum/index.php?showtopic=24055&st=25&p=359214&#entry359214
uint16 nitems = s->readUint16LE();
_checkListNotTooLong(nitems, "dialogs");
- list.resize(nitems);
+ uint startsize = list.size();
+ list.resize(startsize + nitems);
- for (Dialog &dst : list) {
+ for (uint i = startsize; i < list.size(); i++) {
+ Dialog &dst = list[i];
dst._num = s->readUint16LE();
+ dst._fileNum = filenum;
dst._rect.x = s->readUint16LE();
dst._rect.y = s->readUint16LE();
dst._rect.width = s->readUint16LE();
@@ -400,11 +411,12 @@ bool Scene::readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog>
dst._frameType = static_cast<DialogFrameType>(s->readUint16LE());
dst._time = s->readUint16LE();
if (isVersionOver(" 1.215")) {
- s->readUint16LE();
- error("TODO: what is this extra int in dialog action list?");
+ dst._nextDialogFileNum = s->readUint16LE();
+ } else {
+ dst._nextDialogFileNum = 0;
}
if (isVersionOver(" 1.207")) {
- dst._nextDialogNum = s->readUint16LE();
+ dst._nextDialogDlgNum = s->readUint16LE();
}
uint16 nbytes = s->readUint16LE();
@@ -586,7 +598,10 @@ bool Scene::runSceneOp(const SceneOp &op) {
// This implicitly changes scene num
return false;
case kSceneOpShowDlg:
- showDialog(op._args[0]);
+ if (op._args.size() == 1)
+ showDialog(0, op._args[0]);
+ else
+ showDialog(op._args[0], op._args[1]);
break;
case kSceneOpShowInvButton:
engine->getScene()->addInvButtonToHotAreaList();
@@ -640,6 +655,26 @@ bool Scene::runSceneOp(const SceneOp &op) {
case kSceneOpHideMouse:
CursorMan.showMouse(false);
break;
+ case kSceneOpLoadTalkDataAndSetFlags: // args: tdsnum to load, headnum
+ engine->getScene()->loadTalkDataAndSomething(op._args[0], op._args[1]);
+ break;
+ case kSceneOpDrawVisibleTalkHeads: // args: none
+ engine->getScene()->drawVisibleTalkers();
+ break;
+ case kSceneOpLoadTalkData: // args: tds num to load
+ engine->getScene()->loadTalkData(op._args[0]);
+ break;
+ case kSceneOpLoadDDSData: // args: dds num to load
+ if (op._args[0])
+ engine->getScene()->loadDialogData(op._args[0]);
+ break;
+ case kSceneOpFreeDDSData: // args: dds num to free
+ engine->getScene()->freeDialogData(op._args[0]);
+ break;
+ case kSceneOpFreeTalkData: // args: tds num to free
+ engine->getScene()->freeTalkData(op._args[0]);
+ break;
+
default:
warning("TODO: Implement generic scene op %d", op._opCode);
break;
@@ -701,9 +736,7 @@ bool Scene::runChinaOp(const SceneOp &op) {
engine->setMenuToTrigger(kMenuSkipPlayIntro);
break;
case kSceneOpOpenChinaStartIntro:
- // TODO: This is the intro scene but it doesn't work directly.. what's different?
// The game first jumps to scene 100, and then to 98
- warning("TODO: Implement start intro opcode");
engine->changeScene(98);
return false;
default:
@@ -957,6 +990,225 @@ void SDSScene::checkTriggers() {
}
}
+
+Dialog *SDSScene::loadDialogData(uint16 num) {
+ if (num == 0)
+ return &_dialogs.front();
+
+ for (auto &dlg: _dialogs)
+ if (dlg._fileNum == num)
+ return &dlg;
+
+ const Common::String filename = Common::String::format("D%d.DDS", num);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ ResourceManager *resourceManager = engine->getResourceManager();
+ Common::SeekableReadStream *dlgFile = resourceManager->getResource(filename);
+ if (!dlgFile)
+ error("Dialog file %s not found", filename.c_str());
+
+ DgdsChunkReader chunk(dlgFile);
+ Decompressor *decompressor = engine->getDecompressor();
+
+ bool result = false;
+
+ while (chunk.readNextHeader(EX_DDS, filename)) {
+ if (chunk.isContainer()) {
+ continue;
+ }
+
+ chunk.readContent(decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+
+ if (chunk.isSection(ID_DDS)) {
+ uint32 magic = stream->readUint32LE();
+ if (magic != _magic)
+ error("Dialog file magic mismatch %08x vs scene %08x", magic, _magic);
+ Common::String fileVersion = stream->readString();
+ Common::String fileId = stream->readString();
+ // slight hack, set file version while loading
+ Common::String oldVer = _version;
+ _version = fileVersion;
+ result = readDialogList(stream, _dialogs, num);
+ _version = oldVer;
+ }
+ }
+
+ delete dlgFile;
+
+ if (!result)
+ return nullptr;
+
+ for (auto &dlg : _dialogs) {
+ if (dlg._nextDialogDlgNum && !dlg._nextDialogFileNum) {
+ dlg._nextDialogFileNum = num;
+ }
+ }
+
+ // TODO: Maybe not this?
+ return &_dialogs.front();
+}
+
+void SDSScene::freeDialogData(uint16 num) {
+ if (!num)
+ return;
+
+ for (uint i = 0; i < _dialogs.size(); i++) {
+ if (_dialogs[i]._num == num) {
+ _dialogs.remove_at(i);
+ i--;
+ }
+ }
+}
+
+bool SDSScene::readTalkData(Common::SeekableReadStream *s, TalkData &dst) {
+ dst._bmpFile = s->readString();
+
+ uint16 nvals = s->readUint16LE();
+ _checkListNotTooLong(nvals, "talk data");
+ dst._heads.resize(nvals);
+ for (auto &h : dst._heads) {
+ h._num = s->readUint16LE();
+ h._drawType = s->readUint16LE();
+ h._drawCol = s->readUint16LE();
+ h._rect.x = s->readUint16LE();
+ h._rect.y = s->readUint16LE();
+ h._rect.width = s->readUint16LE();
+ h._rect.height = s->readUint16LE();
+ uint16 nsub = s->readUint16LE();
+ _checkListNotTooLong(nsub, "talk head frames");
+ h._headFrames.resize(nsub);
+ for (auto &sub : h._headFrames) {
+ sub._frameNo = s->readUint16LE();
+ sub._xoff = s->readUint16LE();
+ sub._yoff = s->readUint16LE();
+ }
+ }
+
+ return true;
+}
+
+bool SDSScene::loadTalkData(uint16 num) {
+ if (!num)
+ return false;
+
+ for (auto &talk : _talkData) {
+ if (talk._num == num)
+ return true;
+ }
+
+ const Common::String filename = Common::String::format("T%d.TDS", num);
+ DgdsEngine *engine = static_cast<DgdsEngine *>(g_engine);
+ ResourceManager *resourceManager = engine->getResourceManager();
+ Common::SeekableReadStream *dlgFile = resourceManager->getResource(filename);
+ if (!dlgFile)
+ error("Talk file %s not found", filename.c_str());
+
+ DgdsChunkReader chunk(dlgFile);
+ Decompressor *decompressor = engine->getDecompressor();
+
+ bool result = false;
+
+ while (chunk.readNextHeader(EX_TDS, filename)) {
+ if (chunk.isContainer()) {
+ continue;
+ }
+
+ chunk.readContent(decompressor);
+ Common::SeekableReadStream *stream = chunk.getContent();
+
+ if (chunk.isSection(ID_THD)) {
+ uint32 magic = stream->readUint32LE();
+ if (magic != _magic)
+ error("Talk file magic mismatch %08x vs scene %08x", magic, _magic);
+ Common::String fileVersion = stream->readString();
+ Common::String fileId = stream->readString();
+ // slight hack, set file version while loading
+ Common::String oldVer = _version;
+ _version = fileVersion;
+ _talkData.insert_at(0, TalkData());
+ result = readTalkData(stream, _talkData.front());
+ _talkData.front()._num = num;
+ _version = oldVer;
+ }
+ }
+
+ delete dlgFile;
+
+ return result;
+}
+
+void SDSScene::freeTalkData(uint16 num) {
+ for (uint i = 0; i < _talkData.size(); i++) {
+ if (_talkData[i]._num == num) {
+ _talkData.remove_at(i);
+ i--;
+ }
+ }
+}
+
+void SDSScene::drawVisibleTalkers() {
+ for (auto &data : _talkData) {
+ for (auto &head : data._heads) {
+ if (head._flags & kHeadFlagVisible)
+ updateHead(head);
+ }
+ }
+}
+
+void SDSScene::drawHead(Graphics::ManagedSurface *dst, const TalkData &data, const TalkDataHead &head) {
+ uint drawtype = head._drawType ? head._drawType : 1;
+ switch (drawtype) {
+ case 1:
+ drawHeadType1(dst, head, *data._shape);
+ break;
+ case 2:
+ drawHeadType2(dst, head, *data._shape);
+ break;
+ case 3:
+ drawHeadType3(dst, head, *data._shape);
+ break;
+ default:
+ error("Unsupported head draw type %d", drawtype);
+ }
+}
+
+void SDSScene::drawHeadType1(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img) {
+
+}
+
+void SDSScene::drawHeadType2(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img) {
+
+}
+
+void SDSScene::drawHeadType3(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img) {
+
+}
+
+void SDSScene::updateHead(TalkDataHead &head) {
+ warning("TODO: Update head");
+ head._flags = static_cast<HeadFlags>(head._flags & ~(kHeadFlag1 | kHeadFlag8 | kHeadFlag10 | kHeadFlagVisible));
+}
+
+void SDSScene::loadTalkDataAndSomething(uint16 talknum, uint16 headnum) {
+ drawVisibleTalkers();
+ if (loadTalkData(talknum)) {
+ for (auto &data : _talkData) {
+ if (data._num != talknum)
+ continue;
+
+ for (auto &head : data._heads) {
+ if (head._num != headnum)
+ continue;
+ head._flags = static_cast<HeadFlags>(head._flags & ~(kHeadFlag1 | kHeadFlag10));
+ head._flags = static_cast<HeadFlags>(head._flags | (kHeadFlag8 | kHeadFlagVisible));
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
static const uint16 TIRED_DLG_ID = 7777;
void SDSScene::addAndShowTiredDialog() {
@@ -981,7 +1233,7 @@ void SDSScene::addAndShowTiredDialog() {
dlg._str = "Boy, am I tired. Better get some sleep in about an hour.";
_dialogs.push_back(dlg);
}
- showDialog(TIRED_DLG_ID);
+ showDialog(0, TIRED_DLG_ID);
}
@@ -1065,9 +1317,12 @@ void SDSScene::sceneOpUpdatePasscodeGlobal() {
engine->getGDSScene()->setGlobal(0x20, globalval);
}
-void SDSScene::showDialog(uint16 num) {
+void SDSScene::showDialog(uint16 fileNum, uint16 dlgNum) {
+ if (fileNum)
+ loadDialogData(fileNum);
+
for (auto &dialog : _dialogs) {
- if (dialog._num == num) {
+ if (dialog._num == dlgNum) {
dialog.clearFlag(kDlgFlagHiFinished);
dialog.clearFlag(kDlgFlagRedrawSelectedActionChanged);
dialog.clearFlag(kDlgFlagHi10);
@@ -1137,9 +1392,9 @@ bool SDSScene::checkDialogActive() {
}
}
}
- if (dlg._nextDialogNum) {
+ if (dlg._nextDialogDlgNum) {
dlg.setFlag(kDlgFlagHiFinished);
- showDialog(dlg._nextDialogNum);
+ showDialog(dlg._nextDialogFileNum, dlg._nextDialogDlgNum);
}
}
if (dlg.hasFlag(kDlgFlagVisible)) {
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 2a0f8fa1fd3..fb68d628cf7 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -103,6 +103,14 @@ enum SceneOpCode {
kSceneOpHideClock = 17, // args: none. set clock script-hidden.
kSceneOpShowMouse = 18, // args: none.
kSceneOpHideMouse = 19, // args: none.
+ // Op 20 onward are common, but not in dragon
+
+ kSceneOpLoadTalkDataAndSetFlags = 20, // args: tdsnum to load, headnum
+ kSceneOpDrawVisibleTalkHeads = 21, // args: none
+ kSceneOpLoadTalkData = 22, // args: tds num to load
+ kSceneOpLoadDDSData = 24, // args: dds num to load
+ kSceneOpFreeDDSData = 25, // args: dds num to free
+ kSceneOpFreeTalkData = 26, // args: tds num to free
// Dragon-specific opcodes
kSceneOpPasscode = 100, // args: none.
@@ -119,6 +127,8 @@ enum SceneOpCode {
kSceneOpOpenChinaOpenGameOverMenu = 114, // args: none.
kSceneOpOpenChinaOpenSkipCreditsMenu = 115, // args: none.
kSceneOpOpenChinaStartIntro = 116, // args: none.
+ kSceneOpChina117 = 117, // args: none. ??
+ kSceneOpChina118 = 118, // args: none. ??
// Beamish-specific opcodes
kSceneOpOpenBeamishOpenSkipCreditsMenu = 101,
@@ -217,6 +227,53 @@ private:
};
+class TalkDataHeadFrame {
+public:
+ TalkDataHeadFrame() : _xoff(0), _yoff(0), _frameNo(0) {}
+ Common::String dump(const Common::String &indent) const;
+
+ uint16 _frameNo;
+ uint16 _xoff;
+ uint16 _yoff;
+};
+
+enum HeadFlags {
+ kHeadFlagNone = 0,
+ kHeadFlag1 = 1,
+ kHeadFlag2 = 2,
+ kHeadFlag4 = 4,
+ kHeadFlag8 = 8,
+ kHeadFlag10 = 0x10,
+ kHeadFlagVisible = 0x20,
+};
+
+class TalkDataHead {
+public:
+ TalkDataHead() : _num(0), _drawType(0), _drawCol(0), _val3(0), _flags(kHeadFlagNone) {}
+ Common::String dump(const Common::String &indent) const;
+
+ uint16 _num;
+ uint16 _drawType;
+ uint16 _drawCol;
+ DgdsRect _rect;
+ Common::Array<TalkDataHeadFrame> _headFrames;
+ uint16 _val3;
+ HeadFlags _flags;
+};
+
+class TalkData {
+public:
+ TalkData() : _num(0) {}
+ Common::String dump(const Common::String &indent) const;
+
+ uint16 _num;
+ Common::SharedPtr<Image> _shape;
+ Common::Array<TalkDataHead> _heads;
+ uint16 _val;
+ Common::String _bmpFile;
+};
+
+
/**
* A scene is described by an SDS file, which points to the ADS script to load
* and holds the dialog info.
@@ -233,8 +290,8 @@ public:
uint32 getMagic() const { return _magic; }
const Common::String &getVersion() const { return _version; }
- void runPreTickOps() { runOps(_preTickOps); }
- void runPostTickOps() { runOps(_postTickOps); }
+ bool runPreTickOps() { return runOps(_preTickOps); }
+ bool runPostTickOps() { return runOps(_postTickOps); }
void mouseMoved(const Common::Point pt);
void mouseClicked(const Common::Point pt);
@@ -251,13 +308,13 @@ protected:
bool readMouseHotspotList(Common::SeekableReadStream *s, Common::Array<MouseCursor> &list) const;
bool readObjInteractionList(Common::SeekableReadStream *s, Common::Array<ObjectInteraction> &list) const;
bool readOpList(Common::SeekableReadStream *s, Common::Array<SceneOp> &list) const;
- bool readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list) const;
+ bool readDialogList(Common::SeekableReadStream *s, Common::Array<Dialog> &list, int16 filenum = 0) const;
bool readTriggerList(Common::SeekableReadStream *s, Common::Array<SceneTrigger> &list) const;
bool readDialogActionList(Common::SeekableReadStream *s, Common::Array<DialogAction> &list) const;
bool checkConditions(const Common::Array<SceneConditions> &cond) const;
- virtual void showDialog(uint16 num) {}
+ virtual void showDialog(uint16 fileNum, uint16 dlgNum) {}
virtual void globalOps(const Common::Array<uint16> &args) {}
virtual void segmentStateOps(const Common::Array<uint16> &args);
@@ -378,16 +435,30 @@ public:
void onDragFinish(const Common::Point &pt);
void enableTrigger(uint16 num, bool enable = true) override;
+ Dialog *loadDialogData(uint16 num);
+ void freeDialogData(uint16 num);
+ bool loadTalkData(uint16 num);
+ void freeTalkData(uint16 num);
+ void drawVisibleTalkers();
+ void loadTalkDataAndSomething(uint16 talknum, uint16 headnum);
+
// dragon-specific scene ops
void addAndShowTiredDialog();
void sceneOpUpdatePasscodeGlobal();
+
protected:
HotArea *findAreaUnderMouse(const Common::Point &pt);
private:
- void showDialog(uint16 num) override;
+ void showDialog(uint16 fileNum, uint16 dlgNum) override;
Dialog *getVisibleDialog();
+ bool readTalkData(Common::SeekableReadStream *s, TalkData &dst);
+ void updateHead(TalkDataHead &head);
+ void drawHead(Graphics::ManagedSurface *dst, const TalkData &data, const TalkDataHead &head);
+ void drawHeadType1(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img);
+ void drawHeadType2(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img);
+ void drawHeadType3(Graphics::ManagedSurface *dst, const TalkDataHead &head, const Image &img);
int _num;
Common::Array<SceneOp> _enterSceneOps;
@@ -402,6 +473,8 @@ private:
//uint _field12_0x2b;
//uint _field15_0x33;
+ Common::Array<TalkData> _talkData;
+
// From here on is mutable stuff that might need saving
Common::Array<Dialog> _dialogs;
Common::Array<SceneTrigger> _triggers;
More information about the Scummvm-git-logs
mailing list