[Scummvm-git-logs] scummvm branch-2-6 -> 6cfb6dbef8e2fd6b8653492cd95e29ce73552ce1

criezy noreply at scummvm.org
Sun Jun 19 20:01:25 UTC 2022


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

Summary:
f1ba20cefd AGS: Fixes for MemoryStream: proper seek support for writing mode
ffefd81c6b AGS: Refactored do_conversation()
006b96ccc3 AGS: Fixed renderer error if room backgrounds are of different size
e4c42034ac AGS: Fixed frame delay was skipped each time the game speed changes
5a3ce2831c AGS: Fixed sprite cache limit was reset on sprite file open
2da9b88588 AGS: Fixed CreateTextCore not passing room layer flag further
966cd9038e AGS: Fixed rendering scaled up WFN fonts
2b8a7be704 AGS: Fixed trying to erase background speech overlays twice
18db659ae3 AGS: Fix implementation of std::list::insert
08ebc88612 AGS: In unload_game_file() don't error if quit during the of dialog
a4fb95365b AGS: Store camera & viewport handles, not script ptrs, for safety
6cfb6dbef8 AGS: Store certain overlay handles, not script ptrs, for safety


Commit: f1ba20cefd6420520b28c98fb018e71a1ca73a3f
    https://github.com/scummvm/scummvm/commit/f1ba20cefd6420520b28c98fb018e71a1ca73a3f
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:53:13+01:00

Commit Message:
AGS: Fixes for MemoryStream: proper seek support for writing mode

>From upstream 80a17c94f6fc44955dcee5c559247ea73a8c0a76

Changed paths:
    engines/ags/shared/util/memory_stream.cpp
    engines/ags/shared/util/memory_stream.h


diff --git a/engines/ags/shared/util/memory_stream.cpp b/engines/ags/shared/util/memory_stream.cpp
index 69bcd01f1bd..08fb485afc9 100644
--- a/engines/ags/shared/util/memory_stream.cpp
+++ b/engines/ags/shared/util/memory_stream.cpp
@@ -31,19 +31,25 @@ MemoryStream::MemoryStream(const uint8_t *cbuf, size_t buf_sz, DataEndianess str
 	, _cbuf(cbuf)
 	, _buf_sz(buf_sz)
 	, _len(buf_sz)
-	, _buf(nullptr)
 	, _mode(kStream_Read)
-	, _pos(0) {
+	, _pos(0)
+	, _buf(nullptr) {
 }
 
 MemoryStream::MemoryStream(uint8_t *buf, size_t buf_sz, StreamWorkMode mode, DataEndianess stream_endianess)
 	: DataStream(stream_endianess)
-	, _buf(buf)
+	, _cbuf(nullptr)
 	, _buf_sz(buf_sz)
 	, _len(0)
-	, _cbuf(nullptr)
 	, _mode(mode)
-	, _pos(0) {
+	, _pos(0)
+	, _buf(nullptr) {
+	if (mode == kStream_Read) {
+		_cbuf = buf;
+		_len = buf_sz;
+	} else {
+		_buf = buf;
+	}
 }
 
 void MemoryStream::Close() {
@@ -83,7 +89,7 @@ bool MemoryStream::CanWrite() const {
 }
 
 bool MemoryStream::CanSeek() const {
-	return CanRead(); // TODO: support seeking in writable stream?
+	return true;
 }
 
 size_t MemoryStream::Read(void *buffer, size_t size) {
@@ -123,20 +129,25 @@ bool MemoryStream::Seek(soff_t offset, StreamSeek origin) {
 }
 
 size_t MemoryStream::Write(const void *buffer, size_t size) {
-	if (_pos >= _buf_sz) {
+	if (!_buf || (_pos >= _buf_sz)) {
 		return 0;
 	}
 	size = MIN(size, _buf_sz - _pos);
 	memcpy(_buf + _pos, buffer, size);
 	_pos += size;
-	_len += size;
+	// will increase len if writing after eos, otherwise = overwrite at pos
+	_len = MAX(_len, _pos);
 	return size;
 }
 
 int32_t MemoryStream::WriteByte(uint8_t val) {
-	if (_pos >= _buf_sz) { return -1; }
+	if (!_buf || (_pos >= _buf_sz)) {
+		return -1;
+	}
 	*(_buf + _pos) = val;
-	_pos++; _len++;
+	_pos++;
+	// will increase len if writing after eos, otherwise = overwrite at pos
+	_len = MAX(_len, _pos);
 	return val;
 }
 
@@ -147,7 +158,7 @@ VectorStream::VectorStream(const std::vector<uint8_t> &cbuf, DataEndianess strea
 }
 
 VectorStream::VectorStream(std::vector<uint8_t> &buf, StreamWorkMode mode, DataEndianess stream_endianess)
-	: MemoryStream((mode == kStream_Read) ? &buf.front() : nullptr, buf.size(), mode, stream_endianess)
+	: MemoryStream(((mode == kStream_Read) && (buf.size() > 0)) ? &buf.front() : nullptr, buf.size(), mode, stream_endianess)
 	, _vec(&buf) {
 }
 
@@ -156,17 +167,32 @@ void VectorStream::Close() {
 	MemoryStream::Close();
 }
 
+bool VectorStream::CanRead() const {
+	return _mode == kStream_Read;
+}
+
+bool VectorStream::CanWrite() const {
+	return _mode == kStream_Write;
+}
+
 size_t VectorStream::Write(const void *buffer, size_t size) {
-	_vec->resize(_vec->size() + size);
+	if (_pos + size > _len) {
+		_vec->resize(_pos + size);
+		_len = _pos + size;
+	}
 	memcpy(_vec->data() + _pos, buffer, size);
 	_pos += size;
-	_len += size;
 	return size;
 }
 
 int32_t VectorStream::WriteByte(uint8_t val) {
-	_vec->push_back(val);
-	_pos++; _len++;
+	if (_pos == _len) {
+		_vec->push_back(val);
+		_len++;
+	} else {
+		(*_vec)[_pos] = val;
+	}
+	_pos++;
 	return val;
 }
 
diff --git a/engines/ags/shared/util/memory_stream.h b/engines/ags/shared/util/memory_stream.h
index 5cba412d206..d3394412b8d 100644
--- a/engines/ags/shared/util/memory_stream.h
+++ b/engines/ags/shared/util/memory_stream.h
@@ -78,14 +78,14 @@ public:
 	bool    Seek(soff_t offset, StreamSeek origin) override;
 
 protected:
-	const uint8_t *_cbuf;
-	size_t                   _buf_sz; // hard buffer limit
-	size_t                   _len; // calculated length of stream
+	const uint8_t           *_cbuf = nullptr; // readonly buffer ptr
+	size_t                   _buf_sz = 0u; // hard buffer limit
+	size_t                   _len = 0u; // calculated length of stream
 	const StreamWorkMode     _mode;
-	size_t                   _pos; // current stream pos
+	size_t                   _pos = 0u; // current stream pos
 
 private:
-	uint8_t *_buf;
+	uint8_t                 *_buf = nullptr; // writeable buffer ptr
 };
 
 
@@ -101,11 +101,14 @@ public:
 
 	void    Close() override;
 
+	bool    CanRead() const override;
+	bool    CanWrite() const override;
+
 	size_t  Write(const void *buffer, size_t size) override;
 	int32_t WriteByte(uint8_t b) override;
 
 private:
-	std::vector<uint8_t> *_vec; // writeable vector (may be null)
+	std::vector<uint8_t> *_vec = nullptr; // writeable vector (may be null)
 };
 
 } // namespace Shared


Commit: ffefd81c6b857b6ae016091a94831f7e1af9a89f
    https://github.com/scummvm/scummvm/commit/ffefd81c6b857b6ae016091a94831f7e1af9a89f
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:53:34+01:00

Commit Message:
AGS: Refactored do_conversation()

Split do_conversation into multiple functions, simplified the running
the dialog topics chain code and removed code duplication as possible.
+ Removed the limit of nested dialogs.
+ This also fixes "goto-previous" not working from the first sub-dialog.

>From upstream 7bb167f5f6ee6a1976b829a1d67423d69346dc6e

Changed paths:
    engines/ags/engine/ac/dialog.cpp


diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index 6719c366edb..a12373db57b 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "common/stack.h"
 #include "ags/engine/ac/dialog.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/character.h"
@@ -390,7 +391,6 @@ bool get_custom_dialog_options_dimensions(int dlgnum) {
 	return false;
 }
 
-#define MAX_TOPIC_HISTORY 50
 #define DLG_OPTION_PARSER 99
 
 struct DialogOptions {
@@ -1048,69 +1048,65 @@ int show_dialog_options(int _dlgnum, int sayChosenOption, bool _runGameLoopsInBa
 	return dialog_choice;
 }
 
-void do_conversation(int dlgnum) {
-	EndSkippingUntilCharStops();
-
-	// AGS 2.x always makes the mouse cursor visible when displaying a dialog.
-	if (_G(loaded_game_file_version) <= kGameVersion_272)
-		_GP(play).mouse_cursor_hidden = 0;
-
-	int dlgnum_was = dlgnum;
-	int previousTopics[MAX_TOPIC_HISTORY];
-	int numPrevTopics = 0;
-	DialogTopic *dtop = &_G(dialog)[dlgnum];
+// Dialog execution state
+struct DialogExec {
+	int DlgNum = -1;
+	int DlgWas = -1;
+	// CHECKME: this may be unnecessary, investigate later
+	bool IsFirstEntry = true;
+	// nested dialogs "stack"
+	Common::Stack<int> TopicHist;
+
+	DialogExec(int start_dlgnum) : DlgNum(start_dlgnum) {}
+	int HandleDialogResult(int res);
+	void Run();
+};
 
-	// run the startup script
-	int tocar = run_dialog_script(dlgnum, dtop->startupentrypoint, 0);
-	if ((tocar == RUN_DIALOG_STOP_DIALOG) ||
-	        (tocar == RUN_DIALOG_GOTO_PREVIOUS)) {
-		// 'stop' or 'goto-previous' from first startup script
-		remove_screen_overlay(OVER_COMPLETE);
-		_GP(play).in_conversation--;
-		return;
-	} else if (tocar >= 0)
-		dlgnum = tocar;
-
-	while (dlgnum >= 0) {
-		if (dlgnum >= _GP(game).numdialog)
-			quit("!RunDialog: invalid dialog number specified");
-
-		dtop = &_G(dialog)[dlgnum];
-
-		if (dlgnum != dlgnum_was) {
-			// dialog topic changed, so play the startup
-			// script for the new topic
-			tocar = run_dialog_script(dlgnum, dtop->startupentrypoint, 0);
-			dlgnum_was = dlgnum;
-			if (tocar == RUN_DIALOG_GOTO_PREVIOUS) {
-				if (numPrevTopics < 1) {
-					// goto-previous on first topic -- end dialog
-					tocar = RUN_DIALOG_STOP_DIALOG;
-				} else {
-					tocar = previousTopics[numPrevTopics - 1];
-					numPrevTopics--;
-				}
-			}
-			if (tocar == RUN_DIALOG_STOP_DIALOG)
-				break;
-			else if (tocar >= 0) {
-				// save the old topic number in the history
-				if (numPrevTopics < MAX_TOPIC_HISTORY) {
-					previousTopics[numPrevTopics] = dlgnum;
-					numPrevTopics++;
-				}
-				dlgnum = tocar;
-				continue;
-			}
+int DialogExec::HandleDialogResult(int res) {
+	// Handle goto-previous, see if there's any previous dialog in history
+	if (res == RUN_DIALOG_GOTO_PREVIOUS) {
+		if (TopicHist.size() == 0)
+			return RUN_DIALOG_STOP_DIALOG;
+		res = TopicHist.top();
+		TopicHist.pop();
+	}
+	// Continue to the next dialog
+	if (res >= 0) {
+		// save the old topic number in the history, and switch to the new one
+		TopicHist.push(DlgNum);
+		DlgNum = res;
+		return DlgNum;
+	}
+	return res;
+ }
+
+void DialogExec::Run() {
+	while (DlgNum >= 0) {
+		if (DlgNum < 0 || DlgNum >= _GP(game).numdialog)
+			quitprintf("!RunDialog: invalid dialog number specified: %d", DlgNum);
+
+		// current dialog object
+		DialogTopic *dtop = &_G(dialog)[DlgNum];
+		int res = 0; // dialog execution result
+		// If a new dialog topic: run dialog entry point
+		if (DlgNum != DlgWas) {
+			res = run_dialog_script(DlgNum, dtop->startupentrypoint, 0);
+			DlgWas = DlgNum;
+
+			// Handle the dialog entry's result
+			res = HandleDialogResult(res);
+			if (res == RUN_DIALOG_STOP_DIALOG)
+				return; // stop the dialog
+			IsFirstEntry = false;
+			if (res != RUN_DIALOG_STAY)
+				continue; // skip to the next dialog
 		}
 
-		int chose = show_dialog_options(dlgnum, SAYCHOSEN_USEFLAG, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
-
+		// Show current dialog's options
+		int chose = show_dialog_options(DlgNum, SAYCHOSEN_USEFLAG, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
 		if (chose == CHOSE_TEXTPARSER) {
 			_G(said_speech_line) = 0;
-
-			tocar = run_dialog_request(dlgnum);
-
+			res = run_dialog_request(DlgNum);
 			if (_G(said_speech_line) > 0) {
 				// fix the problem with the close-up face remaining on screen
 				DisableInterface();
@@ -1119,28 +1115,34 @@ void do_conversation(int dlgnum) {
 				set_mouse_cursor(CURS_ARROW);
 			}
 		} else if (chose >= 0) {
-			tocar = run_dialog_script(dlgnum, dtop->entrypoints[chose], chose + 1);
+			// chose some option - run its script
+			res = run_dialog_script(DlgNum, dtop->entrypoints[chose], chose + 1);
 		} else {
-			tocar = RUN_DIALOG_STOP_DIALOG;
+			return; // no option chosen? - stop the dialog
 		}
 
-		if (tocar == RUN_DIALOG_GOTO_PREVIOUS) {
-			if (numPrevTopics < 1) {
-				tocar = RUN_DIALOG_STOP_DIALOG;
-			} else {
-				tocar = previousTopics[numPrevTopics - 1];
-				numPrevTopics--;
-			}
-		}
-		if (tocar == RUN_DIALOG_STOP_DIALOG) break;
-		else if (tocar >= 0) {
-			// save the old topic number in the history
-			if (numPrevTopics < MAX_TOPIC_HISTORY) {
-				previousTopics[numPrevTopics] = dlgnum;
-				numPrevTopics++;
-			}
-			dlgnum = tocar;
-		}
+		// Handle the dialog option's result
+		res = HandleDialogResult(res);
+		if (res == RUN_DIALOG_STOP_DIALOG)
+			return; // stop the dialog
+		// continue to the next dialog or show same dialog's options again
+	}
+}
+
+void do_conversation(int dlgnum) {
+	EndSkippingUntilCharStops();
+
+	// AGS 2.x always makes the mouse cursor visible when displaying a dialog.
+	if (_G(loaded_game_file_version) <= kGameVersion_272)
+		_GP(play).mouse_cursor_hidden = 0;
+
+	DialogExec dlgexec(dlgnum);
+	dlgexec.Run();
+	// CHECKME: find out if this is safe to do always, regardless of number of iterations
+	if (dlgexec.IsFirstEntry) {
+		// bail out from first startup script
+		remove_screen_overlay(OVER_COMPLETE);
+		_GP(play).in_conversation--;
 	}
 }
 


Commit: 006b96ccc3c64253b8ba319167c707fd2e1e266c
    https://github.com/scummvm/scummvm/commit/006b96ccc3c64253b8ba319167c707fd2e1e266c
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:53:45+01:00

Commit Message:
AGS: Fixed renderer error if room backgrounds are of different size

>From upstream 660857d193b9bcac3a7bb1bba70be8149b1e2d7e

Changed paths:
    engines/ags/engine/ac/draw.cpp


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 5660172d894..bbe69d33a46 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1690,12 +1690,11 @@ void prepare_room_sprites() {
 	// Background sprite is required for the non-software renderers always,
 	// and for software renderer in case there are overlapping viewports.
 	// Note that software DDB is just a tiny wrapper around bitmap, so overhead is negligible.
-	if (_G(roomBackgroundBmp) == nullptr) {
+	if (_G(current_background_is_dirty) || !_G(roomBackgroundBmp)) {
 		update_polled_stuff_if_runtime();
-		_G(roomBackgroundBmp) = _G(gfxDriver)->CreateDDBFromBitmap(_GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic.get(), false, true);
-	} else if (_G(current_background_is_dirty)) {
-		update_polled_stuff_if_runtime();
-		_G(gfxDriver)->UpdateDDBFromBitmap(_G(roomBackgroundBmp), _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic.get(), false);
+		_G(roomBackgroundBmp) =
+			recycle_ddb_bitmap(_G(roomBackgroundBmp), _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic.get(), false, true);
+
 	}
 	if (_G(gfxDriver)->RequiresFullRedrawEachFrame()) {
 		if (_G(current_background_is_dirty) || _G(walkBehindsCachedForBgNum) != _GP(play).bg_frame) {


Commit: e4c42034ac8f9744b0ea6a1c53460098a539f570
    https://github.com/scummvm/scummvm/commit/e4c42034ac8f9744b0ea6a1c53460098a539f570
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:53:56+01:00

Commit Message:
AGS: Fixed frame delay was skipped each time the game speed changes

This was not correct, and could cause endless frame skipping if
SetGameSpeed() is called repeatedly in game script.
>From upstream 690f08b8468dd61ae570c7480098708ba6dc669f

Changed paths:
    engines/ags/engine/ac/timer.cpp


diff --git a/engines/ags/engine/ac/timer.cpp b/engines/ags/engine/ac/timer.cpp
index 281d119ced4..05ec0b3b9cd 100644
--- a/engines/ags/engine/ac/timer.cpp
+++ b/engines/ags/engine/ac/timer.cpp
@@ -30,7 +30,7 @@
 namespace AGS3 {
 
 namespace {
-const auto MAXIMUM_FALL_BEHIND = 3;
+const auto MAXIMUM_FALL_BEHIND = 3; // number of full frames
 }
 
 std::chrono::microseconds GetFrameDuration() {
@@ -46,8 +46,8 @@ int setTimerFps(int new_fps) {
 	_G(framerate) = new_fps;
 	_G(framerate_maxed) = new_fps >= 1000;
 
-	_G(last_tick_time) = AGS_Clock::now();
-	_G(next_frame_timestamp) = AGS_Clock::now();
+	// Update next frame time
+	_G(next_frame_timestamp) = _G(last_tick_time) + _G(tick_duration);
 	return old_fps;
 }
 
@@ -56,11 +56,12 @@ bool isTimerFpsMaxed() {
 }
 
 void WaitForNextFrame() {
-	auto now = AGS_Clock::now();
-	auto frameDuration = GetFrameDuration();
+	const auto now = AGS_Clock::now();
+	const auto frameDuration = GetFrameDuration();
 
 	// early exit if we're trying to maximise framerate
 	if (frameDuration <= std::chrono::milliseconds::zero()) {
+		_G(last_tick_time) = _G(next_frame_timestamp);
 		_G(next_frame_timestamp) = now;
 		// suspend while the game is being switched out
 		while (_G(game_update_suspend)) {
@@ -80,6 +81,7 @@ void WaitForNextFrame() {
 		std::this_thread::sleep_for(frame_time_remaining);
 	}
 
+	_G(last_tick_time) = _G(next_frame_timestamp);
 	_G(next_frame_timestamp) += frameDuration;
 
 	// suspend while the game is being switched out


Commit: 5a3ce2831c3ee906574abcd594d84c532813abf2
    https://github.com/scummvm/scummvm/commit/5a3ce2831c3ee906574abcd594d84c532813abf2
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:54:08+01:00

Commit Message:
AGS: Fixed sprite cache limit was reset on sprite file open

>From upstream 4f57730e2b3d41af4fd0300e8b092d31d448f544

Changed paths:
    engines/ags/engine/ac/game_setup.h
    engines/ags/engine/ac/global_debug.cpp
    engines/ags/engine/main/config.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/shared/ac/sprite_cache.cpp
    engines/ags/shared/ac/sprite_cache.h


diff --git a/engines/ags/engine/ac/game_setup.h b/engines/ags/engine/ac/game_setup.h
index d1d703656e7..ce0edb245e0 100644
--- a/engines/ags/engine/ac/game_setup.h
+++ b/engines/ags/engine/ac/game_setup.h
@@ -92,6 +92,7 @@ struct GameSetup {
 	MouseSpeedDef mouse_speed_def;
 	bool  RenderAtScreenRes; // render sprites at screen resolution, as opposed to native one
 	int   Supersampling;
+	size_t SpriteCacheSize = 0u;
 	bool  clear_cache_on_room_change; // for low-end devices: clear resource caches on room change
 	bool  load_latest_save; // load latest saved game on launch
 	ScreenRotation rotation;
diff --git a/engines/ags/engine/ac/global_debug.cpp b/engines/ags/engine/ac/global_debug.cpp
index 7874a530fb6..a0df887f507 100644
--- a/engines/ags/engine/ac/global_debug.cpp
+++ b/engines/ags/engine/ac/global_debug.cpp
@@ -59,7 +59,7 @@ String GetRuntimeInfo() {
 		"Adventure Game Studio run-time engine[ACI version %s"
 		"[Game resolution %d x %d (%d-bit)"
 		"[Running %d x %d at %d-bit%s[GFX: %s; %s[Draw frame %d x %d["
-		"Sprite cache size: %d KB (limit %d KB; %d locked)",
+		"Sprite cache size: %d KB (limit %d KB; %d KB locked)",
 		_G(EngineVersion).LongString.GetCStr(), _GP(game).GetGameRes().Width, _GP(game).GetGameRes().Height, _GP(game).GetColorDepth(),
 		mode.Width, mode.Height, mode.ColorDepth,
 		mode.IsWindowed() ? " W" : "",
diff --git a/engines/ags/engine/main/config.cpp b/engines/ags/engine/main/config.cpp
index 709ff95c9cb..37ce15c2c7d 100644
--- a/engines/ags/engine/main/config.cpp
+++ b/engines/ags/engine/main/config.cpp
@@ -326,7 +326,7 @@ void apply_config(const ConfigTree &cfg) {
 
 		int cache_size_kb = CfgReadInt(cfg, "misc", "cachemax", DEFAULTCACHESIZE_KB);
 		if (cache_size_kb > 0)
-			_GP(spriteset).SetMaxCacheSize((size_t)cache_size_kb * 1024);
+			_GP(usetup).SpriteCacheSize = cache_size_kb * 1024;
 
 		_GP(usetup).mouse_auto_lock = CfgReadBoolInt(cfg, "mouse", "auto_lock");
 
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index c7aeee52c71..73ebbd5f8c8 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -509,7 +509,6 @@ void show_preload() {
 
 int engine_init_sprites() {
 	Debug::Printf(kDbgMsg_Info, "Initialize sprites");
-
 	HError err = _GP(spriteset).InitFile(SpriteFile::DefaultSpriteFileName, SpriteFile::DefaultSpriteIndexName);
 	if (!err) {
 		sys_main_shutdown();
@@ -521,6 +520,8 @@ int engine_init_sprites() {
 		return EXIT_ERROR;
 	}
 
+	if (_GP(usetup).SpriteCacheSize > 0)
+		_GP(spriteset).SetMaxCacheSize(_GP(usetup).SpriteCacheSize);
 	return 0;
 }
 
diff --git a/engines/ags/shared/ac/sprite_cache.cpp b/engines/ags/shared/ac/sprite_cache.cpp
index 2940e93d8a8..ff375e35731 100644
--- a/engines/ags/shared/ac/sprite_cache.cpp
+++ b/engines/ags/shared/ac/sprite_cache.cpp
@@ -68,8 +68,8 @@ SpriteCache::SpriteData::~SpriteData() {
 }
 
 SpriteCache::SpriteCache(std::vector<SpriteInfo> &sprInfos)
-	: _sprInfos(sprInfos) {
-	Init();
+	: _sprInfos(sprInfos), _maxCacheSize(DEFAULTCACHESIZE_KB * 1024u),
+	_cacheSize(0u), _lockedSize(0u), _liststart(-1), _listend(-1) {
 }
 
 SpriteCache::~SpriteCache() {
@@ -96,14 +96,6 @@ void SpriteCache::SetMaxCacheSize(size_t size) {
 	_maxCacheSize = size;
 }
 
-void SpriteCache::Init() {
-	_cacheSize = 0;
-	_lockedSize = 0;
-	_maxCacheSize = (size_t)DEFAULTCACHESIZE_KB * 1024;
-	_liststart = -1;
-	_listend = -1;
-}
-
 void SpriteCache::Reset() {
 	_file.Close();
 	// TODO: find out if it's safe to simply always delete _spriteData.Image with array element
@@ -115,10 +107,13 @@ void SpriteCache::Reset() {
 	}
 	_spriteData.clear();
 
+	_cacheSize = 0;
+	_lockedSize = 0;
 	_mrulist.clear();
 	_mrubacklink.clear();
 
-	Init();
+	_liststart = -1;
+	_listend = -1;
 }
 
 void SpriteCache::SetSprite(sprkey_t index, Bitmap *sprite) {
diff --git a/engines/ags/shared/ac/sprite_cache.h b/engines/ags/shared/ac/sprite_cache.h
index 93b63d83773..d2a1b5b2412 100644
--- a/engines/ags/shared/ac/sprite_cache.h
+++ b/engines/ags/shared/ac/sprite_cache.h
@@ -146,7 +146,6 @@ public:
 	Shared::Bitmap *operator[](sprkey_t index);
 
 private:
-	void        Init();
 	// Load sprite from game resource
 	size_t      LoadSprite(sprkey_t index);
 	// Gets the index of a sprite which data is used for the given slot;


Commit: 2da9b88588eac33ffd4b17224c21d8bd6161a405
    https://github.com/scummvm/scummvm/commit/2da9b88588eac33ffd4b17224c21d8bd6161a405
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:54:20+01:00

Commit Message:
AGS: Fixed CreateTextCore not passing room layer flag further

>From upstream e5aaa87573c6357edeb50a526892619ff748ea12

Changed paths:
    engines/ags/engine/ac/overlay.cpp


diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 770d8a7689a..7716fc504c4 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -213,7 +213,7 @@ ScreenOverlay *Overlay_CreateTextCore(bool room_layer, int x, int y, int width,
 	if (width < 8) width = _GP(play).GetUIViewport().GetWidth() / 2;
 	if (x < 0) x = _GP(play).GetUIViewport().GetWidth() / 2 - width / 2;
 	if (text_color == 0) text_color = 16;
-	return _display_main(x, y, width, text, disp_type, font, -text_color, 0, allow_shrink, false);
+	return _display_main(x, y, width, text, disp_type, font, -text_color, 0, allow_shrink, false, room_layer);
 }
 
 ScriptOverlay *Overlay_CreateGraphicalEx(bool room_layer, int x, int y, int slot, int transparent, bool clone) {


Commit: 966cd9038e56fc90a297dc05851f901a86a96485
    https://github.com/scummvm/scummvm/commit/966cd9038e56fc90a297dc05851f901a86a96485
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:54:33+01:00

Commit Message:
AGS: Fixed rendering scaled up WFN fonts

>From upstream adc9121f30c028a071783ffb6645bb72aee482ea

Changed paths:
    engines/ags/shared/font/wfn_font_renderer.cpp


diff --git a/engines/ags/shared/font/wfn_font_renderer.cpp b/engines/ags/shared/font/wfn_font_renderer.cpp
index e5eb6d6d140..1cca2fc4763 100644
--- a/engines/ags/shared/font/wfn_font_renderer.cpp
+++ b/engines/ags/shared/font/wfn_font_renderer.cpp
@@ -111,7 +111,7 @@ static int RenderChar(Bitmap *ds, const int at_x, const int at_y, Rect clip,
 		for (int w = sw, x = sx; w < width && x < ex; ++w, x += scale) {
 			if (((actdata[h * bytewid + (w / 8)] & (0x80 >> (w % 8))) != 0)) {
 				if (scale > 1) {
-					ds->FillRect(RectWH(x, y, scale - 1, scale - 1), text_color);
+					ds->FillRect(RectWH(x, y, scale, scale), text_color);
 				} else {
 					ds->PutPixel(x, y, text_color);
 				}


Commit: 2b8a7be704fc54080003b91f473f300643e49a65
    https://github.com/scummvm/scummvm/commit/2b8a7be704fc54080003b91f473f300643e49a65
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:54:47+01:00

Commit Message:
AGS: Fixed trying to erase background speech overlays twice

>From upstream 5f137874738c86852b5ef7da2933fab7e78ae89b

Changed paths:
    engines/ags/engine/ac/overlay.cpp


diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 7716fc504c4..6c98bbddaa4 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -291,7 +291,11 @@ static void invalidate_and_subref(ScreenOverlay &over, ScriptOverlay **scover) {
 	if (scover && (*scover)) {
 		(*scover)->overlayId = -1;
 		*scover = nullptr;
+	} else if (over.associatedOverlayHandle > 0) {
+		ScriptOverlay *scoverlay = const_cast<ScriptOverlay*>((const ScriptOverlay* )ccGetObjectAddressFromHandle(over.associatedOverlayHandle));
+		if (scoverlay) scoverlay->overlayId = -1;
 	}
+
 	if (over.associatedOverlayHandle > 0) {
 		ccReleaseObjectReference(over.associatedOverlayHandle);
 		over.associatedOverlayHandle = 0;
@@ -313,6 +317,9 @@ static void dispose_overlay(ScreenOverlay &over) {
 }
 
 void remove_screen_overlay_index(size_t over_idx) {
+	assert(over_idx < _GP(screenover).size());
+	if (over_idx >= _GP(screenover).size())
+		return; // something is wrong
 	ScreenOverlay &over = _GP(screenover)[over_idx];
 	// TODO: move these custom settings outside of this function
 	if (over.type == _GP(play).complete_overlay_on) {
@@ -323,7 +330,7 @@ void remove_screen_overlay_index(size_t over_idx) {
 	} else if (over.type == OVER_PICTURE) { // release internal ref for speech face
 		invalidate_and_subref(over, &_GP(play).speech_face_scover);
 		_G(face_talking) = -1;
-	} else if (over.bgSpeechForChar > 0) { // release internal ref for bg speech
+	} else if (over.bgSpeechForChar >= 0) { // release internal ref for bg speech
 		invalidate_and_subref(over, nullptr);
 	}
 	dispose_overlay(over);


Commit: 18db659ae350af3ec7235a46a08f02998d49c807
    https://github.com/scummvm/scummvm/commit/18db659ae350af3ec7235a46a08f02998d49c807
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:54:58+01:00

Commit Message:
AGS: Fix implementation of std::list::insert

Instead of returning an iterator to the inserted item, it was
returning an iterator to the next item. This was for example causing
bugs in the SpriteCache.

Changed paths:
    engines/ags/lib/std/list.h


diff --git a/engines/ags/lib/std/list.h b/engines/ags/lib/std/list.h
index d0e037bdcbb..86be1e580f2 100644
--- a/engines/ags/lib/std/list.h
+++ b/engines/ags/lib/std/list.h
@@ -59,7 +59,7 @@ public:
 	typename Common::List<T>::iterator insert(typename Common::List<T>::iterator pos,
 			const T &element) {
 		Common::List<T>::insert(pos, element);
-		return pos;
+		return --pos;
 	}
 
 	reverse_iterator rbegin() {


Commit: 08ebc886124cb6799733b1eea7ffdee09920cb65
    https://github.com/scummvm/scummvm/commit/08ebc886124cb6799733b1eea7ffdee09920cb65
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:55:08+01:00

Commit Message:
AGS: In unload_game_file() don't error if quit during the of dialog

>From upstream c7bd448dfffc197c4398a38395b444457c958d24

Changed paths:
    engines/ags/engine/ac/game.cpp


diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index f5818ca7dff..8f7e1589b43 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -355,7 +355,6 @@ void free_do_once_tokens() {
 
 
 // Free all the memory associated with the game
-// TODO: call this when exiting the game (currently only called in RunAGSGame)
 void unload_game_file() {
 	close_translation();
 
@@ -371,16 +370,10 @@ void unload_game_file() {
 	delete _G(gameinst);
 	_G(gameinstFork) = nullptr;
 	_G(gameinst) = nullptr;
-
 	_GP(gamescript).reset();
 
-	if ((_G(dialogScriptsInst) != nullptr) && (_G(dialogScriptsInst)->pc != 0)) {
-		quit("Error: unload_game called while dialog script still running");
-	} else if (_G(dialogScriptsInst) != nullptr) {
-		delete _G(dialogScriptsInst);
-		_G(dialogScriptsInst) = nullptr;
-	}
-
+	delete _G(dialogScriptsInst);
+	_G(dialogScriptsInst) = nullptr;
 	_GP(dialogScriptsScript).reset();
 
 	for (size_t i = 0; i < _G(numScriptModules); ++i) {


Commit: a4fb95365b8f624dddc217e31fe82bb05825df1f
    https://github.com/scummvm/scummvm/commit/a4fb95365b8f624dddc217e31fe82bb05825df1f
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:55:18+01:00

Commit Message:
AGS: Store camera & viewport handles, not script ptrs, for safety

>From ustream dc1421a88cd620bd1d34f8bf856e8baa57a50904
Also includes upstream 09c27c38c3afa27194b0b5dd9276036b76267488

Changed paths:
    engines/ags/engine/ac/game_state.cpp
    engines/ags/engine/ac/game_state.h


diff --git a/engines/ags/engine/ac/game_state.cpp b/engines/ags/engine/ac/game_state.cpp
index 25481f57330..f55a403acb8 100644
--- a/engines/ags/engine/ac/game_state.cpp
+++ b/engines/ags/engine/ac/game_state.cpp
@@ -242,9 +242,8 @@ PViewport GameState::CreateRoomViewport() {
 	PViewport viewport(new Viewport());
 	viewport->SetID(index);
 	viewport->SetRect(_mainViewport.GetRect());
-	ScriptViewport *scv = new ScriptViewport(index);
 	_roomViewports.push_back(viewport);
-	_scViewportRefs.push_back(std::make_pair<ScriptViewport*, int32_t>(scv, 0));
+	_scViewportHandles.push_back(0);
 	_roomViewportsSorted.push_back(viewport);
 	_roomViewportZOrderChanged = true;
 	on_roomviewport_created(index);
@@ -254,32 +253,37 @@ PViewport GameState::CreateRoomViewport() {
 ScriptViewport *GameState::RegisterRoomViewport(int index, int32_t handle) {
 	if (index < 0 || (size_t)index >= _roomViewports.size())
 		return nullptr;
-	auto &scobj = _scViewportRefs[index];
+	auto scview = new ScriptViewport(index);
 	if (handle == 0) {
-		handle = ccRegisterManagedObject(scobj.first, scobj.first);
+		handle = ccRegisterManagedObject(scview, scview);
 		ccAddObjectReference(handle); // one reference for the GameState
 	} else {
-		ccRegisterUnserializedObject(handle, scobj.first, scobj.first);
+		ccRegisterUnserializedObject(handle, scview, scview);
 	}
-	scobj.second = handle;
-	return scobj.first;
+	_scViewportHandles[index] = handle; // save handle for us
+	return scview;
 }
 
 void GameState::DeleteRoomViewport(int index) {
 	// NOTE: viewport 0 can not be deleted
 	if (index <= 0 || (size_t)index >= _roomViewports.size())
 		return;
-	auto scobj = _scViewportRefs[index];
-	scobj.first->Invalidate();
-	ccReleaseObjectReference(scobj.second);
+	auto handle = _scViewportHandles[index];
+	auto scobj = const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(handle));
+	if (scobj)
+		scobj->Invalidate();
+	ccReleaseObjectReference(handle);
 	auto cam = _roomViewports[index]->GetCamera();
 	if (cam)
 		cam->UnlinkFromViewport(index);
 	_roomViewports.erase(_roomViewports.begin() + index);
-	_scViewportRefs.erase(_scViewportRefs.begin() + index);
+	_scViewportHandles.erase(_scViewportHandles.begin() + index);
 	for (size_t i = index; i < _roomViewports.size(); ++i) {
 		_roomViewports[i]->SetID(i);
-		_scViewportRefs[i].first->SetID(i);
+		handle = _scViewportHandles[index];
+		scobj = const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(handle));
+		if (scobj)
+			scobj->SetID(i);
 	}
 	for (size_t i = 0; i < _roomViewportsSorted.size(); ++i) {
 		if (_roomViewportsSorted[i]->GetID() == index) {
@@ -300,8 +304,7 @@ PCamera GameState::CreateRoomCamera() {
 	camera->SetID(index);
 	camera->SetAt(0, 0);
 	camera->SetSize(_mainViewport.GetRect().GetSize());
-	ScriptCamera *scam = new ScriptCamera(index);
-	_scCameraRefs.push_back(std::make_pair<ScriptCamera*, int32_t>(scam, 0));
+	_scCameraHandles.push_back(0);
 	_roomCameras.push_back(camera);
 	return camera;
 }
@@ -309,34 +312,39 @@ PCamera GameState::CreateRoomCamera() {
 ScriptCamera *GameState::RegisterRoomCamera(int index, int32_t handle) {
 	if (index < 0 || (size_t)index >= _roomCameras.size())
 		return nullptr;
-	auto &scobj = _scCameraRefs[index];
+	auto sccamera = new ScriptCamera(index);
 	if (handle == 0) {
-		handle = ccRegisterManagedObject(scobj.first, scobj.first);
+		handle = ccRegisterManagedObject(sccamera, sccamera);
 		ccAddObjectReference(handle); // one reference for the GameState
 	} else {
-		ccRegisterUnserializedObject(handle, scobj.first, scobj.first);
+		ccRegisterUnserializedObject(handle, sccamera, sccamera);
 	}
-	scobj.second = handle;
-	return scobj.first;
+	_scCameraHandles[index] = handle;
+	return sccamera;
 }
 
 void GameState::DeleteRoomCamera(int index) {
 	// NOTE: camera 0 can not be deleted
 	if (index <= 0 || (size_t)index >= _roomCameras.size())
 		return;
-	auto scobj = _scCameraRefs[index];
-	scobj.first->Invalidate();
-	ccReleaseObjectReference(scobj.second);
+	auto handle = _scCameraHandles[index];
+	auto scobj = const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(handle));
+	if (scobj)
+		scobj->Invalidate();
+	ccReleaseObjectReference(handle);
 	for (auto &viewref : _roomCameras[index]->GetLinkedViewports()) {
 		auto view = viewref.lock();
 		if (view)
 			view->LinkCamera(nullptr);
 	}
 	_roomCameras.erase(_roomCameras.begin() + index);
-	_scCameraRefs.erase(_scCameraRefs.begin() + index);
+	_scCameraHandles.erase(_scCameraHandles.begin() + index);
 	for (size_t i = index; i < _roomCameras.size(); ++i) {
 		_roomCameras[i]->SetID(i);
-		_scCameraRefs[i].first->SetID(i);
+		handle = _scCameraHandles[index];
+		scobj = const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(handle));
+		if (scobj)
+			scobj->SetID(i);
 	}
 }
 
@@ -347,13 +355,13 @@ int GameState::GetRoomCameraCount() const {
 ScriptViewport *GameState::GetScriptViewport(int index) {
 	if (index < 0 || (size_t)index >= _roomViewports.size())
 		return nullptr;
-	return _scViewportRefs[index].first;
+	return const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(_scViewportHandles[index]));
 }
 
 ScriptCamera *GameState::GetScriptCamera(int index) {
 	if (index < 0 || (size_t)index >= _roomCameras.size())
 		return nullptr;
-	return _scCameraRefs[index].first;
+	return const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(_scCameraHandles[index]));
 }
 
 bool GameState::IsIgnoringInput() const {
@@ -818,17 +826,21 @@ void GameState::FreeProperties() {
 void GameState::FreeViewportsAndCameras() {
 	_roomViewports.clear();
 	_roomViewportsSorted.clear();
-	for (auto &scobj : _scViewportRefs) {
-		scobj.first->Invalidate();
-		ccReleaseObjectReference(scobj.second);
+	for (auto handle : _scViewportHandles) {
+		auto scview = const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(handle));
+		if (scview)
+			scview->Invalidate();
+		ccReleaseObjectReference(handle);
 	}
-	_scViewportRefs.clear();
+	_scViewportHandles.clear();
 	_roomCameras.clear();
-	for (auto &scobj : _scCameraRefs) {
-		scobj.first->Invalidate();
-		ccReleaseObjectReference(scobj.second);
+	for (auto handle : _scCameraHandles) {
+		auto sccam = const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(handle));
+		if (sccam)
+			sccam->Invalidate();
+		ccReleaseObjectReference(handle);
 	}
-	_scCameraRefs.clear();
+	_scCameraHandles.clear();
 }
 
 void GameState::ReadCustomProperties_v340(Shared::Stream *in) {
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index cddf8991b65..f8db2536781 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -404,11 +404,10 @@ private:
 	std::vector<PViewport> _roomViewportsSorted;
 	// Cameras defines the position of a "looking eye" inside the room.
 	std::vector<PCamera> _roomCameras;
-	// Script viewports and cameras are references to real data export to
-	// user script. They became invalidated as the actual object gets
-	// destroyed, but are kept in memory to prevent script errors.
-	std::vector<std::pair<ScriptViewport *, int32_t>> _scViewportRefs;
-	std::vector<std::pair<ScriptCamera *, int32_t>> _scCameraRefs;
+	// We keep handles to the script refs to viewports and cameras, so that we
+	// could address them and invalidate as the actual object gets destroyed.
+	std::vector<int32_t> _scViewportHandles;
+	std::vector<int32_t> _scCameraHandles;
 
 	// Tells that the main viewport's position has changed since last game update
 	bool  _mainViewportHasChanged = false;


Commit: 6cfb6dbef8e2fd6b8653492cd95e29ce73552ce1
    https://github.com/scummvm/scummvm/commit/6cfb6dbef8e2fd6b8653492cd95e29ce73552ce1
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-19T20:55:24+01:00

Commit Message:
AGS: Store certain overlay handles, not script ptrs, for safety

>From upstream b73553d6b4655feec2f82ee1feaa67a6bc9fca23

Changed paths:
    engines/ags/engine/ac/game_state.cpp
    engines/ags/engine/ac/game_state.h
    engines/ags/engine/ac/overlay.cpp
    engines/ags/engine/ac/speech.cpp


diff --git a/engines/ags/engine/ac/game_state.cpp b/engines/ags/engine/ac/game_state.cpp
index f55a403acb8..7f3e3a27cb9 100644
--- a/engines/ags/engine/ac/game_state.cpp
+++ b/engines/ags/engine/ac/game_state.cpp
@@ -270,9 +270,10 @@ void GameState::DeleteRoomViewport(int index) {
 		return;
 	auto handle = _scViewportHandles[index];
 	auto scobj = const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(handle));
-	if (scobj)
+	if (scobj) {
 		scobj->Invalidate();
-	ccReleaseObjectReference(handle);
+		ccReleaseObjectReference(handle);
+	}
 	auto cam = _roomViewports[index]->GetCamera();
 	if (cam)
 		cam->UnlinkFromViewport(index);
@@ -329,9 +330,10 @@ void GameState::DeleteRoomCamera(int index) {
 		return;
 	auto handle = _scCameraHandles[index];
 	auto scobj = const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(handle));
-	if (scobj)
+	if (scobj) {
 		scobj->Invalidate();
-	ccReleaseObjectReference(handle);
+		ccReleaseObjectReference(handle);
+	}
 	for (auto &viewref : _roomCameras[index]->GetLinkedViewports()) {
 		auto view = viewref.lock();
 		if (view)
@@ -828,17 +830,19 @@ void GameState::FreeViewportsAndCameras() {
 	_roomViewportsSorted.clear();
 	for (auto handle : _scViewportHandles) {
 		auto scview = const_cast<ScriptViewport*>((const ScriptViewport*)ccGetObjectAddressFromHandle(handle));
-		if (scview)
+		if (scview) {
 			scview->Invalidate();
-		ccReleaseObjectReference(handle);
+			ccReleaseObjectReference(handle);
+		}
 	}
 	_scViewportHandles.clear();
 	_roomCameras.clear();
 	for (auto handle : _scCameraHandles) {
 		auto sccam = const_cast<ScriptCamera*>((const ScriptCamera*)ccGetObjectAddressFromHandle(handle));
-		if (sccam)
+		if (sccam) {
 			sccam->Invalidate();
-		ccReleaseObjectReference(handle);
+			ccReleaseObjectReference(handle);
+		}
 	}
 	_scCameraHandles.clear();
 }
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index f8db2536781..1cefd30ef6d 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -254,12 +254,12 @@ struct GameState {
 	int  complete_overlay_on = 0;
 	// Is there a blocking text overlay on screen (contains overlay ID)
 	int  text_overlay_on = 0;
-	// Script overlay objects, because we must return same pointers
+	// Script overlay handles, because we must return same script objects
 	// whenever user script queries for them.
-	// Blocking speech overlay managed object, for accessing in scripts
-	ScriptOverlay *speech_text_scover = nullptr;
-	// Speech portrait overlay managed object
-	ScriptOverlay *speech_face_scover = nullptr;
+	// Blocking speech overlay managed handle
+	int  speech_text_schandle = 0;
+	// Speech portrait overlay managed handle
+	int  speech_face_schandle = 0;
 
 	int shake_screen_yoff = 0; // y offset of the shaking screen
 
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 6c98bbddaa4..8911b7eca1d 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -279,27 +279,24 @@ ScriptOverlay *create_scriptoverlay(ScreenOverlay &over, bool internal_ref) {
 	ScriptOverlay *scover = new ScriptOverlay();
 	scover->overlayId = over.type;
 	int handl = ccRegisterManagedObject(scover, scover);
-	over.associatedOverlayHandle = handl;
-	if (internal_ref)
+	over.associatedOverlayHandle = handl; // save the handle for access
+	if (internal_ref) // requested additional ref
 		ccAddObjectReference(handl);
 	return scover;
 }
 
 // Invalidates existing script object to let user know that previous overlay is gone,
 // and releases engine's internal reference (script object may exist while there are user refs)
-static void invalidate_and_subref(ScreenOverlay &over, ScriptOverlay **scover) {
-	if (scover && (*scover)) {
-		(*scover)->overlayId = -1;
-		*scover = nullptr;
-	} else if (over.associatedOverlayHandle > 0) {
-		ScriptOverlay *scoverlay = const_cast<ScriptOverlay*>((const ScriptOverlay* )ccGetObjectAddressFromHandle(over.associatedOverlayHandle));
-		if (scoverlay) scoverlay->overlayId = -1;
-	}
+static void invalidate_and_subref(ScreenOverlay &over) {
+	if (over.associatedOverlayHandle <= 0)
+		return; // invalid handle
 
-	if (over.associatedOverlayHandle > 0) {
+	ScriptOverlay *scover = const_cast<ScriptOverlay*>((const ScriptOverlay*)ccGetObjectAddressFromHandle(over.associatedOverlayHandle));
+	if (scover) {
+		scover->overlayId = -1; // invalidate script object
 		ccReleaseObjectReference(over.associatedOverlayHandle);
-		over.associatedOverlayHandle = 0;
 	}
+	over.associatedOverlayHandle = 0; // reset internal handle
 }
 
 // Frees overlay resources and tell to dispose script object if there are no refs left
@@ -325,13 +322,15 @@ void remove_screen_overlay_index(size_t over_idx) {
 	if (over.type == _GP(play).complete_overlay_on) {
 		_GP(play).complete_overlay_on = 0;
 	} else if (over.type == _GP(play).text_overlay_on) { // release internal ref for speech text
-		invalidate_and_subref(over, &_GP(play).speech_text_scover);
+		invalidate_and_subref(over);
+		_GP(play).speech_text_schandle = 0;
 		_GP(play).text_overlay_on = 0;
 	} else if (over.type == OVER_PICTURE) { // release internal ref for speech face
-		invalidate_and_subref(over, &_GP(play).speech_face_scover);
+		invalidate_and_subref(over);
+		_GP(play).speech_face_schandle = 0;
 		_G(face_talking) = -1;
 	} else if (over.bgSpeechForChar >= 0) { // release internal ref for bg speech
-		invalidate_and_subref(over, nullptr);
+		invalidate_and_subref(over);
 	}
 	dispose_overlay(over);
 	_GP(screenover).erase(_GP(screenover).begin() + over_idx);
@@ -393,10 +392,13 @@ size_t add_screen_overlay_impl(bool roomlayer, int x, int y, int type, int sprnu
 		_GP(play).text_overlay_on = type;
 		// only make script object for blocking speech now, because messagebox blocks all script
 		// and therefore cannot be accessed, so no practical reason for that atm
-		if (type == OVER_TEXTSPEECH)
-			_GP(play).speech_text_scover = create_scriptoverlay(over, true);
+		if (type == OVER_TEXTSPEECH) {
+			create_scriptoverlay(over, true);
+			_GP(play).speech_text_schandle = over.associatedOverlayHandle;
+		}
 	} else if (type == OVER_PICTURE) {
-		_GP(play).speech_face_scover = create_scriptoverlay(over, true);
+		create_scriptoverlay(over, true);
+		_GP(play).speech_face_schandle = over.associatedOverlayHandle;
 	}
 	over.MarkChanged();
 	_GP(screenover).push_back(std::move(over));
diff --git a/engines/ags/engine/ac/speech.cpp b/engines/ags/engine/ac/speech.cpp
index 17efec2e829..b6f2167b53b 100644
--- a/engines/ags/engine/ac/speech.cpp
+++ b/engines/ags/engine/ac/speech.cpp
@@ -28,6 +28,7 @@
 #include "ags/engine/ac/game_state.h"
 #include "ags/engine/ac/global_audio.h"
 #include "ags/engine/ac/global_display.h"
+#include "ags/engine/ac/dynobj/cc_dynamic_object.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
@@ -149,11 +150,11 @@ String get_voice_assetpath() {
 //=============================================================================
 
 ScriptOverlay *Speech_GetTextOverlay() {
-	return _GP(play).speech_text_scover;
+	return const_cast<ScriptOverlay*>((const ScriptOverlay*)ccGetObjectAddressFromHandle(_GP(play).speech_text_schandle));
 }
 
 ScriptOverlay *Speech_GetPortraitOverlay() {
-	return _GP(play).speech_face_scover;
+	return const_cast<ScriptOverlay*>((const ScriptOverlay*)ccGetObjectAddressFromHandle(_GP(play).speech_face_schandle));
 }
 
 RuntimeScriptValue Sc_Speech_GetAnimationStopTimeMargin(const RuntimeScriptValue *params, int32_t param_count) {




More information about the Scummvm-git-logs mailing list