[Scummvm-git-logs] scummvm master -> 337aed1915c84ed7d415a7f325a680c1bdc35ea4

somaen noreply at scummvm.org
Thu May 26 19:50:33 UTC 2022


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

Summary:
3580c17cc5 TINSEL: Implement Notebook logic for adding clues and showing pages.
9519288acd TINSEL: Implement library function CROSSCLUE
337aed1915 TINSEL: Close Inventories when switching between them.


Commit: 3580c17cc52af43ee95c05b9c98eb49d3750e346
    https://github.com/scummvm/scummvm/commit/3580c17cc52af43ee95c05b9c98eb49d3750e346
Author: Einar Johan Trøan Sømåen (einarjohants at gmail.com)
Date: 2022-05-26T21:48:17+02:00

Commit Message:
TINSEL: Implement Notebook logic for adding clues and showing pages.

Changed paths:
  A engines/tinsel/noir/notebook_page.cpp
  A engines/tinsel/noir/notebook_page.h
    engines/tinsel/dialogs.cpp
    engines/tinsel/dialogs.h
    engines/tinsel/inv_objects.h
    engines/tinsel/module.mk
    engines/tinsel/noir/notebook.cpp
    engines/tinsel/noir/notebook.h
    engines/tinsel/noir/sysreel.h
    engines/tinsel/tinlib.cpp


diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index 2e0ba004644..1f251867399 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -1208,7 +1208,7 @@ bool Dialogs::GetIsInvObject(int id) {
 /**
  * Convert item ID number to index.
  */
-int Dialogs::GetObjectIndex(int id) {
+int Dialogs::GetObjectIndex(int id) const {
 	int index = _invObjects->GetObjectIndexIfExists(id);
 	if (index == -1) {
 		error("GetObjectIndex(%d): Trying to manipulate undefined inventory icon", id);
@@ -5142,6 +5142,10 @@ void Dialogs::EventToInventory(PLR_EVENT pEvent, const Common::Point &coOrds) {
 /************************* Odds and Ends **********************************/
 /**************************************************************************/
 
+const FILM *Dialogs::GetObjectFilm(int object) const {
+	return (const FILM*)_vm->_handle->LockMem(_invFilms[GetObjectIndex(object)]);
+}
+
 /**
  * Called from Glitter function invdepict()
  * Changes (permanently) the animation film for that object.
@@ -5149,6 +5153,10 @@ void Dialogs::EventToInventory(PLR_EVENT pEvent, const Common::Point &coOrds) {
 void Dialogs::SetObjectFilm(int object, SCNHANDLE hFilm) {
 	_invObjects->SetObjectFilm(object, hFilm);
 
+	if (TinselVersion == 3) {
+		_invFilms[GetObjectIndex(object)] = hFilm;
+	}
+
 	if (_heldItem != object)
 		_ItemsChanged = true;
 }
@@ -5570,6 +5578,9 @@ void Dialogs::Redraw() {
 			}
 		}
 	}
+	if (TinselVersion == 3) {
+		_vm->_notebook->StepAnimScripts();
+	}
 }
 
 // Noir
diff --git a/engines/tinsel/dialogs.h b/engines/tinsel/dialogs.h
index 703bb95bea6..018d51084be 100644
--- a/engines/tinsel/dialogs.h
+++ b/engines/tinsel/dialogs.h
@@ -342,6 +342,7 @@ public:
 	bool MenuActive();
 	bool IsConvWindow();
 
+	const FILM *GetObjectFilm(int object) const;
 	void SetObjectFilm(int object, SCNHANDLE hFilm);
 	void CallFunction(BFUNC boxFunc);
 
@@ -393,7 +394,7 @@ private:
 	void DumpObjArray();
 	void FirstScene(int first);
 	void FirstFile(int first);
-	int GetObjectIndex(int id);
+	int GetObjectIndex(int id) const;
 	void InvSaveGame();
 	void InvLoadGame();
 	int InvArea(int x, int y);
diff --git a/engines/tinsel/inv_objects.h b/engines/tinsel/inv_objects.h
index 3add4afd52b..d736b893c74 100644
--- a/engines/tinsel/inv_objects.h
+++ b/engines/tinsel/inv_objects.h
@@ -84,6 +84,9 @@ public:
 		_title = stream.readUint32();
 	}
 	// Noir:
+	bool isNotebookTitle() const {
+		return (getAttribute() & (int)InvObjAttr::NOTEBOOK_TITLE) != 0;
+	}
 	int32 getUnknown() const {
 		return _unknown;
 	}
diff --git a/engines/tinsel/module.mk b/engines/tinsel/module.mk
index 5a5f2693196..e7b30e8cb23 100644
--- a/engines/tinsel/module.mk
+++ b/engines/tinsel/module.mk
@@ -50,6 +50,7 @@ MODULE_OBJS := \
 	tinsel.o \
 	token.o \
 	noir/notebook.o \
+	noir/notebook_page.o \
 	noir/sysreel.o \
 
 # This module can be built as a plugin
diff --git a/engines/tinsel/noir/notebook.cpp b/engines/tinsel/noir/notebook.cpp
index 21e93b04632..7c342e53715 100644
--- a/engines/tinsel/noir/notebook.cpp
+++ b/engines/tinsel/noir/notebook.cpp
@@ -21,7 +21,14 @@
 
 #include "tinsel/noir/notebook.h"
 
+#include "tinsel/background.h"
 #include "tinsel/dialogs.h"
+#include "tinsel/film.h"
+#include "tinsel/handle.h"
+#include "tinsel/multiobj.h"
+#include "tinsel/noir/sysreel.h"
+#include "tinsel/pdisplay.h"
+#include "tinsel/timers.h"
 
 namespace Tinsel {
 
@@ -61,13 +68,114 @@ void Notebook::AddHyperlink(int32 id1, int32 id2) {
 	error("Too many hyperlinks");
 }
 
+void Notebook::ClearNotebookPage() {
+	if (_prevPage != -1) {
+		_pages[_prevPage].Clear();
+	}
+	_prevPage = -1;
+	_pages[_currentPage].Clear();
+}
+
+void Notebook::Refresh() {
+	auto reel = (_currentPage == 0 ? SysReel::NOTEPAD_CLOSED : SysReel::NOTEPAD_OPEN);
+	auto film = GetSystemReelFilm(reel);
+	InitStepAnimScript(&_anim, _object, film->reels->script, ONE_SECOND / film->frate);
+	ClearNotebookPage();
+	if (_currentPage != 0) {
+		_pages[_currentPage].FillIn();
+	}
+}
+
+int Notebook::AddTitle(const InventoryObjectT3 &invObject) {
+	int id = invObject.getId();
+	assert(invObject.isNotebookTitle());
+	for (int i = 0; i < _numPages; i++) {
+		if (_pages[i].GetTitle() == id) {
+			return i;
+		}
+	}
+	int linkedFromPage = invObject.getUnknown();
+
+	// 0 page is the closed notebook, has no entries.
+	if (linkedFromPage != 0) {
+		// Allocate a line on the linked from page.
+		assert(_pages[linkedFromPage].GetTitle() != 0);
+		_pages[linkedFromPage].AddLine(id);
+	}
+	int pageIndex = _numPages++;
+	_pages[pageIndex].SetTitle(id);
+	return pageIndex;
+}
+
+void Notebook::AddClue(const InventoryObjectT3 &invObject) {
+	// Add title if missing, otherwise just get the page it's on.
+	auto titleObject = _vm->_dialogs->GetInvObjectT3(invObject.getUnknown());
+	int pageIndex = AddTitle(*titleObject);
+	_pages[pageIndex].AddLine(invObject.getId());
+	if (invObject.getTitle() != 0) {
+		auto secondTitleObject = _vm->_dialogs->GetInvObjectT3(invObject.getTitle());
+		pageIndex = AddTitle(*secondTitleObject);
+	 	_pages[pageIndex].AddLine(invObject.getId());
+	}
+}
+
+void Notebook::AddClue(int id) {
+	auto invObject = _vm->_dialogs->GetInvObjectT3(id);
+	if (invObject->isNotebookTitle()) {
+		AddTitle(*invObject);
+	} else {
+		AddClue(*invObject);
+	}
+}
+
+void InitNotebookAnim(OBJECT **obj, ANIM &anim, SysReel reel, int zPosition) {
+	auto film = GetSystemReelFilm(reel);
+	MultiDeleteObjectIfExists(FIELD_STATUS, obj);
+	*obj = InsertReelObj(film->reels);
+	MultiSetZPosition(*obj, zPosition);
+	InitStepAnimScript(&anim, *obj, film->reels->script, ONE_SECOND / film->frate);
+}
+
+void Notebook::SetNextPage(int pageIndex) {
+	assert(_prevPage == -1 || _prevPage == _currentPage); // Check that we've cleaned any outstanding page.
+	_prevPage = _currentPage;
+	_currentPage = pageIndex;
+}
 
 void Notebook::Show(bool isOpen) {
-	error("TODO: Implement Notebook::Show()");
+	auto reel = (isOpen ? SysReel::NOTEPAD_OPEN : SysReel::NOTEPAD_OPENING);
+	InitNotebookAnim(&_object, _anim, reel, Z_INV_MFRAME);
+
+	_state = (isOpen ? BOOKSTATE::OPENED : BOOKSTATE::OPEN_ANIMATING);
+	SetNextPage(1);
+	Refresh();
+	DisableTags(); // Tags disabled in Notebook
+	DisablePointing(); // Pointing disabled in Notebook
 }
 
 bool Notebook::IsOpen() const {
 	return _state != BOOKSTATE::CLOSED;
 }
 
+void Notebook::Close() {
+	ClearNotebookPage();
+	MultiDeleteObjectIfExists(FIELD_STATUS, &_object);
+	MultiDeleteObjectIfExists(FIELD_STATUS, &_pageObject);
+	_state = BOOKSTATE::CLOSED;
+	if (_vm->_dialogs->InventoryOrNotebookActive()) {
+		EnablePointing();
+		EnableTags();
+	}
+}
+
+void Notebook::StepAnimScripts() {
+	if (_state == BOOKSTATE::OPEN_ANIMATING) {
+		auto state = StepAnimScript(&_anim);
+		if (state == ScriptFinished) {
+			_state = BOOKSTATE::OPENED;
+			Refresh();
+		}
+	}
+}
+
 } // End of namespace Tinsel
diff --git a/engines/tinsel/noir/notebook.h b/engines/tinsel/noir/notebook.h
index 79b7bcdb071..5656adf7121 100644
--- a/engines/tinsel/noir/notebook.h
+++ b/engines/tinsel/noir/notebook.h
@@ -24,13 +24,16 @@
 
 #include "common/scummsys.h"
 
+#include "notebook_page.h"
+#include "tinsel/anim.h"
 #include "tinsel/events.h"
+#include "tinsel/object.h"
 
 namespace Tinsel {
 // links two clue/title objects together
 struct HYPERLINK {
-	int32 id1;
-	int32 id2;
+	int32 id1 = 0;
+	int32 id2 = 0;
 };
 
 // 6 bytes large
@@ -50,34 +53,51 @@ enum class BOOKSTATE {
 	OPENED = 3
 };
 
+class InventoryObjectT3;
+
 class Notebook {
 public:
 	Notebook() = default;
 
-	// Can be a title or clue
-	void AddEntry(int32 entryIdx, int32 page1, int32 page2);
 	// Adds a connection between a clue/title
 	void AddHyperlink(int32 id1, int32 id2);
+	void AddClue(int id);
 	// Called within InventoryProcess loop
 	void Redraw();
-	// Called by EventToInventory
-	void EventToNotebook(PLR_EVENT event, bool p2, bool p3);
+
 	// Called from OPENNOTEBOOK
 	void Show(bool isOpen);
 	bool IsOpen() const;
+	void Close();
+
+	void StepAnimScripts();
+	void Refresh();
 private:
-	const static uint32 MAX_ENTRIES = 100;
+	int AddTitle(const InventoryObjectT3 &invObject);
+	void AddClue(const InventoryObjectT3 &invObject);
+
+	void ClearNotebookPage();
+
+	void SetNextPage(int pageIndex);
+
 	const static uint32 MAX_PAGES = 0x15;
 	const static uint32 MAX_HYPERS = 0xf;
-	const static uint32 MAX_ENTRIES_PER_PAGE = 8;
 
 	HYPERLINK _hyperlinks[MAX_HYPERS];
 
-	const static uint32 _numEntries = 0;
+	uint32 _numPages = 1;
+	uint32 _prevPage = -1;
+	uint32 _currentPage = 1;
+
+	NotebookPage _pages[MAX_PAGES] = {};
+
+	ANIM _anim = {};
+	OBJECT *_object = nullptr;
 
-	ENTRY _entries[MAX_ENTRIES];
+	ANIM _pageAnim = {};
+	OBJECT *_pageObject = nullptr;
 
-	BOOKSTATE _state;
+	BOOKSTATE _state = BOOKSTATE::CLOSED;
 };
 
 } // End of namespace Tinsel
diff --git a/engines/tinsel/noir/notebook_page.cpp b/engines/tinsel/noir/notebook_page.cpp
new file mode 100644
index 00000000000..afa99fc16fb
--- /dev/null
+++ b/engines/tinsel/noir/notebook_page.cpp
@@ -0,0 +1,134 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+#include "tinsel/noir/notebook_page.h"
+#include "tinsel/dialogs.h"
+#include "tinsel/dw.h"
+#include "tinsel/film.h"
+#include "tinsel/handle.h"
+#include "tinsel/multiobj.h"
+#include "tinsel/polygons.h"
+#include "tinsel/timers.h"
+#include "tinsel/tinsel.h"
+#include "tinsel/noir/sysreel.h"
+
+namespace Tinsel {
+
+void NotebookLine::Clear() {
+	MultiDeleteObjectIfExists(FIELD_STATUS, &_obj);
+}
+
+bool HasReelFrame(SCNHANDLE pReel) {
+	if (pReel) {
+		const FREEL* reel = (const FREEL*)_vm->_handle->LockMem(pReel);
+		if (reel && reel->mobj) {
+			const MULTI_INIT* pmi = reel->GetMultiInit();
+			if (pmi) {
+				return pmi->GetFrame() != nullptr;
+			}
+		}
+	}
+	return false;
+}
+
+int FindReelIndexForEntry(const FILM *pFilm, int pageLine) {
+	if (HasReelFrame(pFilm->reels[pageLine].mobj)) {
+		return pageLine;
+	}
+	for (int i = pageLine; i < pFilm->numreels; i++) {
+		if (HasReelFrame(pFilm->reels[i].mobj)) {
+			return i;
+		}
+	}
+	for (int i = pageLine; i >= 0; i--) {
+		if (HasReelFrame(pFilm->reels[i].mobj)) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+void NotebookLine::FillIn(int pageLine) {
+	const FILM *pFilm = _vm->_dialogs->GetObjectFilm(_id);
+	if (!pFilm)
+		return;
+
+	int reelIndex = FindReelIndexForEntry(pFilm, pageLine);
+	assert(reelIndex >= 0);
+	const FREEL *reel = &pFilm->reels[reelIndex];
+	MultiDeleteObjectIfExists(FIELD_STATUS, &_obj);
+	_obj = InsertReelObj(reel);
+
+	MultiSetZPosition(_obj, 17);
+	InitStepAnimScript(&_anim, _obj, pFilm->reels[reelIndex].script, ONE_SECOND / pFilm->frate);
+
+	if (_crossedOut) {
+		auto scribbleFilm = GetSystemReelFilm(SysReel::SCRIBBLES);
+		_scribbles = InsertReelObj(&scribbleFilm->reels[reelIndex]);
+		MultiSetZPosition(_scribbles, 18);
+
+		InitStepAnimScript(&_scribbleAnim, _scribbles, scribbleFilm->reels[reelIndex].script, ONE_SECOND / pFilm->frate);
+	}
+}
+
+void NotebookLine::CrossOut() {
+	_crossedOut = true;
+}
+
+bool NotebookPage::ContainsClue(int id) {
+	for (int i = 0; i < _numLines; i++) {
+		if (_lines[i]._id == id) {
+			return true;
+		}
+	}
+	return false;
+}
+void NotebookPage::AddLine(int id) {
+	if (ContainsClue(id)) {
+		return;
+	}
+	assert(_numLines < MAX_ENTRIES_PER_PAGE);
+	_lines[_numLines++]._id = id;
+}
+
+void NotebookPage::SetTitle(int id) {
+	_lines[0]._id = id;
+	if (_numLines == 0) {
+		_numLines++;
+	}
+}
+int32 NotebookPage::GetTitle() const {
+	return _lines[0]._id;
+}
+
+void NotebookPage::FillIn() {
+	for (int i = 0; i < _numLines; i++) {
+		_lines[i].FillIn(i);
+	}
+}
+
+void NotebookPage::Clear() {
+	for (int i = 0; i < _numLines; i++) {
+		_lines[i].Clear();
+	}
+}
+
+} // End of namespace Tinsel
diff --git a/engines/tinsel/noir/notebook_page.h b/engines/tinsel/noir/notebook_page.h
new file mode 100644
index 00000000000..8ef36b49c80
--- /dev/null
+++ b/engines/tinsel/noir/notebook_page.h
@@ -0,0 +1,62 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+#ifndef TINSEL_NOTEBOOK_PAGE_H // prevent multiple includes
+#define TINSEL_NOTEBOOK_PAGE_H
+
+#include "common/scummsys.h"
+#include "tinsel/anim.h"
+#include "tinsel/tinsel.h"
+#include "tinsel/object.h"
+
+namespace Tinsel {
+
+class NotebookLine {
+public:
+	int _id = 0;
+	void CrossOut();
+	void Clear();
+	void FillIn(int pageLine);
+private:
+	bool _crossedOut = false;
+	ANIM _anim = {};
+	OBJECT *_obj = nullptr;
+	OBJECT *_scribbles = nullptr;
+	ANIM _scribbleAnim = {};
+};
+
+class NotebookPage {
+public:
+	bool ContainsClue(int id);
+	void AddLine(int id);
+	void SetTitle(int id);
+	int32 GetTitle() const;
+	void FillIn();
+	void Clear();
+private:
+	const static uint32 MAX_ENTRIES_PER_PAGE = 8;
+	NotebookLine _lines[MAX_ENTRIES_PER_PAGE] = {};
+	uint32 _numLines = 0;
+};
+
+} // End of namespace Tinsel
+
+#endif // SCUMMVM_NOTEBOOK_PAGE_H
diff --git a/engines/tinsel/noir/sysreel.h b/engines/tinsel/noir/sysreel.h
index a003751fcb7..f1d2cc46133 100644
--- a/engines/tinsel/noir/sysreel.h
+++ b/engines/tinsel/noir/sysreel.h
@@ -32,6 +32,7 @@ enum class SysReel {
 	NOTEPAD_CLOSED = 6,
 	NOTEPAD_FLIPDOWN = 7,
 	NOTEPAD_FLIPUP = 8,
+	SCRIBBLES = 9,
 	CURSOR = 11,
 	INVMAIN = 15,
 	SLIDER = 16,
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 508f3b825f0..2bec883eb96 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -5395,7 +5395,7 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi
 
 	case ADDNOTEBOOK:
 		// Noir Only
-		warning("TODO: Implement ADDNOTEBOOK");
+		_vm->_notebook->AddClue(pp[0]);
 		return -1;
 
 	case ADDOPENINV:


Commit: 9519288acd58adbdc9d5a89ef45294a6500b730f
    https://github.com/scummvm/scummvm/commit/9519288acd58adbdc9d5a89ef45294a6500b730f
Author: Einar Johan Trøan Sømåen (einarjohants at gmail.com)
Date: 2022-05-26T21:49:16+02:00

Commit Message:
TINSEL: Implement library function CROSSCLUE

Changed paths:
    engines/tinsel/debugger.cpp
    engines/tinsel/debugger.h
    engines/tinsel/noir/notebook.cpp
    engines/tinsel/noir/notebook.h
    engines/tinsel/noir/notebook_page.cpp
    engines/tinsel/noir/notebook_page.h
    engines/tinsel/tinlib.cpp


diff --git a/engines/tinsel/debugger.cpp b/engines/tinsel/debugger.cpp
index de46b7ded06..09fbbb1cc6c 100644
--- a/engines/tinsel/debugger.cpp
+++ b/engines/tinsel/debugger.cpp
@@ -28,6 +28,7 @@
 #include "tinsel/music.h"
 #include "tinsel/font.h"
 #include "tinsel/strres.h"
+#include "tinsel/noir/notebook.h"
 
 namespace Tinsel {
 
@@ -61,6 +62,10 @@ int strToInt(const char *s) {
 //----------------- CONSOLE CLASS  ---------------------
 
 Console::Console() : GUI::Debugger() {
+	if (TinselVersion == 3) {
+		registerCmd("add_clue",		WRAP_METHOD(Console, cmd_add_clue));
+		registerCmd("cross_clue",		WRAP_METHOD(Console, cmd_cross_clue));
+	}
 	registerCmd("item",		WRAP_METHOD(Console, cmd_item));
 	registerCmd("scene",		WRAP_METHOD(Console, cmd_scene));
 	registerCmd("music",		WRAP_METHOD(Console, cmd_music));
@@ -160,4 +165,27 @@ bool Console::cmd_string(int argc, const char **argv) {
 	return true;
 }
 
+// Noir:
+bool Console::cmd_add_clue(int argc, const char **argv) {
+	if (argc < 2) {
+		debugPrintf("%s clue_id\n", argv[0]);
+		debugPrintf("Adds a clue to the notebook\n");
+		return true;
+	}
+
+	_vm->_notebook->AddClue(strToInt(argv[1]));
+	return false;
+}
+
+bool Console::cmd_cross_clue(int argc, const char **argv) {
+	if (argc < 2) {
+		debugPrintf("%s clue_id\n", argv[0]);
+		debugPrintf("Crosses out a clue in the notebook\n");
+		return true;
+	}
+
+	_vm->_notebook->CrossClue(strToInt(argv[1]));
+	return false;
+}
+
 } // End of namespace Tinsel
diff --git a/engines/tinsel/debugger.h b/engines/tinsel/debugger.h
index 4813acc432c..f40d0d03e5e 100644
--- a/engines/tinsel/debugger.h
+++ b/engines/tinsel/debugger.h
@@ -34,6 +34,8 @@ public:
 	~Console() override;
 
 private:
+	bool cmd_add_clue(int argc, const char **argv);
+	bool cmd_cross_clue(int argc, const char **argv);
 	bool cmd_item(int argc, const char **argv);
 	bool cmd_scene(int argc, const char **argv);
 	bool cmd_music(int argc, const char **argv);
diff --git a/engines/tinsel/noir/notebook.cpp b/engines/tinsel/noir/notebook.cpp
index 7c342e53715..d138be5b373 100644
--- a/engines/tinsel/noir/notebook.cpp
+++ b/engines/tinsel/noir/notebook.cpp
@@ -128,6 +128,35 @@ void Notebook::AddClue(int id) {
 	}
 }
 
+int Notebook::GetPageWithTitle(int id) {
+	for (int i = 0; i < _numPages; i++) {
+		if (_pages[i].GetTitle() == id) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+void Notebook::CrossClue(int id) {
+	auto invObject = _vm->_dialogs->GetInvObjectT3(id);
+	if (invObject->isNotebookTitle()) {
+		return;
+	}
+	int titles[2] = {
+		invObject->getUnknown(),
+		invObject->getTitle()
+	};
+	for (int i = 0; i < 2; i++) {
+		if (titles[i] == 0) {
+			continue;
+		}
+		int page = GetPageWithTitle(titles[i]);
+		if (page != -1) {
+			_pages[page].CrossClue(id);
+		}
+	}
+}
+
 void InitNotebookAnim(OBJECT **obj, ANIM &anim, SysReel reel, int zPosition) {
 	auto film = GetSystemReelFilm(reel);
 	MultiDeleteObjectIfExists(FIELD_STATUS, obj);
diff --git a/engines/tinsel/noir/notebook.h b/engines/tinsel/noir/notebook.h
index 5656adf7121..58beda8da7c 100644
--- a/engines/tinsel/noir/notebook.h
+++ b/engines/tinsel/noir/notebook.h
@@ -62,6 +62,7 @@ public:
 	// Adds a connection between a clue/title
 	void AddHyperlink(int32 id1, int32 id2);
 	void AddClue(int id);
+	void CrossClue(int id);
 	// Called within InventoryProcess loop
 	void Redraw();
 
@@ -75,6 +76,7 @@ public:
 private:
 	int AddTitle(const InventoryObjectT3 &invObject);
 	void AddClue(const InventoryObjectT3 &invObject);
+	int GetPageWithTitle(int id);
 
 	void ClearNotebookPage();
 
diff --git a/engines/tinsel/noir/notebook_page.cpp b/engines/tinsel/noir/notebook_page.cpp
index afa99fc16fb..848f1866823 100644
--- a/engines/tinsel/noir/notebook_page.cpp
+++ b/engines/tinsel/noir/notebook_page.cpp
@@ -93,14 +93,25 @@ void NotebookLine::CrossOut() {
 	_crossedOut = true;
 }
 
-bool NotebookPage::ContainsClue(int id) {
+int NotebookPage::IndexOfClue(int id) const {
 	for (int i = 0; i < _numLines; i++) {
 		if (_lines[i]._id == id) {
-			return true;
+			return i;
 		}
 	}
-	return false;
+	return -1;
+}
+
+bool NotebookPage::ContainsClue(int id) {
+	return IndexOfClue(id) != -1;
 }
+
+void NotebookPage::CrossClue(int id) {
+	int index = IndexOfClue(id);
+	assert(index != -1);
+	_lines[index].CrossOut();
+}
+
 void NotebookPage::AddLine(int id) {
 	if (ContainsClue(id)) {
 		return;
diff --git a/engines/tinsel/noir/notebook_page.h b/engines/tinsel/noir/notebook_page.h
index 8ef36b49c80..17b5bfc80a4 100644
--- a/engines/tinsel/noir/notebook_page.h
+++ b/engines/tinsel/noir/notebook_page.h
@@ -46,12 +46,14 @@ private:
 class NotebookPage {
 public:
 	bool ContainsClue(int id);
+	void CrossClue(int id);
 	void AddLine(int id);
 	void SetTitle(int id);
 	int32 GetTitle() const;
 	void FillIn();
 	void Clear();
 private:
+	int IndexOfClue(int id) const;
 	const static uint32 MAX_ENTRIES_PER_PAGE = 8;
 	NotebookLine _lines[MAX_ENTRIES_PER_PAGE] = {};
 	uint32 _numLines = 0;
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index 2bec883eb96..32ba1fe0bc0 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -156,7 +156,7 @@ enum MASTER_LIB_CODES {
 	WALKTAG, WALKXPOS, WALKYPOS, WHICHCD, WHICHINVENTORY, ZZZZZZ, DEC3D, DECINVMAIN,
 	ADDNOTEBOOK, ADDINV3, ADDCONV, SET3DTEXTURE, FADEMUSIC, VOICEOVER, SETVIEW,
 	HELDOBJECTORTOPIC, BOOKADDHYPERLINK, OPENNOTEBOOK, NTBPOLYENTRY, NTBPOLYPREVPAGE,
-	NTBPOLYNEXTPAGE, HIGHEST_LIBCODE
+	NTBPOLYNEXTPAGE, CROSSCLUE, HIGHEST_LIBCODE
 };
 
 static const MASTER_LIB_CODES DW1DEMO_CODES[] = {
@@ -4446,7 +4446,10 @@ NoirMapping translateNoirLibCode(int libCode, int32 *pp) {
 		debug(7, "%s(%08X)", mapping.name, pp[0]);
 		break;
 	case 39: // 1 param
-		error("Unsupported libCode %d to set_notebook _entry_bool", libCode);
+		mapping = NoirMapping{"CROSSCLUE", CROSSCLUE, 1};
+		pp -= mapping.numArgs - 1;
+		debug(7, "%s(0x%08X)", mapping.name, pp[0]);
+		break;
 	case 40:
 		mapping = NoirMapping{"CURSOR", CURSOR, 1};
 		pp -= mapping.numArgs - 1;
@@ -5570,6 +5573,11 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi
 		ConvTopic(pp[0]);
 		return -1;
 
+	case CROSSCLUE:
+		// Noir only
+		_vm->_notebook->CrossClue(pp[0]);
+		return -1;
+
 	case CURSOR:
 		// DW2 only
 		ToggleCursor(pp[0]);


Commit: 337aed1915c84ed7d415a7f325a680c1bdc35ea4
    https://github.com/scummvm/scummvm/commit/337aed1915c84ed7d415a7f325a680c1bdc35ea4
Author: Einar Johan Trøan Sømåen (einarjohants at gmail.com)
Date: 2022-05-26T21:49:53+02:00

Commit Message:
TINSEL: Close Inventories when switching between them.

Changed paths:
    engines/tinsel/events.cpp


diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp
index 75e67d24ac6..76ff3133206 100644
--- a/engines/tinsel/events.cpp
+++ b/engines/tinsel/events.cpp
@@ -399,6 +399,18 @@ void ProcessKeyEvent(PLR_EVENT ke) {
 	lastRealAction = DwGetCurrentTime(); \
 }
 
+void CloseOpenInventories() {
+	if (_vm->_notebook->IsOpen()) {
+		_vm->_notebook->Close();
+	} else {
+		if (_vm->_dialogs->InventoryActive()) {
+			if (_vm->_dialogs->WhichInventoryOpen() != INV_3) {
+				_vm->_dialogs->KillInventory();
+			}
+		}
+	}
+}
+
 /**
  * Main interface point for specifying player atcions
  */
@@ -446,17 +458,22 @@ void PlayerEvent(PLR_EVENT pEvent, const Common::Point &coOrds) {
 		break;
 
 	case PLR_MENU:
+		if (TinselVersion == 3) {
+			CloseOpenInventories();
+		}
 		_vm->_dialogs->OpenMenu(MAIN_MENU);
 		break;
 
 	case PLR_INVENTORY:
 		if (TinselVersion == 3) {
+			CloseOpenInventories();
 			_vm->_dialogs->PopUpInventory(INV_1);
 		}
 		break;
 
 	case PLR_NOTEBOOK:
 		if (TinselVersion == 3) {
+			CloseOpenInventories();
 			_vm->_notebook->Show(false);
 		}
 		break;
@@ -466,10 +483,16 @@ void PlayerEvent(PLR_EVENT pEvent, const Common::Point &coOrds) {
 		break;
 
 	case PLR_SAVE:
+		if (TinselVersion == 3) {
+			CloseOpenInventories();
+		}
 		_vm->_dialogs->OpenMenu(SAVE_MENU);
 		break;
 
 	case PLR_LOAD:
+		if (TinselVersion == 3) {
+			CloseOpenInventories();
+		}
 		_vm->_dialogs->OpenMenu(LOAD_MENU);
 		break;
 




More information about the Scummvm-git-logs mailing list