[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