[Scummvm-git-logs] scummvm master -> 7c7c94d85a709ae6f946e22048abd8beae821aaa

dreammaster noreply at scummvm.org
Wed May 11 04:40:41 UTC 2022


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

Summary:
81a99e5fc4 AGS: Fix keypresses in textboxes
898650ebbd AGS: Fix WriteOverlays method
d39c6cb31f AGS: Added "sound volume" param to all Animate() functions
214ef6eec3 AGS: Implemented Character.AnimationVolume
4718557ac8 AGS: Made Animate's volume be relative to Character.AnimateVolume
316d213372 AGS: Fixed WFN clip causing misplaced letters + small tidyup
c465ba977d AGS: Bitmap make data const in functor
c54f4d1c10 AGS: Guibutton, removes non-updated comment
eb7421400c AGS: Use empty() to check for emptiness in vector
706766f4b5 AGS: Guimain tidy-up
4d2bad4cfa AGS: cc_script GetSectionName can be made const
23f8e4f87c AGS: Avoid copying PfnWriteExtBlock in data_ext
8a4186f225 AGS: Bit simplified DDB::GetWidthToRender()
91d25a3098 AGS: Added animation volumes to save format
1933841f79 AGS: Removed numgui* variables, use size of vectors instead
7c7c94d85a AGS: Fixed crash when quitting with error during restoring a save


Commit: 81a99e5fc443f8b66d69fd13e876881031f6d841
    https://github.com/scummvm/scummvm/commit/81a99e5fc443f8b66d69fd13e876881031f6d841
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T20:17:22-07:00

Commit Message:
AGS: Fix keypresses in textboxes

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


diff --git a/engines/ags/engine/ac/sys_events.cpp b/engines/ags/engine/ac/sys_events.cpp
index 20b3d0ab097..182efc6e5f3 100644
--- a/engines/ags/engine/ac/sys_events.cpp
+++ b/engines/ags/engine/ac/sys_events.cpp
@@ -65,6 +65,7 @@ static void(*_on_switchout_callback)(void) = nullptr;
 KeyInput ags_keycode_from_scummvm(const Common::Event &event, bool old_keyhandle) {
 	KeyInput ki;
 
+	ki.UChar = event.kbd.ascii;
 	ki.Key = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, old_keyhandle);
 	ki.CompatKey = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, true);
 


Commit: 898650ebbdb2b0fca9e3f44ff5eec624acb83c73
    https://github.com/scummvm/scummvm/commit/898650ebbdb2b0fca9e3f44ff5eec624acb83c73
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:52-07:00

Commit Message:
AGS: Fix WriteOverlays method

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


diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index f0ce10426d7..2af2e578fe1 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -759,6 +759,7 @@ HSaveError ReadDynamicSprites(Stream *in, int32_t /*cmp_ver*/, const PreservedPa
 }
 
 HSaveError WriteOverlays(Stream *out) {
+	out->WriteInt32(_GP(screenover).size());
 	for (const auto &over : _GP(screenover)) {
 		over.WriteToFile(out);
 		if (!over.IsSpriteReference())


Commit: d39c6cb31f473d323f994648fd78abca1ae28700
    https://github.com/scummvm/scummvm/commit/d39c6cb31f473d323f994648fd78abca1ae28700
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:59-07:00

Commit Message:
AGS: Added "sound volume" param to all Animate() functions

>From upstream 926220f9706baafa80d05ff6264f7fa13296dc16

Changed paths:
    engines/ags/engine/ac/button.cpp
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/character.h
    engines/ags/engine/ac/character_extras.h
    engines/ags/engine/ac/character_info_engine.cpp
    engines/ags/engine/ac/global_object.cpp
    engines/ags/engine/ac/global_object.h
    engines/ags/engine/ac/object.cpp
    engines/ags/engine/ac/room_object.cpp
    engines/ags/engine/ac/room_object.h
    engines/ags/engine/ac/view_frame.cpp
    engines/ags/engine/ac/view_frame.h
    engines/ags/engine/gui/animating_gui_button.h
    engines/ags/engine/script/script_api.h


diff --git a/engines/ags/engine/ac/button.cpp b/engines/ags/engine/ac/button.cpp
index ae62bb535bc..207d41767f6 100644
--- a/engines/ags/engine/ac/button.cpp
+++ b/engines/ags/engine/ac/button.cpp
@@ -55,7 +55,8 @@ void UpdateButtonState(const AnimatingGUIButton &abtn) {
 	_GP(guibuts)[abtn.buttonid].MouseOverImage = 0;
 }
 
-void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe) {
+void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed,
+		int repeat, int blocking, int direction, int sframe, int volume = -1) {
 	int guin = butt->ParentId;
 	int objn = butt->Id;
 
@@ -82,6 +83,8 @@ void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat
 	if ((direction < 0) || (direction > 1))
 		quit("!AnimateButton: invalid direction");
 
+	volume = std::min(volume, 100); // NOTE: negative volume means use defaults
+
 	// if it's already animating, stop it
 	FindAndRemoveButtonAnimation(guin, objn);
 
@@ -104,6 +107,7 @@ void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat
 	abtn.direction = direction;
 	abtn.frame = sframe;
 	abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
+	abtn.volume = volume;
 	_GP(animbuts).push_back(abtn);
 	// launch into the first frame, and play the first frame's sound
 	UpdateButtonState(abtn);
@@ -115,7 +119,7 @@ void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat
 }
 
 void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat) {
-	Button_AnimateEx(butt, view, loop, speed, repeat, IN_BACKGROUND, FORWARDS, 0);
+	Button_AnimateEx(butt, view, loop, speed, repeat, IN_BACKGROUND, FORWARDS, 0, -1);
 }
 
 const char *Button_GetText_New(GUIButton *butt) {
@@ -260,7 +264,7 @@ bool UpdateAnimatingButton(int bu) {
 	if (!CycleViewAnim(abtn.view, abtn.loop, abtn.frame, !abtn.direction,
 		abtn.repeat != 0 ? ANIM_REPEAT : ANIM_ONCE))
 		return false;
-	CheckViewFrame(abtn.view, abtn.loop, abtn.frame);
+	CheckViewFrame(abtn.view, abtn.loop, abtn.frame, abtn.volume);
 	abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
 	UpdateButtonState(abtn);
 	return true;
@@ -341,7 +345,7 @@ RuntimeScriptValue Sc_Button_Animate(void *self, const RuntimeScriptValue *param
 }
 
 RuntimeScriptValue Sc_Button_AnimateEx(void *self, const RuntimeScriptValue *params, int32_t param_count) {
-	API_OBJCALL_VOID_PINT7(GUIButton, Button_AnimateEx);
+	API_OBJCALL_VOID_PINT8(GUIButton, Button_AnimateEx);
 }
 
 // const char* | GUIButton *butt
@@ -454,7 +458,7 @@ RuntimeScriptValue Sc_Button_GetView(void *self, const RuntimeScriptValue *param
 
 void RegisterButtonAPI() {
 	ccAddExternalObjectFunction("Button::Animate^4", Sc_Button_Animate);
-	ccAddExternalObjectFunction("Button::Animate^7", Sc_Button_AnimateEx);
+	ccAddExternalObjectFunction("Button::Animate^8", Sc_Button_AnimateEx);
 	ccAddExternalObjectFunction("Button::Click^1", Sc_Button_Click);
 	ccAddExternalObjectFunction("Button::GetText^1", Sc_Button_GetText);
 	ccAddExternalObjectFunction("Button::SetText^1", Sc_Button_SetText);
diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index 983561e3f1a..f46a41383fd 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -153,25 +153,32 @@ void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) {
 
 }
 
-void Character_AnimateFrom(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction, int sframe) {
-
+void Character_AnimateEx(CharacterInfo *chaa, int loop, int delay, int repeat,
+	int blocking, int direction, int sframe, int volume = -1) {
 	if (direction == FORWARDS)
 		direction = 0;
 	else if (direction == BACKWARDS)
 		direction = 1;
-	else
-		quit("!Character.Animate: Invalid DIRECTION parameter");
+	if (blocking == BLOCKING)
+		blocking = 1;
+	else if (blocking == IN_BACKGROUND)
+		blocking = 0;
 
-	animate_character(chaa, loop, delay, repeat, 0, direction, sframe);
+	if ((repeat < 0) || (repeat > 1))
+		quit("!Character.Animate: invalid repeat value");
+	if ((blocking < 0) || (blocking > 1))
+		quit("!Character.Animate: invalid blocking value");
+	if ((direction < 0) || (direction > 1))
+		quit("!Character.Animate: invalid direction");
 
-	if ((blocking == BLOCKING) || (blocking == 1))
+	animate_character(chaa, loop, delay, repeat, 0, direction, sframe, volume);
+
+	if (blocking != 0)
 		GameLoopUntilValueIsZero(&chaa->animating);
-	else if ((blocking != IN_BACKGROUND) && (blocking != 0))
-		quit("!Character.Animate: Invalid BLOCKING parameter");
 }
 
 void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction) {
-	Character_AnimateFrom(chaa, loop, delay, repeat, blocking, direction, 0);
+	Character_AnimateEx(chaa, loop, delay, repeat, blocking, direction, 0, -1);
 }
 
 void Character_ChangeRoomAutoPosition(CharacterInfo *chaa, int room, int newPos) {
@@ -259,7 +266,7 @@ void Character_ChangeView(CharacterInfo *chap, int vii) {
 	debug_script_log("%s: Change view to %d", chap->scrname, vii + 1);
 	chap->defview = vii;
 	chap->view = vii;
-	chap->animating = 0;
+	stop_character_anim(chap);
 	chap->frame = 0;
 	chap->wait = 0;
 	chap->walkwait = 0;
@@ -548,7 +555,7 @@ void Character_LockViewEx(CharacterInfo *chap, int vii, int stopMoving) {
 		Character_StopMoving(chap);
 	}
 	chap->view = vii;
-	chap->animating = 0;
+	stop_character_anim(chap);
 	FindReasonableLoopForCharacter(chap);
 	chap->frame = 0;
 	chap->wait = 0;
@@ -932,7 +939,7 @@ void Character_UnlockViewEx(CharacterInfo *chaa, int stopMoving) {
 			maxloop = 4;
 		FindReasonableLoopForCharacter(chaa);
 	}
-	chaa->animating = 0;
+	stop_character_anim(chaa);
 	chaa->idleleft = chaa->idletime;
 	chaa->pic_xoffs = 0;
 	chaa->pic_yoffs = 0;
@@ -1585,7 +1592,7 @@ void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims)
 	}
 
 	if ((chin->animating) && (autoWalkAnims))
-		chin->animating = 0;
+		stop_character_anim(chin);
 
 	if (chin->idleleft < 0) {
 		ReleaseCharacterView(chac);
@@ -2013,13 +2020,14 @@ void setup_player_character(int charid) {
 	}
 }
 
-void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int noidleoverride, int direction, int sframe) {
-
+void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept,
+	int noidleoverride, int direction, int sframe, int volume) {
 	if ((chap->view < 0) || (chap->view > _GP(game).numviews)) {
 		quitprintf("!AnimateCharacter: you need to set the view number first\n"
-		           "(trying to animate '%s' using loop %d. View is currently %d).", chap->name, loopn, chap->view + 1);
+			"(trying to animate '%s' using loop %d. View is currently %d).", chap->name, loopn, chap->view + 1);
 	}
-	debug_script_log("%s: Start anim view %d loop %d, spd %d, repeat %d, frame: %d", chap->scrname, chap->view + 1, loopn, sppd, rept, sframe);
+	debug_script_log("%s: Start anim view %d loop %d, spd %d, repeat %d, frame: %d",
+		chap->scrname, chap->view + 1, loopn, sppd, rept, sframe);
 	if ((chap->idleleft < 0) && (noidleoverride == 0)) {
 		// if idle view in progress for the character (and this is not the
 		// "start idle animation" animate_character call), stop the idle anim
@@ -2046,30 +2054,39 @@ void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int n
 			sframe = _GP(views)[chap->view].loops[loopn].numFrames - (-sframe);
 	}
 	chap->frame = sframe;
-
 	chap->wait = sppd + _GP(views)[chap->view].loops[loopn].frames[chap->frame].speed;
+	_GP(charextra)[chap->index_id].cur_anim_volume = std::min(100, volume);
+
 	CheckViewFrameForCharacter(chap);
 }
 
-void CheckViewFrameForCharacter(CharacterInfo *chi) {
-
-	int soundVolume = SCR_NO_VALUE;
+void stop_character_anim(CharacterInfo *chap) { // TODO: may expand with resetting more properties,
+  // but have to be careful to not break logic somewhere
+	chap->animating = 0;
+	_GP(charextra)[chap->index_id].cur_anim_volume = -1;
+}
 
+void CheckViewFrameForCharacter(CharacterInfo *chi) {
+	int frame_vol = -1;
+	// If there's an explicit animation volume - use that first
+	if (_GP(charextra)[chi->index_id].cur_anim_volume >= 0) {
+		frame_vol = _GP(charextra)[chi->index_id].cur_anim_volume;
+	}
+	// Adjust the sound volume using the character's zoom level
+	// NOTE: historically scales only in 0-100 range :/
 	if (chi->flags & CHF_SCALEVOLUME) {
-		// adjust the sound volume using the character's zoom level
 		int zoom_level = _GP(charextra)[chi->index_id].zoom;
-		if (zoom_level == 0)
+		if (zoom_level <= 0)
 			zoom_level = 100;
-
-		soundVolume = zoom_level;
-
-		if (soundVolume < 0)
-			soundVolume = 0;
-		if (soundVolume > 100)
-			soundVolume = 100;
+		else
+			zoom_level = std::min(zoom_level, 100);
+		if (frame_vol < 0)
+			frame_vol = zoom_level;
+		else
+			frame_vol = frame_vol * zoom_level / 100;
 	}
 
-	CheckViewFrame(chi->view, chi->loop, chi->frame, soundVolume);
+	CheckViewFrame(chi->view, chi->loop, chi->frame, frame_vol);
 }
 
 Bitmap *GetCharacterImage(int charid, int *isFlipped) {
@@ -2696,7 +2713,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 		if (_G(loaded_game_file_version) > kGameVersion_272)
 			speakingChar->loop = oldloop;
 
-		speakingChar->animating = 0;
+		stop_character_anim(speakingChar);
 		speakingChar->frame = charFrameWas;
 		speakingChar->wait = 0;
 		speakingChar->idleleft = speakingChar->idletime;
@@ -2834,8 +2851,12 @@ RuntimeScriptValue Sc_Character_Animate(void *self, const RuntimeScriptValue *pa
 	API_OBJCALL_VOID_PINT5(CharacterInfo, Character_Animate);
 }
 
-RuntimeScriptValue Sc_Character_AnimateFrom(void *self, const RuntimeScriptValue *params, int32_t param_count) {
-	API_OBJCALL_VOID_PINT6(CharacterInfo, Character_AnimateFrom);
+RuntimeScriptValue Sc_Character_Animate6(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT6(CharacterInfo, Character_AnimateEx);
+}
+
+RuntimeScriptValue Sc_Character_Animate7(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT7(CharacterInfo, Character_AnimateEx);
 }
 
 // void | CharacterInfo *chaa, int room, int x, int y
@@ -3545,7 +3566,8 @@ void RegisterCharacterAPI(ScriptAPIVersion base_api, ScriptAPIVersion /* compat_
 	ccAddExternalObjectFunction("Character::AddInventory^2",            Sc_Character_AddInventory);
 	ccAddExternalObjectFunction("Character::AddWaypoint^2",             Sc_Character_AddWaypoint);
 	ccAddExternalObjectFunction("Character::Animate^5",                 Sc_Character_Animate);
-	ccAddExternalObjectFunction("Character::Animate^6",                 Sc_Character_AnimateFrom);
+	ccAddExternalObjectFunction("Character::Animate^6",                 Sc_Character_Animate6);
+	ccAddExternalObjectFunction("Character::Animate^7",                 Sc_Character_Animate7);
 	ccAddExternalObjectFunction("Character::ChangeRoom^3",              Sc_Character_ChangeRoom);
 	ccAddExternalObjectFunction("Character::ChangeRoom^4",              Sc_Character_ChangeRoomSetLoop);
 	ccAddExternalObjectFunction("Character::ChangeRoomAutoPosition^2",  Sc_Character_ChangeRoomAutoPosition);
diff --git a/engines/ags/engine/ac/character.h b/engines/ags/engine/ac/character.h
index 43d139347ac..6b36281e414 100644
--- a/engines/ags/engine/ac/character.h
+++ b/engines/ags/engine/ac/character.h
@@ -176,7 +176,10 @@ class Bitmap;
 }
 using namespace AGS; // FIXME later
 
-void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int noidleoverride = 0, int direction = 0, int sframe = 0);
+void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept,
+	int noidleoverride = 0, int direction = 0, int sframe = 0, int volume = -1);
+// Clears up animation parameters
+void stop_character_anim(CharacterInfo *chap);
 void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims);
 int  find_looporder_index(int curloop);
 // returns 0 to use diagonal, 1 to not
diff --git a/engines/ags/engine/ac/character_extras.h b/engines/ags/engine/ac/character_extras.h
index 71f71d64a54..45de68b1745 100644
--- a/engines/ags/engine/ac/character_extras.h
+++ b/engines/ags/engine/ac/character_extras.h
@@ -54,6 +54,7 @@ struct CharacterExtras {
 	int8  process_idle_this_time = 0;
 	int8  slow_move_counter = 0;
 	short animwait = 0;
+	int   cur_anim_volume = -1; // current animation sound volume (-1 = default)
 
 	void ReadFromFile(Shared::Stream *in);
 	void WriteToFile(Shared::Stream *out);
diff --git a/engines/ags/engine/ac/character_info_engine.cpp b/engines/ags/engine/ac/character_info_engine.cpp
index 5418cac2e28..d661f358059 100644
--- a/engines/ags/engine/ac/character_info_engine.cpp
+++ b/engines/ags/engine/ac/character_info_engine.cpp
@@ -294,18 +294,19 @@ int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
 			// Normal view animation
 			const int oldframe = frame;
 
+			bool done_anim = false;
 			if ((aa == _G(char_speaking)) &&
 				(_GP(play).speech_in_post_state ||
 				((!_GP(play).speech_has_voice) &&
 					(_GP(play).close_mouth_speech_time > 0) &&
 					(_GP(play).messagetime < _GP(play).close_mouth_speech_time)))) {
 				// finished talking - stop animation
-				animating = 0;
+				done_anim = true;
 				frame = 0;
 			} else {
 				if (!CycleViewAnim(view, loop, frame, (animating & CHANIM_BACKWARDS) == 0,
 					(animating & CHANIM_REPEAT) ? ANIM_REPEAT : ANIM_ONCE)) {
-					animating = 0; // finished animating
+					done_anim = true; // finished animating
 					// end of idle anim
 					if (idleleft < 0) {
 						// constant anim, reset (need this cos animating==0)
@@ -329,6 +330,9 @@ int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
 
 			if (frame != oldframe)
 				CheckViewFrameForCharacter(this);
+
+			if (done_anim)
+				stop_character_anim(this);
 		}
 	}
 
diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index 9c2eb1caf95..ae83f7640d0 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "ags/lib/std/algorithm.h"
 #include "ags/engine/ac/global_object.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/object.h"
@@ -213,7 +214,7 @@ int GetObjectBaseline(int obn) {
 	return _G(objs)[obn].baseline;
 }
 
-void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, int blocking, int sframe) {
+void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, int blocking, int sframe, int volume) {
 	if (obn >= MANOBJNUM) {
 		scAnimateCharacter(obn - 100, loopn, spdd, rept);
 		return;
@@ -257,7 +258,8 @@ void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, in
 	_G(objs)[obn].num = Math::InRangeOrDef<uint16_t>(pic, 0);
 	if (pic > UINT16_MAX)
 		debug_script_warn("Warning: object's (id %d) sprite %d is outside of internal range (%d), reset to 0", obn, pic, UINT16_MAX);
-	CheckViewFrame(_G(objs)[obn].view, loopn, _G(objs)[obn].frame);
+	_G(objs)[obn].anim_volume = std::min(volume, 100); // NOTE: negative volume means use defaults
+	CheckViewFrame(_G(objs)[obn].view, loopn, _G(objs)[obn].frame, _G(objs)[obn].anim_volume);
 
 	if (blocking)
 		GameLoopUntilValueIsZero(&_G(objs)[obn].cycling);
diff --git a/engines/ags/engine/ac/global_object.h b/engines/ags/engine/ac/global_object.h
index 32f54e9632b..394d2f67ea7 100644
--- a/engines/ags/engine/ac/global_object.h
+++ b/engines/ags/engine/ac/global_object.h
@@ -50,7 +50,7 @@ void SetObjectBaseline(int obn, int basel);
 int  GetObjectBaseline(int obn);
 void AnimateObjectEx(int obn, int loopn, int spdd, int rept, int direction, int blocking);
 void AnimateObject(int obn, int loopn, int spdd, int rept);
-void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, int blocking, int sframe);
+void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, int blocking, int sframe, int volume = -1);
 void MergeObject(int obn);
 void StopObjectMoving(int objj);
 void ObjectOff(int obn);
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index cf731e84a10..b3b95b2e268 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -120,26 +120,29 @@ int Object_GetBaseline(ScriptObject *objj) {
 	return GetObjectBaseline(objj->id);
 }
 
-void Object_AnimateFrom(ScriptObject *objj, int loop, int delay, int repeat, int blocking, int direction, int sframe) {
+void Object_AnimateEx(ScriptObject *objj, int loop, int delay, int repeat,
+	int blocking, int direction, int sframe, int volume = -1) {
 	if (direction == FORWARDS)
 		direction = 0;
 	else if (direction == BACKWARDS)
 		direction = 1;
-	else
-		quit("!Object.Animate: Invalid DIRECTION parameter");
-
-	if ((blocking == BLOCKING) || (blocking == 1))
+	if (blocking == BLOCKING)
 		blocking = 1;
-	else if ((blocking == IN_BACKGROUND) || (blocking == 0))
+	else if (blocking == IN_BACKGROUND)
 		blocking = 0;
-	else
-		quit("!Object.Animate: Invalid BLOCKING parameter");
 
-	AnimateObjectImpl(objj->id, loop, delay, repeat, direction, blocking, sframe);
+	if ((repeat < 0) || (repeat > 1))
+		quit("!Object.Animate: invalid repeat value");
+	if ((blocking < 0) || (blocking > 1))
+		quit("!Object.Animate: invalid blocking value");
+	if ((direction < 0) || (direction > 1))
+		quit("!Object.Animate: invalid direction");
+
+	AnimateObjectImpl(objj->id, loop, delay, repeat, direction, blocking, sframe, volume);
 }
 
 void Object_Animate(ScriptObject *objj, int loop, int delay, int repeat, int blocking, int direction) {
-	Object_AnimateFrom(objj, loop, delay, repeat, blocking, direction, 0);
+	Object_AnimateEx(objj, loop, delay, repeat, blocking, direction, 0, -1);
 }
 
 void Object_StopAnimating(ScriptObject *objj) {
@@ -629,8 +632,12 @@ RuntimeScriptValue Sc_Object_Animate(void *self, const RuntimeScriptValue *param
 	API_OBJCALL_VOID_PINT5(ScriptObject, Object_Animate);
 }
 
-RuntimeScriptValue Sc_Object_AnimateFrom(void *self, const RuntimeScriptValue *params, int32_t param_count) {
-	API_OBJCALL_VOID_PINT6(ScriptObject, Object_AnimateFrom);
+RuntimeScriptValue Sc_Object_Animate6(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT6(ScriptObject, Object_AnimateEx);
+}
+
+RuntimeScriptValue Sc_Object_Animate7(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT7(ScriptObject, Object_AnimateEx);
 }
 
 // int (ScriptObject *objj, ScriptObject *obj2)
@@ -935,7 +942,8 @@ RuntimeScriptValue Sc_Object_SetY(void *self, const RuntimeScriptValue *params,
 
 void RegisterObjectAPI() {
 	ccAddExternalObjectFunction("Object::Animate^5", Sc_Object_Animate);
-	ccAddExternalObjectFunction("Object::Animate^6", Sc_Object_AnimateFrom);
+	ccAddExternalObjectFunction("Object::Animate^6", Sc_Object_Animate6);
+	ccAddExternalObjectFunction("Object::Animate^7", Sc_Object_Animate7);
 	ccAddExternalObjectFunction("Object::IsCollidingWithObject^1", Sc_Object_IsCollidingWithObject);
 	ccAddExternalObjectFunction("Object::GetName^1", Sc_Object_GetName);
 	ccAddExternalObjectFunction("Object::GetProperty^1", Sc_Object_GetProperty);
diff --git a/engines/ags/engine/ac/room_object.cpp b/engines/ags/engine/ac/room_object.cpp
index 907e3411bf1..d1d714a68e6 100644
--- a/engines/ags/engine/ac/room_object.cpp
+++ b/engines/ags/engine/ac/room_object.cpp
@@ -96,7 +96,7 @@ void RoomObject::UpdateCyclingView(int ref_id) {
 		return;
 
 	wait = vfptr->speed + overall_speed;
-	CheckViewFrame(view, loop, frame);
+	CheckViewFrame(view, loop, frame, anim_volume);
 }
 
 void RoomObject::ReadFromSavegame(Stream *in, int save_ver) {
diff --git a/engines/ags/engine/ac/room_object.h b/engines/ags/engine/ac/room_object.h
index ab77382dffe..1692029f650 100644
--- a/engines/ags/engine/ac/room_object.h
+++ b/engines/ags/engine/ac/room_object.h
@@ -65,6 +65,7 @@ struct RoomObject {
 	int8  flags;
 	// Down to here is a part of the plugin API
 	short blocking_width, blocking_height;
+	int   anim_volume = -1; // current animation volume
 	Shared::String name;
 
 	RoomObject();
diff --git a/engines/ags/engine/ac/view_frame.cpp b/engines/ags/engine/ac/view_frame.cpp
index 18b1abc316e..e8b3161d950 100644
--- a/engines/ags/engine/ac/view_frame.cpp
+++ b/engines/ags/engine/ac/view_frame.cpp
@@ -117,15 +117,15 @@ void precache_view(int view) {
 	}
 }
 
-// the specified frame has just appeared, see if we need
-// to play a sound or whatever
+// Handle the new animation frame (play linked sounds, etc)
 void CheckViewFrame(int view, int loop, int frame, int sound_volume) {
 	ScriptAudioChannel *channel = nullptr;
+	// Play a sound, if one is linked to this frame
 	if (_GP(game).IsLegacyAudioSystem()) {
 		// sound field contains legacy sound num, so we also need an actual clip index
 		const int sound = _GP(views)[view].loops[loop].frames[frame].sound;
-		int &clip_id = _GP(views)[view].loops[loop].frames[frame].audioclip;
 		if (sound > 0) {
+			int &clip_id = _GP(views)[view].loops[loop].frames[frame].audioclip;
 			if (clip_id < 0) {
 				ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(_GP(game), false, sound);
 				if (!clip)
@@ -136,13 +136,12 @@ void CheckViewFrame(int view, int loop, int frame, int sound_volume) {
 		}
 	} else {
 		if (_GP(views)[view].loops[loop].frames[frame].sound >= 0) {
-			// play this sound (eg. footstep)
 			channel = play_audio_clip_by_index(_GP(views)[view].loops[loop].frames[frame].sound);
 		}
 	}
-	if (sound_volume != SCR_NO_VALUE && channel != nullptr) {
+	if (channel && (sound_volume >= 0)) {
+		sound_volume = std::min(sound_volume, 100);
 		auto *ch = AudioChans::GetChannel(channel->id);
-
 		if (ch)
 			ch->set_volume100(ch->get_volume100() * sound_volume / 100);
 	}
diff --git a/engines/ags/engine/ac/view_frame.h b/engines/ags/engine/ac/view_frame.h
index ca23a7e6732..29f63e3ee60 100644
--- a/engines/ags/engine/ac/view_frame.h
+++ b/engines/ags/engine/ac/view_frame.h
@@ -51,7 +51,8 @@ int  ViewFrame_GetLoop(ScriptViewFrame *svf);
 int  ViewFrame_GetFrame(ScriptViewFrame *svf);
 
 void precache_view(int view);
-void CheckViewFrame(int view, int loop, int frame, int sound_volume = SCR_NO_VALUE);
+// Handle the new animation frame (play linked sounds, etc)
+void CheckViewFrame(int view, int loop, int frame, int sound_volume = -1);
 // draws a view frame, flipped if appropriate
 void DrawViewFrame(Shared::Bitmap *ds, const ViewFrame *vframe, int x, int y, bool alpha_blend = false);
 
diff --git a/engines/ags/engine/gui/animating_gui_button.h b/engines/ags/engine/gui/animating_gui_button.h
index 00caa64f78d..d8f41d6218e 100644
--- a/engines/ags/engine/gui/animating_gui_button.h
+++ b/engines/ags/engine/gui/animating_gui_button.h
@@ -39,12 +39,13 @@ class Stream;
 using namespace AGS; // FIXME later
 
 struct AnimatingGUIButton {
-	// index into _GP(guibuts) array, GUI, button
-	short buttonid = 0, ongui = 0, onguibut = 0;
+	// index into guibuts array, GUI, button
+	short buttonid = -1, ongui = -1, onguibut = -1;
 	// current animation status
 	uint16_t view = 0, loop = 0, frame = 0;
-	short speed = 0, repeat = 0, blocking = 0,
-		direction = 0, wait = 0;
+	short speed = 0, repeat = 0, blocking = 0, direction = 0, wait = 0;
+	// relative volume of the frame sounds
+	int volume = -1;
 
 	void ReadFromFile(Shared::Stream *in, int cmp_ver);
 	void WriteToFile(Shared::Stream *out);
diff --git a/engines/ags/engine/script/script_api.h b/engines/ags/engine/script/script_api.h
index 3670c05ee36..a90fee29681 100644
--- a/engines/ags/engine/script/script_api.h
+++ b/engines/ags/engine/script/script_api.h
@@ -443,6 +443,11 @@ inline const char *ScriptVSprintf(char *buffer, size_t buf_length, const char *f
     METHOD((CLASS*)self, params[0].IValue, params[1].IValue, params[2].IValue, params[3].IValue, params[4].IValue, params[5].IValue, params[6].IValue); \
     return RuntimeScriptValue((int32_t)0)
 
+#define API_OBJCALL_VOID_PINT8(CLASS, METHOD) \
+    ASSERT_OBJ_PARAM_COUNT(METHOD, 8); \
+    METHOD((CLASS*)self, params[0].IValue, params[1].IValue, params[2].IValue, params[3].IValue, params[4].IValue, params[5].IValue, params[6].IValue, params[7].IValue); \
+    return RuntimeScriptValue((int32_t)0)
+
 #define API_OBJCALL_VOID_PFLOAT(CLASS, METHOD) \
 	ASSERT_OBJ_PARAM_COUNT(METHOD, 1); \
 	METHOD((CLASS*)self, params[0].FValue); \


Commit: 214ef6eec3fa07106317e127dd265477d19abdd6
    https://github.com/scummvm/scummvm/commit/214ef6eec3fa07106317e127dd265477d19abdd6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:59-07:00

Commit Message:
AGS: Implemented Character.AnimationVolume

>From upstream a2cbdac3ebc79c59b0ee44df2ce85a7017d724cc

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


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index f46a41383fd..fb5cc8d6445 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -1069,6 +1069,15 @@ void Character_SetAnimationSpeed(CharacterInfo *chaa, int newval) {
 		chaa->idle_anim_speed = chaa->animspeed + 5;
 }
 
+int Character_GetAnimationVolume(CharacterInfo *chaa) {
+	return _GP(charextra)[chaa->index_id].anim_volume;
+}
+
+void Character_SetAnimationVolume(CharacterInfo *chaa, int newval) {
+
+	_GP(charextra)[chaa->index_id].anim_volume = std::min(newval, 100); // negative means default
+}
+
 int Character_GetBaseline(CharacterInfo *chaa) {
 	if (chaa->baseline < 1)
 		return 0;
@@ -2072,6 +2081,10 @@ void CheckViewFrameForCharacter(CharacterInfo *chi) {
 	if (_GP(charextra)[chi->index_id].cur_anim_volume >= 0) {
 		frame_vol = _GP(charextra)[chi->index_id].cur_anim_volume;
 	}
+	// Next check the character's animation volume setting
+	else if (_GP(charextra)[chi->index_id].anim_volume >= 0) {
+		frame_vol = _GP(charextra)[chi->index_id].anim_volume;
+	}
 	// Adjust the sound volume using the character's zoom level
 	// NOTE: historically scales only in 0-100 range :/
 	if (chi->flags & CHF_SCALEVOLUME) {
@@ -3159,6 +3172,14 @@ RuntimeScriptValue Sc_Character_SetAnimationSpeed(void *self, const RuntimeScrip
 	API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetAnimationSpeed);
 }
 
+RuntimeScriptValue Sc_Character_GetAnimationVolume(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_INT(CharacterInfo, Character_GetAnimationVolume);
+}
+
+RuntimeScriptValue Sc_Character_SetAnimationVolume(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetAnimationVolume);
+}
+
 // int (CharacterInfo *chaa)
 RuntimeScriptValue Sc_Character_GetBaseline(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(CharacterInfo, Character_GetBaseline);
@@ -3628,6 +3649,8 @@ void RegisterCharacterAPI(ScriptAPIVersion base_api, ScriptAPIVersion /* compat_
 	ccAddExternalObjectFunction("Character::get_Animating",             Sc_Character_GetAnimating);
 	ccAddExternalObjectFunction("Character::get_AnimationSpeed",        Sc_Character_GetAnimationSpeed);
 	ccAddExternalObjectFunction("Character::set_AnimationSpeed",        Sc_Character_SetAnimationSpeed);
+	ccAddExternalObjectFunction("Character::get_AnimationVolume",       Sc_Character_GetAnimationVolume);
+	ccAddExternalObjectFunction("Character::set_AnimationVolume",       Sc_Character_SetAnimationVolume);
 	ccAddExternalObjectFunction("Character::get_Baseline",              Sc_Character_GetBaseline);
 	ccAddExternalObjectFunction("Character::set_Baseline",              Sc_Character_SetBaseline);
 	ccAddExternalObjectFunction("Character::get_BlinkInterval",         Sc_Character_GetBlinkInterval);
diff --git a/engines/ags/engine/ac/character_extras.h b/engines/ags/engine/ac/character_extras.h
index 45de68b1745..13f4b60d13e 100644
--- a/engines/ags/engine/ac/character_extras.h
+++ b/engines/ags/engine/ac/character_extras.h
@@ -54,6 +54,7 @@ struct CharacterExtras {
 	int8  process_idle_this_time = 0;
 	int8  slow_move_counter = 0;
 	short animwait = 0;
+	int   anim_volume = -1; // default animation volume (-1 use clip default)
 	int   cur_anim_volume = -1; // current animation sound volume (-1 = default)
 
 	void ReadFromFile(Shared::Stream *in);


Commit: 4718557ac8f2990becbdadd0bf5c83e691cc7d44
    https://github.com/scummvm/scummvm/commit/4718557ac8f2990becbdadd0bf5c83e691cc7d44
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:59-07:00

Commit Message:
AGS: Made Animate's volume be relative to Character.AnimateVolume

>From upstream e079deb39511994cfb741a5f9dcf42335835c002

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 fb5cc8d6445..5a58beffe5e 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -2075,17 +2075,18 @@ void stop_character_anim(CharacterInfo *chap) { // TODO: may expand with resetti
 	_GP(charextra)[chap->index_id].cur_anim_volume = -1;
 }
 
-void CheckViewFrameForCharacter(CharacterInfo *chi) {
-	int frame_vol = -1;
-	// If there's an explicit animation volume - use that first
-	if (_GP(charextra)[chi->index_id].cur_anim_volume >= 0) {
+void CheckViewFrameForCharacter(CharacterInfo * chi) {
+	// We view the audio property relation as the relation of the entities:
+	// system -> audio type -> audio emitter (character) -> animation's audio
+	// therefore the sound volume is a multiplication of factors.
+	int frame_vol = 100; // default to full volume
+	// Try the active animation volume
+	if (_GP(charextra)[chi->index_id].cur_anim_volume >= 0)
 		frame_vol = _GP(charextra)[chi->index_id].cur_anim_volume;
-	}
-	// Next check the character's animation volume setting
-	else if (_GP(charextra)[chi->index_id].anim_volume >= 0) {
-		frame_vol = _GP(charextra)[chi->index_id].anim_volume;
-	}
-	// Adjust the sound volume using the character's zoom level
+	// Try the character's own animation volume property
+	if (_GP(charextra)[chi->index_id].anim_volume >= 0)
+		frame_vol = frame_vol * _GP(charextra)[chi->index_id].anim_volume / 100;
+	// Try the character's zoom volume scaling (optional)
 	// NOTE: historically scales only in 0-100 range :/
 	if (chi->flags & CHF_SCALEVOLUME) {
 		int zoom_level = _GP(charextra)[chi->index_id].zoom;
@@ -2093,10 +2094,7 @@ void CheckViewFrameForCharacter(CharacterInfo *chi) {
 			zoom_level = 100;
 		else
 			zoom_level = std::min(zoom_level, 100);
-		if (frame_vol < 0)
-			frame_vol = zoom_level;
-		else
-			frame_vol = frame_vol * zoom_level / 100;
+		frame_vol = frame_vol * zoom_level / 100;
 	}
 
 	CheckViewFrame(chi->view, chi->loop, chi->frame, frame_vol);


Commit: 316d2133724ee8444fa11dfe65807ce2a06ee1e4
    https://github.com/scummvm/scummvm/commit/316d2133724ee8444fa11dfe65807ce2a06ee1e4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:59-07:00

Commit Message:
AGS: Fixed WFN clip causing misplaced letters + small tidyup

>From upstream fdff20fd724a377dc06baf04187e52949d21d923

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 9b2e904e102..e5eb6d6d140 100644
--- a/engines/ags/shared/font/wfn_font_renderer.cpp
+++ b/engines/ags/shared/font/wfn_font_renderer.cpp
@@ -36,8 +36,6 @@ static unsigned char GetCharCode(unsigned char wanted_code, const WFNFont *font)
 	return wanted_code < font->GetCharCount() ? wanted_code : '?';
 }
 
-static int RenderChar(Bitmap *ds, const int at_x, const int at_y, const WFNChar &wfn_char, const int scale, const color_t text_color);
-
 void WFNFontRenderer::AdjustYCoordinateForFont(int *ycoord, int fontNumber) {
 	// Do nothing
 }
@@ -78,34 +76,39 @@ int WFNFontRenderer::GetTextHeight(const char *text, int fontNumber) {
 	return max_height * params.SizeMultiplier;
 }
 
-Bitmap render_wrapper;
+static int RenderChar(Bitmap *ds, const int at_x, const int at_y, Rect clip,
+	const WFNChar &wfn_char, const int scale, const color_t text_color);
+
 void WFNFontRenderer::RenderText(const char *text, int fontNumber, BITMAP *destination, int x, int y, int colour) {
 	int oldeip = get_our_eip();
 	set_our_eip(415);
 
 	const WFNFont *font = _fontData[fontNumber].Font;
 	const FontRenderParams &params = _fontData[fontNumber].Params;
-	render_wrapper.WrapAllegroBitmap(destination, true);
+	Bitmap ds(destination, true);
 
+	// NOTE: allegro's putpixel ignores clipping (optimization),
+	// so we'll have to accomodate for that ourselves
+	Rect clip = ds.GetClip();
 	for (; *text; ++text)
-		x += RenderChar(&render_wrapper, x, y, font->GetChar(GetCharCode(*text, font)), params.SizeMultiplier, colour);
+		x += RenderChar(&ds, x, y, clip, font->GetChar(GetCharCode(*text, font)), params.SizeMultiplier, colour);
 
 	set_our_eip(oldeip);
 }
 
-int RenderChar(Bitmap *ds, const int at_x, const int at_y, const WFNChar &wfn_char, const int scale, const color_t text_color) {
+static int RenderChar(Bitmap *ds, const int at_x, const int at_y, Rect clip,
+	const WFNChar &wfn_char, const int scale, const color_t text_color) {
 	const int width = wfn_char.Width;
 	const int height = wfn_char.Height;
 	const unsigned char *actdata = wfn_char.Data;
 	const int bytewid = wfn_char.GetRowByteCount();
 
-	// 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) {
+	int sx = std::max(at_x, clip.Left), ex = clip.Right + 1;
+	int sy = std::max(at_y, clip.Top), ey = clip.Bottom + 1;
+	int sw = std::max(0, clip.Left - at_x);
+	int sh = std::max(0, clip.Top - at_y);
+	for (int h = sh, y = sy; h < height && y < ey; ++h, y += scale) {
+		for (int w = sw, x = sx; w < width && x < ex; ++w, x += scale) {
 			if (((actdata[h * bytewid + (w / 8)] & (0x80 >> (w % 8))) != 0)) {
 				if (scale > 1) {
 					ds->FillRect(RectWH(x, y, scale - 1, scale - 1), text_color);


Commit: c465ba977dce59cf629273fbf246d2d435329320
    https://github.com/scummvm/scummvm/commit/c465ba977dce59cf629273fbf246d2d435329320
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:17:59-07:00

Commit Message:
AGS: Bitmap make data const in functor

>From upstream 7581848b93ca915943139df8064e7fd51f39f7c4

Changed paths:
    engines/ags/shared/gfx/bitmap.cpp


diff --git a/engines/ags/shared/gfx/bitmap.cpp b/engines/ags/shared/gfx/bitmap.cpp
index b9daa1fd732..8e046b6ebe3 100644
--- a/engines/ags/shared/gfx/bitmap.cpp
+++ b/engines/ags/shared/gfx/bitmap.cpp
@@ -151,7 +151,7 @@ struct PixelTransCpy32 {
 // Functor that tells to skip pixels if they match the mask color or have alpha = 0
 struct PixelTransSkip32 {
 	inline bool operator ()(uint8_t *data, uint32_t mask_color, bool use_alpha) const {
-		return *(uint32_t *)data == mask_color || (use_alpha && data[3] == 0);
+		return *(const uint32_t *)data == mask_color || (use_alpha && data[3] == 0);
 	}
 };
 


Commit: c54f4d1c1042605bfcd312fac813ef0ec7d9ba49
    https://github.com/scummvm/scummvm/commit/c54f4d1c1042605bfcd312fac813ef0ec7d9ba49
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:00-07:00

Commit Message:
AGS: Guibutton, removes non-updated comment

>From upstream 50f1677770e54eb4a5d366a936ffb8366a0432eb

Changed paths:
    engines/ags/shared/gui/gui_button.cpp


diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 7f7c2cea7fb..a35dddac415 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -240,8 +240,6 @@ void GUIButton::OnMouseUp() {
 	IsPushed = false;
 }
 
-// TODO: replace string serialization with StrUtil::ReadString and WriteString
-// methods in the future, to keep this organized.
 void GUIButton::WriteToFile(Stream *out) const {
 	GUIObject::WriteToFile(out);
 


Commit: eb7421400c070292f5e690f158076b962ad12708
    https://github.com/scummvm/scummvm/commit/eb7421400c070292f5e690f158076b962ad12708
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:00-07:00

Commit Message:
AGS: Use empty() to check for emptiness in vector

>From upstream 166803dd6cb99851e424f9eb9d150169cd3909fe

Changed paths:
    engines/ags/shared/gui/gui_listbox.cpp
    engines/ags/shared/util/buffered_stream.cpp


diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 636478ece8e..c54740a8608 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -117,7 +117,7 @@ int GUIListBox::AddItem(const String &text) {
 }
 
 void GUIListBox::Clear() {
-	if (Items.size() == 0)
+	if (Items.empty())
 		return;
 
 	Items.clear();
diff --git a/engines/ags/shared/util/buffered_stream.cpp b/engines/ags/shared/util/buffered_stream.cpp
index a3d65a6bc11..924a8c3feee 100644
--- a/engines/ags/shared/util/buffered_stream.cpp
+++ b/engines/ags/shared/util/buffered_stream.cpp
@@ -77,9 +77,7 @@ size_t BufferedStream::Read(void *toBuffer, size_t toSize) {
 		if (_position < _bufferPosition || _position >= _bufferPosition + _buffer.size()) {
 			FillBufferFromPosition(_position);
 		}
-		if (_buffer.size() <= 0) {
-			break;
-		} // reached EOS
+		if (_buffer.empty()) { break; } // reached EOS
 		assert(_position >= _bufferPosition && _position < _bufferPosition + _buffer.size());  // sanity check only, should be checked by above.
 
 		soff_t bufferOffset = _position - _bufferPosition;


Commit: 706766f4b53fb395d5d4cfa24bd6606be36a1076
    https://github.com/scummvm/scummvm/commit/706766f4b53fb395d5d4cfa24bd6606be36a1076
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:00-07:00

Commit Message:
AGS: Guimain tidy-up

>From upstream fd656469bc71385ffd9da50ad0315641cd5f6d22

Changed paths:
    engines/ags/lib/std/vector.h
    engines/ags/shared/gui/gui_main.cpp


diff --git a/engines/ags/lib/std/vector.h b/engines/ags/lib/std/vector.h
index 340a7b06138..d46b84023f2 100644
--- a/engines/ags/lib/std/vector.h
+++ b/engines/ags/lib/std/vector.h
@@ -22,6 +22,7 @@
 #ifndef AGS_STD_VECTOR_H
 #define AGS_STD_VECTOR_H
 
+#include "ags/lib/std/type_traits.h"
 #include "ags/lib/std/utility.h"
 #include "common/scummsys.h"
 #include "common/algorithm.h"
@@ -194,6 +195,12 @@ public:
 			insert_aux(end(), &element, &element + 1);
 	}
 
+	template<class... Args>
+	void emplace_back(Args... args) {
+		T tmp(args...);
+		push_back(tmp);
+	}
+
 	/** Append an element to the end of the array. */
 	void push_back(const vector<T> &array) {
 		if (_size + array.size() <= _capacity) {
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 6a5f9656421..5518ac66b70 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -209,7 +209,7 @@ void GUIMain::ClearChanged() {
 }
 
 void GUIMain::AddControl(GUIControlType type, int32_t id, GUIObject *control) {
-	_ctrlRefs.push_back(std::make_pair(type, id));
+	_ctrlRefs.emplace_back(type, id);
 	_controls.push_back(control);
 }
 


Commit: 4d2bad4cfa395e4095fbe4452c9fccaecc72035e
    https://github.com/scummvm/scummvm/commit/4d2bad4cfa395e4095fbe4452c9fccaecc72035e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:00-07:00

Commit Message:
AGS: cc_script GetSectionName can be made const

>From upstream efd1afa67938b4a6f2781892b3711efad7246d30

Changed paths:
    engines/ags/shared/script/cc_script.cpp
    engines/ags/shared/script/cc_script.h


diff --git a/engines/ags/shared/script/cc_script.cpp b/engines/ags/shared/script/cc_script.cpp
index c33ce46626b..3536300e1e2 100644
--- a/engines/ags/shared/script/cc_script.cpp
+++ b/engines/ags/shared/script/cc_script.cpp
@@ -342,8 +342,7 @@ void ccScript::Free() {
 	numSections = 0;
 }
 
-const char *ccScript::GetSectionName(int32_t offs) {
-
+const char *ccScript::GetSectionName(int32_t offs) const {
 	int i;
 	for (i = 0; i < numSections; i++) {
 		if (sectionOffsets[i] < offs)
diff --git a/engines/ags/shared/script/cc_script.h b/engines/ags/shared/script/cc_script.h
index 501514dd5ab..7fbfab0a3d8 100644
--- a/engines/ags/shared/script/cc_script.h
+++ b/engines/ags/shared/script/cc_script.h
@@ -70,7 +70,7 @@ public:
 	void        Write(Shared::Stream *out);
 	// read back a script written with Write
 	bool        Read(Shared::Stream *in);
-	const char *GetSectionName(int32_t offset);
+	const char *GetSectionName(int32_t offset) const;;
 
 protected:
 	// free the memory occupied by the script - do NOT attempt to run the


Commit: 23f8e4f87ca1f5c1ef9b79fa3663e68c53027e8c
    https://github.com/scummvm/scummvm/commit/23f8e4f87ca1f5c1ef9b79fa3663e68c53027e8c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:00-07:00

Commit Message:
AGS: Avoid copying PfnWriteExtBlock in data_ext

>From upstream df40976317787b919d2e15a9042e495a911aaa23

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


diff --git a/engines/ags/shared/util/data_ext.cpp b/engines/ags/shared/util/data_ext.cpp
index 4e56b2898f0..7b7bfdeb140 100644
--- a/engines/ags/shared/util/data_ext.cpp
+++ b/engines/ags/shared/util/data_ext.cpp
@@ -122,7 +122,7 @@ HError DataExtReader::Read() {
 }
 
 // Generic function that saves a block and automatically adds its size into header
-void WriteExtBlock(int block, const String &ext_id, PfnWriteExtBlock writer, int flags, Stream *out) {
+void WriteExtBlock(int block, const String &ext_id, const PfnWriteExtBlock &writer, int flags, Stream *out) {
 	// Write block's header
 	(flags & kDataExt_NumID32) != 0 ?
 		out->WriteInt32(block) :
diff --git a/engines/ags/shared/util/data_ext.h b/engines/ags/shared/util/data_ext.h
index 060c53930bc..6eb5399ce33 100644
--- a/engines/ags/shared/util/data_ext.h
+++ b/engines/ags/shared/util/data_ext.h
@@ -156,7 +156,7 @@ protected:
 
 // Type of function that writes a single data block.
 typedef void(*PfnWriteExtBlock)(Stream *out);
-void WriteExtBlock(int block, const String &ext_id, PfnWriteExtBlock writer, int flags, Stream *out);
+void WriteExtBlock(int block, const String &ext_id, const PfnWriteExtBlock &writer, int flags, Stream *out);
 // Writes a block with a new-style string id
 inline void WriteExtBlock(const String &ext_id, PfnWriteExtBlock writer, int flags, Stream *out) {
 	WriteExtBlock(0, ext_id, writer, flags, out);


Commit: 8a4186f225148d74970bf8c5d2448df7ec572d74
    https://github.com/scummvm/scummvm/commit/8a4186f225148d74970bf8c5d2448df7ec572d74
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:01-07:00

Commit Message:
AGS: Bit simplified DDB::GetWidthToRender()

>From upstream 7cfb38f490e297387be4689c6c68ef7aa3d6c8b1

Changed paths:
    engines/ags/engine/gfx/ali_3d_scummvm.h


diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index b4a95236570..423242e62a7 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -85,6 +85,8 @@ public:
 		_height = height;
 		_colDepth = color_depth;
 		_opaque = opaque;
+		_stretchToWidth = _width;
+		_stretchToHeight = _height;
 	}
 
 	ALSoftwareBitmap(Bitmap *bmp, bool opaque, bool hasAlpha) {
@@ -94,13 +96,15 @@ public:
 		_colDepth = bmp->GetColorDepth();
 		_opaque = opaque;
 		_hasAlpha = hasAlpha;
+		_stretchToWidth = _width;
+		_stretchToHeight = _height;
 	}
 
 	int GetWidthToRender() {
-		return (_stretchToWidth > 0) ? _stretchToWidth : _width;
+		return _stretchToWidth;
 	}
 	int GetHeightToRender() {
-		return (_stretchToHeight > 0) ? _stretchToHeight : _height;
+		return _stretchToHeight;
 	}
 
 	void Dispose() {


Commit: 91d25a3098b0ef967ae4eaf4e830d21cc1922631
    https://github.com/scummvm/scummvm/commit/91d25a3098b0ef967ae4eaf4e830d21cc1922631
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:18:01-07:00

Commit Message:
AGS: Added animation volumes to save format

>From upstream 752da45aa7666355e383df0f1017cf5c5842fea1

Changed paths:
    engines/ags/engine/ac/character_extras.cpp
    engines/ags/engine/ac/character_extras.h
    engines/ags/engine/ac/room_object.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/engine/game/savegame_v321.cpp
    engines/ags/engine/gui/animating_gui_button.cpp
    engines/ags/engine/gui/animating_gui_button.h
    engines/ags/shared/gui/gui_defines.h


diff --git a/engines/ags/engine/ac/character_extras.cpp b/engines/ags/engine/ac/character_extras.cpp
index 3f9e283b702..915a0de11d4 100644
--- a/engines/ags/engine/ac/character_extras.cpp
+++ b/engines/ags/engine/ac/character_extras.cpp
@@ -26,7 +26,7 @@ namespace AGS3 {
 
 using AGS::Shared::Stream;
 
-void CharacterExtras::ReadFromFile(Stream *in) {
+void CharacterExtras::ReadFromSavegame(Stream *in, int save_ver) {
 	in->ReadArrayOfInt16(invorder, MAX_INVORDER);
 	invorder_count = in->ReadInt16();
 	width = in->ReadInt16();
@@ -42,9 +42,16 @@ void CharacterExtras::ReadFromFile(Stream *in) {
 	process_idle_this_time = in->ReadInt8();
 	slow_move_counter = in->ReadInt8();
 	animwait = in->ReadInt16();
+	if (save_ver >= 2) // expanded at ver 2
+	{
+		anim_volume = in->ReadInt8();
+		cur_anim_volume = in->ReadInt8();
+		in->ReadInt8(); // reserved to fill int32
+		in->ReadInt8();
+	}
 }
 
-void CharacterExtras::WriteToFile(Stream *out) {
+void CharacterExtras::WriteToSavegame(Stream *out) {
 	out->WriteArrayOfInt16(invorder, MAX_INVORDER);
 	out->WriteInt16(invorder_count);
 	out->WriteInt16(width);
@@ -60,6 +67,10 @@ void CharacterExtras::WriteToFile(Stream *out) {
 	out->WriteInt8(process_idle_this_time);
 	out->WriteInt8(slow_move_counter);
 	out->WriteInt16(animwait);
+	out->WriteInt8(anim_volume);
+	out->WriteInt8(cur_anim_volume);
+	out->WriteInt8(0); // reserved to fill int32
+	out->WriteInt8(0);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/character_extras.h b/engines/ags/engine/ac/character_extras.h
index 13f4b60d13e..6f3cb72376c 100644
--- a/engines/ags/engine/ac/character_extras.h
+++ b/engines/ags/engine/ac/character_extras.h
@@ -57,8 +57,8 @@ struct CharacterExtras {
 	int   anim_volume = -1; // default animation volume (-1 use clip default)
 	int   cur_anim_volume = -1; // current animation sound volume (-1 = default)
 
-	void ReadFromFile(Shared::Stream *in);
-	void WriteToFile(Shared::Stream *out);
+	void ReadFromSavegame(Shared::Stream *in, int save_ver);
+	void WriteToSavegame(Shared::Stream *out);
 };
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/room_object.cpp b/engines/ags/engine/ac/room_object.cpp
index d1d714a68e6..2ae9e6a1ac6 100644
--- a/engines/ags/engine/ac/room_object.cpp
+++ b/engines/ags/engine/ac/room_object.cpp
@@ -124,9 +124,15 @@ void RoomObject::ReadFromSavegame(Stream *in, int save_ver) {
 	flags = in->ReadInt8();
 	blocking_width = in->ReadInt16();
 	blocking_height = in->ReadInt16();
-	if (save_ver > 0) {
+	if (save_ver >= 1) {
 		name = StrUtil::ReadString(in);
 	}
+	if (save_ver >= 2) {
+		anim_volume = in->ReadInt8();
+		in->ReadInt8(); // reserved to fill int32
+		in->ReadInt8();
+		in->ReadInt8();
+	}
 }
 
 void RoomObject::WriteToSavegame(Stream *out) const {
@@ -155,6 +161,10 @@ void RoomObject::WriteToSavegame(Stream *out) const {
 	out->WriteInt16(blocking_width);
 	out->WriteInt16(blocking_height);
 	StrUtil::WriteString(name, out);
+	out->WriteInt8(anim_volume);
+	out->WriteInt8(0); // reserved to fill int32
+	out->WriteInt8(0);
+	out->WriteInt8(0);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 2af2e578fe1..3947de57c68 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -483,7 +483,7 @@ HSaveError WriteCharacters(Stream *out) {
 	out->WriteInt32(_GP(game).numcharacters);
 	for (int i = 0; i < _GP(game).numcharacters; ++i) {
 		_GP(game).chars[i].WriteToFile(out);
-		_GP(charextra)[i].WriteToFile(out);
+		_GP(charextra)[i].WriteToSavegame(out);
 		Properties::WriteValues(_GP(play).charProps[i], out);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			WriteTimesRun272(*_GP(game).intrChar[i], out);
@@ -499,7 +499,7 @@ HSaveError ReadCharacters(Stream *in, int32_t cmp_ver, const PreservedParams & /
 		return err;
 	for (int i = 0; i < _GP(game).numcharacters; ++i) {
 		_GP(game).chars[i].ReadFromFile(in);
-		_GP(charextra)[i].ReadFromFile(in);
+		_GP(charextra)[i].ReadFromSavegame(in, cmp_ver);
 		Properties::ReadValues(_GP(play).charProps[i], in);
 		if (_G(loaded_game_file_version) <= kGameVersion_272)
 			ReadTimesRun272(*_GP(game).intrChar[i], in);
@@ -571,7 +571,7 @@ HSaveError WriteGUI(Stream *out) {
 	size_t num_abuts = GetAnimatingButtonCount();
 	out->WriteInt32(num_abuts);
 	for (size_t i = 0; i < num_abuts; ++i)
-		GetAnimatingButtonByIndex(i)->WriteToFile(out);
+		GetAnimatingButtonByIndex(i)->WriteToSavegame(out);
 	return HSaveError::None();
 }
 
@@ -635,7 +635,7 @@ HSaveError ReadGUI(Stream *in, int32_t cmp_ver, const PreservedParams & /*pp*/,
 	int anim_count = in->ReadInt32();
 	for (int i = 0; i < anim_count; ++i) {
 		AnimatingGUIButton abut;
-		abut.ReadFromFile(in, cmp_ver);
+		abut.ReadFromSavegame(in, cmp_ver);
 		AddButtonAnimation(abut);
 	}
 	return err;
@@ -1040,7 +1040,7 @@ ComponentHandler ComponentHandlers[] = {
 	},
 	{
 		"Characters",
-		1,
+		2,
 		0,
 		WriteCharacters,
 		ReadCharacters
@@ -1054,7 +1054,7 @@ ComponentHandler ComponentHandlers[] = {
 	},
 	{
 		"GUI",
-		kGuiSvgVersion_36023,
+		kGuiSvgVersion_36025,
 		kGuiSvgVersion_Initial,
 		WriteGUI,
 		ReadGUI
@@ -1110,14 +1110,14 @@ ComponentHandler ComponentHandlers[] = {
 	},
 	{
 		"Room States",
-		2,
+		3,
 		0,
 		WriteRoomStates,
 		ReadRoomStates
 	},
 	{
 		"Loaded Room State",
-		2, // should correspond to "Room States"
+		3, // must correspond to "Room States"
 		0,
 		WriteThisRoom,
 		ReadThisRoom
diff --git a/engines/ags/engine/game/savegame_v321.cpp b/engines/ags/engine/game/savegame_v321.cpp
index b2f329f96b8..4cfb35d240a 100644
--- a/engines/ags/engine/game/savegame_v321.cpp
+++ b/engines/ags/engine/game/savegame_v321.cpp
@@ -188,7 +188,7 @@ static void ReadGameSetupStructBase_Aligned(Stream *in) {
 static void ReadCharacterExtras_Aligned(Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
 	for (int i = 0; i < _GP(game).numcharacters; ++i) {
-		_GP(charextra)[i].ReadFromFile(&align_s);
+		_GP(charextra)[i].ReadFromSavegame(&align_s, 0);
 		align_s.Reset();
 	}
 }
@@ -214,7 +214,7 @@ void ReadAnimatedButtons_Aligned(Stream *in, int num_abuts) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
 	for (int i = 0; i < num_abuts; ++i) {
 		AnimatingGUIButton abtn;
-		abtn.ReadFromFile(&align_s, 0);
+		abtn.ReadFromSavegame(&align_s, 0);
 		AddButtonAnimation(abtn);
 		align_s.Reset();
 	}
diff --git a/engines/ags/engine/gui/animating_gui_button.cpp b/engines/ags/engine/gui/animating_gui_button.cpp
index ded337e5c37..dd9e51eb2be 100644
--- a/engines/ags/engine/gui/animating_gui_button.cpp
+++ b/engines/ags/engine/gui/animating_gui_button.cpp
@@ -20,13 +20,14 @@
  */
 
 #include "ags/engine/gui/animating_gui_button.h"
+#include "ags/shared/gui/gui_defines.h"
 #include "ags/shared/util/stream.h"
 
 namespace AGS3 {
 
-using AGS::Shared::Stream;
+using namespace AGS::Shared;
 
-void AnimatingGUIButton::ReadFromFile(Stream *in, int cmp_ver) {
+void AnimatingGUIButton::ReadFromSavegame(Stream *in, int cmp_ver) {
 	buttonid = in->ReadInt16();
 	ongui = in->ReadInt16();
 	onguibut = in->ReadInt16();
@@ -37,13 +38,20 @@ void AnimatingGUIButton::ReadFromFile(Stream *in, int cmp_ver) {
 	uint16_t anim_flags = in->ReadInt16(); // was repeat (0,1)
 	wait = in->ReadInt16();
 
-	if (cmp_ver < 2) anim_flags &= 0x1; // restrict to repeat only
+	if (cmp_ver < kGuiSvgVersion_36020) anim_flags &= 0x1; // restrict to repeat only
 	repeat = anim_flags & 0x1;
 	blocking = (anim_flags >> 1) & 0x1;
 	direction = (anim_flags >> 2) & 0x1;
+
+	if (cmp_ver >= kGuiSvgVersion_36025) {
+		volume = in->ReadInt8();
+		in->ReadInt8(); // reserved to fill int32
+		in->ReadInt8();
+		in->ReadInt8();
+	}
 }
 
-void AnimatingGUIButton::WriteToFile(Stream *out) {
+void AnimatingGUIButton::WriteToSavegame(Stream *out) {
 	uint16_t anim_flags =
 		(repeat & 0x1) |
 		(blocking & 0x1) << 1 |
@@ -58,6 +66,10 @@ void AnimatingGUIButton::WriteToFile(Stream *out) {
 	out->WriteInt16(speed);
 	out->WriteInt16(anim_flags); // was repeat (0,1)
 	out->WriteInt16(wait);
+	out->WriteInt8(volume);
+	out->WriteInt8(0); // reserved to fill int32
+	out->WriteInt8(0);
+	out->WriteInt8(0);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/gui/animating_gui_button.h b/engines/ags/engine/gui/animating_gui_button.h
index d8f41d6218e..c52f712f3c2 100644
--- a/engines/ags/engine/gui/animating_gui_button.h
+++ b/engines/ags/engine/gui/animating_gui_button.h
@@ -47,8 +47,8 @@ struct AnimatingGUIButton {
 	// relative volume of the frame sounds
 	int volume = -1;
 
-	void ReadFromFile(Shared::Stream *in, int cmp_ver);
-	void WriteToFile(Shared::Stream *out);
+	void ReadFromSavegame(Shared::Stream *in, int cmp_ver);
+	void WriteToSavegame(Shared::Stream *out);
 };
 
 } // namespace AGS3
diff --git a/engines/ags/shared/gui/gui_defines.h b/engines/ags/shared/gui/gui_defines.h
index bb1c44d6d70..a6fa2d11b19 100644
--- a/engines/ags/shared/gui/gui_defines.h
+++ b/engines/ags/shared/gui/gui_defines.h
@@ -186,7 +186,8 @@ enum GuiSvgVersion {
 	kGuiSvgVersion_Initial = 0,
 	kGuiSvgVersion_350,
 	kGuiSvgVersion_36020,
-	kGuiSvgVersion_36023
+	kGuiSvgVersion_36023,
+	kGuiSvgVersion_36025
 };
 
 enum GuiDisableStyle {


Commit: 1933841f79655615ba7540051be2462520d12b53
    https://github.com/scummvm/scummvm/commit/1933841f79655615ba7540051be2462520d12b53
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:35:19-07:00

Commit Message:
AGS: Removed numgui* variables, use size of vectors instead

>From upstream 095cf9d77c96fb3a1f9e887d7aaa1ef1e92ebe60

Changed paths:
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/global_inv_window.cpp
    engines/ags/engine/game/game_init.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/engine/main/engine_setup.cpp
    engines/ags/globals.h
    engines/ags/shared/gui/gui_main.cpp


diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index 4fe72fbdfbd..f5818ca7dff 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -1344,21 +1344,21 @@ void game_sprite_updated(int sprnum) {
 	reset_objcache_for_sprite(sprnum);
 
 	// gui backgrounds
-	for (size_t i = 0; i < (size_t)_GP(game).numgui; ++i) {
-		if (_GP(guis)[i].BgImage == sprnum) {
-			_GP(guis)[i].MarkChanged();
+	for (auto &gui : _GP(guis)) {
+		if (gui.BgImage == sprnum) {
+			gui.MarkChanged();
 		}
 	}
 	// gui buttons
-	for (size_t i = 0; i < (size_t)_G(numguibuts); ++i) {
-		if (_GP(guibuts)[i].CurrentImage == sprnum) {
-			_GP(guibuts)[i].MarkChanged();
+	for (auto &but : _GP(guibuts)) {
+		if (but.CurrentImage == sprnum) {
+			but.MarkChanged();
 		}
 	}
 	// gui sliders
-	for (size_t i = 0; i < (size_t)_G(numguislider); ++i) {
-		if ((_GP(guislider)[i].BgImage == sprnum) || (_GP(guislider)[i].HandleImage == sprnum)) {
-			_GP(guislider)[i].MarkChanged();
+	for (auto &slider : _GP(guislider)) {
+		if ((slider.BgImage == sprnum) || (slider.HandleImage == sprnum)) {
+			slider.MarkChanged();
 		}
 	}
 	// overlays
@@ -1386,27 +1386,27 @@ void game_sprite_deleted(int sprnum) {
 		}
 	}
 	// gui buttons
-	for (size_t i = 0; i < (size_t)_G(numguibuts); ++i) {
-		if (_GP(guibuts)[i].Image == sprnum)
-			_GP(guibuts)[i].Image = 0;
-		if (_GP(guibuts)[i].MouseOverImage == sprnum)
-			_GP(guibuts)[i].MouseOverImage = 0;
-		if (_GP(guibuts)[i].PushedImage == sprnum)
-			_GP(guibuts)[i].PushedImage = 0;
-
-		if (_GP(guibuts)[i].CurrentImage == sprnum) {
-			_GP(guibuts)[i].CurrentImage = 0;
-			_GP(guibuts)[i].MarkChanged();
+	for (auto &but : _GP(guibuts)) {
+		if (but.Image == sprnum)
+			but.Image = 0;
+		if (but.MouseOverImage == sprnum)
+			but.MouseOverImage = 0;
+		if (but.PushedImage == sprnum)
+			but.PushedImage = 0;
+
+		if (but.CurrentImage == sprnum) {
+			but.CurrentImage = 0;
+			but.MarkChanged();
 		}
 	}
 	// gui sliders
-	for (size_t i = 0; i < (size_t)_G(numguislider); ++i) {
-		if ((_GP(guislider)[i].BgImage == sprnum) || (_GP(guislider)[i].HandleImage == sprnum))
-			_GP(guislider)[i].MarkChanged();
-		if (_GP(guislider)[i].BgImage == sprnum)
-			_GP(guislider)[i].BgImage = 0;
-		if (_GP(guislider)[i].HandleImage == sprnum)
-			_GP(guislider)[i].HandleImage = 0;
+	for (auto &slider : _GP(guislider)) {
+		if ((slider.BgImage == sprnum) || (slider.HandleImage == sprnum))
+			slider.MarkChanged();
+		if (slider.BgImage == sprnum)
+			slider.BgImage = 0;
+		if (slider.HandleImage == sprnum)
+			slider.HandleImage = 0;
 	}
 	// views
 	for (size_t v = 0; v < (size_t)_GP(game).numviews; ++v) {
diff --git a/engines/ags/engine/ac/global_inv_window.cpp b/engines/ags/engine/ac/global_inv_window.cpp
index fa0eb19794e..67f91ee4377 100644
--- a/engines/ags/engine/ac/global_inv_window.cpp
+++ b/engines/ags/engine/ac/global_inv_window.cpp
@@ -41,10 +41,10 @@ void SetInvDimensions(int ww, int hh) {
 	_GP(play).inv_item_hit = hh;
 	_GP(play).inv_numdisp = 0;
 	// backwards compatibility
-	for (int i = 0; i < _G(numguiinv); i++) {
-		_GP(guiinv)[i].ItemWidth = ww;
-		_GP(guiinv)[i].ItemHeight = hh;
-		_GP(guiinv)[i].OnResized();
+	for (auto &inv : _GP(guiinv)) {
+		inv.ItemWidth = ww;
+		inv.ItemHeight = hh;
+		inv.OnResized();
 	}
 }
 
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index 7462af2625a..e7f12572ad0 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -403,9 +403,9 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 	//
 	// 5. Initialize runtime state of certain game objects
 	//
-	for (int i = 0; i < _G(numguilabels); ++i) {
+	for (auto &label : _GP(guilabels)) {
 		// labels are not clickable by default
-		_GP(guilabels)[i].SetClickable(false);
+		label.SetClickable(false);
 	}
 	_GP(play).gui_draw_order.resize(game.numgui);
 	for (int i = 0; i < game.numgui; ++i)
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 3947de57c68..f563094e54e 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -533,38 +533,38 @@ HSaveError WriteGUI(Stream *out) {
 	// GUI state
 	WriteFormatTag(out, "GUIs");
 	out->WriteInt32(_GP(game).numgui);
-	for (int i = 0; i < _GP(game).numgui; ++i)
-		_GP(guis)[i].WriteToSavegame(out);
+	for (const auto &gui : _GP(guis))
+		gui.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUIButtons");
-	out->WriteInt32(_G(numguibuts));
-	for (int i = 0; i < _G(numguibuts); ++i)
-		_GP(guibuts)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guibuts).size()));
+	for (const auto &but : _GP(guibuts))
+		but.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUILabels");
-	out->WriteInt32(_G(numguilabels));
-	for (int i = 0; i < _G(numguilabels); ++i)
-		_GP(guilabels)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guilabels).size()));
+	for (const auto &label : _GP(guilabels))
+		label.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUIInvWindows");
-	out->WriteInt32(_G(numguiinv));
-	for (int i = 0; i < _G(numguiinv); ++i)
-		_GP(guiinv)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guiinv).size()));
+	for (const auto &inv : _GP(guiinv))
+		inv.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUISliders");
-	out->WriteInt32(_G(numguislider));
-	for (int i = 0; i < _G(numguislider); ++i)
-		_GP(guislider)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guislider).size()));
+	for (const auto &slider : _GP(guislider))
+		slider.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUITextBoxes");
-	out->WriteInt32(_G(numguitext));
-	for (int i = 0; i < _G(numguitext); ++i)
-		_GP(guitext)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guitext).size()));
+	for (const auto &tb : _GP(guitext))
+		tb.WriteToSavegame(out);
 
 	WriteFormatTag(out, "GUIListBoxes");
-	out->WriteInt32(_G(numguilist));
-	for (int i = 0; i < _G(numguilist); ++i)
-		_GP(guilist)[i].WriteToSavegame(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guilist).size()));
+	for (const auto &list : _GP(guilist))
+		list.WriteToSavegame(out);
 
 	// Animated buttons
 	WriteFormatTag(out, "AnimatedButtons");
@@ -581,52 +581,52 @@ HSaveError ReadGUI(Stream *in, int32_t cmp_ver, const PreservedParams & /*pp*/,
 	// GUI state
 	if (!AssertFormatTagStrict(err, in, "GUIs"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numgui, "GUIs"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(game).numgui, "GUIs"))
 		return err;
 	for (int i = 0; i < _GP(game).numgui; ++i)
 		_GP(guis)[i].ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUIButtons"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguibuts), "GUI Buttons"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guibuts).size(), "GUI Buttons"))
 		return err;
-	for (int i = 0; i < _G(numguibuts); ++i)
-		_GP(guibuts)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &but : _GP(guibuts))
+		but.ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUILabels"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguilabels), "GUI Labels"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guilabels).size(), "GUI Labels"))
 		return err;
-	for (int i = 0; i < _G(numguilabels); ++i)
-		_GP(guilabels)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &label : _GP(guilabels))
+		label.ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUIInvWindows"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguiinv), "GUI InvWindows"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guiinv).size(), "GUI InvWindows"))
 		return err;
-	for (int i = 0; i < _G(numguiinv); ++i)
-		_GP(guiinv)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &inv : _GP(guiinv))
+		inv.ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUISliders"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguislider), "GUI Sliders"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guislider).size(), "GUI Sliders"))
 		return err;
-	for (int i = 0; i < _G(numguislider); ++i)
-		_GP(guislider)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &slider : _GP(guislider))
+		slider.ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUITextBoxes"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguitext), "GUI TextBoxes"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guitext).size(), "GUI TextBoxes"))
 		return err;
-	for (int i = 0; i < _G(numguitext); ++i)
-		_GP(guitext)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &tb : _GP(guitext))
+		tb.ReadFromSavegame(in, svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUIListBoxes"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), _G(numguilist), "GUI ListBoxes"))
+	if (!AssertGameContent(err, static_cast<size_t>(in->ReadInt32()), _GP(guilist).size(), "GUI ListBoxes"))
 		return err;
-	for (int i = 0; i < _G(numguilist); ++i)
-		_GP(guilist)[i].ReadFromSavegame(in, svg_ver);
+	for (auto &list : _GP(guilist))
+		list.ReadFromSavegame(in, svg_ver);
 
 	// Animated buttons
 	if (!AssertFormatTagStrict(err, in, "AnimatedButtons"))
diff --git a/engines/ags/engine/main/engine_setup.cpp b/engines/ags/engine/main/engine_setup.cpp
index d458f98e96b..12542f3e73b 100644
--- a/engines/ags/engine/main/engine_setup.cpp
+++ b/engines/ags/engine/main/engine_setup.cpp
@@ -107,10 +107,10 @@ void convert_objects_to_data_resolution(GameDataVersion filever) {
 		_GP(game).chars[i].y /= mul;
 	}
 
-	for (int i = 0; i < _G(numguiinv); ++i) {
-		_GP(guiinv)[i].ItemWidth /= mul;
-		_GP(guiinv)[i].ItemHeight /= mul;
-		_GP(guiinv)[i].OnResized();
+	for (auto &inv : _GP(guiinv)) {
+		inv.ItemWidth /= mul;
+		inv.ItemHeight /= mul;
+		inv.OnResized();
 	}
 }
 
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 214f5d3da91..bf6e7642e15 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -941,7 +941,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUIButton> *_guibuts;
-	int _numguibuts = 0;
 
 	/**@}*/
 
@@ -975,7 +974,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUIInvWindow> *_guiinv;
-	int _numguiinv = 0;
 
 	/**@}*/
 
@@ -986,7 +984,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUILabel> *_guilabels;
-	int _numguilabels = 0;
 
 	/**@}*/
 
@@ -997,7 +994,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUIListBox> *_guilist;
-	int _numguilist = 0;
 
 	/**@}*/
 
@@ -1019,7 +1015,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUISlider> *_guislider;
-	int _numguislider = 0;
 
 	/**@}*/
 
@@ -1030,7 +1025,6 @@ public:
 	 */
 
 	std::vector<AGS::Shared::GUITextBox> *_guitext;
-	int _numguitext = 0;
 
 	/**@}*/
 
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 5518ac66b70..96cae7694ce 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -835,45 +835,45 @@ HError ReadGUI(Stream *in, bool is_savegame) {
 	}
 
 	// buttons
-	_G(numguibuts) = in->ReadInt32();
-	_GP(guibuts).resize(_G(numguibuts));
-	for (int i = 0; i < _G(numguibuts); ++i) {
+	size_t numguibuts = static_cast<uint32_t>(in->ReadInt32());
+	_GP(guibuts).resize(numguibuts);
+	for (size_t i = 0; i < numguibuts; ++i) {
 		_GP(guibuts)[i].ReadFromFile(in, GameGuiVersion);
 	}
 	// labels
-	_G(numguilabels) = in->ReadInt32();
-	_GP(guilabels).resize(_G(numguilabels));
-	for (int i = 0; i < _G(numguilabels); ++i) {
+	size_t numguilabels = static_cast<uint32_t>(in->ReadInt32());
+	_GP(guilabels).resize(numguilabels);
+	for (size_t i = 0; i < numguilabels; ++i) {
 		_GP(guilabels)[i].ReadFromFile(in, GameGuiVersion);
 	}
 	// inv controls
-	_G(numguiinv) = in->ReadInt32();
-	_GP(guiinv).resize(_G(numguiinv));
-	for (int i = 0; i < _G(numguiinv); ++i) {
+	size_t numguiinv = static_cast<uint32_t>(in->ReadInt32());
+	_GP(guiinv).resize(numguiinv);
+	for (size_t i = 0; i < numguiinv; ++i) {
 		_GP(guiinv)[i].ReadFromFile(in, GameGuiVersion);
 	}
 
 	if (GameGuiVersion >= kGuiVersion_214) {
 		// sliders
-		_G(numguislider) = in->ReadInt32();
-		_GP(guislider).resize(_G(numguislider));
-		for (int i = 0; i < _G(numguislider); ++i) {
+		size_t numguislider = static_cast<uint32_t>(in->ReadInt32());
+		_GP(guislider).resize(numguislider);
+		for (size_t i = 0; i < numguislider; ++i) {
 			_GP(guislider)[i].ReadFromFile(in, GameGuiVersion);
 		}
 	}
 	if (GameGuiVersion >= kGuiVersion_222) {
 		// text boxes
-		_G(numguitext) = in->ReadInt32();
-		_GP(guitext).resize(_G(numguitext));
-		for (int i = 0; i < _G(numguitext); ++i) {
+		size_t numguitext = static_cast<uint32_t>(in->ReadInt32());
+		_GP(guitext).resize(numguitext);
+		for (size_t i = 0; i < numguitext; ++i) {
 			_GP(guitext)[i].ReadFromFile(in, GameGuiVersion);
 		}
 	}
 	if (GameGuiVersion >= kGuiVersion_230) {
 		// list boxes
-		_G(numguilist) = in->ReadInt32();
-		_GP(guilist).resize(_G(numguilist));
-		for (int i = 0; i < _G(numguilist); ++i) {
+		size_t numguilist = static_cast<uint32_t>(in->ReadInt32());
+		_GP(guilist).resize(numguilist);
+		for (size_t i = 0; i < numguilist; ++i) {
 			_GP(guilist)[i].ReadFromFile(in, GameGuiVersion);
 		}
 	}
@@ -885,32 +885,32 @@ void WriteGUI(Stream *out) {
 	out->WriteInt32(kGuiVersion_Current);
 	out->WriteInt32(_GP(guis).size());
 
-	for (size_t i = 0; i < _GP(guis).size(); ++i) {
-		_GP(guis)[i].WriteToFile(out);
-	} 
-	out->WriteInt32(_G(numguibuts));
-	for (int i = 0; i < _G(numguibuts); ++i) {
-		_GP(guibuts)[i].WriteToFile(out);
+	for (const auto &gui : _GP(guis)) {
+		gui.WriteToFile(out);
 	}
-	out->WriteInt32(_G(numguilabels));
-	for (int i = 0; i < _G(numguilabels); ++i) {
-		_GP(guilabels)[i].WriteToFile(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guibuts).size()));
+	for (const auto &but : _GP(guibuts)) {
+		but.WriteToFile(out);
 	}
-	out->WriteInt32(_G(numguiinv));
-	for (int i = 0; i < _G(numguiinv); ++i) {
-		_GP(guiinv)[i].WriteToFile(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guilabels).size()));
+	for (const auto &label : _GP(guilabels)) {
+		label.WriteToFile(out);
 	}
-	out->WriteInt32(_G(numguislider));
-	for (int i = 0; i < _G(numguislider); ++i) {
-		_GP(guislider)[i].WriteToFile(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guiinv).size()));
+	for (const auto &inv : _GP(guiinv)) {
+		inv.WriteToFile(out);
 	}
-	out->WriteInt32(_G(numguitext));
-	for (int i = 0; i < _G(numguitext); ++i) {
-		_GP(guitext)[i].WriteToFile(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guislider).size()));
+	for (const auto &slider : _GP(guislider)) {
+		slider.WriteToFile(out);
 	}
-	out->WriteInt32(_G(numguilist));
-	for (int i = 0; i < _G(numguilist); ++i) {
-		_GP(guilist)[i].WriteToFile(out);
+	out->WriteInt32(static_cast<int32_t>(_GP(guitext).size()));
+	for (const auto &tb : _GP(guitext)) {
+		tb.WriteToFile(out);
+	}
+	out->WriteInt32(static_cast<int32_t>(_GP(guilist).size()));
+	for (const auto &list : _GP(guilist)) {
+		list.WriteToFile(out);
 	}
 }
 


Commit: 7c7c94d85a709ae6f946e22048abd8beae821aaa
    https://github.com/scummvm/scummvm/commit/7c7c94d85a709ae6f946e22048abd8beae821aaa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-10T21:38:24-07:00

Commit Message:
AGS: Fixed crash when quitting with error during restoring a save

>From upstream 6f2156704e4e6534b71094c4a90666d5aa3a8daf

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


diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index b2dfc689ded..3f2c81cc643 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -358,6 +358,7 @@ void DoBeforeRestore(PreservedParams &pp) {
 		pp.ScMdDataSize[i] = _GP(moduleInst)[i]->globaldatasize;
 		delete _GP(moduleInstFork)[i];
 		delete _GP(moduleInst)[i];
+		_GP(moduleInstFork)[i] = nullptr;
 		_GP(moduleInst)[i] = nullptr;
 	}
 




More information about the Scummvm-git-logs mailing list