[Scummvm-git-logs] scummvm master -> 645124bb4575efec9322d5a61383543f1011d5ec

dreammaster noreply at scummvm.org
Mon Apr 11 02:41:28 UTC 2022


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

Summary:
54fae0267d AGS: Adding comments to stream class methods
a378e6e06b AGS: Fixed potential crash on room load if bg frame is set too high
c9cd87d39a AGS: Updated build version (3.5.1.14) and year (2022)
9986e16a3a AGS: AnimateCharacter better invalid loop error
f5cfc86d70 AGS: Audio core init may throw
3425f8faf2 AGS: Moved couple of gui-related global vars into GuiOptions struct
e4a6bd71f6 AGS: Option to clip GUI Controls' contents to their rect
7f0169dd54 AGS: Apply bitmap clipping in WFN renderer
c883fb2373 AGS: fixed SpriteFile::LoadRawData()
6fb506b1fe AGS: Prevent reacting to window events during gfx mode init
a2cf1dd946 AGS: Properly reset SpriteCache and SpiteFile when they reinit
959b8a78e1 AGS: Fixed SaveSpriteFile unintentionally restoring deleted sprites
6473ae69cd AGS: Updated build version (3.6.0.15)
9b5f0c6221 AGS: Fixed default values for restoring of audiochannels
787d68277b AGS: Cleanup some unused code/comments
d147a541ec AGS: Cleanup some unused code/comments
fabab1285d AGS: Made Hotspot.Name and Object.Name settable
cb95772ad9 AGS: Update @OVERHOTSPOT@ when object/hotspot name changes
eaf4b00125 AGS: Fixed pre-3.6.0 games loosing object names on restoring a save
e0ef5ad2be AGS: Fix signed comparison warning
dc4c149e30 AGS: Fixed PackfileFromAsset() - potential nullptr access
dbcebe50d4 AGS: Added Character.IdleAnimationDelay and editor property
25d6339101 AGS: Fixed redo_walkable_areas() in case of out of range colors
dcb1099f2b AGS: Cursor.AnimationDelay property and arg to ChangeModeView()
2d63a71b22 AGS: Fixed formatting of soff_t values
645124bb45 AGS: RLE decompressing: Redefined char as int8


Commit: 54fae0267d6db2bc317020fa14974ffbf500fb23
    https://github.com/scummvm/scummvm/commit/54fae0267d6db2bc317020fa14974ffbf500fb23
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:04-07:00

Commit Message:
AGS: Adding comments to stream class methods

Changed paths:
    engines/ags/shared/api/stream_api.h
    engines/ags/shared/util/stream.h


diff --git a/engines/ags/shared/api/stream_api.h b/engines/ags/shared/api/stream_api.h
index 7834e04c573..9fc11ef9611 100644
--- a/engines/ags/shared/api/stream_api.h
+++ b/engines/ags/shared/api/stream_api.h
@@ -64,11 +64,20 @@ public:
 	virtual bool        CanWrite() const = 0;
 	virtual bool        CanSeek() const = 0;
 
+	// Reads number of bytes in the provided buffer
 	virtual size_t      Read(void *buffer, size_t size) = 0;
+	// ReadByte conforms to fgetc behavior:
+	// - if stream is valid, then returns an *unsigned char* packed in the int
+	// - if EOS, then returns -1
 	virtual int32_t     ReadByte() = 0;
+	// Writes number of bytes from the provided buffer
 	virtual size_t      Write(const void *buffer, size_t size) = 0;
+	// WriteByte conforms to fputc behavior:
+	// - on success, returns the unsigned char packed in the int
+	// - on failure, returns -1
 	virtual int32_t     WriteByte(uint8_t b) = 0;
 
+	// Convenience methods for reading values of particular size
 	virtual int8_t      ReadInt8() = 0;
 	virtual int16_t     ReadInt16() = 0;
 	virtual int32_t     ReadInt32() = 0;
@@ -80,6 +89,7 @@ public:
 	virtual size_t      ReadArrayOfInt32(int32_t *buffer, size_t count) = 0;
 	virtual size_t      ReadArrayOfInt64(int64_t *buffer, size_t count) = 0;
 
+	// Convenience methods for writing values of particular size
 	virtual size_t      WriteInt8(int8_t val) = 0;
 	virtual size_t      WriteInt16(int16_t val) = 0;
 	virtual size_t      WriteInt32(int32_t val) = 0;
diff --git a/engines/ags/shared/util/stream.h b/engines/ags/shared/util/stream.h
index cd322903e89..ed7a2c03e89 100644
--- a/engines/ags/shared/util/stream.h
+++ b/engines/ags/shared/util/stream.h
@@ -63,29 +63,29 @@ public:
 	//-----------------------------------------------------
 	// Helper methods
 	//-----------------------------------------------------
-	inline int8_t ReadInt8() override {
+	int8_t ReadInt8() override {
 		return ReadByte();
 	}
 
-	inline size_t WriteInt8(int8_t val) override {
+	size_t WriteInt8(int8_t val) override {
 		int32_t ival = WriteByte(val);
 		return ival >= 0 ? ival : 0;
 	}
 
-	inline bool ReadBool() override {
+	bool ReadBool() override {
 		return ReadInt8() != 0;
 	}
 
-	inline size_t WriteBool(bool val) override {
+	size_t WriteBool(bool val) override {
 		return WriteInt8(val ? 1 : 0);
 	}
 
 	// Practically identical to Read() and Write(), these two helpers' only
 	// meaning is to underline the purpose of data being (de)serialized
-	inline size_t ReadArrayOfInt8(int8_t *buffer, size_t count) override {
+	size_t ReadArrayOfInt8(int8_t *buffer, size_t count) override {
 		return Read(buffer, count);
 	}
-	inline size_t WriteArrayOfInt8(const int8_t *buffer, size_t count) override {
+	size_t WriteArrayOfInt8(const int8_t *buffer, size_t count) override {
 		return Write(buffer, count);
 	}
 


Commit: a378e6e06b7b36773b9e10ff366e2a1294f65de0
    https://github.com/scummvm/scummvm/commit/a378e6e06b7b36773b9e10ff366e2a1294f65de0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:04-07:00

Commit Message:
AGS: Fixed potential crash on room load if bg frame is set too high

>From upstream a31b60bf25c7fdebcf0bb04050bdeeeb9ce560da

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


diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index 5fee3073380..cc99c7042dc 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -476,6 +476,10 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	_GP(play).anim_background_speed = _GP(thisroom).BgAnimSpeed;
 	_GP(play).bg_anim_delay = _GP(play).anim_background_speed;
 
+	// Fixup the frame index, in case the new room does not have enough background frames
+	if (_GP(play).bg_frame < 0 || _GP(play).bg_frame >= _GP(thisroom).BgFrameCount)
+		_GP(play).bg_frame = 0;
+
 	// do the palette
 	for (cc = 0; cc < 256; cc++) {
 		if (_GP(game).paluses[cc] == PAL_BACKGROUND)


Commit: c9cd87d39a8e387b20bcefef070df4ab68be773d
    https://github.com/scummvm/scummvm/commit/c9cd87d39a8e387b20bcefef070df4ab68be773d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:04-07:00

Commit Message:
AGS: Updated build version (3.5.1.14) and year (2022)

>From upstream 2cc2971259f8242f1b25930b3e62f14c59b5b704

Changed paths:
    engines/ags/shared/core/def_version.h


diff --git a/engines/ags/shared/core/def_version.h b/engines/ags/shared/core/def_version.h
index c6a02278c5d..31ba60bc7ae 100644
--- a/engines/ags/shared/core/def_version.h
+++ b/engines/ags/shared/core/def_version.h
@@ -22,13 +22,13 @@
 #ifndef AGS_SHARED_CORE_DEFVERSION_H
 #define AGS_SHARED_CORE_DEFVERSION_H
 
-#define ACI_VERSION_STR      "3.6.0.13"
+#define ACI_VERSION_STR      "3.6.0.14"
 #if defined (RC_INVOKED) // for MSVC resource compiler
-#define ACI_VERSION_MSRC_DEF  3.6.0.13
+#define ACI_VERSION_MSRC_DEF  3.6.0.14
 #endif
 
 #define SPECIAL_VERSION ""
 
-#define ACI_COPYRIGHT_YEARS "2011-2021"
+#define ACI_COPYRIGHT_YEARS "2011-2022"
 
 #endif


Commit: 9986e16a3acd8eba1b64a9fa8bae000880eb1e9f
    https://github.com/scummvm/scummvm/commit/9986e16a3acd8eba1b64a9fa8bae000880eb1e9f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:04-07:00

Commit Message:
AGS: AnimateCharacter better invalid loop error

>From upstream 546e85323e5c79566f7c6712363c593fcde64080

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


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index dff1918865c..a09f6919f71 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -2023,8 +2023,10 @@ void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int n
 		Character_UnlockView(chap);
 		chap->idleleft = chap->idletime;
 	}
-	if ((loopn < 0) || (loopn >= _GP(views)[chap->view].numLoops))
-		quit("!AnimateCharacter: invalid loop number specified");
+	if ((loopn < 0) || (loopn >= _GP(views)[chap->view].numLoops)) {
+		quitprintf("!AnimateCharacter: invalid loop number\n"
+			"(trying to animate '%s' using loop %d. View is currently %d).", chap->name, loopn, chap->view + 1);
+	}
 	if ((sframe < 0) || (sframe >= _GP(views)[chap->view].loops[loopn].numFrames))
 		quit("!AnimateCharacter: invalid starting frame number specified");
 	Character_StopMoving(chap);


Commit: f5cfc86d70c977ade5975cf0c68965e56e6fa689
    https://github.com/scummvm/scummvm/commit/f5cfc86d70c977ade5975cf0c68965e56e6fa689
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:05-07:00

Commit Message:
AGS: Audio core init may throw

>From upstream 0bd5a95eaabb87afc1ef577f3757f90b8953761d

Changed paths:
    engines/ags/engine/main/engine.cpp


diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index c955f7387aa..6f9de652f8f 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -326,10 +326,16 @@ void engine_init_timer() {
 
 void engine_init_audio() {
 #if !AGS_PLATFORM_SCUMMVM
-	if (_GP(usetup).audio_backend != 0) {
-		Debug::Printf("Initializing audio");
-		audio_core_init(); // audio core system
-	}
+	if (usetup.audio_backend != 0)
+    {
+        Debug::Printf("Initializing audio");
+        try {
+            audio_core_init(); // audio core system
+        } catch(std::runtime_error) {
+            Debug::Printf("Failed to initialize audio, disabling.");
+            usetup.audio_backend = 0;
+        }
+    }
 #endif
 
 	_G(our_eip) = -181;


Commit: 3425f8faf2e886a4693a0e8adf3d1906bc134d74
    https://github.com/scummvm/scummvm/commit/3425f8faf2e886a4693a0e8adf3d1906bc134d74
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:06-07:00

Commit Message:
AGS: Moved couple of gui-related global vars into GuiOptions struct

>From upstream 973d238a2c20368d8932ade22d2965d121cb7793

Changed paths:
    engines/ags/engine/ac/draw.cpp
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_gui.cpp
    engines/ags/engine/ac/gui.cpp
    engines/ags/engine/ac/gui.h
    engines/ags/engine/ac/gui_inv.cpp
    engines/ags/engine/game/savegame.cpp
    engines/ags/engine/gui/gui_engine.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/globals.h
    engines/ags/shared/ac/game_struct_defines.h
    engines/ags/shared/gui/gui_button.cpp
    engines/ags/shared/gui/gui_defines.h
    engines/ags/shared/gui/gui_main.cpp
    engines/ags/shared/gui/gui_main.h
    engines/ags/shared/gui/gui_object.h


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 12f7b625fad..13edc7c7df7 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2008,9 +2008,9 @@ void draw_gui_and_overlays() {
 			if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
 
 			// Don't draw GUI if "GUIs Turn Off When Disabled"
-			if ((_GP(game).options[OPT_DISABLEOFF] == 3) &&
-			        (_G(all_buttons_disabled) > 0) &&
-			        (_GP(guis)[aa].PopupStyle != kGUIPopupNoAutoRemove))
+			if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
+					(_G(all_buttons_disabled) >= 0) &&
+					(_GP(guis)[aa].PopupStyle != kGUIPopupNoAutoRemove))
 				continue;
 
 			_GP(guibgbmp)[aa]->SetTransparency(_GP(guis)[aa].Transparency);
@@ -2024,9 +2024,9 @@ void draw_gui_and_overlays() {
 			for (int gg = 0; gg < _GP(game).numgui; gg++) {
 				if (!_GP(guis)[gg].IsDisplayed()) continue; // not on screen
 				// Don't touch GUI if "GUIs Turn Off When Disabled"
-				if ((_GP(game).options[OPT_DISABLEOFF] == 3) &&
-					(_G(all_buttons_disabled) > 0) &&
-					(_GP(guis)[gg].PopupStyle != kGUIPopupNoAutoRemove))
+				if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
+						(_G(all_buttons_disabled) >= 0) &&
+						(_GP(guis)[gg].PopupStyle != kGUIPopupNoAutoRemove))
 					continue;
 				_GP(guis)[gg].Poll();
 			}
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 4b651da6c56..f758fc339e1 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -418,7 +418,7 @@ int SetGameOption(int opt, int setting) {
 	if (opt == OPT_DUPLICATEINV)
 		update_invorder();
 	else if (opt == OPT_DISABLEOFF) {
-		_G(gui_disabled_style) = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
+		GUI::Options.DisabledStyle = static_cast<GuiDisableStyle>(_GP(game).options[OPT_DISABLEOFF]);
 		// If GUI was disabled at this time then also update it, as visual style could've changed
 		if (_GP(play).disabled_user_interface > 0) {
 			GUI::MarkAllGUIForUpdate();
diff --git a/engines/ags/engine/ac/global_gui.cpp b/engines/ags/engine/ac/global_gui.cpp
index ef6f5b5099c..74035f542b9 100644
--- a/engines/ags/engine/ac/global_gui.cpp
+++ b/engines/ags/engine/ac/global_gui.cpp
@@ -207,8 +207,9 @@ void SetGUIBackgroundPic(int guin, int slotn) {
 }
 
 void DisableInterface() {
-	if (_GP(play).disabled_user_interface == 0 && // only if was enabled before
-	        _G(gui_disabled_style) != GUIDIS_UNCHANGED) { // If GUI looks change when disabled, then update them all
+	if ((_GP(play).disabled_user_interface == 0) && // only if was enabled before
+		(GUI::Options.DisabledStyle != kGuiDis_Unchanged)) {
+		// If GUI looks change when disabled, then update them all
 		GUI::MarkAllGUIForUpdate();
 	}
 	_GP(play).disabled_user_interface++;
@@ -220,11 +221,12 @@ void EnableInterface() {
 	if (_GP(play).disabled_user_interface < 1) {
 		_GP(play).disabled_user_interface = 0;
 		set_default_cursor();
-		if (_G(gui_disabled_style) != GUIDIS_UNCHANGED) { // If GUI looks change when disabled, then update them all
+		if (GUI::Options.DisabledStyle != kGuiDis_Unchanged) { // If GUI looks change when disabled, then update them all
 			GUI::MarkAllGUIForUpdate();
 		}
 	}
 }
+
 // Returns 1 if user interface is enabled, 0 if disabled
 int IsInterfaceEnabled() {
 	return (_GP(play).disabled_user_interface > 0) ? 0 : 1;
diff --git a/engines/ags/engine/ac/gui.cpp b/engines/ags/engine/ac/gui.cpp
index d5f3b50714e..d3908450c68 100644
--- a/engines/ags/engine/ac/gui.cpp
+++ b/engines/ags/engine/ac/gui.cpp
@@ -454,32 +454,14 @@ void unexport_gui_controls(int ee) {
 	}
 }
 
-int convert_gui_disabled_style(int oldStyle) {
-	int toret = GUIDIS_GREYOUT;
-
-	// if GUIs Turn Off is selected, don't grey out buttons for
-	// any Persistent GUIs which remain
-	// set to 0x80 so that it is still non-zero, but has no effect
-	if (oldStyle == 3)
-		toret = GUIDIS_GUIOFF;
-	// GUIs Go Black
-	else if (oldStyle == 1)
-		toret = GUIDIS_BLACKOUT;
-	// GUIs unchanged
-	else if (oldStyle == 2)
-		toret = GUIDIS_UNCHANGED;
-
-	return toret;
-}
-
 void update_gui_disabled_status() {
 	// update GUI display status (perhaps we've gone into
 	// an interface disabled state)
 	int all_buttons_was = _G(all_buttons_disabled);
-	_G(all_buttons_disabled) = 0;
+	_G(all_buttons_disabled) = -1;
 
 	if (!IsInterfaceEnabled()) {
-		_G(all_buttons_disabled) = _G(gui_disabled_style);
+		_G(all_buttons_disabled) = GUI::Options.DisabledStyle;
 	}
 
 	if (all_buttons_was != _G(all_buttons_disabled)) {
@@ -488,16 +470,14 @@ void update_gui_disabled_status() {
 		for (int aa = 0; aa < _GP(game).numgui; aa++) {
 			_GP(guis)[aa].OnControlPositionChanged(); // this marks GUI as changed too
 		}
-
-		if (_G(gui_disabled_style) != GUIDIS_UNCHANGED) {
+		if (GUI::Options.DisabledStyle != kGuiDis_Unchanged) {
 			invalidate_screen();
 		}
 	}
 }
 
-
 int adjust_x_for_guis(int xx, int yy) {
-	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (_G(all_buttons_disabled) > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) && (_G(all_buttons_disabled) >= 0))
 		return xx;
 	// If it's covered by a GUI, move it right a bit
 	for (int aa = 0; aa < _GP(game).numgui; aa++) {
@@ -520,7 +500,7 @@ int adjust_x_for_guis(int xx, int yy) {
 }
 
 int adjust_y_for_guis(int yy) {
-	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (_G(all_buttons_disabled) > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) && (_G(all_buttons_disabled) >= 0))
 		return yy;
 	// If it's covered by a GUI, move it down a bit
 	for (int aa = 0; aa < _GP(game).numgui; aa++) {
@@ -543,7 +523,7 @@ int adjust_y_for_guis(int yy) {
 }
 
 int gui_get_interactable(int x, int y) {
-	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (_G(all_buttons_disabled) > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) && (_G(all_buttons_disabled) >= 0))
 		return -1;
 	return GetGUIAt(x, y);
 }
@@ -551,7 +531,7 @@ int gui_get_interactable(int x, int y) {
 int gui_on_mouse_move() {
 	int mouse_over_gui = -1;
 	// If all GUIs are off, skip the loop
-	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (_G(all_buttons_disabled) > 0));
+	if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) && (_G(all_buttons_disabled) >= 0));
 	else {
 		// Scan for mouse-y-pos GUIs, and pop one up if appropriate
 		// Also work out the mouse-over GUI while we're at it
diff --git a/engines/ags/engine/ac/gui.h b/engines/ags/engine/ac/gui.h
index 41d848634ca..3bbeceaa0a5 100644
--- a/engines/ags/engine/ac/gui.h
+++ b/engines/ags/engine/ac/gui.h
@@ -74,7 +74,6 @@ void    replace_macro_tokens(const char *text, AGS::Shared::String &fixed_text);
 void    update_gui_zorder();
 void    export_gui_controls(int ee);
 void    unexport_gui_controls(int ee);
-int     convert_gui_disabled_style(int oldStyle);
 void    update_gui_disabled_status();
 int     adjust_x_for_guis(int xx, int yy);
 int     adjust_y_for_guis(int yy);
diff --git a/engines/ags/engine/ac/gui_inv.cpp b/engines/ags/engine/ac/gui_inv.cpp
index 59428f3e797..5c314f2cc52 100644
--- a/engines/ags/engine/ac/gui_inv.cpp
+++ b/engines/ags/engine/ac/gui_inv.cpp
@@ -29,14 +29,6 @@
 #include "ags/shared/gfx/bitmap.h"
 
 namespace AGS3 {
-
-
-
-
-
-
-
-
 namespace AGS {
 namespace Shared {
 
@@ -49,7 +41,7 @@ int GUIInvWindow::GetCharacterId() const {
 
 void GUIInvWindow::Draw(Bitmap *ds) {
 	const bool enabled = IsGUIEnabled(this);
-	if (!enabled && (_G(gui_disabled_style) == GUIDIS_BLACKOUT))
+	if (!enabled && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
 		return;
 
 	// backwards compatibility
@@ -84,7 +76,7 @@ void GUIInvWindow::Draw(Bitmap *ds) {
 	}
 
 	if (!enabled &&
-	        _G(gui_disabled_style) == GUIDIS_GREYOUT &&
+			GUI::Options.DisabledStyle == kGuiDis_Greyout &&
 	        _GP(play).inventory_greys_out == 1) {
 		// darken the inventory when disabled
 		GUI::DrawDisabledEffect(ds, RectWH(X, Y, Width, Height));
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 8a4819a5d0f..fc8fa7a61ba 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -535,7 +535,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 		on_background_frame_change();
 	}
 
-	_G(gui_disabled_style) = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
+	GUI::Options.DisabledStyle = static_cast<GuiDisableStyle>(_GP(game).options[OPT_DISABLEOFF]);
 
 	// restore the queue now that the music is playing
 	_GP(play).music_queue_size = queuedMusicSize;
diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index 10193dff03a..97bbb4fbaff 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -98,8 +98,6 @@ int get_eip_guiobj() {
 	return _G(eip_guiobj);
 }
 
-bool outlineGuiObjects = false;
-
 namespace AGS {
 namespace Shared {
 
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 6f9de652f8f..5470b4c284e 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -759,9 +759,10 @@ void engine_init_game_settings() {
 	_GP(play).game_speed_modifier = 0;
 	if (_G(debug_flags) & DBG_DEBUGMODE)
 		_GP(play).debug_mode = 1;
-	_G(gui_disabled_style) = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
 	_GP(play).shake_screen_yoff = 0;
 
+	GUI::Options.DisabledStyle = static_cast<GuiDisableStyle>(_GP(game).options[OPT_DISABLEOFF]);
+
 	memset(&_GP(play).walkable_areas_on[0], 1, MAX_WALK_AREAS + 1);
 	memset(&_GP(play).script_timers[0], 0, MAX_TIMERS * sizeof(int));
 	memset(&_GP(play).default_audio_type_volumes[0], -1, MAX_AUDIO_TYPES * sizeof(int));
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index a54885c24b1..2917a4e7684 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -461,7 +461,7 @@ static void check_keyboard_controls() {
 	// pressed, but exclude control characters (<32) and
 	// extended keys (eg. up/down arrow; 256+)
 	if ((((kgn >= 32) && (kgn <= 255) && (kgn != '[')) || (kgn == eAGSKeyCodeReturn) || (kgn == eAGSKeyCodeBackspace))
-	        && !_G(all_buttons_disabled)) {
+			&& (_G(all_buttons_disabled) < 0)) {
 		for (int guiIndex = 0; guiIndex < _GP(game).numgui; guiIndex++) {
 			auto &gui = _GP(guis)[guiIndex];
 
@@ -859,7 +859,7 @@ static int UpdateWaitMode() {
 	auto was_disabled_for = _G(user_disabled_for);
 
 	set_default_cursor();
-	if (_G(gui_disabled_style) != GUIDIS_UNCHANGED) { // If GUI looks change when disabled, then update them all
+	if (GUI::Options.DisabledStyle != kGuiDis_Unchanged) { // If GUI looks change when disabled, then update them all
 		GUI::MarkAllGUIForUpdate();
 	}
 	_GP(play).disabled_user_interface--;
@@ -905,7 +905,7 @@ static int GameTick() {
 
 static void SetupLoopParameters(int untilwhat, const void *udata) {
 	_GP(play).disabled_user_interface++;
-	if (_G(gui_disabled_style) != GUIDIS_UNCHANGED) { // If GUI looks change when disabled, then update them all
+	if (GUI::Options.DisabledStyle != kGuiDis_Unchanged) { // If GUI looks change when disabled, then update them all
 		GUI::MarkAllGUIForUpdate();
 	}
 	// Only change the mouse cursor if it hasn't been specifically changed first
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 5830cc6b5f7..5329f58330a 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -996,8 +996,7 @@ public:
 	 */
 
 	int _guis_need_update = 1;
-	int _all_buttons_disabled = 0, _gui_inv_pic = -1;
-	int _gui_disabled_style = 0;
+	int _all_buttons_disabled = -1, _gui_inv_pic = -1;
 
 	/**@}*/
 
diff --git a/engines/ags/shared/ac/game_struct_defines.h b/engines/ags/shared/ac/game_struct_defines.h
index 7c36950dc5c..1bb58fa6410 100644
--- a/engines/ags/shared/ac/game_struct_defines.h
+++ b/engines/ags/shared/ac/game_struct_defines.h
@@ -76,9 +76,7 @@ namespace AGS3 {
 #define OPT_GLOBALTALKANIMSPD 39
 #define OPT_HIGHESTOPTION_321 39
 #define OPT_SPRITEALPHA     40
-#define OPT_HIGHESTOPTION_330 OPT_SPRITEALPHA
 #define OPT_SAFEFILEPATHS   41
-#define OPT_HIGHESTOPTION_335 OPT_SAFEFILEPATHS
 #define OPT_DIALOGOPTIONSAPI 42 // version of dialog options API (-1 for pre-3.4.0 API)
 #define OPT_BASESCRIPTAPI   43 // version of the Script API (ScriptAPIVersion) used to compile game script
 #define OPT_SCRIPTCOMPATLEV 44 // level of API compatibility (ScriptAPIVersion) used to compile game script
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 10c909f2a56..83557c3c1ff 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -97,15 +97,15 @@ void GUIButton::Draw(Bitmap *ds) {
 	bool draw_disabled = !IsGUIEnabled(this);
 
 	// if it's "Unchanged when disabled" or "GUI Off", don't grey out
-	if (_G(gui_disabled_style) == GUIDIS_UNCHANGED ||
-	        _G(gui_disabled_style) == GUIDIS_GUIOFF) {
+	if ((GUI::Options.DisabledStyle == kGuiDis_Unchanged) ||
+		(GUI::Options.DisabledStyle == kGuiDis_Off)) {
 		draw_disabled = false;
 	}
 	// TODO: should only change properties in reaction to particular events
 	if (CurrentImage <= 0 || draw_disabled)
 		CurrentImage = Image;
 
-	if (draw_disabled && _G(gui_disabled_style) == GUIDIS_BLACKOUT)
+	if (draw_disabled && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
 		// buttons off when disabled - no point carrying on
 		return;
 
@@ -311,7 +311,7 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 		}
 	}
 
-	if ((draw_disabled) && (_G(gui_disabled_style) == GUIDIS_GREYOUT)) {
+	if ((draw_disabled) && (GUI::Options.DisabledStyle == kGuiDis_Greyout)) {
 		// darken the button when disabled
 		GUI::DrawDisabledEffect(ds, RectWH(X, Y,
 		                                   _GP(spriteset)[CurrentImage]->GetWidth(),
diff --git a/engines/ags/shared/gui/gui_defines.h b/engines/ags/shared/gui/gui_defines.h
index 75286c145d3..c3d471fbc4c 100644
--- a/engines/ags/shared/gui/gui_defines.h
+++ b/engines/ags/shared/gui/gui_defines.h
@@ -27,7 +27,6 @@ namespace AGS3 {
 #define GUIMAGIC          0xcafebeef
 #define MAX_GUIOBJ_EVENTS 10
 #define TEXTWINDOW_PADDING_DEFAULT  3
-//#define MAX_OBJ_EACH_TYPE 251
 
 // TODO: find out more about gui version history
 //=============================================================================
@@ -188,6 +187,21 @@ enum GuiSvgVersion {
 	kGuiSvgVersion_350 = 1
 };
 
+enum GuiDisableStyle {
+	kGuiDis_Greyout = 0,
+	kGuiDis_Blackout = 1,
+	kGuiDis_Unchanged = 2,
+	kGuiDis_Off = 3
+};
+
+// Global GUI options
+struct GuiOptions {
+	// How the GUI controls are drawn when the interface is disabled
+	GuiDisableStyle DisabledStyle = kGuiDis_Unchanged;
+	// Whether to graphically outline GUI controls
+	bool OutlineControls = false;
+};
+
 } // namespace Shared
 } // namespace AGS
 } // namespace AGS3
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 35593916d3b..b92486ee123 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "ags/lib/std/algorithm.h"
+#include "ags/shared/gui/gui_main.h"
 #include "ags/shared/ac/game_version.h"
 #include "ags/shared/ac/sprite_cache.h"
 #include "ags/shared/debugging/out.h"
@@ -28,7 +29,6 @@
 #include "ags/shared/gui/gui_inv.h"
 #include "ags/shared/gui/gui_label.h"
 #include "ags/shared/gui/gui_listbox.h"
-#include "ags/shared/gui/gui_main.h"
 #include "ags/shared/gui/gui_slider.h"
 #include "ags/shared/gui/gui_textbox.h"
 #include "ags/shared/util/stream.h"
@@ -47,6 +47,8 @@ using namespace AGS::Shared;
 namespace AGS {
 namespace Shared {
 
+GuiOptions GUI::Options;
+
 /* static */ String GUIMain::FixupGUIName(const String &name) {
 	if (name.GetLength() > 0 && name[0u] != 'g')
 		return String::FromFormat("g%c%s", name[0u], name.Mid(1).Lower().GetCStr());
@@ -243,15 +245,15 @@ void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
 
 	SET_EIP(379)
 
-	if (_G(all_buttons_disabled) && _G(gui_disabled_style) == GUIDIS_BLACKOUT)
-		return; // don't draw GUI controls
+	if ((_G(all_buttons_disabled) >= 0) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
+        return; // don't draw GUI controls
 
 	for (size_t ctrl_index = 0; ctrl_index < _controls.size(); ++ctrl_index) {
 		set_eip_guiobj(_ctrlDrawOrder[ctrl_index]);
 
 		GUIObject *objToDraw = _controls[_ctrlDrawOrder[ctrl_index]];
 
-		if (!objToDraw->IsEnabled() && _G(gui_disabled_style) == GUIDIS_BLACKOUT)
+		if (!objToDraw->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
 			continue;
 		if (!objToDraw->IsVisible())
 			continue;
@@ -261,7 +263,7 @@ void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
 		int selectedColour = 14;
 
 		if (HighlightCtrl == _ctrlDrawOrder[ctrl_index]) {
-			if (outlineGuiObjects)
+			if (GUI::Options.OutlineControls)
 				selectedColour = 13;
 			draw_color = subbmp.GetCompatibleColor(selectedColour);
 			DrawBlob(&subbmp, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1, objToDraw->Y, draw_color);
@@ -270,7 +272,7 @@ void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
 			DrawBlob(&subbmp, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1,
 			         objToDraw->Y + objToDraw->Height - get_fixed_pixel_size(1) - 1, draw_color);
 		}
-		if (outlineGuiObjects) {
+		if (GUI::Options.OutlineControls) {
 			// draw a dotted outline round all objects
 			draw_color = subbmp.GetCompatibleColor(selectedColour);
 			for (int i = 0; i < objToDraw->Width; i += 2) {
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index bf855794760..5c6739a13df 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -206,6 +206,7 @@ public:
 
 namespace GUI {
 extern GuiVersion GameGuiVersion;
+extern GuiOptions Options;
 
 // Draw standart "shading" effect over rectangle
 void DrawDisabledEffect(Bitmap *ds, const Rect &rc);
@@ -252,8 +253,6 @@ extern int get_text_width_outlined(Shared::Bitmap *ds, const char *tex, int font
 extern void set_eip_guiobj(int eip);
 extern int get_eip_guiobj();
 
-extern bool outlineGuiObjects;
-
 } // namespace AGS3
 
 #endif
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index 653a5ba6ac1..4d74e1675e6 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -30,11 +30,6 @@
 
 namespace AGS3 {
 
-#define GUIDIS_GREYOUT   1
-#define GUIDIS_BLACKOUT  2
-#define GUIDIS_UNCHANGED 4
-#define GUIDIS_GUIOFF  0x80
-
 struct KeyInput;
 
 namespace AGS {
@@ -138,7 +133,7 @@ HorAlignment ConvertLegacyGUIAlignment(LegacyGUIAlignment align);
 
 // Tells if the given control is considered enabled, taking global flag into account
 inline bool IsGUIEnabled(AGS::Shared::GUIObject *g) {
-	return !_G(all_buttons_disabled) && g->IsEnabled();
+	return (_G(all_buttons_disabled) < 0) && g->IsEnabled();
 }
 
 } // namespace AGS3


Commit: e4a6bd71f6eb09a11ab269b9b642ca800f5292e1
    https://github.com/scummvm/scummvm/commit/e4a6bd71f6eb09a11ab269b9b642ca800f5292e1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:06-07:00

Commit Message:
AGS: Option to clip GUI Controls' contents to their rect

>From upstream 6c2612eb087924255a04d2da1dc1d5c8559d28b3

Changed paths:
    engines/ags/engine/main/engine.cpp
    engines/ags/shared/ac/game_struct_defines.h
    engines/ags/shared/gui/gui_button.cpp
    engines/ags/shared/gui/gui_defines.h
    engines/ags/shared/gui/gui_main.cpp


diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 5470b4c284e..4790bd1bb0d 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -762,6 +762,7 @@ void engine_init_game_settings() {
 	_GP(play).shake_screen_yoff = 0;
 
 	GUI::Options.DisabledStyle = static_cast<GuiDisableStyle>(_GP(game).options[OPT_DISABLEOFF]);
+	GUI::Options.ClipControls = _GP(game).options[OPT_CLIPGUICONTROLS] != 0;
 
 	memset(&_GP(play).walkable_areas_on[0], 1, MAX_WALK_AREAS + 1);
 	memset(&_GP(play).script_timers[0], 0, MAX_TIMERS * sizeof(int));
diff --git a/engines/ags/shared/ac/game_struct_defines.h b/engines/ags/shared/ac/game_struct_defines.h
index 1bb58fa6410..6fa6cf154e7 100644
--- a/engines/ags/shared/ac/game_struct_defines.h
+++ b/engines/ags/shared/ac/game_struct_defines.h
@@ -83,6 +83,7 @@ namespace AGS3 {
 #define OPT_RENDERATSCREENRES 45 // scale sprites at the (final) screen resolution
 #define OPT_RELATIVEASSETRES 46 // relative asset resolution mode (where sprites are resized to match game type)
 #define OPT_WALKSPEEDABSOLUTE 47 // if movement speeds are independent of walkable mask resolution
+#define OPT_CLIPGUICONTROLS 48 // clip drawn gui control contents to the control's rectangle
 #define OPT_HIGHESTOPTION   OPT_WALKSPEEDABSOLUTE
 #define OPT_NOMODMUSIC      98
 #define OPT_LIPSYNCTEXT     99
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 83557c3c1ff..9c9d611b364 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -284,8 +284,8 @@ void GUIButton::WriteToSavegame(Stream *out) const {
 
 void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 	// NOTE: the CLIP flag only clips the image, not the text
-	if (IsClippingImage())
-		ds->SetClip(Rect(X, Y, X + Width - 1, Y + Height - 1));
+	if (IsClippingImage() && !GUI::Options.ClipControls)
+		ds->SetClip(RectWH(X, Y, Width, Height));
 	if (_GP(spriteset)[CurrentImage] != nullptr)
 		draw_gui_sprite(ds, CurrentImage, X, Y, true);
 
@@ -317,11 +317,13 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 		                                   _GP(spriteset)[CurrentImage]->GetWidth(),
 		                                   _GP(spriteset)[CurrentImage]->GetHeight()));
 	}
-	ds->ResetClip();
 
 	// Don't print Text of (INV) (INVSHR) (INVNS)
 	if (_placeholder == kButtonPlace_None && !_unnamed)
 		DrawText(ds, draw_disabled);
+
+	if (IsClippingImage() && !GUI::Options.ClipControls)
+		ds->ResetClip();
 }
 
 void GUIButton::DrawText(Bitmap *ds, bool draw_disabled) {
diff --git a/engines/ags/shared/gui/gui_defines.h b/engines/ags/shared/gui/gui_defines.h
index c3d471fbc4c..d88a61c29f4 100644
--- a/engines/ags/shared/gui/gui_defines.h
+++ b/engines/ags/shared/gui/gui_defines.h
@@ -196,6 +196,8 @@ enum GuiDisableStyle {
 
 // Global GUI options
 struct GuiOptions {
+	// Clip GUI control's contents to the control's rectangle
+	bool ClipControls = true;
 	// How the GUI controls are drawn when the interface is disabled
 	GuiDisableStyle DisabledStyle = kGuiDis_Unchanged;
 	// Whether to graphically outline GUI controls
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index b92486ee123..51e7c488f49 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -258,6 +258,8 @@ void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
 		if (!objToDraw->IsVisible())
 			continue;
 
+		if (GUI::Options.ClipControls)
+			subbmp.SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
 		objToDraw->Draw(&subbmp);
 
 		int selectedColour = 14;


Commit: 7f0169dd54ab7be20b89c28352f00650069ffc3c
    https://github.com/scummvm/scummvm/commit/7f0169dd54ab7be20b89c28352f00650069ffc3c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:06-07:00

Commit Message:
AGS: Apply bitmap clipping in WFN renderer

>From upstream a2f3738f892641bfcd7e7ca930808c52f0757e23

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 8a5d8c6f0f6..9b2e904e102 100644
--- a/engines/ags/shared/font/wfn_font_renderer.cpp
+++ b/engines/ags/shared/font/wfn_font_renderer.cpp
@@ -19,11 +19,11 @@
  *
  */
 
+#include "ags/shared/font/wfn_font_renderer.h"
 #include "ags/shared/ac/common.h" // our_eip
 #include "ags/shared/core/asset_manager.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/shared/font/wfn_font.h"
-#include "ags/shared/font/wfn_font_renderer.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/shared/util/stream.h"
 #include "ags/globals.h"
@@ -99,23 +99,21 @@ int RenderChar(Bitmap *ds, const int at_x, const int at_y, const WFNChar &wfn_ch
 	const unsigned char *actdata = wfn_char.Data;
 	const int bytewid = wfn_char.GetRowByteCount();
 
-	int x = at_x;
-	int y = at_y;
-	for (int h = 0; h < height; ++h) {
-		for (int w = 0; w < width; ++w) {
+	// NOTE: allegro's putpixel ignores clipping (optimization),
+	// so we'll have to accomodate for that ourselves
+	Rect clip = ds->GetClip();
+	int sx = MAX(at_x, clip.Left), ex = MIN(at_x + width * scale, clip.Right + 1);
+	int sy = MAX(at_y, clip.Top), ey = MIN(at_y + height * scale, clip.Bottom + 1);
+	for (int h = 0, y = sy; h < height && y < ey; ++h, y += scale) {
+		for (int w = 0, x = sx; w < width && x < ex; ++w, x += scale) {
 			if (((actdata[h * bytewid + (w / 8)] & (0x80 >> (w % 8))) != 0)) {
 				if (scale > 1) {
-					ds->FillRect(Rect(x + w, y + h, x + w + (scale - 1),
-					                  y + h + (scale - 1)), text_color);
+					ds->FillRect(RectWH(x, y, scale - 1, scale - 1), text_color);
 				} else {
-					ds->PutPixel(x + w, y + h, text_color);
+					ds->PutPixel(x, y, text_color);
 				}
 			}
-
-			x += scale - 1;
 		}
-		y += scale - 1;
-		x = at_x;
 	}
 	return width * scale;
 }


Commit: c883fb2373942545e4bbcae1982095efde58c2a8
    https://github.com/scummvm/scummvm/commit/c883fb2373942545e4bbcae1982095efde58c2a8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:06-07:00

Commit Message:
AGS: fixed SpriteFile::LoadRawData()

>From upstream a5743472104595276c48f96625ac6a19e76d1ca7

Changed paths:
    engines/ags/shared/ac/sprite_file.cpp


diff --git a/engines/ags/shared/ac/sprite_file.cpp b/engines/ags/shared/ac/sprite_file.cpp
index 6d1d8ee0a1e..db399b9d66b 100644
--- a/engines/ags/shared/ac/sprite_file.cpp
+++ b/engines/ags/shared/ac/sprite_file.cpp
@@ -429,13 +429,17 @@ HError SpriteFile::LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector
 	size_t data_size = 0;
 	soff_t data_pos = _stream->GetPosition();
 	// Optional palette
-	data_size += hdr.PalCount * GetPaletteBPP(hdr.SFormat);
+	size_t pal_size = hdr.PalCount * GetPaletteBPP(hdr.SFormat);
+	data_size += pal_size;
+	_stream->Seek(pal_size);
+	// Pixel data
 	if ((_version >= kSprfVersion_StorageFormats) || _compress != kSprCompress_None)
 		data_size += (uint32_t)_stream->ReadInt32() + sizeof(uint32_t);
 	else
 		data_size += hdr.Width * hdr.Height * hdr.BPP;
+	// Seek back and read all at once
 	data.resize(data_size);
-	_stream->Seek(data_pos);
+	_stream->Seek(data_pos, kSeekBegin);
 	_stream->Read(&data[0], data_size);
 
 	_curPos = index + 1; // mark correct pos


Commit: 6fb506b1fec503d245c62ef918d9221291538a16
    https://github.com/scummvm/scummvm/commit/6fb506b1fec503d245c62ef918d9221291538a16
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:07-07:00

Commit Message:
AGS: Prevent reacting to window events during gfx mode init

>From upstream b288b1ccb35b615bec9eb049352fa51adab1415a

Changed paths:
    engines/ags/engine/ac/sys_events.cpp
    engines/ags/engine/ac/sys_events.h
    engines/ags/engine/main/engine.cpp


diff --git a/engines/ags/engine/ac/sys_events.cpp b/engines/ags/engine/ac/sys_events.cpp
index 953870c7609..8d9bed8072b 100644
--- a/engines/ags/engine/ac/sys_events.cpp
+++ b/engines/ags/engine/ac/sys_events.cpp
@@ -21,7 +21,6 @@
 
 #include "common/events.h"
 #include "ags/engine/ac/sys_events.h"
-//include <deque>
 #include "ags/shared/core/platform.h"
 #include "ags/shared/ac/common.h"
 #include "ags/shared/ac/game_setup_struct.h"
@@ -312,4 +311,9 @@ void sys_evt_process_pending(void) {
 		sys_process_event(e);
 }
 
+void sys_flush_events(void) {
+	::AGS::g_events->clearEvents();
+	ags_clear_input_state();
+}
+
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/sys_events.h b/engines/ags/engine/ac/sys_events.h
index d78b094d4e5..88e64d70d13 100644
--- a/engines/ags/engine/ac/sys_events.h
+++ b/engines/ags/engine/ac/sys_events.h
@@ -116,10 +116,10 @@ extern void sys_evt_set_quit_callback(void(*proc)(void));
 // Set engine callback for when input focus is received or lost by the window.
 extern void sys_evt_set_focus_callbacks(void(*switch_in)(void), void(*switch_out)(void));
 
-// Process single event.
-//extern void sys_evt_process_one(const Common::Event &event);
 // Process all events in the backend's queue.
 extern void sys_evt_process_pending(void);
+// Flushes system events following window initialization.
+void sys_flush_events(void);
 
 } // namespace AGS3
 
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 4790bd1bb0d..d1e0f2c327c 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -1214,12 +1214,14 @@ bool engine_try_set_gfxmode_any(const DisplayModeSetup &setup) {
 	engine_shutdown_gfxmode();
 
 	const Size init_desktop = get_desktop_size();
-	if (!graphics_mode_init_any(GraphicResolution(_GP(game).GetGameRes(), _GP(game).color_depth * 8),
-		setup, ColorDepthOption(_GP(game).GetColorDepth())))
-		return false;
+	bool res = graphics_mode_init_any(GraphicResolution(_GP(game).GetGameRes(), _GP(game).color_depth * 8),
+		setup, ColorDepthOption(_GP(game).GetColorDepth()));
 
-	engine_post_gfxmode_setup(init_desktop);
-	return true;
+	if (res)
+		engine_post_gfxmode_setup(init_desktop);
+	// Make sure that we don't receive window events queued during init
+	sys_flush_events();
+	return res;
 }
 
 bool engine_try_switch_windowed_gfxmode() {
@@ -1268,7 +1270,9 @@ bool engine_try_switch_windowed_gfxmode() {
 			init_desktop = get_desktop_size();
 		engine_post_gfxmode_setup(init_desktop);
 	}
-	ags_clear_input_state();
+
+	// Make sure that we don't receive window events queued during init
+	sys_flush_events();
 	return res;
 }
 


Commit: a2cf1dd946d68f7de6e0f6a0cd0bf5f13dbe6959
    https://github.com/scummvm/scummvm/commit/a2cf1dd946d68f7de6e0f6a0cd0bf5f13dbe6959
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:07-07:00

Commit Message:
AGS: Properly reset SpriteCache and SpiteFile when they reinit

>From upstream 938d7300f70180f55b6f2056ec5fb0d894a63735

Changed paths:
    engines/ags/shared/ac/sprite_cache.cpp
    engines/ags/shared/ac/sprite_file.cpp
    engines/ags/shared/ac/sprite_file.h


diff --git a/engines/ags/shared/ac/sprite_cache.cpp b/engines/ags/shared/ac/sprite_cache.cpp
index 9236fb7f8c0..293aa79c681 100644
--- a/engines/ags/shared/ac/sprite_cache.cpp
+++ b/engines/ags/shared/ac/sprite_cache.cpp
@@ -438,6 +438,8 @@ int SpriteCache::SaveToFile(const String &filename, int store_flags, SpriteCompr
 }
 
 HError SpriteCache::InitFile(const String &filename, const String &sprindex_filename) {
+	Reset();
+
 	std::vector<Size> metrics;
 	HError err = _file.OpenFile(filename, sprindex_filename, metrics);
 	if (!err)
@@ -453,7 +455,6 @@ HError SpriteCache::InitFile(const String &filename, const String &sprindex_file
 		if (!metrics[i].IsNull()) {
 			// Existing sprite
 			_spriteData[i].Flags = SPRCACHEFLAG_ISASSET;
-			_spriteData[i].Image = nullptr;
 			get_new_size_for_sprite(i, metrics[i].Width, metrics[i].Height, _sprInfos[i].Width, _sprInfos[i].Height);
 		} else {
 			// Handle empty slot: remap to sprite 0
diff --git a/engines/ags/shared/ac/sprite_file.cpp b/engines/ags/shared/ac/sprite_file.cpp
index db399b9d66b..83e38deb561 100644
--- a/engines/ags/shared/ac/sprite_file.cpp
+++ b/engines/ags/shared/ac/sprite_file.cpp
@@ -147,7 +147,9 @@ SpriteFile::SpriteFile() {
 }
 
 HError SpriteFile::OpenFile(const String &filename, const String &sprindex_filename,
-	std::vector<Size> &metrics) {
+		std::vector<Size> &metrics) {
+	Close();
+
 	char buff[20];
 	soff_t spr_initial_offs = 0;
 	int spriteFileID = 0;
@@ -219,6 +221,10 @@ HError SpriteFile::OpenFile(const String &filename, const String &sprindex_filen
 
 void SpriteFile::Close() {
 	_stream.reset();
+	_spriteData.clear();
+	_version = kSprfVersion_Undefined;
+	_storeFlags = 0;
+	_compress = kSprCompress_None;
 	_curPos = -2;
 }
 
diff --git a/engines/ags/shared/ac/sprite_file.h b/engines/ags/shared/ac/sprite_file.h
index 49910040fd7..607c190c897 100644
--- a/engines/ags/shared/ac/sprite_file.h
+++ b/engines/ags/shared/ac/sprite_file.h
@@ -45,6 +45,7 @@ class Bitmap;
 
 // TODO: research old version differences
 enum SpriteFileVersion {
+	kSprfVersion_Undefined = 0,
 	kSprfVersion_Uncompressed = 4,
 	kSprfVersion_Compressed = 5,
 	kSprfVersion_Last32bit = 6,
@@ -152,8 +153,6 @@ public:
 	HError      LoadSprite(sprkey_t index, Bitmap *&sprite);
 	// Loads a raw sprite element data into the buffer, stores header info separately
 	HError      LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector<uint8_t> &data);
-	HError      LoadSpriteData(sprkey_t index, SpriteDatHeader &hdr, std::vector<uint8_t> &data,
-		std::vector<uint32_t> &palette);
 
 private:
 	// Seek stream to sprite


Commit: 959b8a78e1c204dd5d9eef43746016b7793e4adb
    https://github.com/scummvm/scummvm/commit/959b8a78e1c204dd5d9eef43746016b7793e4adb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:07-07:00

Commit Message:
AGS: Fixed SaveSpriteFile unintentionally restoring deleted sprites

>From upstream f2973226e29120d4ef193e81a1d098c6c40f5b36

Changed paths:
    engines/ags/shared/ac/sprite_cache.cpp
    engines/ags/shared/ac/sprite_file.cpp
    engines/ags/shared/ac/sprite_file.h


diff --git a/engines/ags/shared/ac/sprite_cache.cpp b/engines/ags/shared/ac/sprite_cache.cpp
index 293aa79c681..2940e93d8a8 100644
--- a/engines/ags/shared/ac/sprite_cache.cpp
+++ b/engines/ags/shared/ac/sprite_cache.cpp
@@ -424,15 +424,15 @@ void SpriteCache::RemapSpriteToSprite0(sprkey_t index) {
 }
 
 int SpriteCache::SaveToFile(const String &filename, int store_flags, SpriteCompression compress, SpriteFileIndex &index) {
-	std::vector<Bitmap *> sprites;
-	for (const auto &data : _spriteData) {
+	std::vector<std::pair<bool, Bitmap *>> sprites;
+	for (size_t i = 0; i < _spriteData.size(); ++i) {
 		// NOTE: this is a horrible hack:
 		// because Editor expects slightly different RGB order, it swaps colors
 		// when loading them (call to initialize_sprite), so here we basically
 		// unfix that fix to save the data in a way that engine will expect.
 		// TODO: perhaps adjust the editor to NOT need this?!
-		pre_save_sprite(data.Image);
-		sprites.push_back(data.Image);
+		pre_save_sprite(_spriteData[i].Image);
+		sprites.push_back(std::make_pair(DoesSpriteExist(i), _spriteData[i].Image));
 	}
 	return SaveSpriteFile(filename, sprites, &_file, store_flags, compress, index);
 }
diff --git a/engines/ags/shared/ac/sprite_file.cpp b/engines/ags/shared/ac/sprite_file.cpp
index 83e38deb561..e1472a22bdb 100644
--- a/engines/ags/shared/ac/sprite_file.cpp
+++ b/engines/ags/shared/ac/sprite_file.cpp
@@ -461,25 +461,24 @@ void SpriteFile::SeekToSprite(sprkey_t index) {
 }
 
 
-// Finds the topmost occupied slot index. Warning: may be slow.
-static sprkey_t FindTopmostSprite(const std::vector<Bitmap *> &sprites) {
+// Finds the topmost occupied slot index
+static sprkey_t FindTopmostSprite(const std::vector<std::pair<bool, Bitmap *>> &sprites) {
 	sprkey_t topmost = -1;
 	for (sprkey_t i = 0; i < static_cast<sprkey_t>(sprites.size()); ++i)
-		if (sprites[i])
+		if (sprites[i].first)
 			topmost = i;
 	return topmost;
 }
 
 int SaveSpriteFile(const String &save_to_file,
-		const std::vector<Bitmap *> &sprites, SpriteFile *read_from_file,
+		const std::vector<std::pair<bool, Bitmap *> > &sprites,
+		SpriteFile *read_from_file,
 		int store_flags, SpriteCompression compress, SpriteFileIndex &index) {
 	std::unique_ptr<Stream> output(File::CreateFile(save_to_file));
 	if (output == nullptr)
 		return -1;
 
-	sprkey_t lastslot = read_from_file ? read_from_file->GetTopmostSprite() : 0;
-	lastslot = std::max(lastslot, FindTopmostSprite(sprites));
-
+	sprkey_t lastslot = FindTopmostSprite(sprites);
 	SpriteFileWriter writer(output);
 	writer.Begin(store_flags, compress, lastslot);
 
@@ -493,8 +492,12 @@ int SaveSpriteFile(const String &save_to_file,
 			read_from_file->GetStoreFlags() != store_flags);
 
 	for (sprkey_t i = 0; i <= lastslot; ++i) {
-		Bitmap *image = (size_t)i < sprites.size() ? sprites[i] : nullptr;
+		if (!sprites[i].first) { // empty slot
+			writer.WriteEmptySlot();
+			continue;
+		}
 
+		Bitmap *image = sprites[i].second;
 		// if compression setting is different, load the sprite into memory
 		// (otherwise we will be able to simply copy bytes from one file to another
 		if ((image == nullptr) && diff_compress) {
diff --git a/engines/ags/shared/ac/sprite_file.h b/engines/ags/shared/ac/sprite_file.h
index 607c190c897..749ad873465 100644
--- a/engines/ags/shared/ac/sprite_file.h
+++ b/engines/ags/shared/ac/sprite_file.h
@@ -215,10 +215,13 @@ private:
 	std::vector<uint8_t> _membuf;
 };
 
-// Saves all sprites to file; fills in index data for external use
+// Saves all sprites to file; fills in index data for external use.
 // TODO: refactor to be able to save main file and index file separately (separate function for gather data?)
-extern int SaveSpriteFile(const String &save_to_file,
-	const std::vector<Bitmap *> &sprites, // available sprites (may contain nullptrs)
+// Accepts available sprites as pairs of bool and Bitmap pointer, where boolean value
+// tells if sprite exists and Bitmap pointer may be null;
+// If a sprite's bitmap is missing, it will try reading one from the input file stream.
+int SaveSpriteFile(const String &save_to_file,
+	const std::vector<std::pair<bool, Bitmap *> > &sprites,
 	SpriteFile *read_from_file, // optional file to read missing sprites from
 	int store_flags, SpriteCompression compress, SpriteFileIndex &index);
 // Saves sprite index table in a separate file


Commit: 6473ae69cd9f50145f421811c34b4a0bb3c8757a
    https://github.com/scummvm/scummvm/commit/6473ae69cd9f50145f421811c34b4a0bb3c8757a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:07-07:00

Commit Message:
AGS: Updated build version (3.6.0.15)

>From upstream cc5ca2234a67cd4f7c3b5a70681fd1af681612ce

Changed paths:
    engines/ags/shared/core/def_version.h


diff --git a/engines/ags/shared/core/def_version.h b/engines/ags/shared/core/def_version.h
index 31ba60bc7ae..88a446b3e21 100644
--- a/engines/ags/shared/core/def_version.h
+++ b/engines/ags/shared/core/def_version.h
@@ -22,9 +22,9 @@
 #ifndef AGS_SHARED_CORE_DEFVERSION_H
 #define AGS_SHARED_CORE_DEFVERSION_H
 
-#define ACI_VERSION_STR      "3.6.0.14"
+#define ACI_VERSION_STR      "3.6.0.15"
 #if defined (RC_INVOKED) // for MSVC resource compiler
-#define ACI_VERSION_MSRC_DEF  3.6.0.14
+#define ACI_VERSION_MSRC_DEF  3.6.0.15
 #endif
 
 #define SPECIAL_VERSION ""


Commit: 9b5f0c6221ff030b52949345372ffa1596202cf5
    https://github.com/scummvm/scummvm/commit/9b5f0c6221ff030b52949345372ffa1596202cf5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:07-07:00

Commit Message:
AGS: Fixed default values for restoring of audiochannels

>From upstream 970e023af4db037e2fe24488e583b9dd3ad935aa

Changed paths:
    engines/ags/engine/game/savegame_internal.h


diff --git a/engines/ags/engine/game/savegame_internal.h b/engines/ags/engine/game/savegame_internal.h
index 12430ba53fa..c17714cc362 100644
--- a/engines/ags/engine/game/savegame_internal.h
+++ b/engines/ags/engine/game/savegame_internal.h
@@ -91,7 +91,7 @@ struct RestoredData {
 	int                     CursorMode;
 	// General audio
 	struct ChannelInfo {
-		int ClipID = 0;
+		int ClipID = -1;
 		int Pos = 0;
 		int Priority = 0;
 		int Repeat = 0;


Commit: 787d68277b91f0b4a14ae4fdfa4ebd07b14c2dfb
    https://github.com/scummvm/scummvm/commit/787d68277b91f0b4a14ae4fdfa4ebd07b14c2dfb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Cleanup some unused code/comments

>From upstream 585ab2b826ad4f319c660c1a898ec3eb009b20c5

Changed paths:
    engines/ags/shared/ac/interface_element.h
    engines/ags/shared/ac/words_dictionary.cpp
    engines/ags/shared/script/cc_script.cpp
    engines/ags/shared/util/lzw.cpp


diff --git a/engines/ags/shared/ac/interface_element.h b/engines/ags/shared/ac/interface_element.h
index 1deb1b0279d..a4e0a834816 100644
--- a/engines/ags/shared/ac/interface_element.h
+++ b/engines/ags/shared/ac/interface_element.h
@@ -42,21 +42,6 @@ struct InterfaceElement {
 	InterfaceElement();
 };
 
-/*struct InterfaceStyle {
-int  playareax1,playareay1,playareax2,playareay2; // where the game takes place
-int  vtextxp,vtextyp;
-char vtext[40];
-int  numbuttons,popupbuttons;
-InterfaceButton button[MAXBUTTON];
-int  invx1,invy1,invx2,invy2;  // set invx1=-1 for Sierra-style inventory
-InterfaceStyle() {  // sierra interface
-playareax1=0; playareay1=13; playareax2=319; playareay2=199;
-vtextxp=160; vtextyp=2; strcpy(vtext,"@SCORETEXT@$r at GAMENAME@");
-invx1=-1; numbuttons=2; popupbuttons=1;
-button[0].set(0,13,3,-1,0);
-}
-};*/
-
 } // namespace AGS3
 
 #endif
diff --git a/engines/ags/shared/ac/words_dictionary.cpp b/engines/ags/shared/ac/words_dictionary.cpp
index a11479a0cbe..3bc5697c82e 100644
--- a/engines/ags/shared/ac/words_dictionary.cpp
+++ b/engines/ags/shared/ac/words_dictionary.cpp
@@ -169,7 +169,7 @@ void write_dictionary(WordsDictionary *dict, Stream *out) {
 	out->WriteInt32(dict->num_words);
 	for (ii = 0; ii < dict->num_words; ii++) {
 		write_string_encrypt(out, dict->word[ii]);
-		out->WriteInt16(dict->wordnum[ii]);//__putshort__lilendian(dict->wordnum[ii], writeto);
+		out->WriteInt16(dict->wordnum[ii]);
 	}
 }
 
diff --git a/engines/ags/shared/script/cc_script.cpp b/engines/ags/shared/script/cc_script.cpp
index ab10fbd34c2..9b1972632a1 100644
--- a/engines/ags/shared/script/cc_script.cpp
+++ b/engines/ags/shared/script/cc_script.cpp
@@ -209,7 +209,6 @@ bool ccScript::Read(Stream *in) {
 	int n;
 	char gotsig[5];
 	_G(currentline) = -1;
-	// MACPORT FIX: swap 'size' and 'nmemb'
 	in->Read(gotsig, 4);
 	gotsig[4] = 0;
 
@@ -226,24 +225,18 @@ bool ccScript::Read(Stream *in) {
 
 	if (globaldatasize > 0) {
 		globaldata = (char *)malloc(globaldatasize);
-		// MACPORT FIX: swap
 		in->Read(globaldata, globaldatasize);
 	} else
 		globaldata = nullptr;
 
 	if (codesize > 0) {
 		code = (int32_t *)malloc(codesize * sizeof(int32_t));
-		// MACPORT FIX: swap
-
-		// 64 bit: Read code into 8 byte array, necessary for being able to perform
-		// relocations on the references.
 		in->ReadArrayOfInt32(code, codesize);
 	} else
 		code = nullptr;
 
 	if (stringssize > 0) {
 		strings = (char *)malloc(stringssize);
-		// MACPORT FIX: swap
 		in->Read(strings, stringssize);
 	} else
 		strings = nullptr;
@@ -252,7 +245,6 @@ bool ccScript::Read(Stream *in) {
 	if (numfixups > 0) {
 		fixuptypes = (char *)malloc(numfixups);
 		fixups = (int32_t *)malloc(numfixups * sizeof(int32_t));
-		// MACPORT FIX: swap 'size' and 'nmemb'
 		in->Read(fixuptypes, numfixups);
 		in->ReadArrayOfInt32(fixups, numfixups);
 	} else {
diff --git a/engines/ags/shared/util/lzw.cpp b/engines/ags/shared/util/lzw.cpp
index 4bc1cc9143a..41714a9446e 100644
--- a/engines/ags/shared/util/lzw.cpp
+++ b/engines/ags/shared/util/lzw.cpp
@@ -224,7 +224,6 @@ bool lzwexpand(Stream *lzw_in, Stream *out, size_t out_size) {
 	while ((bits = lzw_in->ReadByte()) != -1) {
 		for (mask = 0x01; mask & 0xFF; mask <<= 1) {
 			if (bits & mask) {
-				// MACPORT FIX: read to short and expand
 				short jshort = 0;
 				jshort = lzw_in->ReadInt16();
 				j = jshort;


Commit: d147a541ec9873865cd4054f82ee935ebdb932f5
    https://github.com/scummvm/scummvm/commit/d147a541ec9873865cd4054f82ee935ebdb932f5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Cleanup some unused code/comments

>From upstream f0dc4b364888f019c037afee6ee66aa0726fb560

Changed paths:
    engines/ags/engine/ac/character_extras.h
    engines/ags/engine/main/game_run.cpp
    engines/ags/engine/script/executing_script.cpp


diff --git a/engines/ags/engine/ac/character_extras.h b/engines/ags/engine/ac/character_extras.h
index ac1fe48acba..d5c48a886e4 100644
--- a/engines/ags/engine/ac/character_extras.h
+++ b/engines/ags/engine/ac/character_extras.h
@@ -34,9 +34,9 @@ class Stream;
 }
 using namespace AGS; // FIXME later
 
+// The CharacterInfo struct size is fixed because it's exposed to script
+// and plugin API, therefore new stuff has to go here
 struct CharacterExtras {
-	// UGLY UGLY UGLY!! The CharacterInfo struct size is fixed because it's
-	// used in the scripts, therefore overflowing stuff has to go here
 	short invorder[MAX_INVORDER];
 	short invorder_count;
 	// TODO: implement full AABB and keep updated, so that engine could rely on these cached values all time;
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index 2917a4e7684..948e521923d 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -336,7 +336,6 @@ bool run_service_key_controls(KeyInput &out_key) {
 		// ctrl+D - show info
 		char infobuf[900];
 		int ff;
-		// MACPORT FIX 9/6/5: added last %s
 		sprintf(infobuf, "In room %d %s[Player at %d, %d (view %d, loop %d, frame %d)%s%s%s",
 		        _G(displayed_room), (_G(noWalkBehindsAtAll) ? "(has no walk-behinds)" : ""), _G(playerchar)->x, _G(playerchar)->y,
 		        _G(playerchar)->view + 1, _G(playerchar)->loop, _G(playerchar)->frame,
diff --git a/engines/ags/engine/script/executing_script.cpp b/engines/ags/engine/script/executing_script.cpp
index 8833aaf6e90..2a1b3a597bb 100644
--- a/engines/ags/engine/script/executing_script.cpp
+++ b/engines/ags/engine/script/executing_script.cpp
@@ -47,7 +47,6 @@ int ExecutingScript::queue_action(PostScriptAction act, int data, const char *an
 			           aname, postScriptActionNames[numPostScriptActions - 1],
 			           postScriptActionPositions[numPostScriptActions - 1].Section.GetCStr(), postScriptActionPositions[numPostScriptActions - 1].Line);
 			break;
-		// MACPORT FIX 9/6/5: added default clause to remove warning
 		default:
 			break;
 		}


Commit: fabab1285d4347246f814744e35efeb3e383d1a5
    https://github.com/scummvm/scummvm/commit/fabab1285d4347246f814744e35efeb3e383d1a5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Made Hotspot.Name and Object.Name settable

>From upstream 6a7271c4df1765dc86f88d7676337b63fcef17aa

Changed paths:
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_hotspot.cpp
    engines/ags/engine/ac/global_object.cpp
    engines/ags/engine/ac/hotspot.cpp
    engines/ags/engine/ac/object.cpp
    engines/ags/engine/ac/room.cpp
    engines/ags/engine/ac/room_object.cpp
    engines/ags/engine/ac/room_object.h
    engines/ags/engine/ac/room_status.cpp
    engines/ags/engine/ac/room_status.h
    engines/ags/engine/game/savegame_components.cpp


diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index f758fc339e1..36aebd0753d 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -587,7 +587,7 @@ void GetLocationName(int xxx, int yyy, char *tempo) {
 	// on object
 	if (loctype == LOCTYPE_OBJ) {
 		aa = _G(getloctype_index);
-		strcpy(tempo, get_translation(_GP(thisroom).Objects[aa].Name.GetCStr()));
+		strcpy(tempo, get_translation(_G(croom)->obj[aa].name.GetCStr()));
 		// Compatibility: < 3.1.1 games returned space for nameless object
 		// (presumably was a bug, but fixing it affected certain games behavior)
 		if (_G(loaded_game_file_version) < kGameVersion_311 && tempo[0] == 0) {
@@ -600,7 +600,7 @@ void GetLocationName(int xxx, int yyy, char *tempo) {
 		return;
 	}
 	onhs = _G(getloctype_index);
-	if (onhs > 0) strcpy(tempo, get_translation(_GP(thisroom).Hotspots[onhs].Name.GetCStr()));
+	if (onhs > 0) strcpy(tempo, get_translation(_G(croom)->hotspot[onhs].Name.GetCStr()));
 	if (_GP(play).get_loc_name_last_time != onhs)
 		GUI::MarkSpecialLabelsForUpdate(kLabelMacro_Overhotspot);
 	_GP(play).get_loc_name_last_time = onhs;
diff --git a/engines/ags/engine/ac/global_hotspot.cpp b/engines/ags/engine/ac/global_hotspot.cpp
index 3e24e0b295c..eaedca8d8d6 100644
--- a/engines/ags/engine/ac/global_hotspot.cpp
+++ b/engines/ags/engine/ac/global_hotspot.cpp
@@ -41,23 +41,17 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-
-
-
-
-
 void DisableHotspot(int hsnum) {
 	if ((hsnum < 1) | (hsnum >= MAX_ROOM_HOTSPOTS))
 		quit("!DisableHotspot: invalid hotspot specified");
-	_G(croom)->hotspot_enabled[hsnum] = 0;
+	_G(croom)->hotspot[hsnum].Enabled = false;
 	debug_script_log("Hotspot %d disabled", hsnum);
 }
 
 void EnableHotspot(int hsnum) {
 	if ((hsnum < 1) | (hsnum >= MAX_ROOM_HOTSPOTS))
 		quit("!EnableHotspot: invalid hotspot specified");
-	_G(croom)->hotspot_enabled[hsnum] = 1;
+	_G(croom)->hotspot[hsnum].Enabled = true;
 	debug_script_log("Hotspot %d re-enabled", hsnum);
 }
 
@@ -92,7 +86,7 @@ void GetHotspotName(int hotspot, char *buffer) {
 	if ((hotspot < 0) || (hotspot >= MAX_ROOM_HOTSPOTS))
 		quit("!GetHotspotName: invalid hotspot number");
 
-	strcpy(buffer, get_translation(_GP(thisroom).Hotspots[hotspot].Name.GetCStr()));
+	strcpy(buffer, get_translation(_G(croom)->hotspot[hotspot].Name.GetCStr()));
 }
 
 void RunHotspotInteraction(int hotspothere, int mood) {
diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index 44b688c862e..f6d4f3e11ce 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -385,7 +385,7 @@ void GetObjectName(int obj, char *buffer) {
 	if (!is_valid_object(obj))
 		quit("!GetObjectName: invalid object number");
 
-	strcpy(buffer, get_translation(_GP(thisroom).Objects[obj].Name.GetCStr()));
+	strcpy(buffer, get_translation(_G(croom)->obj[obj].name.GetCStr()));
 }
 
 void MoveObject(int objj, int xx, int yy, int spp) {
diff --git a/engines/ags/engine/ac/hotspot.cpp b/engines/ags/engine/ac/hotspot.cpp
index cd7e04f4342..7cc5c5df289 100644
--- a/engines/ags/engine/ac/hotspot.cpp
+++ b/engines/ags/engine/ac/hotspot.cpp
@@ -41,11 +41,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-
-
-
-
 void Hotspot_SetEnabled(ScriptHotspot *hss, int newval) {
 	if (newval)
 		EnableHotspot(hss->id);
@@ -54,7 +49,7 @@ void Hotspot_SetEnabled(ScriptHotspot *hss, int newval) {
 }
 
 int Hotspot_GetEnabled(ScriptHotspot *hss) {
-	return _G(croom)->hotspot_enabled[hss->id];
+	return _G(croom)->hotspot[hss->id].Enabled ? 1 : 0;
 }
 
 int Hotspot_GetID(ScriptHotspot *hss) {
@@ -82,7 +77,15 @@ void Hotspot_GetName(ScriptHotspot *hss, char *buffer) {
 }
 
 const char *Hotspot_GetName_New(ScriptHotspot *hss) {
-	return CreateNewScriptString(get_translation(_GP(thisroom).Hotspots[hss->id].Name.GetCStr()));
+	if ((hss->id < 0) || (hss->id >= MAX_ROOM_HOTSPOTS))
+		quit("!Hotspot.Name: invalid hotspot number");
+	return CreateNewScriptString(get_translation(_G(croom)->hotspot[hss->id].Name.GetCStr()));
+}
+
+void Hotspot_SetName(ScriptHotspot *hss, const char *newName) {
+	if ((hss->id < 0) || (hss->id >= MAX_ROOM_HOTSPOTS))
+		quit("!Hotspot.Name: invalid hotspot number");
+	_G(croom)->hotspot[hss->id].Name = newName;
 }
 
 bool Hotspot_IsInteractionAvailable(ScriptHotspot *hhot, int mood) {
@@ -122,7 +125,7 @@ bool Hotspot_SetTextProperty(ScriptHotspot *hss, const char *property, const cha
 int get_hotspot_at(int xpp, int ypp) {
 	int onhs = _GP(thisroom).HotspotMask->GetPixel(room_to_mask_coord(xpp), room_to_mask_coord(ypp));
 	if (onhs <= 0 || onhs >= MAX_ROOM_HOTSPOTS) return 0;
-	if (_G(croom)->hotspot_enabled[onhs] == 0) return 0;
+	if (!_G(croom)->hotspot[onhs].Enabled) return 0;
 	return onhs;
 }
 
@@ -203,6 +206,10 @@ RuntimeScriptValue Sc_Hotspot_GetName_New(void *self, const RuntimeScriptValue *
 	API_CONST_OBJCALL_OBJ(ScriptHotspot, const char, _GP(myScriptStringImpl), Hotspot_GetName_New);
 }
 
+RuntimeScriptValue Sc_Hotspot_SetName(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_POBJ(ScriptHotspot, Hotspot_SetName, const char);
+}
+
 // int (ScriptHotspot *hss)
 RuntimeScriptValue Sc_Hotspot_GetWalkToX(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(ScriptHotspot, Hotspot_GetWalkToX);
@@ -231,6 +238,7 @@ void RegisterHotspotAPI() {
 	ccAddExternalObjectFunction("Hotspot::set_Enabled", Sc_Hotspot_SetEnabled);
 	ccAddExternalObjectFunction("Hotspot::get_ID", Sc_Hotspot_GetID);
 	ccAddExternalObjectFunction("Hotspot::get_Name", Sc_Hotspot_GetName_New);
+	ccAddExternalObjectFunction("Hotspot::set_Name", Sc_Hotspot_SetName);
 	ccAddExternalObjectFunction("Hotspot::get_WalkToX", Sc_Hotspot_GetWalkToX);
 	ccAddExternalObjectFunction("Hotspot::get_WalkToY", Sc_Hotspot_GetWalkToY);
 }
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index 1b3e35b4d02..ceb23ce7341 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -279,7 +279,13 @@ const char *Object_GetName_New(ScriptObject *objj) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.Name: invalid object number");
 
-	return CreateNewScriptString(get_translation(_GP(thisroom).Objects[objj->id].Name.GetCStr()));
+	return CreateNewScriptString(get_translation(_G(croom)->obj[objj->id].name.GetCStr()));
+}
+
+void Object_SetName(ScriptObject *objj, const char *newName) {
+	if (!is_valid_object(objj->id))
+		quit("!Object.Name: invalid object number");
+	_G(croom)->obj[objj->id].name = newName;
 }
 
 bool Object_IsInteractionAvailable(ScriptObject *oobj, int mood) {
@@ -790,6 +796,10 @@ RuntimeScriptValue Sc_Object_GetName_New(void *self, const RuntimeScriptValue *p
 	API_CONST_OBJCALL_OBJ(ScriptObject, const char, _GP(myScriptStringImpl), Object_GetName_New);
 }
 
+RuntimeScriptValue Sc_Object_SetName(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_POBJ(ScriptObject, Object_SetName, const char);
+}
+
 RuntimeScriptValue Sc_Object_GetScaling(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(ScriptObject, Object_GetScaling);
 }
@@ -903,6 +913,7 @@ void RegisterObjectAPI() {
 	ccAddExternalObjectFunction("Object::set_ManualScaling", Sc_Object_SetManualScaling);
 	ccAddExternalObjectFunction("Object::get_Moving", Sc_Object_GetMoving);
 	ccAddExternalObjectFunction("Object::get_Name", Sc_Object_GetName_New);
+	ccAddExternalObjectFunction("Object::set_Name", Sc_Object_SetName);
 	ccAddExternalObjectFunction("Object::get_Scaling", Sc_Object_GetScaling);
 	ccAddExternalObjectFunction("Object::set_Scaling", Sc_Object_SetScaling);
 	ccAddExternalObjectFunction("Object::get_Solid", Sc_Object_GetSolid);
diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index cc99c7042dc..f13da1c29fe 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -576,6 +576,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 			_G(croom)->obj[cc].last_height = 0;
 			_G(croom)->obj[cc].blocking_width = 0;
 			_G(croom)->obj[cc].blocking_height = 0;
+			_G(croom)->obj[cc].name = _GP(thisroom).Objects[cc].Name;
 			if (_GP(thisroom).Objects[cc].Baseline >= 0)
 				_G(croom)->obj[cc].baseline = _GP(thisroom).Objects[cc].Baseline;
 			if (_GP(thisroom).Objects[cc].Sprite > UINT16_MAX)
@@ -594,7 +595,8 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		_G(croom)->objcond[cc]=_GP(thisroom).objcond[cc];*/
 
 		for (cc = 0; cc < MAX_ROOM_HOTSPOTS; cc++) {
-			_G(croom)->hotspot_enabled[cc] = 1;
+			_G(croom)->hotspot[cc].Enabled = true;
+			_G(croom)->hotspot[cc].Name = _GP(thisroom).Hotspots[cc].Name;
 		}
 		for (cc = 0; cc < MAX_ROOM_REGIONS; cc++) {
 			_G(croom)->region_enabled[cc] = 1;
diff --git a/engines/ags/engine/ac/room_object.cpp b/engines/ags/engine/ac/room_object.cpp
index da0cc6ab5ea..9f95b150aba 100644
--- a/engines/ags/engine/ac/room_object.cpp
+++ b/engines/ags/engine/ac/room_object.cpp
@@ -30,6 +30,7 @@
 #include "ags/engine/main/update.h"
 #include "ags/shared/util/math.h"
 #include "ags/shared/util/stream.h"
+#include "ags/shared/util/string_utils.h"
 
 namespace AGS3 {
 
@@ -153,7 +154,7 @@ void RoomObject::update_cycle_view_backwards() {
 	}
 }
 
-void RoomObject::ReadFromFile(Stream *in) {
+void RoomObject::ReadFromSavegame(Stream *in, int save_ver) {
 	x = in->ReadInt32();
 	y = in->ReadInt32();
 	transparent = in->ReadInt32();
@@ -178,9 +179,12 @@ void RoomObject::ReadFromFile(Stream *in) {
 	flags = in->ReadInt8();
 	blocking_width = in->ReadInt16();
 	blocking_height = in->ReadInt16();
+	if (save_ver > 0) {
+		name = StrUtil::ReadString(in);
+	}
 }
 
-void RoomObject::WriteToFile(Stream *out) const {
+void RoomObject::WriteToSavegame(Stream *out) const {
 	out->WriteInt32(x);
 	out->WriteInt32(y);
 	out->WriteInt32(transparent);
@@ -205,6 +209,7 @@ void RoomObject::WriteToFile(Stream *out) const {
 	out->WriteInt8(flags);
 	out->WriteInt16(blocking_width);
 	out->WriteInt16(blocking_height);
+	StrUtil::WriteString(name, out);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/room_object.h b/engines/ags/engine/ac/room_object.h
index 9dc0e9e8f02..56242364eef 100644
--- a/engines/ags/engine/ac/room_object.h
+++ b/engines/ags/engine/ac/room_object.h
@@ -30,6 +30,7 @@
 
 #include "ags/shared/core/types.h"
 #include "ags/shared/ac/common_defines.h"
+#include "ags/shared/util/string.h"
 
 namespace AGS3 {
 
@@ -60,7 +61,9 @@ struct RoomObject {
 	int8  overall_speed;
 	int8  on;
 	int8  flags;
+	// Down to here is a part of the plugin API
 	short blocking_width, blocking_height;
+	Shared::String name;
 
 	RoomObject();
 
@@ -79,8 +82,8 @@ struct RoomObject {
 	void update_cycle_view_forwards();
 	void update_cycle_view_backwards();
 
-	void ReadFromFile(Shared::Stream *in);
-	void WriteToFile(Shared::Stream *out) const;
+	void ReadFromSavegame(Shared::Stream *in, int save_ver);
+	void WriteToSavegame(Shared::Stream *out) const;
 };
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/room_status.cpp b/engines/ags/engine/ac/room_status.cpp
index 94d7ef796a8..86b6e7afc41 100644
--- a/engines/ags/engine/ac/room_status.cpp
+++ b/engines/ags/engine/ac/room_status.cpp
@@ -25,6 +25,7 @@
 #include "ags/shared/game/custom_properties.h"
 #include "ags/engine/game/savegame_components.h"
 #include "ags/shared/util/aligned_stream.h"
+#include "ags/shared/util/string_utils.h"
 #include "ags/globals.h"
 
 namespace AGS3 {
@@ -32,6 +33,18 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
+void HotspotState::ReadFromSavegame(Shared::Stream *in, int save_ver) {
+	Enabled = in->ReadInt8() != 0;
+	if (save_ver > 0) {
+		Name = StrUtil::ReadString(in);
+	}
+}
+
+void HotspotState::WriteToSavegame(Shared::Stream *out) const {
+	out->WriteInt8(Enabled);
+	StrUtil::WriteString(Name, out);
+}
+
 RoomStatus::RoomStatus() {
 	beenhere = 0;
 	numobj = 0;
@@ -39,7 +52,6 @@ RoomStatus::RoomStatus() {
 	tsdatasize = 0;
 	tsdata = nullptr;
 
-	memset(&hotspot_enabled, 0, sizeof(hotspot_enabled));
 	memset(&region_enabled, 0, sizeof(region_enabled));
 	memset(&walkbehind_base, 0, sizeof(walkbehind_base));
 	memset(&interactionVariableValues, 0, sizeof(interactionVariableValues));
@@ -84,7 +96,8 @@ void RoomStatus::ReadFromFile_v321(Stream *in) {
 		intrRegion[i].ReadFromSavedgame_v321(in);
 	}
 	intrRoom.ReadFromSavedgame_v321(in);
-	in->ReadArrayOfInt8((int8_t *)hotspot_enabled, MAX_ROOM_HOTSPOTS);
+	for (size_t i = 0; i < MAX_ROOM_HOTSPOTS; ++i)
+		hotspot[i].Enabled = in->ReadInt8() != 0;
 	in->ReadArrayOfInt8((int8_t *)region_enabled, MAX_ROOM_REGIONS);
 	in->ReadArrayOfInt16(walkbehind_base, MAX_WALK_BEHINDS);
 	in->ReadArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
@@ -103,25 +116,25 @@ void RoomStatus::ReadFromFile_v321(Stream *in) {
 void RoomStatus::ReadRoomObjects_Aligned(Shared::Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
 	for (int i = 0; i < MAX_ROOM_OBJECTS; ++i) {
-		obj[i].ReadFromFile(&align_s);
+		obj[i].ReadFromSavegame(&align_s, 0);
 		align_s.Reset();
 	}
 }
 
-void RoomStatus::ReadFromSavegame(Stream *in) {
+void RoomStatus::ReadFromSavegame(Stream *in, int save_ver) {
 	FreeScriptData();
 	FreeProperties();
 
 	beenhere = in->ReadInt8();
 	numobj = in->ReadInt32();
 	for (int i = 0; i < numobj; ++i) {
-		obj[i].ReadFromFile(in);
+		obj[i].ReadFromSavegame(in, save_ver);
 		Properties::ReadValues(objProps[i], in);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			SavegameComponents::ReadInteraction272(intrObject[i], in);
 	}
 	for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
-		hotspot_enabled[i] = in->ReadInt8();
+		hotspot[i].ReadFromSavegame(in, save_ver);
 		Properties::ReadValues(hsProps[i], in);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			SavegameComponents::ReadInteraction272(intrHotspot[i], in);
@@ -152,13 +165,13 @@ void RoomStatus::WriteToSavegame(Stream *out) const {
 	out->WriteInt8(beenhere);
 	out->WriteInt32(numobj);
 	for (int i = 0; i < numobj; ++i) {
-		obj[i].WriteToFile(out);
+		obj[i].WriteToSavegame(out);
 		Properties::WriteValues(objProps[i], out);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			SavegameComponents::WriteInteraction272(intrObject[i], out);
 	}
 	for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
-		out->WriteInt8(hotspot_enabled[i]);
+		hotspot[i].WriteToSavegame(out);
 		Properties::WriteValues(hsProps[i], out);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			SavegameComponents::WriteInteraction272(intrHotspot[i], out);
diff --git a/engines/ags/engine/ac/room_status.h b/engines/ags/engine/ac/room_status.h
index 5c98f9f075e..584cb2b6107 100644
--- a/engines/ags/engine/ac/room_status.h
+++ b/engines/ags/engine/ac/room_status.h
@@ -39,6 +39,14 @@ class Stream;
 using AGS::Shared::Stream;
 using AGS::Shared::Interaction;
 
+struct HotspotState {
+	bool Enabled = false;
+	Shared::String Name;
+
+	void ReadFromSavegame(Shared::Stream *in, int save_ver);
+	void WriteToSavegame(Shared::Stream *out) const;
+};
+
 // This struct is saved in the save games - it contains everything about
 // a room that could change
 struct RoomStatus {
@@ -62,7 +70,7 @@ struct RoomStatus {
 	EventBlock objcond[MAX_ROOM_OBJECTS];
 	EventBlock misccond;
 #endif
-	int8  hotspot_enabled[MAX_ROOM_HOTSPOTS];
+	HotspotState hotspot[MAX_ROOM_HOTSPOTS];
 	int8  region_enabled[MAX_ROOM_REGIONS];
 	short walkbehind_base[MAX_WALK_BEHINDS];
 	int32_t interactionVariableValues[MAX_GLOBAL_VARIABLES];
@@ -75,7 +83,7 @@ struct RoomStatus {
 
 	void ReadFromFile_v321(Shared::Stream *in);
 	void ReadRoomObjects_Aligned(Shared::Stream *in);
-	void ReadFromSavegame(Shared::Stream *in);
+	void ReadFromSavegame(Shared::Stream *in, int save_ver);
 	void WriteToSavegame(Shared::Stream *out) const;
 };
 
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 4058ebd998d..c607e4433b6 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -876,7 +876,7 @@ HSaveError ReadRoomStates(Stream *in, int32_t cmp_ver, const PreservedParams &pp
 			if (!AssertFormatTagStrict(err, in, "RoomState", true))
 				return err;
 			RoomStatus *roomstat = getRoomStatus(id);
-			roomstat->ReadFromSavegame(in);
+			roomstat->ReadFromSavegame(in, cmp_ver);
 			if (!AssertFormatTagStrict(err, in, "RoomState", false))
 				return err;
 		}
@@ -959,7 +959,7 @@ HSaveError ReadThisRoom(Stream *in, int32_t cmp_ver, const PreservedParams &pp,
 	if (!AssertCompatLimit(err, objmls_count, CHMLSOFFS, "room object move lists"))
 		return err;
 	for (int i = 0; i < objmls_count; ++i) {
-		err = _G(mls)[i].ReadFromFile(in, cmp_ver > 0 ? 1 : 0);
+		err = _G(mls)[i].ReadFromFile(in, cmp_ver > 0 ? 1 : 0); // FIXME!!
 		if (!err)
 			return err;
 	}
@@ -969,7 +969,7 @@ HSaveError ReadThisRoom(Stream *in, int32_t cmp_ver, const PreservedParams &pp,
 
 	// read the current troom state, in case they saved in temporary room
 	if (!in->ReadBool())
-		_GP(troom).ReadFromSavegame(in);
+		_GP(troom).ReadFromSavegame(in, cmp_ver > 1 ? 1 : 0); // FIXME!!
 
 	return HSaveError::None();
 }
@@ -1101,14 +1101,14 @@ ComponentHandler ComponentHandlers[] = {
 	},
 	{
 		"Room States",
-		0,
+		1,
 		0,
 		WriteRoomStates,
 		ReadRoomStates
 	},
 	{
 		"Loaded Room State",
-		1,
+		2,
 		0,
 		WriteThisRoom,
 		ReadThisRoom


Commit: cb95772ad921bdc874e26f32e04b031bcc663cd5
    https://github.com/scummvm/scummvm/commit/cb95772ad921bdc874e26f32e04b031bcc663cd5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Update @OVERHOTSPOT@ when object/hotspot name changes

>From upstream 64bb4fe130908d078c7945c000e0b43dfea49a14

Changed paths:
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/hotspot.cpp
    engines/ags/engine/ac/object.cpp


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index a09f6919f71..c43bce630af 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -1325,6 +1325,7 @@ const char *Character_GetName(CharacterInfo *chaa) {
 void Character_SetName(CharacterInfo *chaa, const char *newName) {
 	strncpy(chaa->name, newName, 40);
 	chaa->name[39] = 0;
+	GUI::MarkSpecialLabelsForUpdate(kLabelMacro_Overhotspot);
 }
 
 int Character_GetNormalView(CharacterInfo *chaa) {
diff --git a/engines/ags/engine/ac/hotspot.cpp b/engines/ags/engine/ac/hotspot.cpp
index 7cc5c5df289..1e1f155c3ff 100644
--- a/engines/ags/engine/ac/hotspot.cpp
+++ b/engines/ags/engine/ac/hotspot.cpp
@@ -30,6 +30,7 @@
 #include "ags/engine/ac/string.h"
 #include "ags/shared/game/room_struct.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/shared/gui/gui_main.h"
 #include "ags/engine/script/runtime_script_value.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
@@ -86,6 +87,7 @@ void Hotspot_SetName(ScriptHotspot *hss, const char *newName) {
 	if ((hss->id < 0) || (hss->id >= MAX_ROOM_HOTSPOTS))
 		quit("!Hotspot.Name: invalid hotspot number");
 	_G(croom)->hotspot[hss->id].Name = newName;
+	GUI::MarkSpecialLabelsForUpdate(kLabelMacro_Overhotspot);
 }
 
 bool Hotspot_IsInteractionAvailable(ScriptHotspot *hhot, int mood) {
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index ceb23ce7341..15c98dcc5ac 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -42,6 +42,7 @@
 #include "ags/shared/ac/view.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/shared/gfx/gfx_def.h"
+#include "ags/shared/gui/gui_main.h"
 #include "ags/engine/script/runtime_script_value.h"
 #include "ags/engine/ac/dynobj/cc_object.h"
 #include "ags/engine/ac/move_list.h"
@@ -286,6 +287,7 @@ void Object_SetName(ScriptObject *objj, const char *newName) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.Name: invalid object number");
 	_G(croom)->obj[objj->id].name = newName;
+	GUI::MarkSpecialLabelsForUpdate(kLabelMacro_Overhotspot);
 }
 
 bool Object_IsInteractionAvailable(ScriptObject *oobj, int mood) {


Commit: eaf4b001251d2c49d5be25c20167811868df3aaa
    https://github.com/scummvm/scummvm/commit/eaf4b001251d2c49d5be25c20167811868df3aaa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Fixed pre-3.6.0 games loosing object names on restoring a save

>From upstream c745e75a62bee53dcdb0552a10c2b8053717b38f

Changed paths:
    engines/ags/engine/ac/room.cpp
    engines/ags/shared/ac/game_version.h


diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index f13da1c29fe..f1bedd04961 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -539,6 +539,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		_G(croom) = getRoomStatus(newnum);
 	else _G(croom) = &_GP(troom);
 
+	// Decide what to do if we have been or not in this room before
 	if (_G(croom)->beenhere > 0) {
 		// if we've been here before, save the Times Run information
 		// since we will overwrite the actual NewInteraction structs
@@ -554,8 +555,18 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 			for (cc = 0; cc < MAX_ROOM_REGIONS; cc++)
 				_GP(thisroom).Regions[cc].Interaction->CopyTimesRun(_G(croom)->intrRegion[cc]);
 		}
-	}
-	if (_G(croom)->beenhere == 0) {
+		for (size_t i = 0; i < _GP(thisroom).LocalVariables.size() && i < (size_t)MAX_GLOBAL_VARIABLES; ++i)
+			_GP(thisroom).LocalVariables[i].Value = _G(croom)->interactionVariableValues[i];
+
+		// Always copy object and hotspot names for < 3.6.0 games, because they were not settable
+		if (_G(loaded_game_file_version) < kGameVersion_360_16) {
+			for (cc = 0; cc < _G(croom)->numobj; ++cc)
+				_G(croom)->obj[cc].name = _GP(thisroom).Objects[cc].Name;
+			for (cc = 0; cc < MAX_ROOM_HOTSPOTS; cc++)
+				_G(croom)->hotspot[cc].Name = _GP(thisroom).Hotspots[cc].Name;
+		}
+	} else {
+		// If we have not been in this room before, then copy necessary fields from _GP(thisroom)
 		_G(croom)->numobj = _GP(thisroom).ObjectCount;
 		_G(croom)->tsdatasize = 0;
 		for (cc = 0; cc < _G(croom)->numobj; cc++) {
@@ -604,10 +615,6 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 		_G(croom)->beenhere = 1;
 		_G(in_new_room) = 2;
-	} else {
-		// We have been here before
-		for (size_t i = 0; i < _GP(thisroom).LocalVariables.size() && i < (size_t)MAX_GLOBAL_VARIABLES; ++i)
-			_GP(thisroom).LocalVariables[i].Value = _G(croom)->interactionVariableValues[i];
 	}
 
 	update_polled_stuff_if_runtime();
diff --git a/engines/ags/shared/ac/game_version.h b/engines/ags/shared/ac/game_version.h
index 8ccd1fd61ab..9451c15eb1e 100644
--- a/engines/ags/shared/ac/game_version.h
+++ b/engines/ags/shared/ac/game_version.h
@@ -153,7 +153,8 @@ enum GameDataVersion {
 	kGameVersion_350 = 50,
 	kGameVersion_360 = 3060000,
 	kGameVersion_360_11 = 3060011,
-	kGameVersion_Current = kGameVersion_360_11
+	kGameVersion_360_16 = 3060016,
+	kGameVersion_Current = kGameVersion_360_16
 };
 
 } // namespace AGS3


Commit: e0ef5ad2be1fe2650adf54e6c55e618843d61715
    https://github.com/scummvm/scummvm/commit/e0ef5ad2be1fe2650adf54e6c55e618843d61715
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:08-07:00

Commit Message:
AGS: Fix signed comparison warning

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


diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index f1bedd04961..5c6c3eca191 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -477,7 +477,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	_GP(play).bg_anim_delay = _GP(play).anim_background_speed;
 
 	// Fixup the frame index, in case the new room does not have enough background frames
-	if (_GP(play).bg_frame < 0 || _GP(play).bg_frame >= _GP(thisroom).BgFrameCount)
+	if (_GP(play).bg_frame < 0 || _GP(play).bg_frame >= (int)_GP(thisroom).BgFrameCount)
 		_GP(play).bg_frame = 0;
 
 	// do the palette


Commit: dc4c149e3012c0bba33240a56bcb4181920fba65
    https://github.com/scummvm/scummvm/commit/dc4c149e3012c0bba33240a56bcb4181920fba65
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: Fixed PackfileFromAsset() - potential nullptr access

>From upstream 0f675976046afbc9c1440b078b78f08d68363456

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


diff --git a/engines/ags/engine/ac/file.cpp b/engines/ags/engine/ac/file.cpp
index c2287d3d2d2..b3e4fe2f37a 100644
--- a/engines/ags/engine/ac/file.cpp
+++ b/engines/ags/engine/ac/file.cpp
@@ -509,15 +509,14 @@ static PACKFILE_VTABLE ags_packfile_vtable = {
 
 PACKFILE *PackfileFromAsset(const AssetPath &path) {
 	Stream *asset_stream = _GP(AssetMgr)->OpenAsset(path);
+	if (!asset_stream) return nullptr;
 	const size_t asset_size = asset_stream->GetLength();
-	if (asset_stream && asset_size > 0) {
-		AGS_PACKFILE_OBJ *obj = new AGS_PACKFILE_OBJ;
-		obj->stream.reset(asset_stream);
-		obj->asset_size = asset_size;
-		obj->remains = asset_size;
-		return pack_fopen_vtable(&ags_packfile_vtable, obj);
-	}
-	return nullptr;
+	if (asset_size == 0) return nullptr;
+	AGS_PACKFILE_OBJ *obj = new AGS_PACKFILE_OBJ;
+	obj->stream.reset(asset_stream);
+	obj->asset_size = asset_size;
+	obj->remains = asset_size;
+	return pack_fopen_vtable(&ags_packfile_vtable, obj);
 }
 
 String find_assetlib(const String &filename) {


Commit: dbcebe50d406d7d87ae7e741a8c2454f4a43a492
    https://github.com/scummvm/scummvm/commit/dbcebe50d406d7d87ae7e741a8c2454f4a43a492
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: Added Character.IdleAnimationDelay and editor property

>From upstream 73b2aaaa859f92b5a73d5ab78118653974529402

Changed paths:
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/character_info_engine.cpp
    engines/ags/shared/ac/character_info.cpp
    engines/ags/shared/ac/character_info.h


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index c43bce630af..e6bf1325384 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -1062,12 +1062,12 @@ int Character_GetAnimationSpeed(CharacterInfo *chaa) {
 }
 
 void Character_SetAnimationSpeed(CharacterInfo *chaa, int newval) {
-
 	chaa->animspeed = newval;
+	if (_G(loaded_game_file_version) < kGameVersion_360_16)
+		chaa->idle_anim_speed = chaa->animspeed + 5;
 }
 
 int Character_GetBaseline(CharacterInfo *chaa) {
-
 	if (chaa->baseline < 1)
 		return 0;
 
@@ -1433,8 +1433,15 @@ void Character_SetSpeechAnimationDelay(CharacterInfo *chaa, int newDelay) {
 	chaa->speech_anim_speed = newDelay;
 }
 
-int Character_GetSpeechView(CharacterInfo *chaa) {
+int Character_GetIdleAnimationDelay(CharacterInfo *chaa) {
+	return chaa->idle_anim_speed;
+}
+
+void Character_SetIdleAnimationDelay(CharacterInfo *chaa, int newDelay) {
+	chaa->idle_anim_speed = newDelay;
+}
 
+int Character_GetSpeechView(CharacterInfo *chaa) {
 	return chaa->talkview + 1;
 }
 
@@ -3409,6 +3416,15 @@ RuntimeScriptValue Sc_Character_SetSpeechAnimationDelay(void *self, const Runtim
 	API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetSpeechAnimationDelay);
 }
 
+RuntimeScriptValue Sc_Character_GetIdleAnimationDelay(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_INT(CharacterInfo, Character_GetIdleAnimationDelay);
+}
+
+// void (CharacterInfo *chaa, int newDelay)
+RuntimeScriptValue Sc_Character_SetIdleAnimationDelay(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetIdleAnimationDelay);
+}
+
 // int (CharacterInfo *chaa)
 RuntimeScriptValue Sc_Character_GetSpeechColor(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(CharacterInfo, Character_GetSpeechColor);
@@ -3621,6 +3637,8 @@ void RegisterCharacterAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api
 		ccAddExternalObjectFunction("Character::get_HasExplicitTint",       Sc_Character_GetHasExplicitTint);
 	ccAddExternalObjectFunction("Character::get_ID",                    Sc_Character_GetID);
 	ccAddExternalObjectFunction("Character::get_IdleView",              Sc_Character_GetIdleView);
+	ccAddExternalObjectFunction("Character::get_IdleAnimationDelay",    Sc_Character_GetIdleAnimationDelay);
+	ccAddExternalObjectFunction("Character::set_IdleAnimationDelay",    Sc_Character_SetIdleAnimationDelay);
 	ccAddExternalObjectFunction("Character::geti_InventoryQuantity",    Sc_Character_GetIInventoryQuantity);
 	ccAddExternalObjectFunction("Character::seti_InventoryQuantity",    Sc_Character_SetIInventoryQuantity);
 	ccAddExternalObjectFunction("Character::get_IgnoreLighting",        Sc_Character_GetIgnoreLighting);
diff --git a/engines/ags/engine/ac/character_info_engine.cpp b/engines/ags/engine/ac/character_info_engine.cpp
index d30c4f7f005..1e069308e9b 100644
--- a/engines/ags/engine/ac/character_info_engine.cpp
+++ b/engines/ags/engine/ac/character_info_engine.cpp
@@ -360,7 +360,7 @@ int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
 			wait = _GP(views)[view].loops[loop].frames[frame].speed;
 			// idle anim doesn't have speed stored cos animating==0
 			if (idleleft < 0)
-				wait += animspeed + 5;
+				wait += idle_anim_speed;
 			else
 				wait += (animating >> 8) & 0x00ff;
 
@@ -485,10 +485,9 @@ void CharacterInfo::update_character_idle(CharacterExtras *chex, int &doing_noth
 			else if (useloop >= maxLoops)
 				useloop = 0;
 
-			animate_character(this, useloop,
-			                  animspeed + 5, (idletime == 0) ? 1 : 0, 1);
+			animate_character(this, useloop, idle_anim_speed, (idletime == 0) ? 1 : 0, 1);
 
-			// don't set Animating while the idle anim plays
+			// don't set Animating while the idle anim plays (TODO: investigate why?)
 			animating = 0;
 		}
 	}  // end do idle animation
diff --git a/engines/ags/shared/ac/character_info.cpp b/engines/ags/shared/ac/character_info.cpp
index 43fd014601a..1f37d51c93f 100644
--- a/engines/ags/shared/ac/character_info.cpp
+++ b/engines/ags/shared/ac/character_info.cpp
@@ -21,13 +21,14 @@
 
 #include "common/str.h"
 #include "ags/shared/ac/character_info.h"
+#include "ags/shared/ac/game_version.h"
 #include "ags/shared/util/stream.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using AGS::Shared::Stream;
 
-
 void CharacterInfo::ReadFromFile(Stream *in) {
 	defview = in->ReadInt32();
 	talkview = in->ReadInt32();
@@ -57,7 +58,7 @@ void CharacterInfo::ReadFromFile(Stream *in) {
 	z = in->ReadInt32();
 	walkwait = in->ReadInt32();
 	speech_anim_speed = in->ReadInt16();
-	reserved1 = in->ReadInt16();
+	idle_anim_speed = in->ReadInt16();
 	blocking_width = in->ReadInt16();
 	blocking_height = in->ReadInt16();
 	index_id = in->ReadInt32();
@@ -75,6 +76,9 @@ void CharacterInfo::ReadFromFile(Stream *in) {
 	in->Read(name, 40);
 	in->Read(scrname, MAX_SCRIPT_NAME_LEN);
 	on = in->ReadInt8();
+
+	if (_G(loaded_game_file_version) < kGameVersion_360_16)
+		idle_anim_speed = animspeed + 5;
 }
 
 void CharacterInfo::WriteToFile(Stream *out) {
@@ -106,7 +110,7 @@ void CharacterInfo::WriteToFile(Stream *out) {
 	out->WriteInt32(z);
 	out->WriteInt32(walkwait);
 	out->WriteInt16(speech_anim_speed);
-	out->WriteInt16(reserved1);
+	out->WriteInt16(idle_anim_speed);
 	out->WriteInt16(blocking_width);
 	out->WriteInt16(blocking_height);
 	out->WriteInt32(index_id);
diff --git a/engines/ags/shared/ac/character_info.h b/engines/ags/shared/ac/character_info.h
index bda7799db9c..1f4ae82b648 100644
--- a/engines/ags/shared/ac/character_info.h
+++ b/engines/ags/shared/ac/character_info.h
@@ -61,8 +61,10 @@ using namespace AGS; // FIXME later
 #define FOLLOW_ALWAYSONTOP  0x7ffe
 
 struct CharacterExtras; // forward declaration
-// remember - if change this struct, also change AGSDEFNS.SH and
-// plugin header file struct
+// IMPORTANT: exposed to script API, and plugin API as AGSCharacter!
+// For older script compatibility the struct also has to maintain its size;
+// do not extend or change existing fields, unless planning breaking compatibility.
+// Use CharacterExtras struct for any extensions
 struct CharacterInfo {
 	int   defview;
 	int   talkview;
@@ -85,7 +87,7 @@ struct CharacterInfo {
 	short pic_yoffs; // this is fixed in screen coordinates
 	int   z;    // z-location, for flying etc
 	int   walkwait;
-	short speech_anim_speed, reserved1;  // only 1 reserved left!!
+	short speech_anim_speed, idle_anim_speed;
 	short blocking_width, blocking_height;
 	int   index_id;  // used for object functions to know the id
 	short pic_xoffs; // this is fixed in screen coordinates


Commit: 25d6339101cf75b91769dc0148d722c71bdcdcff
    https://github.com/scummvm/scummvm/commit/25d6339101cf75b91769dc0148d722c71bdcdcff
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: Fixed redo_walkable_areas() in case of out of range colors

>From upstream 81bb535b6e152d503695834b8b118e280c0449d8

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


diff --git a/engines/ags/engine/ac/walkable_area.cpp b/engines/ags/engine/ac/walkable_area.cpp
index 73e4042f976..8b1aa21b7d0 100644
--- a/engines/ags/engine/ac/walkable_area.cpp
+++ b/engines/ags/engine/ac/walkable_area.cpp
@@ -38,18 +38,15 @@ namespace AGS3 {
 using namespace AGS::Shared;
 
 void redo_walkable_areas() {
-	_GP(thisroom).WalkAreaMask->Blit(_G(walkareabackup), 0, 0, 0, 0, _GP(thisroom).WalkAreaMask->GetWidth(), _GP(thisroom).WalkAreaMask->GetHeight());
-
-	int hh, ww;
-	for (hh = 0; hh < _G(walkareabackup)->GetHeight(); hh++) {
-		uint8_t *walls_scanline = _GP(thisroom).WalkAreaMask->GetScanLineForWriting(hh);
-		for (ww = 0; ww < _G(walkareabackup)->GetWidth(); ww++) {
-			//      if (_GP(play).walkable_areas_on[_getpixel(_GP(thisroom).WalkAreaMask,ww,hh)]==0)
-			if (_GP(play).walkable_areas_on[walls_scanline[ww]] == 0)
-				walls_scanline[ww] = 0;
+	_GP(thisroom).WalkAreaMask->Blit(_G(walkareabackup), 0, 0);
+	for (int h = 0; h < _G(walkareabackup)->GetHeight(); ++h) {
+		uint8_t *walls_scanline = _GP(thisroom).WalkAreaMask->GetScanLineForWriting(h);
+		for (int w = 0; w < _G(walkareabackup)->GetWidth(); ++w) {
+			if ((walls_scanline[w] >= sizeof(_GP(play).walkable_areas_on)) ||
+				(_GP(play).walkable_areas_on[walls_scanline[w]] == 0))
+				walls_scanline[w] = 0;
 		}
 	}
-
 }
 
 int get_walkable_area_pixel(int x, int y) {


Commit: dcb1099f2bfed167c0a42447c653c91ab1da856a
    https://github.com/scummvm/scummvm/commit/dcb1099f2bfed167c0a42447c653c91ab1da856a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: Cursor.AnimationDelay property and arg to ChangeModeView()

>From upstream 7393b0a8ee8a23949b63cf8ba57eb1c4f4e381fd

Changed paths:
    engines/ags/engine/ac/draw.cpp
    engines/ags/engine/ac/mouse.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/shared/ac/mouse_cursor.cpp
    engines/ags/shared/ac/mouse_cursor.h
    engines/ags/shared/game/main_game_file.cpp


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 13edc7c7df7..18c8c50cc51 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2204,7 +2204,7 @@ void construct_game_screen_overlay(bool draw_mouse) {
 			if (_G(mouse_frame) >= _GP(views)[viewnum].loops[loopnum].numFrames)
 				_G(mouse_frame) = 0;
 			set_new_cursor_graphic(_GP(views)[viewnum].loops[loopnum].frames[_G(mouse_frame)].pic);
-			_G(mouse_delay) = _GP(views)[viewnum].loops[loopnum].frames[_G(mouse_frame)].speed + 5;
+			_G(mouse_delay) = _GP(views)[viewnum].loops[loopnum].frames[_G(mouse_frame)].speed + _GP(game).mcurs[_G(cur_cursor)].animdelay;
 			CheckViewFrame(viewnum, loopnum, _G(mouse_frame));
 		}
 		_G(lastmx) = _G(mousex);
diff --git a/engines/ags/engine/ac/mouse.cpp b/engines/ags/engine/ac/mouse.cpp
index ac6bbdf9223..8e5edbf4bf5 100644
--- a/engines/ags/engine/ac/mouse.cpp
+++ b/engines/ags/engine/ac/mouse.cpp
@@ -184,13 +184,15 @@ void ChangeCursorHotspot(int curs, int x, int y) {
 		set_mouse_cursor(_G(cur_cursor));
 }
 
-void Mouse_ChangeModeView(int curs, int newview) {
+void Mouse_ChangeModeViewEx(int curs, int newview, int delay) {
 	if ((curs < 0) || (curs >= _GP(game).numcursors))
 		quit("!Mouse.ChangeModeView: invalid mouse cursor");
 
 	newview--;
 
 	_GP(game).mcurs[curs].view = newview;
+	if (delay != SCR_NO_VALUE)
+		_GP(game).mcurs[curs].animdelay = delay;
 
 	if (newview >= 0) {
 		precache_view(newview);
@@ -200,6 +202,10 @@ void Mouse_ChangeModeView(int curs, int newview) {
 		_G(mouse_delay) = 0;  // force update
 }
 
+void Mouse_ChangeModeView(int curs, int newview) {
+	Mouse_ChangeModeViewEx(curs, newview, SCR_NO_VALUE);
+}
+
 void SetNextCursor() {
 	set_cursor_mode(find_next_enabled_cursor(_G(cur_mode) + 1));
 }
@@ -437,10 +443,14 @@ RuntimeScriptValue Sc_ChangeCursorHotspot(const RuntimeScriptValue *params, int3
 }
 
 // void (int curs, int newview)
-RuntimeScriptValue Sc_Mouse_ChangeModeView(const RuntimeScriptValue *params, int32_t param_count) {
+RuntimeScriptValue Sc_Mouse_ChangeModeView_2(const RuntimeScriptValue *params, int32_t param_count) {
 	API_SCALL_VOID_PINT2(Mouse_ChangeModeView);
 }
 
+RuntimeScriptValue Sc_Mouse_ChangeModeView(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_VOID_PINT3(Mouse_ChangeModeViewEx);
+}
+
 // void (int modd)
 RuntimeScriptValue Sc_disable_cursor_mode(const RuntimeScriptValue *params, int32_t param_count) {
 	API_SCALL_VOID_PINT(disable_cursor_mode);
@@ -552,7 +562,8 @@ RuntimeScriptValue Sc_Mouse_SetSpeed(const RuntimeScriptValue *params, int32_t p
 void RegisterMouseAPI() {
 	ccAddExternalStaticFunction("Mouse::ChangeModeGraphic^2", Sc_ChangeCursorGraphic);
 	ccAddExternalStaticFunction("Mouse::ChangeModeHotspot^3", Sc_ChangeCursorHotspot);
-	ccAddExternalStaticFunction("Mouse::ChangeModeView^2", Sc_Mouse_ChangeModeView);
+	ccAddExternalStaticFunction("Mouse::ChangeModeView^2", Sc_Mouse_ChangeModeView_2);
+	ccAddExternalStaticFunction("Mouse::ChangeModeView^3", Sc_Mouse_ChangeModeView);
 	ccAddExternalStaticFunction("Mouse::Click^1", Sc_Mouse_Click);
 	ccAddExternalStaticFunction("Mouse::DisableMode^1", Sc_disable_cursor_mode);
 	ccAddExternalStaticFunction("Mouse::EnableMode^1", Sc_enable_cursor_mode);
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index c607e4433b6..675621cf2e8 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -675,7 +675,7 @@ HSaveError ReadMouseCursors(Stream *in, int32_t cmp_ver, const PreservedParams &
 	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numcursors, "Mouse Cursors"))
 		return err;
 	for (int i = 0; i < _GP(game).numcursors; ++i) {
-		_GP(game).mcurs[i].ReadFromSavegame(in);
+		_GP(game).mcurs[i].ReadFromSavegame(in, cmp_ver);
 	}
 	return err;
 }
@@ -1059,7 +1059,7 @@ ComponentHandler ComponentHandlers[] = {
 	},
 	{
 		"Mouse Cursors",
-		0,
+		1,
 		0,
 		WriteMouseCursors,
 		ReadMouseCursors
diff --git a/engines/ags/shared/ac/mouse_cursor.cpp b/engines/ags/shared/ac/mouse_cursor.cpp
index f4a1f42972d..2dff2e01dc5 100644
--- a/engines/ags/shared/ac/mouse_cursor.cpp
+++ b/engines/ags/shared/ac/mouse_cursor.cpp
@@ -27,18 +27,11 @@ namespace AGS3 {
 
 using AGS::Shared::Stream;
 
-MouseCursor::MouseCursor() {
-	clear();
-}
-
 void MouseCursor::clear() {
-	pic = 2054;
-	hotx = 0;
-	hoty = 0;
+	pic = 0;
+	hotx = hoty = 0;
 	view = -1;
-	for (uint8 i = 0; i < ARRAYSIZE(name); i++) {
-		name[i] = 0;
-	}
+	Common::fill(&name[0], &name[10], '\0');
 	flags = 0;
 }
 
@@ -60,12 +53,14 @@ void MouseCursor::WriteToFile(Stream *out) {
 	out->WriteInt8(flags);
 }
 
-void MouseCursor::ReadFromSavegame(Stream *in) {
+void MouseCursor::ReadFromSavegame(Stream *in, int cmp_ver) {
 	pic = in->ReadInt32();
 	hotx = in->ReadInt32();
 	hoty = in->ReadInt32();
 	view = in->ReadInt32();
 	flags = in->ReadInt32();
+	if (cmp_ver > 0)
+		animdelay = in->ReadInt32();
 }
 
 void MouseCursor::WriteToSavegame(Stream *out) const {
@@ -74,6 +69,7 @@ void MouseCursor::WriteToSavegame(Stream *out) const {
 	out->WriteInt32(hoty);
 	out->WriteInt32(view);
 	out->WriteInt32(flags);
+	out->WriteInt32(animdelay);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/shared/ac/mouse_cursor.h b/engines/ags/shared/ac/mouse_cursor.h
index 807752dbd47..6e65290bdca 100644
--- a/engines/ags/shared/ac/mouse_cursor.h
+++ b/engines/ags/shared/ac/mouse_cursor.h
@@ -38,21 +38,25 @@ using namespace AGS; // FIXME later
 #define MCF_DISABLED 2
 #define MCF_STANDARD 4
 #define MCF_HOTSPOT  8  // only animate when over hotspot
-// this struct is also in the plugin header file
 
+// IMPORTANT: exposed to plugin API as AGSCursor!
+// do not change topmost fields, unless planning breaking compatibility.
 struct MouseCursor {
-	int   pic;
-	short hotx, hoty;
-	short view;
-	char  name[10];
-	int8  flags;
+	int   pic = 0;
+	short hotx = 0, hoty = 0;
+	short view = -1;
+	char  name[10]{};
+	char  flags = 0;
 
-	MouseCursor();
+	// up to here is a part of plugin API
+	int   animdelay = 5;
+
+	MouseCursor() {}
 
 	void clear();
 	void ReadFromFile(Shared::Stream *in);
 	void WriteToFile(Shared::Stream *out);
-	void ReadFromSavegame(Shared::Stream *in);
+	void ReadFromSavegame(Shared::Stream *in, int cmp_ver);
 	void WriteToSavegame(Shared::Stream *out) const;
 };
 
diff --git a/engines/ags/shared/game/main_game_file.cpp b/engines/ags/shared/game/main_game_file.cpp
index cb79f70dfdb..065a5166bb5 100644
--- a/engines/ags/shared/game/main_game_file.cpp
+++ b/engines/ags/shared/game/main_game_file.cpp
@@ -734,6 +734,15 @@ HError GameDataExtReader::ReadBlock(int block_id, const String &ext_id,
 			_in->ReadInt32();
 		}
 		return HError::None();
+	} else if (ext_id.CompareNoCase("v360_cursors") == 0) {
+		for (int i = 0; i < _ents.Game.numcursors; ++i) {
+			_ents.Game.mcurs[i].animdelay = _in->ReadInt32();
+			// reserved
+			_in->ReadInt32();
+			_in->ReadInt32();
+			_in->ReadInt32();
+		}
+		return HError::None();
 	}
 
     return new MainGameFileError(kMGFErr_ExtUnknown, String::FromFormat("Type: %s", ext_id.GetCStr()));


Commit: 2d63a71b22b84885c2abbf11644cf93cc69f4f2e
    https://github.com/scummvm/scummvm/commit/2d63a71b22b84885c2abbf11644cf93cc69f4f2e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: Fixed formatting of soff_t values

>From upstream 80a01b51d66f8ca3c17670527ffc1c661ff47c81

Changed paths:
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/shared/font/wfn_font.cpp
    engines/ags/shared/util/data_ext.cpp


diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 675621cf2e8..fa03c5feeed 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -1199,7 +1199,8 @@ HSaveError ReadComponent(Stream *in, SvgCmpReadHelper &hlp, ComponentInfo &info)
 	if (!err)
 		return err;
 	if (in->GetPosition() - info.DataOffset != info.DataSize)
-		return new SavegameError(kSvgErr_ComponentSizeMismatch, String::FromFormat("Expected: %lld, actual: %lld", info.DataSize, in->GetPosition() - info.DataOffset));
+		return new SavegameError(kSvgErr_ComponentSizeMismatch, String::FromFormat("Expected: %llu, actual: %llu",
+			static_cast<int64>(info.DataSize), static_cast<int64>(in->GetPosition() - info.DataOffset)));
 	if (!AssertFormatTag(in, info.Name, false))
 		return new SavegameError(kSvgErr_ComponentClosingTagFormat);
 	return HSaveError::None();
diff --git a/engines/ags/shared/font/wfn_font.cpp b/engines/ags/shared/font/wfn_font.cpp
index 61c09375ca6..0435a92a934 100644
--- a/engines/ags/shared/font/wfn_font.cpp
+++ b/engines/ags/shared/font/wfn_font.cpp
@@ -67,7 +67,8 @@ WFNError WFNFont::ReadFromFile(Stream *in, const soff_t data_size) {
 
 	const soff_t table_addr = static_cast<uint16_t>(in->ReadInt16()); // offset table relative address
 	if (table_addr < (soff_t)(WFN_FILE_SIG_LENGTH + sizeof(uint16_t)) || table_addr >= used_data_size) {
-		Debug::Printf(kDbgMsg_Error, "\tWFN: bad table address: %lld (%d - %d)", table_addr, WFN_FILE_SIG_LENGTH + sizeof(uint16_t), used_data_size);
+		Debug::Printf(kDbgMsg_Error, "\tWFN: bad table address: %llu (%llu - %llu)", static_cast<int64>(table_addr),
+			static_cast<int64>(WFN_FILE_SIG_LENGTH + sizeof(uint16_t)), static_cast<int64>(used_data_size));
 		return kWFNErr_BadTableAddress; // bad table address
 	}
 
diff --git a/engines/ags/shared/util/data_ext.cpp b/engines/ags/shared/util/data_ext.cpp
index e70de5a50ef..866ae2873b1 100644
--- a/engines/ags/shared/util/data_ext.cpp
+++ b/engines/ags/shared/util/data_ext.cpp
@@ -76,15 +76,15 @@ HError DataExtParser::PostAssert() {
 	const soff_t cur_pos = _in->GetPosition();
 	const soff_t block_end = _blockStart + _blockLen;
 	if (cur_pos > block_end) {
-		String err = String::FromFormat("Block: '%s', expected to end at offset: %lld, finished reading at %lld.",
-			_extID.GetCStr(), block_end, cur_pos);
+		String err = String::FromFormat("Block: '%s', expected to end at offset: %llu, finished reading at %llu.",
+			_extID.GetCStr(), static_cast<int64>(block_end), static_cast<int64>(cur_pos));
 		if (cur_pos <= block_end + GetOverLeeway(_blockID))
 			Debug::Printf(kDbgMsg_Warn, err);
 		else
 			return new DataExtError(kDataExtErr_BlockDataOverlapping, err);
 	} else if (cur_pos < block_end) {
-		Debug::Printf(kDbgMsg_Warn, "WARNING: data blocks nonsequential, block '%s' expected to end at %lld, finished reading at %lld",
-			_extID.GetCStr(), block_end, cur_pos);
+		Debug::Printf(kDbgMsg_Warn, "WARNING: data blocks nonsequential, block '%s' expected to end at %llu, finished reading at %llu",
+			_extID.GetCStr(), static_cast<int64>(block_end), static_cast<int64>(cur_pos));
 		_in->Seek(block_end, Shared::kSeekBegin);
 	}
 	return HError::None();


Commit: 645124bb4575efec9322d5a61383543f1011d5ec
    https://github.com/scummvm/scummvm/commit/645124bb4575efec9322d5a61383543f1011d5ec
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-10T19:39:09-07:00

Commit Message:
AGS: RLE decompressing: Redefined char as int8

>From upstream 22797ccdf6746767cbc5bf99ef9cbad7702d8140

Changed paths:
    engines/ags/shared/util/compress.cpp


diff --git a/engines/ags/shared/util/compress.cpp b/engines/ags/shared/util/compress.cpp
index d8aad60bda7..a123fa88c0b 100644
--- a/engines/ags/shared/util/compress.cpp
+++ b/engines/ags/shared/util/compress.cpp
@@ -154,7 +154,7 @@ static int cunpackbitl(uint8_t *line, size_t size, Stream *in) {
 		if (in->HasErrors())
 			break;
 
-		char cx = ix;
+		int8 cx = ix;
 		if (cx == -128)
 			cx = 0;
 
@@ -191,7 +191,7 @@ static int cunpackbitl16(uint16_t *line, size_t size, Stream *in) {
 		if (in->HasErrors())
 			break;
 
-		char cx = ix;
+		int8 cx = ix;
 		if (cx == -128)
 			cx = 0;
 
@@ -228,7 +228,7 @@ static int cunpackbitl32(uint32_t *line, size_t size, Stream *in) {
 		if (in->HasErrors())
 			break;
 
-		char cx = ix;
+		int8 cx = ix;
 		if (cx == -128)
 			cx = 0;
 




More information about the Scummvm-git-logs mailing list