[Scummvm-git-logs] scummvm master -> 87966be0e7c7a63e6075daccab32bf7a8019727d

neuromancer noreply at scummvm.org
Fri Mar 28 13:32:59 UTC 2025


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:
0fc3fccf8b PRIVATE: Track game events in diary
85466a2e7f PRIVATE: Fix memory movie playback and memory saving
87966be0e7 PRIVATE: Fix unpausing crash, empty memory location crash, and bust movie tracking


Commit: 0fc3fccf8bb5fe655f578b36a0ba97aee8db7a3f
    https://github.com/scummvm/scummvm/commit/0fc3fccf8bb5fe655f578b36a0ba97aee8db7a3f
Author: ellm135 (ellm13531 at gmail.com)
Date: 2025-03-28T14:32:55+01:00

Commit Message:
PRIVATE: Track game events in diary

Changed paths:
    engines/private/funcs.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index aa0573958ca..4ade0a73363 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -77,6 +77,8 @@ static void fDiaryLocList(ArgArray args) {
 	assert(args[2].type == NUM);
 	assert(args[3].type == NUM);
 
+	g_private->_currentDiaryPage = -1;
+
 	debugC(1, kPrivateDebugScript, "DiaryLocList(%d, %d, %d, %d)", args[0].u.val, args[1].u.val, args[2].u.val, args[3].u.val);
 
 	x2 = args[0].u.val;
@@ -90,12 +92,62 @@ static void fDiaryLocList(ArgArray args) {
 }
 
 static void fDiaryGoLoc(ArgArray args) {
-	debugC(1, kPrivateDebugScript, "WARNING: DiaryGoLoc not implemented");
+	debugC(1, kPrivateDebugScript, "DiaryGoLoc(%d, ..)", args[0].u.val);
+
+	ExitInfo e;
+
+	e.rect = *args[1].u.rect;
+	e.nextSetting = "kDiaryMiddle";
+
+	if (args[0].u.val) {
+		e.cursor = "kTurnRight";
+		g_private->_diaryNextPageExit = e;
+	} else {
+		e.cursor = "kTurnLeft";
+		g_private->_diaryPrevPageExit = e;
+	}
+
+	g_private->_exits.push_front(e);
+}
+
+static void fDiaryPageTurn(ArgArray args) {
+	debugC(1, kPrivateDebugScript, "DiaryPageTurn(%d, ..)", args[0].u.val);
+
+	ExitInfo e;
+	e.nextSetting = "kDiaryMiddle";
+	e.rect = *args[1].u.rect;
+
+	if (args[0].u.val == 1) {
+		e.cursor = "kTurnRight";
+
+		if (g_private->_currentDiaryPage == g_private->_diaryPages.size() - 1) {
+			e.nextSetting = "kDiaryLastPage";
+		}
+
+		g_private->_diaryNextPageExit = e;
+	} else {
+		e.cursor = "kTurnLeft";
+
+		if (g_private->_currentDiaryPage == 0) {
+			e.nextSetting = "kDiaryTOC";
+		}
+
+		g_private->_diaryPrevPageExit = e;
+	}
+
+	g_private->_exits.push_front(e);
+}
+
+static void fDiaryPage(ArgArray args) {
+	debugC(1, kPrivateDebugScript, "DiaryPage(%d, %d, %d, %d, ..)", args[0].u.rect->left, args[0].u.rect->top, args[0].u.rect->right, args[0].u.rect->bottom);
+	g_private->loadMemories(*args[0].u.rect, args[1].u.val, args[2].u.val);
 }
 
 static void fDiaryInvList(ArgArray args) {
 	debugC(1, kPrivateDebugScript, "DiaryInvList(%d, ..)", args[0].u.val);
 
+	g_private->_currentDiaryPage = g_private->_diaryPages.size();
+
 	const Common::Rect *r1 = args[1].u.rect;
 	const Common::Rect *r2 = args[2].u.rect;
 
@@ -524,6 +576,7 @@ static void fMovie(ArgArray args) {
 	Common::String nextSetting = *args[1].u.sym->name;
 
 	if (!g_private->_playedMovies.contains(movie) && movie != "\"\"") {
+		g_private->addMemory(movie);
 		g_private->_nextMovie = movie;
 		g_private->_playedMovies.setVal(movie, true);
 		g_private->_nextSetting = nextSetting;
@@ -791,6 +844,8 @@ const FuncTable funcTable[] = {
 
 	// Diary
 	{fDiaryLocList, "DiaryLocList"},
+	{fDiaryPageTurn, "DiaryPageTurn"},
+	{fDiaryPage, "DiaryPage"},
 	{fDiaryInvList, "DiaryInvList"},
 	{fDiaryGoLoc, "DiaryGoLoc"},
 
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index c7b5d75cc4d..00331ef2a3e 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -108,6 +108,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
 
 	// Diary
 	_diaryLocPrefix = "inface/diary/loclist/";
+	_currentDiaryPage = 0;
 
 	// Safe
 	_safeNumberPath = "sg/search_s/sgsaf%d.bmp";
@@ -239,6 +240,8 @@ Common::Error PrivateEngine::run() {
 	_compositeSurface->create(_screenW, _screenH, _pixelFormat);
 	_compositeSurface->setTransparentColor(_transparentColor);
 
+	_currentDiaryPage = 0;
+
 	// Load the game frame once
 	byte *palette;
 	_frameImage = decodeImage(_framePath, nullptr);
@@ -293,6 +296,14 @@ Common::Error PrivateEngine::run() {
 					break;
 				else if (selectSafeDigit(mousePos))
 					break;
+				else if (selectDiaryNextPage(mousePos))
+					break;
+				else if (selectDiaryPrevPage(mousePos))
+					break;
+				else if (selectLocation(mousePos))
+					break;
+				else if (selectMemory(mousePos))
+					break;
 
 				selectPauseGame(mousePos);
 				selectPhoneArea(mousePos);
@@ -391,6 +402,8 @@ void PrivateEngine::initFuncs() {
 void PrivateEngine::clearAreas() {
 	_exits.clear();
 	_masks.clear();
+	_locationMasks.clear();
+	_memoryMasks.clear();
 
 	if (_loadGameMask.surf)
 		_loadGameMask.surf->free();
@@ -737,6 +750,158 @@ void PrivateEngine::selectMask(Common::Point mousePos) {
 	}
 }
 
+bool PrivateEngine::selectLocation(Common::Point mousePos) {
+	if (_locationMasks.size() == 0) {
+		return false;
+	}
+	
+	uint i = 0;
+	uint totalLocations = 0;
+	for (NameList::const_iterator it = maps.locationList.begin(); it != maps.locationList.end(); ++it) {
+		const Private::Symbol *sym = maps.locations.getVal(*it);
+		if (sym->u.val) {
+			if (inMask(_locationMasks[i].surf, mousePos)) {
+				for (uint j = 0; j < _diaryPages.size(); j++) {
+					if (_diaryPages[j].locationID == totalLocations + 1) {
+						_currentDiaryPage = j;
+						break;
+					}
+				}
+	
+				_numberClicks++;
+				_nextSetting = _locationMasks[i].nextSetting;
+
+				return true;
+			}
+			i++;
+		}
+		totalLocations++;
+	}
+
+	return false;
+}
+
+bool PrivateEngine::selectDiaryNextPage(Common::Point mousePos) {
+	mousePos = mousePos - _origin;
+	if (mousePos.x < 0 || mousePos.y < 0)
+		return false;
+
+	if (_diaryNextPageExit.rect.contains(mousePos)) {
+		_currentDiaryPage++;
+		_nextSetting = _diaryNextPageExit.nextSetting;
+
+		return true;
+	}
+
+	return false;
+}
+
+bool PrivateEngine::selectDiaryPrevPage(Common::Point mousePos) {
+	mousePos = mousePos - _origin;
+	if (mousePos.x < 0 || mousePos.y < 0)
+		return false;
+
+	if (_diaryPrevPageExit.rect.contains(mousePos)) {
+		_currentDiaryPage--;
+		_nextSetting = _diaryPrevPageExit.nextSetting;
+
+		return true;
+	}
+
+	return false;
+}
+
+bool PrivateEngine::selectMemory(Common::Point mousePos) {
+	if (_memoryMasks.size() == 0) { 
+		return false;
+	}
+
+	for (uint i = 0; i < _memoryMasks.size(); i++) {
+		if (inMask(_memoryMasks[i].surf, mousePos)) {
+			_masks.clear();
+			_memoryMasks.clear();
+			_exits.clear();
+			_nextMovie = _diaryPages[_currentDiaryPage].memories[i].movie;
+			_nextSetting = "kDiaryMiddle";
+			loadImage("inface\\general\\inface2.bmp", 0, 0);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void PrivateEngine::addMemory(Common::String path) {
+	size_t index = path.findLastOf('\\');
+	Common::String location = path.substr(index + 2, 2);
+
+	Common::String imagePath;
+
+	// Paths to the global folder have a different pattern from other paths
+	if (path.contains("global")) {
+		if (path.contains("spoc00xs")) {
+			imagePath = "inface\\diary\\ss_icons\\global\\transiti\\ipoc00.bmp";
+		} else {
+			imagePath = "inface\\diary\\ss_icons\\global\\transiti\\animatio\\mo\\imo" + path.substr(index + 4, 3) + ".bmp";
+		}
+	} else {
+		// First letter after the last \ is an s, which isn't needed; next 2 are location; and the next 3 are what image to use
+		imagePath = "inface\\diary\\ss_icons\\" + location + "\\i" + location + path.substr(index + 4, 3) + ".bmp";
+	}
+
+
+	if (!Common::File::exists(convertPath(imagePath))) {
+		return;
+	}
+
+	MemoryInfo memory;
+	memory.movie = path;
+	memory.image = imagePath;
+
+	for (int i = _diaryPages.size() - 1; i >= 0; i--) {
+		if (_diaryPages[i].locationName == location) {
+			if (_diaryPages[i].memories.size() == 6) {
+				DiaryPage diaryPage = DiaryPage();
+				diaryPage.locationName = location;
+				diaryPage.locationID = _diaryPages[i].locationID;
+				diaryPage.memories.push_back(memory);
+				_diaryPages.insert_at(i + 1, diaryPage);
+				return;
+			}
+			_diaryPages[i].memories.push_back(memory);
+
+			return;
+		}
+	}
+
+	DiaryPage diaryPage = DiaryPage();
+	diaryPage.locationName = location;
+
+	uint locationIndex = 0;
+	for (NameList::const_iterator it = maps.locationList.begin(); it != maps.locationList.end(); ++it) {
+		const Private::Symbol *sym = maps.locations.getVal(*it);
+		locationIndex++;
+
+		Common::String currentLocation = it->substr(9);
+		currentLocation.toLowercase();
+		if (sym->u.val && currentLocation == location) {
+			diaryPage.locationID = locationIndex;
+			break;
+		}
+	}
+
+	diaryPage.memories.push_back(memory);
+	
+	for (int i = _diaryPages.size() - 1; i >= 0; i--) {
+		if (_diaryPages[i].locationID < diaryPage.locationID) {
+			_diaryPages.insert_at(i + 1, diaryPage);
+			return;
+		}
+	}
+
+	_diaryPages.insert_at(0, diaryPage);
+}
+
 void PrivateEngine::selectAMRadioArea(Common::Point mousePos) {
 	if (_AMRadioArea.surf == nullptr)
 		return;
@@ -969,6 +1134,7 @@ void PrivateEngine::restartGame() {
 	}
 	inventory.clear();
 	_dossiers.clear();
+	_diaryPages.clear();
 
 	// Sounds
 	_AMRadio.clear();
@@ -1497,8 +1663,14 @@ void PrivateEngine::loadLocations(const Common::Rect &rect) {
 			Common::String s =
 				Common::String::format("%sdryloc%d.bmp", _diaryLocPrefix.c_str(), i);
 
-			Graphics::Surface *surface = loadMask(s, rect.left + 120, rect.top + offset, true);
-			delete surface;
+			MaskInfo m;
+			m.surf = loadMask(s, rect.left + 120, rect.top + offset, true);
+			m.cursor = g_private->getExitCursor();
+			m.nextSetting = "kDiaryMiddle";
+			m.flag1 = nullptr;
+			m.flag2 = nullptr;
+			_masks.push_front(m);
+			_locationMasks.push_back(m);
 		}
 	}
 }
@@ -1512,4 +1684,32 @@ void PrivateEngine::loadInventory(uint32 x, const Common::Rect &r1, const Common
 	}
 }
 
+void PrivateEngine::loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset) {
+	Common::String s = Common::String::format("inface\\diary\\loctabs\\drytab%d.bmp", _diaryPages[_currentDiaryPage].locationID);
+	loadImage(s, 0, 0);
+
+	uint memoriesLoaded = 0;
+	uint currentVerticalOffset = 0;
+	uint horizontalOffset = 0;
+
+	for (uint i = 0; i < _diaryPages[_currentDiaryPage].memories.size(); i++) {
+		MaskInfo m;
+		m.surf = loadMask(_diaryPages[_currentDiaryPage].memories[i].image, rect.left + horizontalOffset, rect.top + currentVerticalOffset, true);
+		m.cursor = g_private->getExitCursor();
+		m.nextSetting = "kDiaryMiddle";
+		m.flag1 = nullptr;
+		m.flag2 = nullptr;
+		_masks.push_front(m);
+		_memoryMasks.push_back(m);
+
+		currentVerticalOffset += verticalOffset;
+		memoriesLoaded++;
+
+		if (memoriesLoaded == 3) {
+			horizontalOffset = rightPageOffset;
+			currentVerticalOffset = 0;
+		}
+	}
+}
+
 } // End of namespace Private
diff --git a/engines/private/private.h b/engines/private/private.h
index 874deeaa6db..d730c8168a3 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -112,6 +112,17 @@ typedef struct CursorInfo {
 	Graphics::WinCursorGroup *winCursorGroup;
 } CursorInfo;
 
+typedef struct MemoryInfo {
+	Common::String image;
+	Common::String movie;
+} MemoryInfo;
+
+typedef struct DiaryPage {
+	Common::String locationName;
+	Common::Array<MemoryInfo> memories;
+	uint locationID;
+} DiaryPage;
+
 // funcs
 
 typedef struct FuncTable {
@@ -133,6 +144,7 @@ typedef Common::List<Common::String> InvList;
 // arrays
 
 typedef Common::Array<DossierInfo> DossierArray;
+typedef Common::Array<DiaryPage> DiaryPages;
 
 // hash tables
 
@@ -284,6 +296,18 @@ public:
 	void loadLocations(const Common::Rect &);
 	void loadInventory(uint32, const Common::Rect &, const Common::Rect &);
 	bool _toTake;
+	DiaryPages _diaryPages;
+	uint _currentDiaryPage;
+	ExitInfo _diaryNextPageExit;
+	ExitInfo _diaryPrevPageExit;
+	bool selectDiaryNextPage(Common::Point mousePos);
+	bool selectDiaryPrevPage(Common::Point mousePos);
+	void addMemory(Common::String path);
+	void loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset);
+	bool selectLocation(Common::Point mousePos);
+	Common::Array<MaskInfo> _locationMasks;
+	Common::Array<MaskInfo> _memoryMasks;
+	bool selectMemory(Common::Point mousePos);
 
 	// Save/Load games
 	MaskInfo _saveGameMask;


Commit: 85466a2e7f369ce881aceb54e5090a063443d325
    https://github.com/scummvm/scummvm/commit/85466a2e7f369ce881aceb54e5090a063443d325
Author: ellm135 (ellm13531 at gmail.com)
Date: 2025-03-28T14:32:55+01:00

Commit Message:
PRIVATE: Fix memory movie playback and memory saving

Changed paths:
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 00331ef2a3e..d293cbb9f03 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -261,6 +261,7 @@ Common::Error PrivateEngine::run() {
 	Common::Event event;
 	Common::Point mousePos;
 	_videoDecoder = nullptr;
+	_pausedVideo = nullptr;
 	int saveSlot = ConfMan.getInt("save_slot");
 	if (saveSlot >= 0) { // load the savegame
 		loadGameState(saveSlot);
@@ -268,6 +269,8 @@ Common::Error PrivateEngine::run() {
 		_nextSetting = getGoIntroSetting();
 	}
 
+	_isMemoryMoviePlaying = false;
+
 	while (!shouldQuit()) {
 		checkPhoneCall();
 
@@ -302,8 +305,10 @@ Common::Error PrivateEngine::run() {
 					break;
 				else if (selectLocation(mousePos))
 					break;
-				else if (selectMemory(mousePos))
+				else if (selectMemory(mousePos)) {
+					_isMemoryMoviePlaying = true;
 					break;
+				}
 
 				selectPauseGame(mousePos);
 				selectPhoneArea(mousePos);
@@ -352,13 +357,21 @@ Common::Error PrivateEngine::run() {
 		}
 
 		if (_videoDecoder && !_videoDecoder->isPaused()) {
-			if (_videoDecoder->getCurFrame() == 0)
+			if (_videoDecoder->getCurFrame() == 0) {
 				stopSound(true);
+
+				if (_isMemoryMoviePlaying) {
+					const byte *videoPalette = _videoDecoder->getPalette();
+					g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
+					drawScreenFrame(videoPalette);
+				}
+			} 
 			if (_videoDecoder->endOfVideo()) {
 				_videoDecoder->close();
 				delete _videoDecoder;
 				_videoDecoder = nullptr;
 				_currentMovie = "";
+				_isMemoryMoviePlaying = false;
 			} else if (_videoDecoder->needsUpdate()) {
 				drawScreen();
 			}
@@ -659,6 +672,7 @@ void PrivateEngine::selectPauseGame(Common::Point mousePos) {
 				_nextSetting = getPauseMovieSetting();
 				if (_videoDecoder) {
 					_videoDecoder->pauseVideo(true);
+					_pausedVideo = _videoDecoder;
 				}
 				_compositeSurface->fillRect(_screenRect, 0);
 				_compositeSurface->setPalette(_framePalette, 0, 256);
@@ -675,6 +689,12 @@ void PrivateEngine::resumeGame() {
 	_pausedSetting = "";
 	_mode = 1;
 	_origin = Common::Point(kOriginOne[0], kOriginOne[1]);
+
+	if (_pausedVideo != nullptr) {
+		_videoDecoder = _pausedVideo;
+		_pausedVideo = nullptr;
+	}
+
 	if (_videoDecoder) {
 		_videoDecoder->pauseVideo(false);
 		const byte *videoPalette = g_private->_videoDecoder->getPalette();
@@ -750,15 +770,15 @@ void PrivateEngine::selectMask(Common::Point mousePos) {
 	}
 }
 
-bool PrivateEngine::selectLocation(Common::Point mousePos) {
+bool PrivateEngine::selectLocation(const Common::Point &mousePos) {
 	if (_locationMasks.size() == 0) {
 		return false;
 	}
 	
 	uint i = 0;
 	uint totalLocations = 0;
-	for (NameList::const_iterator it = maps.locationList.begin(); it != maps.locationList.end(); ++it) {
-		const Private::Symbol *sym = maps.locations.getVal(*it);
+	for (auto &it : maps.locationList) {
+		const Private::Symbol *sym = maps.locations.getVal(it);
 		if (sym->u.val) {
 			if (inMask(_locationMasks[i].surf, mousePos)) {
 				for (uint j = 0; j < _diaryPages.size(); j++) {
@@ -811,11 +831,7 @@ bool PrivateEngine::selectDiaryPrevPage(Common::Point mousePos) {
 	return false;
 }
 
-bool PrivateEngine::selectMemory(Common::Point mousePos) {
-	if (_memoryMasks.size() == 0) { 
-		return false;
-	}
-
+bool PrivateEngine::selectMemory(const Common::Point &mousePos) {
 	for (uint i = 0; i < _memoryMasks.size(); i++) {
 		if (inMask(_memoryMasks[i].surf, mousePos)) {
 			_masks.clear();
@@ -823,7 +839,6 @@ bool PrivateEngine::selectMemory(Common::Point mousePos) {
 			_exits.clear();
 			_nextMovie = _diaryPages[_currentDiaryPage].memories[i].movie;
 			_nextSetting = "kDiaryMiddle";
-			loadImage("inface\\general\\inface2.bmp", 0, 0);
 			return true;
 		}
 	}
@@ -831,7 +846,7 @@ bool PrivateEngine::selectMemory(Common::Point mousePos) {
 	return false;
 }
 
-void PrivateEngine::addMemory(Common::String path) {
+void PrivateEngine::addMemory(const Common::String &path) {
 	size_t index = path.findLastOf('\\');
 	Common::String location = path.substr(index + 2, 2);
 
@@ -840,16 +855,15 @@ void PrivateEngine::addMemory(Common::String path) {
 	// Paths to the global folder have a different pattern from other paths
 	if (path.contains("global")) {
 		if (path.contains("spoc00xs")) {
-			imagePath = "inface\\diary\\ss_icons\\global\\transiti\\ipoc00.bmp";
+			imagePath = "inface/diary/ss_icons/global/transiti/ipoc00.bmp";
 		} else {
-			imagePath = "inface\\diary\\ss_icons\\global\\transiti\\animatio\\mo\\imo" + path.substr(index + 4, 3) + ".bmp";
+			imagePath = "inface/diary/ss_icons/global/transiti/animatio/mo/imo" + path.substr(index + 4, 3) + ".bmp";
 		}
 	} else {
 		// First letter after the last \ is an s, which isn't needed; next 2 are location; and the next 3 are what image to use
-		imagePath = "inface\\diary\\ss_icons\\" + location + "\\i" + location + path.substr(index + 4, 3) + ".bmp";
+		imagePath = "inface/diary/ss_icons/" + location + "/i" + location + path.substr(index + 4, 3) + ".bmp";
 	}
 
-
 	if (!Common::File::exists(convertPath(imagePath))) {
 		return;
 	}
@@ -861,7 +875,7 @@ void PrivateEngine::addMemory(Common::String path) {
 	for (int i = _diaryPages.size() - 1; i >= 0; i--) {
 		if (_diaryPages[i].locationName == location) {
 			if (_diaryPages[i].memories.size() == 6) {
-				DiaryPage diaryPage = DiaryPage();
+				DiaryPage diaryPage;
 				diaryPage.locationName = location;
 				diaryPage.locationID = _diaryPages[i].locationID;
 				diaryPage.memories.push_back(memory);
@@ -874,15 +888,15 @@ void PrivateEngine::addMemory(Common::String path) {
 		}
 	}
 
-	DiaryPage diaryPage = DiaryPage();
+	DiaryPage diaryPage;
 	diaryPage.locationName = location;
 
 	uint locationIndex = 0;
-	for (NameList::const_iterator it = maps.locationList.begin(); it != maps.locationList.end(); ++it) {
-		const Private::Symbol *sym = maps.locations.getVal(*it);
+	for (auto &it : maps.locationList) {
+		const Private::Symbol *sym = maps.locations.getVal(it);
 		locationIndex++;
 
-		Common::String currentLocation = it->substr(9);
+		Common::String currentLocation = it.substr(9);
 		currentLocation.toLowercase();
 		if (sym->u.val && currentLocation == location) {
 			diaryPage.locationID = locationIndex;
@@ -1135,6 +1149,7 @@ void PrivateEngine::restartGame() {
 	inventory.clear();
 	_dossiers.clear();
 	_diaryPages.clear();
+	_isMemoryMoviePlaying = false;
 
 	// Sounds
 	_AMRadio.clear();
@@ -1145,6 +1160,7 @@ void PrivateEngine::restartGame() {
 	// Movies
 	_repeatedMovieExit = "";
 	_playedMovies.clear();
+	_pausedVideo = nullptr;
 
 	// Pause
 	_pausedSetting = "";
@@ -1156,6 +1172,7 @@ void PrivateEngine::restartGame() {
 Common::Error PrivateEngine::loadGameStream(Common::SeekableReadStream *stream) {
 	// We don't want to continue with any sound from a previous game
 	stopSound(true);
+	_pausedVideo = nullptr;
 
 	Common::Serializer s(stream, nullptr);
 	debugC(1, kPrivateDebugFunction, "loadGameStream");
@@ -1181,6 +1198,25 @@ Common::Error PrivateEngine::loadGameStream(Common::SeekableReadStream *stream)
 		inventory.push_back(stream->readString());
 	}
 
+	// Diary pages
+	_diaryPages.clear();
+	uint32 diaryPagesSize = stream->readUint32LE();
+	for (uint32 i = 0; i < diaryPagesSize; i++) {
+		DiaryPage diaryPage;
+		diaryPage.locationName = stream->readString();
+		diaryPage.locationID = stream->readUint32LE();
+
+		uint32 memoriesSize = stream->readUint32LE();
+		for (uint32 j = 0; j < memoriesSize; j++) {
+			MemoryInfo memory;
+			memory.image = stream->readString();
+			memory.movie = stream->readString();
+			diaryPage.memories.push_back(memory);
+		}
+
+		_diaryPages.push_back(diaryPage);
+	}
+
 	// Dossiers
 	_dossiers.clear();
 	size = stream->readUint32LE();
@@ -1280,6 +1316,22 @@ Common::Error PrivateEngine::saveGameStream(Common::WriteStream *stream, bool is
 		stream->writeByte(0);
 	}
 
+	stream->writeUint32LE(_diaryPages.size());
+	for (uint i = 0; i < _diaryPages.size(); i++) {
+		stream->writeString(_diaryPages[i].locationName);
+		stream->writeByte(0);
+
+		stream->writeUint32LE(_diaryPages[i].locationID);
+		stream->writeUint32LE(_diaryPages[i].memories.size());
+
+		for (uint j = 0; j < _diaryPages[i].memories.size(); j++) {
+			stream->writeString(_diaryPages[i].memories[j].image);
+			stream->writeByte(0);
+			stream->writeString(_diaryPages[i].memories[j].movie);
+			stream->writeByte(0);
+		}
+	}
+
 	// Dossiers
 	stream->writeUint32LE(_dossiers.size());
 	for (DossierArray::const_iterator it = _dossiers.begin(); it != _dossiers.end(); ++it) {
@@ -1415,6 +1467,7 @@ void PrivateEngine::skipVideo() {
 	delete _videoDecoder;
 	_videoDecoder = nullptr;
 	_currentMovie = "";
+	_isMemoryMoviePlaying = false;
 }
 
 void PrivateEngine::stopSound(bool all) {
@@ -1685,7 +1738,7 @@ void PrivateEngine::loadInventory(uint32 x, const Common::Rect &r1, const Common
 }
 
 void PrivateEngine::loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset) {
-	Common::String s = Common::String::format("inface\\diary\\loctabs\\drytab%d.bmp", _diaryPages[_currentDiaryPage].locationID);
+	Common::String s = Common::String::format("inface/diary/loctabs/drytab%d.bmp", _diaryPages[_currentDiaryPage].locationID);
 	loadImage(s, 0, 0);
 
 	uint memoriesLoaded = 0;
diff --git a/engines/private/private.h b/engines/private/private.h
index d730c8168a3..0210a026c0a 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -172,6 +172,7 @@ public:
 	Audio::SoundHandle _fgSoundHandle;
 	Audio::SoundHandle _bgSoundHandle;
 	Video::SmackerDecoder *_videoDecoder;
+	Video::SmackerDecoder *_pausedVideo;
 	Common::InstallShieldV3 _installerArchive;
 
 	Common::Error run() override;
@@ -302,12 +303,13 @@ public:
 	ExitInfo _diaryPrevPageExit;
 	bool selectDiaryNextPage(Common::Point mousePos);
 	bool selectDiaryPrevPage(Common::Point mousePos);
-	void addMemory(Common::String path);
+	void addMemory(const Common::String &path);
 	void loadMemories(const Common::Rect &rect, uint rightPageOffset, uint verticalOffset);
-	bool selectLocation(Common::Point mousePos);
+	bool selectLocation(const Common::Point &mousePos);
 	Common::Array<MaskInfo> _locationMasks;
 	Common::Array<MaskInfo> _memoryMasks;
-	bool selectMemory(Common::Point mousePos);
+	bool selectMemory(const Common::Point &mousePos);
+	bool _isMemoryMoviePlaying;
 
 	// Save/Load games
 	MaskInfo _saveGameMask;


Commit: 87966be0e7c7a63e6075daccab32bf7a8019727d
    https://github.com/scummvm/scummvm/commit/87966be0e7c7a63e6075daccab32bf7a8019727d
Author: ellm135 (ellm13531 at gmail.com)
Date: 2025-03-28T14:32:55+01:00

Commit Message:
PRIVATE: Fix unpausing crash, empty memory location crash, and bust movie tracking

Changed paths:
    engines/private/funcs.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 4ade0a73363..64d1208b7e5 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -266,6 +266,10 @@ static void fBustMovie(ArgArray args) {
 
 	g_private->_nextMovie = pv;
 	g_private->_nextSetting = args[0].u.sym->name->c_str();
+
+	Common::String memoryPath = pv;
+	memoryPath.replace('/', '\\');
+	g_private->addMemory(memoryPath);
 }
 
 static void fDossierAdd(ArgArray args) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index d293cbb9f03..fdacbbf4093 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -269,7 +269,7 @@ Common::Error PrivateEngine::run() {
 		_nextSetting = getGoIntroSetting();
 	}
 
-	_isMemoryMoviePlaying = false;
+	_needToDrawScreenFrame = false;
 
 	while (!shouldQuit()) {
 		checkPhoneCall();
@@ -306,7 +306,7 @@ Common::Error PrivateEngine::run() {
 				else if (selectLocation(mousePos))
 					break;
 				else if (selectMemory(mousePos)) {
-					_isMemoryMoviePlaying = true;
+					_needToDrawScreenFrame = true;
 					break;
 				}
 
@@ -359,19 +359,20 @@ Common::Error PrivateEngine::run() {
 		if (_videoDecoder && !_videoDecoder->isPaused()) {
 			if (_videoDecoder->getCurFrame() == 0) {
 				stopSound(true);
+			}
+
+			if (_needToDrawScreenFrame && _videoDecoder->getCurFrame() >= 0) {
+				const byte *videoPalette = _videoDecoder->getPalette();
+				g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
+				drawScreenFrame(videoPalette);
+				_needToDrawScreenFrame = false;
+			}
 
-				if (_isMemoryMoviePlaying) {
-					const byte *videoPalette = _videoDecoder->getPalette();
-					g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
-					drawScreenFrame(videoPalette);
-				}
-			} 
 			if (_videoDecoder->endOfVideo()) {
 				_videoDecoder->close();
 				delete _videoDecoder;
 				_videoDecoder = nullptr;
 				_currentMovie = "";
-				_isMemoryMoviePlaying = false;
 			} else if (_videoDecoder->needsUpdate()) {
 				drawScreen();
 			}
@@ -697,9 +698,7 @@ void PrivateEngine::resumeGame() {
 
 	if (_videoDecoder) {
 		_videoDecoder->pauseVideo(false);
-		const byte *videoPalette = g_private->_videoDecoder->getPalette();
-		g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
-		drawScreenFrame(videoPalette);
+		_needToDrawScreenFrame = true;
 	}
 }
 
@@ -781,14 +780,22 @@ bool PrivateEngine::selectLocation(const Common::Point &mousePos) {
 		const Private::Symbol *sym = maps.locations.getVal(it);
 		if (sym->u.val) {
 			if (inMask(_locationMasks[i].surf, mousePos)) {
+				bool diaryPageSet = false;
 				for (uint j = 0; j < _diaryPages.size(); j++) {
 					if (_diaryPages[j].locationID == totalLocations + 1) {
 						_currentDiaryPage = j;
+						diaryPageSet = true;
 						break;
 					}
 				}
-	
+
 				_numberClicks++;
+
+				// Prevent crash if there are no memories for this location
+				if (!diaryPageSet) {
+					return true;
+				}
+	
 				_nextSetting = _locationMasks[i].nextSetting;
 
 				return true;
@@ -1149,7 +1156,6 @@ void PrivateEngine::restartGame() {
 	inventory.clear();
 	_dossiers.clear();
 	_diaryPages.clear();
-	_isMemoryMoviePlaying = false;
 
 	// Sounds
 	_AMRadio.clear();
@@ -1467,7 +1473,6 @@ void PrivateEngine::skipVideo() {
 	delete _videoDecoder;
 	_videoDecoder = nullptr;
 	_currentMovie = "";
-	_isMemoryMoviePlaying = false;
 }
 
 void PrivateEngine::stopSound(bool all) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 0210a026c0a..9b47861ef62 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -249,6 +249,7 @@ public:
 	Common::String _currentVS;
 	Common::Point _origin;
 	void drawScreen();
+	bool _needToDrawScreenFrame;
 
 	// settings
 	Common::String _nextSetting;
@@ -309,7 +310,6 @@ public:
 	Common::Array<MaskInfo> _locationMasks;
 	Common::Array<MaskInfo> _memoryMasks;
 	bool selectMemory(const Common::Point &mousePos);
-	bool _isMemoryMoviePlaying;
 
 	// Save/Load games
 	MaskInfo _saveGameMask;




More information about the Scummvm-git-logs mailing list