[Scummvm-git-logs] scummvm master -> 29bc5487cd9ca061072a491669a7170bf298633f

mduggan noreply at scummvm.org
Mon Dec 30 09:51:22 UTC 2024


This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
3464207be1 DGDS: Fix rendering of Willy Beamish sub-menu header
2f0c00cabf DGDS: Fix dragging items into/out-of inventory in Beamish
14e119bb78 DGDS: Misc fixes for Willy Beamish
f79c7bec8d DGDS: Print debug after loading DDS data
854c2c4665 DGDS: Fix inventory wrapping for Willy Beamish
29bc5487cd DGDS: Implement willy trouble gauge


Commit: 3464207be18eefacf197830abaebc286c486182c
    https://github.com/scummvm/scummvm/commit/3464207be18eefacf197830abaebc286c486182c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:04:15+11:00

Commit Message:
DGDS: Fix rendering of Willy Beamish sub-menu header

Changed paths:
    engines/dgds/request.cpp


diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index a8a769e12e0..140d818b33b 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -69,6 +69,7 @@ static const byte ChinaSliderColors[] = {
 
 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,
@@ -1050,8 +1051,11 @@ void RequestData::drawBackgroundNoSliders(Graphics::ManagedSurface *dst, const C
 	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
+	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*/


Commit: 2f0c00cabf1280d2d669d633a9225dcf96b754d7
    https://github.com/scummvm/scummvm/commit/2f0c00cabf1280d2d669d633a9225dcf96b754d7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:04:15+11:00

Commit Message:
DGDS: Fix dragging items into/out-of inventory in Beamish

Changed paths:
    engines/dgds/inventory.cpp
    engines/dgds/inventory.h


diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index defabceea98..1a2a3aae81a 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -49,10 +49,12 @@ void Inventory::open() {
 	_isOpen = true;
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
-	if (engine->getGameId() == GID_WILLY)
+	int curScene = engine->getScene()->getNum();
+	if (engine->getGameId() == GID_WILLY) {
+		_openedFromSceneNum = curScene;
 		return;
+	}
 
-	int curScene = engine->getScene()->getNum();
 	if (curScene != 2) {
 		_openedFromSceneNum = curScene;
 		engine->changeScene(2);
@@ -362,7 +364,7 @@ GameItem *Inventory::itemUnderMouse(const Common::Point &pt) {
 	return nullptr;
 }
 
-bool Inventory::isItemInInventory(GameItem &item) {
+bool Inventory::isItemInInventory(const GameItem &item) {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 	DgdsGameId gameId = engine->getGameId();
 	bool result = item._inSceneNum == 2; // && (item._flags & 4)
@@ -403,6 +405,8 @@ void Inventory::mouseLUp(const Common::Point &pt) {
 	GameItem *dragItem = engine->getScene()->getDragItem();
 
 	if (dragItem) {
+		if (engine->getGameId() == GID_WILLY)
+			dragItem->_inSceneNum = 2;
 		engine->getScene()->onDragFinish(pt);
 		return;
 	}
@@ -416,7 +420,7 @@ void Inventory::mouseLUp(const Common::Point &pt) {
 		close();
 	} else if (_nextPageBtn->containsPoint(pt) && _nextPageBtn->isVisible()) {
 		int numInvItems = 0;
-		Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
+		const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
 		for (auto &item: items) {
 			if (isItemInInventory(item))
 				numInvItems++;
diff --git a/engines/dgds/inventory.h b/engines/dgds/inventory.h
index 5a8c0ee3aba..d871b476033 100644
--- a/engines/dgds/inventory.h
+++ b/engines/dgds/inventory.h
@@ -60,7 +60,7 @@ public:
 	static const byte HOC_CHARACTER_QUALS[];
 private:
 	GameItem *itemUnderMouse(const Common::Point &pt);
-	bool isItemInInventory(GameItem &item);
+	bool isItemInInventory(const GameItem &item);
 
 	uint16 _openedFromSceneNum;
 


Commit: 14e119bb78d5c39737e3b6d90787b6de2bd78e0b
    https://github.com/scummvm/scummvm/commit/14e119bb78d5c39737e3b6d90787b6de2bd78e0b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:04:15+11:00

Commit Message:
DGDS: Misc fixes for Willy Beamish

* Play sample should be one-shot (don't replay every frame)
* TTM op 0020 should save to background differently (fixes double-drawing)
* Disabled areas still change mouse cursor and hold clicks until enabled,
  properly fixes eg exiting detention at the start
* Fix the way "used" sequences are calculated so Willy can enter his house,
  removing the previous hack
* Refactor scene condition check to separate file
* Small const correctness improvements

Changed paths:
    engines/dgds/ads.cpp
    engines/dgds/clock.cpp
    engines/dgds/clock.h
    engines/dgds/hoc_intro.cpp
    engines/dgds/inventory.cpp
    engines/dgds/minigames/dragon_arcade_ttm.cpp
    engines/dgds/minigames/dragon_arcade_ttm.h
    engines/dgds/scene.cpp
    engines/dgds/scene.h
    engines/dgds/scene_condition.cpp
    engines/dgds/scene_condition.h
    engines/dgds/scene_op.cpp
    engines/dgds/ttm.cpp


diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 1c43841464e..a13d36a47e8 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -132,11 +132,6 @@ bool ADSInterpreter::load(const Common::String &filename) {
 	return true;
 }
 
-static const uint16 ADS_SEQ_OPCODES[] = {
-	0x2000, 0x2005, 0x2010, 0x2015, 0x4000, 0x4010, 0x1330,
-	0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
-};
-
 bool ADSInterpreter::updateSeqTimeAndFrame(const TTMEnviro *env, Common::SharedPtr<TTMSeq> seq) {
 	if (seq->_timeInterval != 0) {
 		uint32 now = DgdsEngine::getInstance()->getThisFrameMs();
@@ -163,16 +158,31 @@ bool ADSInterpreter::updateSeqTimeAndFrame(const TTMEnviro *env, Common::SharedP
 	return true;
 }
 
+static const uint16 ADS_USED_SEQ_OPCODES[] = {
+	0x2000, 0x2005, 0x2010, 0x2015, 0x4000, 0x4010, 0x1330,
+	0x1340, 0x1360, 0x1370, 0x1320, 0x1310, 0x1350
+};
+
 void ADSInterpreter::findUsedSequencesForSegment(int idx) {
 	_adsData->_usedSeqs[idx].clear();
 	int64 startoff = _adsData->scr->pos();
 	uint16 opcode = 0;
 	// Skip the segment number.
 	int16 segno = _adsData->scr->readUint16LE();
+
+	DgdsGameId gameId = DgdsEngine::getInstance()->getGameId();
+	//
+	// HoC and Dragon call a sequence "used" if there is any dependency on
+	// the sequence (reordering, if conditions), but to simplify the use of
+	// getStateForSceneOp, later games only call it "used" if it is directly
+	// started.
+	//
+	int n_ops_to_check = (gameId == GID_DRAGON || gameId == GID_HOC) ? ARRAYSIZE(ADS_USED_SEQ_OPCODES) : 2;
 	while (opcode != 0xffff && _adsData->scr->pos() < _adsData->scr->size()) {
 		opcode = _adsData->scr->readUint16LE();
-		for (uint16 o : ADS_SEQ_OPCODES) {
-			if (opcode == o) {
+		for (int i = 0; i < n_ops_to_check; i++) {
+			uint16 op = ADS_USED_SEQ_OPCODES[i];
+			if (opcode == op) {
 				int16 envno = _adsData->scr->readSint16LE();
 				int16 seqno = _adsData->scr->readSint16LE();
 				Common::SharedPtr<TTMSeq> seq = findTTMSeq(envno, seqno);
@@ -807,7 +817,7 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
 			}
 			return 0;
 		}
-	} else if (DgdsEngine::getInstance()->getGameId() == GID_HOC) {
+	} else {
 		int state = (_adsData->_state[idx] & 0xfff7);
 		if (state != 4 && state != 1) {
 			for (const Common::SharedPtr<TTMSeq> &seq: _adsData->_usedSeqs[idx]) {
@@ -818,24 +828,6 @@ int16 ADSInterpreter::getStateForSceneOp(uint16 segnum) {
 			}
 			return 0;
 		}
-	} else { // WILLY+
-		int state = (_adsData->_state[idx] & 0xfff7);
-		if (state != 4 && state != 1) {
-			for (const Common::SharedPtr<TTMSeq> &seq: _adsData->_usedSeqs[idx]) {
-				if (!seq)
-					error("getStateForSceneOp: used seq for seg %d should not be null", segnum);
-				//
-				// TODO: This last check is a bit of a guess to make Willy Beamish work correctly.
-				// It seems to need sequences to return false from this function even when they
-				// are delayed.  Eg, outside the house (HE.ADS, scene 10), seq 20 (willy scratching
-				// his leg) runs and repeats randomly every 400 to 900 frames, but the door hot area
-				// is not active if that script is "running".
-				//
-				if (seq->_runFlag != kRunTypeStopped && seq->_runFlag != kRunTypeFinished && !seq->_selfLoop && seq->_timeNext <= DgdsEngine::getInstance()->getThisFrameMs())
-					return 1;
-			}
-			return 0;
-		}
 	}
 
 	return 1;
@@ -1007,7 +999,6 @@ void ADSInterpreter::setGotoTarget(int32 target) {
 }
 
 int ADSInterpreter::numArgs(uint16 opcode) const {
-	// TODO: This list is from DRAGON, there may be more entries in newer games.
 	switch (opcode) {
 	case 0x1080:
 	case 0x1090:
diff --git a/engines/dgds/clock.cpp b/engines/dgds/clock.cpp
index e6f248fd86f..e9a4b8821ad 100644
--- a/engines/dgds/clock.cpp
+++ b/engines/dgds/clock.cpp
@@ -173,7 +173,7 @@ void Clock::update(bool gameRunning) {
 		addGameTime(mins_to_add);
 }
 
-Common::String Clock::dump() {
+Common::String Clock::dump() const {
 	return Common::String::format("days %d hours %d mins %d", _days, _mins, _hours);
 }
 
diff --git a/engines/dgds/clock.h b/engines/dgds/clock.h
index 1fcb1e8d600..66c9c699491 100644
--- a/engines/dgds/clock.h
+++ b/engines/dgds/clock.h
@@ -64,7 +64,7 @@ public:
 
 	Common::Error syncState(Common::Serializer &s);
 
-	Common::String dump();
+	Common::String dump() const;
 
 private:
 	uint32 _lastPlayTime;
diff --git a/engines/dgds/hoc_intro.cpp b/engines/dgds/hoc_intro.cpp
index 8bba17c2942..53118d196b6 100644
--- a/engines/dgds/hoc_intro.cpp
+++ b/engines/dgds/hoc_intro.cpp
@@ -134,7 +134,7 @@ void HocIntro::end() {
 	_noMaskImg.reset();
 
 	globals->setIntroState(0);
-	static_cast<HocGlobals *>(engine->getGameGlobals())->setNativeGameState(0);
+	globals->setNativeGameState(0);
 }
 
 void HocIntro::doCopy(int16 x1, int16 y1, int16 x2, int16 y2) {
diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index 1a2a3aae81a..d21ad3078dc 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -277,7 +277,7 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
 	const Common::Rect drawMask(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
 	int offset = _itemOffset;
 	Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
-	for (auto & item: items) {
+	for (auto &item: items) {
 		if (!isItemInInventory(item))
 			continue;
 
diff --git a/engines/dgds/minigames/dragon_arcade_ttm.cpp b/engines/dgds/minigames/dragon_arcade_ttm.cpp
index e4b7aea861b..f2a2e640dab 100644
--- a/engines/dgds/minigames/dragon_arcade_ttm.cpp
+++ b/engines/dgds/minigames/dragon_arcade_ttm.cpp
@@ -28,7 +28,7 @@
 
 namespace Dgds {
 
-Common::String ArcadeFloor::dump() {
+Common::String ArcadeFloor::dump() const {
 	return Common::String::format("ArcadeFloor<x:%d-%d y:%d flg:%d>",
 				x, x + width, yval, flag);
 }
diff --git a/engines/dgds/minigames/dragon_arcade_ttm.h b/engines/dgds/minigames/dragon_arcade_ttm.h
index eb3e4d7ed38..5c36080d644 100644
--- a/engines/dgds/minigames/dragon_arcade_ttm.h
+++ b/engines/dgds/minigames/dragon_arcade_ttm.h
@@ -41,7 +41,7 @@ public:
 	byte yval;
 	bool flag;
 
-	Common::String dump();
+	Common::String dump() const;
 };
 
 
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index c64b42f95f9..5002aff6d28 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -481,7 +481,7 @@ bool Scene::runOps(const Common::Array<SceneOp> ops, int16 addMinuites /* = 0 */
 	bool sceneChanged = false;
 	int16 startSceneNum = engine->getScene()->getNum();
 	for (const SceneOp &op : ops) {
-		if (!checkConditions(op._conditionList))
+		if (!SceneConditions::check(op._conditionList))
 			continue;
 		debug(10, "Exec %s", op.dump("").c_str());
 		if (addMinuites) {
@@ -505,74 +505,12 @@ bool Scene::runOps(const Common::Array<SceneOp> ops, int16 addMinuites /* = 0 */
 	return startSceneNum == endSceneNum;
 }
 
-/*static*/
-bool Scene::checkConditions(const Common::Array<SceneConditions> &conds) {
-	DgdsEngine *engine = DgdsEngine::getInstance();
-
-	uint cnum = 0;
-	while (cnum < conds.size()) {
-		const SceneConditions &c = conds[cnum];
-		int16 refval = c.getVal();
-		int16 checkval = -1;
-		SceneCondition cflag = c.getCond();
-		// Hit an "or" here means the last result was true.
-		if (cflag & kSceneCondOr)
-			return true;
-
-		if (cflag & kSceneCondSceneState) {
-			refval = 1;
-			checkval = engine->adsInterpreter()->getStateForSceneOp(c.getNum());
-			SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
-			if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
-				refval = 0;
-			cflag = kSceneCondEqual;
-		} else if (cflag & kSceneCondNeedItemQuality || cflag & kSceneCondNeedItemSceneNum) {
-			const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
-			for (const auto &item : items) {
-				if (item._num == c.getNum()) {
-					if (cflag & kSceneCondNeedItemSceneNum)
-						checkval = item._inSceneNum;
-					else // cflag & kSceneCondNeedItemQuality
-						checkval = item._quality;
-					break;
-				}
-			}
-		} else {
-			checkval = engine->getGDSScene()->getGlobal(c.getNum());
-			if (!(cflag & kSceneCondAbsVal))
-				refval = engine->getGDSScene()->getGlobal((uint16)refval);
-		}
-
-		bool result = false;
-		cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemQuality));
-		if (cflag == kSceneCondNone)
-			cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
-		if ((cflag & kSceneCondLessThan) && checkval < refval)
-			result = true;
-		if ((cflag & kSceneCondEqual) && checkval == refval)
-			result = true;
-		if (cflag & kSceneCondNegate)
-			result = !result;
-
-		debug(11, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
-
-		if (!result) {
-			// Skip just past the next or, or to the end.
-			while (cnum < conds.size() && !(conds[cnum].getCond() & kSceneCondOr))
-				cnum++;
-			if (cnum >= conds.size())
-				return false;
-		}
-		cnum++;
-	}
-	return true;
-}
-
 
 bool SDSScene::_dlgWithFlagLo8IsClosing = false;
 DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
 
-SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false), _ignoreMouseUp(false), _field6_0x14(0), _rbuttonDown(false), _lbuttonDown(false) {
+SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false), _ignoreMouseUp(false),
+	_field6_0x14(0), _rbuttonDown(false), _lbuttonDown(false) {
 }
 
 bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -715,7 +653,7 @@ void SDSScene::checkTriggers() {
 			continue;
 		}
 
-		if (!checkConditions(trigger.conditionList))
+		if (!SceneConditions::check(trigger.conditionList))
 			continue;
 
 		trigger._enabled = false;
@@ -1232,7 +1170,12 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
 	const HotArea *area = findAreaUnderMouse(pt);
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
-	int16 cursorNum = (!dlg && area) ? area->_cursorNum : 0;
+	int16 cursorNum = 0;
+	if (!dlg) {
+		if (area)
+			cursorNum = area->_cursorNum;
+	}
+
 	if (_dragItem) {
 		if (area && area->_objInteractionRectNum == 1) {
 			// drag over Willy Beamish
@@ -1283,7 +1226,7 @@ static bool _isInRect(const Common::Point &pt, const DgdsRect rect) {
 			&& rect.y <= pt.y && (rect.y + rect.height) > pt.y;
 }
 
-static const ObjectInteraction * _findInteraction(const Common::Array<ObjectInteraction> &interList, int16 droppedNum, uint16 targetNum) {
+static const ObjectInteraction *_findInteraction(const Common::Array<ObjectInteraction> &interList, int16 droppedNum, uint16 targetNum) {
 	for (const auto &i : interList) {
 		if (i.matches(droppedNum, targetNum)) {
 			return &i;
@@ -1294,6 +1237,7 @@ static const ObjectInteraction * _findInteraction(const Common::Array<ObjectInte
 
 void SDSScene::mouseLUp(const Common::Point &pt) {
 	_lbuttonDown = false;
+
 	if (_ignoreMouseUp) {
 		debug(9, "Ignoring mouseup at %d,%d as it was used to clear a dialog", pt.x, pt.y);
 		_ignoreMouseUp = false;
@@ -1394,7 +1338,7 @@ void SDSScene::onDragFinish(const Common::Point &pt) {
 		}
 	}
 
-	SDSScene *scene = engine->getScene();
+	const SDSScene *scene = engine->getScene();
 	for (const auto &area : _hotAreaList) {
 		if (!_isInRect(pt, area._rect))
 			continue;
@@ -1532,13 +1476,13 @@ void SDSScene::updateHotAreasFromDynamicRects() {
 HotArea *SDSScene::findAreaUnderMouse(const Common::Point &pt) {
 	for (auto &item : DgdsEngine::getInstance()->getGDSScene()->getGameItems()) {
 		if (item._inSceneNum == _num && _isInRect(pt, item._rect)
-			&& checkConditions(item.enableConditions)) {
+			&& SceneConditions::check(item.enableConditions)) {
 			return &item;
 		}
 	}
 
 	for (auto &area : _hotAreaList) {
-		if (_isInRect(pt, area._rect) && checkConditions(area.enableConditions)) {
+		if (_isInRect(pt, area._rect) && SceneConditions::check(area.enableConditions)) {
 			return &area;
 		}
 	}
@@ -1661,7 +1605,7 @@ void SDSScene::drawDebugHotAreas(Graphics::ManagedSurface *dst) const {
 	byte greenish = pal.findBestColor(0, 0xff, 0);
 
 	for (const auto &area : _hotAreaList) {
-		bool enabled = checkConditions(area.enableConditions);
+		bool enabled = SceneConditions::check(area.enableConditions);
 		uint32 color = enabled ? greenish : redish;
 		g_system->getPaletteManager();
 		const Common::Rect &r = area._rect.toCommonRect();
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 0d34d27c435..37e1317ff57 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -180,8 +180,6 @@ public:
 	virtual Common::Error syncState(Common::Serializer &s) = 0;
 
 	// These are all static as they are potentially run over scene changes.
-	static bool checkConditions(const Common::Array<SceneConditions> &cond);
-
 	static void segmentStateOps(const Common::Array<uint16> &args);
 	static void setItemAttrOp(const Common::Array<uint16> &args);
 	static void setDragItemOp(const Common::Array<uint16> &args);
@@ -233,8 +231,8 @@ public:
 	Common::Array<GameItem> &getGameItems() { return _gameItems; }
 	int countItemsInInventory() const;
 
-	const Common::Array<ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
-	const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+	const Common::Array<ObjectInteraction> &getObjInteractions1() const { return _objInteractions1; }
+	const Common::Array<ObjectInteraction> &getObjInteractions2() const { return _objInteractions2; }
 
 	Common::Error syncState(Common::Serializer &s) override;
 	void initIconSizes();
@@ -301,8 +299,8 @@ public:
 	GameItem *getDragItem() { return _dragItem; }
 	void setDragItem(GameItem *item) { _dragItem = item; }
 
-	const Common::Array<ObjectInteraction> &getObjInteractions1() { return _objInteractions1; }
-	const Common::Array<ObjectInteraction> &getObjInteractions2() { return _objInteractions2; }
+	const Common::Array<ObjectInteraction> &getObjInteractions1() const { return _objInteractions1; }
+	const Common::Array<ObjectInteraction> &getObjInteractions2() const { return _objInteractions2; }
 
 	bool hasVisibleDialog();
 	bool hasVisibleOrOpeningDialog() const;
diff --git a/engines/dgds/scene_condition.cpp b/engines/dgds/scene_condition.cpp
index 2129e5c61c5..1ae99aede23 100644
--- a/engines/dgds/scene_condition.cpp
+++ b/engines/dgds/scene_condition.cpp
@@ -20,6 +20,9 @@
  */
 
 #include "dgds/scene_condition.h"
+#include "dgds/dgds.h"
+#include "dgds/ads.h"
+#include "dgds/scene.h"
 
 namespace Dgds {
 
@@ -54,6 +57,70 @@ Common::String _sceneConditionStr(SceneCondition cflag) {
 	return ret;
 }
 
+/*static*/
+bool SceneConditions::check(const Common::Array<SceneConditions> &conds) {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+
+	uint cnum = 0;
+	while (cnum < conds.size()) {
+		const SceneConditions &c = conds[cnum];
+		int16 refval = c.getVal();
+		int16 checkval = -1;
+		SceneCondition cflag = c.getCond();
+		// Hit an "or" here means the last result was true.
+		if (cflag & kSceneCondOr)
+			return true;
+
+		if (cflag & kSceneCondSceneState) {
+			refval = 1;
+			checkval = engine->adsInterpreter()->getStateForSceneOp(c.getNum());
+			SceneCondition equalOrNegate = static_cast<SceneCondition>(cflag & (kSceneCondEqual | kSceneCondNegate));
+			if (equalOrNegate != kSceneCondEqual && equalOrNegate != kSceneCondNegate)
+				refval = 0;
+			cflag = kSceneCondEqual;
+		} else if (cflag & kSceneCondNeedItemQuality || cflag & kSceneCondNeedItemSceneNum) {
+			const Common::Array<GameItem> &items = engine->getGDSScene()->getGameItems();
+			for (const auto &item : items) {
+				if (item._num == c.getNum()) {
+					if (cflag & kSceneCondNeedItemSceneNum)
+						checkval = item._inSceneNum;
+					else // cflag & kSceneCondNeedItemQuality
+						checkval = item._quality;
+					break;
+				}
+			}
+		} else {
+			checkval = engine->getGDSScene()->getGlobal(c.getNum());
+			if (!(cflag & kSceneCondAbsVal))
+				refval = engine->getGDSScene()->getGlobal((uint16)refval);
+		}
+
+		bool result = false;
+		cflag = static_cast<SceneCondition>(cflag & ~(kSceneCondSceneState | kSceneCondNeedItemSceneNum | kSceneCondNeedItemQuality));
+		if (cflag == kSceneCondNone)
+			cflag = static_cast<SceneCondition>(kSceneCondEqual | kSceneCondNegate);
+		if ((cflag & kSceneCondLessThan) && checkval < refval)
+			result = true;
+		if ((cflag & kSceneCondEqual) && checkval == refval)
+			result = true;
+		if (cflag & kSceneCondNegate)
+			result = !result;
+
+		debug(11, "Cond: %s -> %s", c.dump("").c_str(), result ? "true": "false");
+
+		if (!result) {
+			// Skip just past the next or, or to the end.
+			while (cnum < conds.size() && !(conds[cnum].getCond() & kSceneCondOr))
+				cnum++;
+			if (cnum >= conds.size())
+				return false;
+		}
+		cnum++;
+	}
+	return true;
+}
+
+
 Common::String SceneConditions::dump(const Common::String &indent) const {
 	return Common::String::format("%sSceneCondition<flg 0x%02x(%s) num %d val %d>", indent.c_str(),
 			_flags, _sceneConditionStr(_flags).c_str(), _num, _val);
diff --git a/engines/dgds/scene_condition.h b/engines/dgds/scene_condition.h
index 5324644efe5..303d69a0530 100644
--- a/engines/dgds/scene_condition.h
+++ b/engines/dgds/scene_condition.h
@@ -24,6 +24,7 @@
 
 #include "common/types.h"
 #include "common/str.h"
+#include "common/array.h"
 
 namespace Dgds {
 
@@ -44,6 +45,8 @@ public:
 	SceneConditions(uint16 num, SceneCondition cond, int16 val) : _num(num), _flags(cond), _val(val) {}
 	Common::String dump(const Common::String &indent) const;
 
+	static bool check(const Common::Array<SceneConditions> &conds);
+
 	uint16 getNum() const { return _num; }
 	SceneCondition getCond() const { return _flags; }
 	int16 getVal() const { return _val; }
diff --git a/engines/dgds/scene_op.cpp b/engines/dgds/scene_op.cpp
index 684a31428f0..615102f194c 100644
--- a/engines/dgds/scene_op.cpp
+++ b/engines/dgds/scene_op.cpp
@@ -381,7 +381,7 @@ bool SceneOp::runBeamishOp() const {
 	if (_opCode & kSceneOpHasConditionalOpsFlag) {
 		uint16 opcode = _opCode & ~kSceneOpHasConditionalOpsFlag;
 		for (const ConditionalSceneOp &cop : engine->getScene()->getConditionalOps()) {
-			if (cop._opCode == opcode && engine->getScene()->checkConditions(cop._conditionList)) {
+			if (cop._opCode == opcode && SceneConditions::check(cop._conditionList)) {
 				if (!Scene::runOps(cop._opList))
 					return true;
 			}
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 5e4d76fb1de..6742e474b61 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -583,16 +583,21 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 			break;
 		//
 		// This appears in the credits, intro sequence, and the
-		// "meanwhile" event with the factory in DRAGON.  It
-		// should reload the background image to clear any previous 0020
-		// event, and then save the current FG over it.
+		// "meanwhile" event with the factory in DRAGON.  It should
+		// copy the front buffer to the stored buffer, then the stored
+		// buffer to the background?
+		//
 		// Credits   - (no scr loaded) Store large image on black bg after loading and before txt scroll
 		// Intro     - (no scr loaded) After each screen change, draw and save the new comic frame as bg
 		//			   on "aaaaah" scene, called after only drawing the AAAH and calling store area
 		// Meanwhile - (scr loaded) Save the foreground people onto the background before walk animation
 		//
-		_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
-		_vm->getBackgroundBuffer().blitFrom(_vm->_compositionBuffer);
+		if (DgdsEngine::getInstance()->getGameId() == GID_WILLY) {
+			_vm->getStoredAreaBuffer().blitFrom(_vm->_compositionBuffer);
+		} else {
+			_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+			_vm->getBackgroundBuffer().blitFrom(_vm->_compositionBuffer);
+		}
 		break;
 	case 0x0070: // FREE PALETTE
 		if (seq._executed) // this is a one-shot op
@@ -951,10 +956,10 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 		Drawing::emptyCircle(ivals[0] + xr, ivals[1] + yr, xr, yr, &_vm->_compositionBuffer, seq._drawColFG);
 		break;
 	}
-	case 0xa500: // DRAW SPRITE: x,y,tile-id,bmp-id:int [-n,+n]
+	case 0xa500: // DRAW SPRITE: x,y,frameno,bmpno:int [-n,+n]
 	case 0xa510: // DRAW SPRITE FLIP V x,y:int
 	case 0xa520: // DRAW SPRITE FLIP H: x,y:int
-	case 0xa530: { // DRAW SPRITE FLIP HV: x,y,tile-id,bmp-id:int	[-n,+n] (CHINA)
+	case 0xa530: { // DRAW SPRITE FLIP HV: x,y,frameno,bmpno:int	[-n,+n] (CHINA+)
 		int frameno;
 		int bmpNo;
 		int dstWidth = 0;
@@ -1009,7 +1014,7 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 						Common::Point(r.left, r.top));
 		break;
 	}
-	case 0xa700: { // DRAW SCROLL x,y,w,h??
+	case 0xa700: { // DRAW SCROLL x,y,w,h
 		if (!env._scrollShape) {
 			warning("Trying to draw scroll with no scrollshape loaded");
 		} else {
@@ -1024,7 +1029,7 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 		f.fill();
 		break;
 	}
-	case 0xaf10: { // DRAW EMPTY POLY
+	case 0xaf10: { // DRAW EMPTY POLY [pts]
 		ClipSurface clipSurf(seq._drawWin, _vm->_compositionBuffer.surfacePtr());
 		for (uint i = 1; i < pts.size(); i++) {
 			const Common::Point &p1 = pts[i - 1];
@@ -1036,7 +1041,7 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 				plotClippedPoint, &clipSurf);
 		break;
 	}
-	case 0xaf20: { // DRAW FILLED POLY
+	case 0xaf20: { // DRAW FILLED POLY [pts]
 		ClipSurface clipSurf(seq._drawWin, _vm->_compositionBuffer.surfacePtr());
 		Common::Array<int> xvals(pts.size());
 		Common::Array<int> yvals(pts.size());
@@ -1054,7 +1059,7 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 		env._creditScrollMeasure = doOpInitCreditScroll(env._scriptShapes[seq._currentBmpId].get());
 		env._creditScrollYOffset = 0;
 		break;
-	case 0xb010: { // DRAW CREDITS SCROLL
+	case 0xb010: { // DRAW CREDITS SCROLL ygap,ystep
 		const Image *img = env._scriptShapes[seq._currentBmpId].get();
 		if (img && img->isLoaded()) {
 			bool finished = doOpCreditsScroll(env._scriptShapes[seq._currentBmpId].get(), ivals[0], env._creditScrollYOffset,
@@ -1093,6 +1098,8 @@ bool TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 		break;
 	}
 	case 0xc050: {	// PLAY SAMPLE: int: i
+		if (seq._executed) // this is a one-shot op
+			break;
 		_vm->_soundPlayer->playMusicOrSFX(ivals[0]);
 		break;
 	}


Commit: f79c7bec8d7434360a6841bdb5983aa548e7cdfd
    https://github.com/scummvm/scummvm/commit/f79c7bec8d7434360a6841bdb5983aa548e7cdfd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:04:15+11:00

Commit Message:
DGDS: Print debug after loading DDS data

Changed paths:
    engines/dgds/scene.cpp


diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 5002aff6d28..b7aa5d2636e 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -693,6 +693,8 @@ Dialog *SDSScene::loadDialogData(uint16 num) {
 
 	bool result = false;
 
+	uint prevSize = _dialogs.size();
+
 	while (chunk.readNextHeader(EX_DDS, filename)) {
 		if (chunk.isContainer()) {
 			continue;
@@ -717,6 +719,12 @@ Dialog *SDSScene::loadDialogData(uint16 num) {
 
 	delete dlgFile;
 
+	if (_dialogs.size() != prevSize) {
+		debug(10, "Read %d dialogs from DDS %s:", _dialogs.size() - prevSize, filename.c_str());
+		for (uint i = prevSize; i < _dialogs.size(); i++)
+			debug(10, "%s", _dialogs[i].dump("").c_str());
+	}
+
 	if (!result)
 		return nullptr;
 


Commit: 854c2c4665d3050dd37cba2caa3a9340dc288870
    https://github.com/scummvm/scummvm/commit/854c2c4665d3050dd37cba2caa3a9340dc288870
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:04:15+11:00

Commit Message:
DGDS: Fix inventory wrapping for Willy Beamish

Changed paths:
    engines/dgds/inventory.cpp


diff --git a/engines/dgds/inventory.cpp b/engines/dgds/inventory.cpp
index d21ad3078dc..7231bc3c7b4 100644
--- a/engines/dgds/inventory.cpp
+++ b/engines/dgds/inventory.cpp
@@ -302,7 +302,7 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
 
 		// calculate draw offset for the image
 		int drawX = imgAreaX + x + (xstep - item._rect.width) / 2;
-		int drawY = imgAreaY + y +  (ystep - item._rect.height) / 2;
+		int drawY = imgAreaY + y + (ystep - item._rect.height) / 2;
 
 		icons->drawBitmap(item._iconNum, drawX, drawY, drawMask, surf);
 
@@ -310,7 +310,9 @@ void Inventory::drawItems(Graphics::ManagedSurface &surf) {
 		item._rect.y = drawY;
 
 		x += xstep;
-		if (x >= _itemArea->_width) {
+
+		// Willy Beamish area is 270 and step is 54, so hack the width slightly.
+		if (x >= _itemArea->_width - 2) {
 			x = 0;
 			y += ystep;
 		}


Commit: 29bc5487cd9ca061072a491669a7170bf298633f
    https://github.com/scummvm/scummvm/commit/29bc5487cd9ca061072a491669a7170bf298633f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-12-30T20:47:58+11:00

Commit Message:
DGDS: Implement willy trouble gauge

Changed paths:
    engines/dgds/dgds.cpp
    engines/dgds/dialog.cpp
    engines/dgds/globals.cpp
    engines/dgds/globals.h


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index f97d5077fbc..0162f05765f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -788,6 +788,7 @@ Common::Error DgdsEngine::run() {
 			frameCount++;
 			_skipNextFrame = false;
 		}
+
 		const uint32 thisFrameEndMillis = g_system->getMillis();
 		const uint32 elapsedMillis = thisFrameEndMillis - startMillis;
 		const uint32 targetMillis = (frameCount * 1000 / 30);
diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index b269b2510cd..cc87f2cbdef 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -165,9 +165,15 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
 
 	Common::String title;
 	Common::String txt;
+
+	//
+	// Colon has to be followed by the first CR to be used as a heading
+	//
 	uint32 colonpos = _str.find(':');
 	uint32 crpos = _str.find('\r');
-	if (colonpos != Common::String::npos && (crpos == Common::String::npos || crpos > colonpos)) {
+	bool haveColon = colonpos != Common::String::npos;
+	bool haveCR = crpos != Common::String::npos;
+	if (haveColon && haveCR && crpos == colonpos + 1) {
 		title = _str.substr(0, colonpos);
 		txt = _str.substr(colonpos + 1);
 		// Most have a CR after the colon? trim it to remove a blank line.
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index bd942ef2146..47fd84ccdf8 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -23,6 +23,8 @@
 #include "dgds/dgds.h"
 #include "dgds/scene.h"
 #include "dgds/game_palettes.h"
+#include "dgds/sound.h"
+#include "dgds/includes.h"
 
 namespace Dgds {
 
@@ -312,14 +314,49 @@ public:
 	}
 };
 
-class WillyDrawGlobal : public RWI16Global {
+class WillyTroubleGlobal : public RWI16Global {
 public:
-	WillyDrawGlobal(uint16 num, int16 *val) : RWI16Global(num, val) {}
+	WillyTroubleGlobal(uint16 num, int16 *val) : RWI16Global(num, val) {}
 	int16 set(int16 val) override {
 		int16 oldVal = get();
 		if (val != oldVal) {
+			// Draw the trouble meter changing.
+			DgdsEngine *engine = DgdsEngine::getInstance();
 			val = CLIP(val, (int16)0, (int16)10);
-			error("TODO: Implement set function for willy global 0x02 val %d.", val);
+			Image img(engine->getResourceManager(), engine->getDecompressor());
+			img.loadBitmap("METER.BMP");
+			uint16 soundNum = (oldVal < val) ? 0x386 : 0x387;
+			engine->_soundPlayer->playSFX(soundNum);
+			Graphics::ManagedSurface &compBuf = engine->_compositionBuffer;
+			const Common::Rect screenRect(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+			int16 sign = val > oldVal ? 1 : -1;
+			int16 prevBarSize = oldVal * 8;
+			int16 newBarSize = val * 8;
+
+			// Animate the trouble bar going up or down
+			compBuf.fillRect(Common::Rect(Common::Point(0x80, 0x8a), 0x47, 3), 16);
+
+			for (int sz = prevBarSize; sz != newBarSize; sz += sign) {
+				RequestData::drawCorners(&compBuf, 0, 0x71, 0x25, 0x5e, 0x7e);
+				compBuf.fillRect(Common::Rect(Common::Point(0x80, 0x3a), 0x47, 0x50), 0);
+				if (sz)
+					compBuf.fillRect(Common::Rect(Common::Point(0x80, 0x8a - sz), 0x47, sz), 0x22);
+				img.drawBitmap(0, 0x80, 0x29, screenRect, compBuf);
+
+				//
+				// TODO: Timing is a bit hackily approximate here.
+				// Measure real game timing more accurately.  Also probably
+				// should pump messages to make the mouse responsive.
+				//
+				g_system->copyRectToScreen(compBuf.getPixels(), SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+				g_system->updateScreen();
+				g_system->delayMillis(100);
+			}
+
+			g_system->delayMillis(900);
+
+			engine->_soundPlayer->stopSfxByNum(soundNum);
 			return RWI16Global::set(val);
 		}
 		return oldVal;
@@ -328,7 +365,7 @@ public:
 
 
 WillyGlobals::WillyGlobals(Clock &clock) : Globals(clock),
-	_unk2(4), _unk3(0), _invDrawTimeSkipButtons(0), _hideMouseCursor(0), _unk74(0), _unk75(300),
+	_trouble(4), _unk3(0), _invDrawTimeSkipButtons(0), _hideMouseCursor(0), _unk74(0), _unk75(300),
 	_palFade(255), _droppedItemNum(0), _characterStance(0), _characterPos(0), _unk81(3),
 	_unk82(1) {
 	_globals.push_back(new DetailLevelROGlobal(0x53));
@@ -344,12 +381,12 @@ WillyGlobals::WillyGlobals(Clock &clock) : Globals(clock),
 	_globals.push_back(new RWI16Global(0x05, &_hideMouseCursor));
 	_globals.push_back(new RWI16Global(0x04, &_invDrawTimeSkipButtons));
 	_globals.push_back(new RWI16Global(0x03, &_unk3));
-	_globals.push_back(new WillyDrawGlobal(0x02, &_unk2));
+	_globals.push_back(new WillyTroubleGlobal(0x02, &_trouble));
 }
 
 Common::Error WillyGlobals::syncState(Common::Serializer &s) {
 	Globals::syncState(s);
-	s.syncAsSint16LE(_unk2);
+	s.syncAsSint16LE(_trouble);
 	s.syncAsSint16LE(_unk3);
 	s.syncAsSint16LE(_invDrawTimeSkipButtons);
 	s.syncAsSint16LE(_hideMouseCursor);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index f99ecc7be9c..0683caf8a3e 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -207,7 +207,7 @@ public:
 
 private:
 	// Willy-specific globals
-	int16 _unk2;
+	int16 _trouble;
 	int16 _unk3;
 	int16 _invDrawTimeSkipButtons;
 	int16 _hideMouseCursor;




More information about the Scummvm-git-logs mailing list