[Scummvm-git-logs] scummvm master -> 60c7f3351610e5794e0cb8dcf8187ced3bf51b39

dreammaster dreammaster at scummvm.org
Wed Jul 28 05:04:09 UTC 2021


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

Summary:
10dfe6cdcc AGS: Janitorial for lib/std/ folder
7a1ee192e2 AGS: Fixup character's view loop in update, prevent having no frame
69157077cf AGS: Fixed Path::GetParent (now it actually works)
5e37a5515b AGS: Implemented GetFiles and GetDirs through the same algorithm
00ade063b9 AGS: In File api functions replaced quit with a warning on error
5ccb07acf9 AGS: implemented bool Room.Exists(int room)
47928c39aa AGS: changed Object.SetView default loop & frame values to 0
5b4ce2d365 AGS: support source rectangle for DrawImage
37c51eeac5 AGS: Support extended params for DrawSurface
9f78c2f22c AGS: Added WaitMouse() to complement existing Wait funcs
b4997729cd AGS: Wait functions return the actual reason they were skipped
0b4b055d6f AGS: Wait functions may have infinite timeout with <0 time arg
529362a2d7 AGS: implemented SkipWait()
9612b5cb35 AGS: distinct overlay types of speech and messagebox
c133e51620 AGS: Speech.TextOverlay for accessing blocking speech overlay
217e55e2d9 AGS: Speech.PortraitOverlay for accessing speech portrait overlay
65f992979e AGS: Implemented Game.BlockingWaitSkipped
e93845cb0c AGS: added eSkipNone to SkipSpeechStyle
cf36b34f0d AGS: Implemented Object.ManualScaling and Object.Scaling
28102f13ab AGS: allow Character.Scaling full range (1-32767)
60c7f33516 AGS: Update engine sync point comments


Commit: 10dfe6cdcc5c6a84343c1a960ac3492878cbac5c
    https://github.com/scummvm/scummvm/commit/10dfe6cdcc5c6a84343c1a960ac3492878cbac5c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:34-07:00

Commit Message:
AGS: Janitorial for lib/std/ folder

Changed paths:
    engines/ags/lib/std/algorithm.h
    engines/ags/lib/std/array.h
    engines/ags/lib/std/chrono.h
    engines/ags/lib/std/functional.h
    engines/ags/lib/std/limits.h
    engines/ags/lib/std/list.h
    engines/ags/lib/std/map.h
    engines/ags/lib/std/math.h
    engines/ags/lib/std/memory.h
    engines/ags/lib/std/queue.h
    engines/ags/lib/std/set.h
    engines/ags/lib/std/type_traits.h
    engines/ags/lib/std/unordered_set.h
    engines/ags/lib/std/utility.h
    engines/ags/lib/std/vector.h
    engines/ags/lib/std/xtr1common.h
    engines/ags/lib/std/xutility.h


diff --git a/engines/ags/lib/std/algorithm.h b/engines/ags/lib/std/algorithm.h
index e657619b04..d7ff0e4690 100644
--- a/engines/ags/lib/std/algorithm.h
+++ b/engines/ags/lib/std/algorithm.h
@@ -30,100 +30,100 @@ namespace AGS3 {
 namespace std {
 
 template<typename T> inline T abs(T x) {
-return ABS(x);
+	return ABS(x);
 }
 template<typename T> inline T min(T a, T b) {
-return MIN(a, b);
+	return MIN(a, b);
 }
 template<typename T> inline T max(T a, T b) {
-return MAX(a, b);
+	return MAX(a, b);
 }
 template<typename T> inline T clip(T v, T amin, T amax) {
-return CLIP(v, amin, amax);
+	return CLIP(v, amin, amax);
 }
 template<typename T> inline T sqrt(T x) {
-return ::sqrt(x);
+	return ::sqrt(x);
 }
 template<typename T> inline void swap(T &a, T &b) {
-SWAP(a, b);
+	SWAP(a, b);
 }
 
 template<class In, class Value>
 In fill(In first, In last, const Value &val) {
-return Common::fill(first, last, val);
+	return Common::fill(first, last, val);
 }
 
 template<typename T, class StrictWeakOrdering>
 void sort(T first, T last, StrictWeakOrdering comp) {
-Common::sort(first, last, comp);
+	Common::sort(first, last, comp);
 }
 
 template<typename T>
 void sort(T *first, T *last) {
-Common::sort(first, last, Common::Less<T>());
+	Common::sort(first, last, Common::Less<T>());
 }
 
 template<class T>
 void sort(T first, T last) {
-Common::sort(first, last);
+	Common::sort(first, last);
 }
 
 template<class In, class T>
 In find(In first, In last, const T &v) {
-return Common::find(first, last, v);
+	return Common::find(first, last, v);
 }
 
 template<class T>
 T unique(T first, T last) {
-T pos;
-for (pos = first + 1; pos < last; ++pos) {
-	// Check for duplicate
-	for (T existingPos = first; existingPos < last; ++existingPos) {
-		if (*pos == *existingPos) {
-			// Found a match, so shift values over the duplicate
-			while (pos < (last - 1)) {
-				T &prior = pos;
-				++pos;
-				prior = pos;
+	T pos;
+	for (pos = first + 1; pos < last; ++pos) {
+		// Check for duplicate
+		for (T existingPos = first; existingPos < last; ++existingPos) {
+			if (*pos == *existingPos) {
+				// Found a match, so shift values over the duplicate
+				while (pos < (last - 1)) {
+					T &prior = pos;
+					++pos;
+					prior = pos;
+				}
+
+				--last;
+				break;
 			}
-
-			--last;
-			break;
 		}
 	}
-}
 
-return pos;
+	return pos;
 }
 
 template<class ForwardIt, class T>
 ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T &value) {
-for (ForwardIt it = first; it < last; ++it) {
-	if (*it >= value)
-		return it;
-}
+	for (ForwardIt it = first; it < last; ++it) {
+		if (*it >= value)
+			return it;
+	}
 
-return last;
+	return last;
 }
 
 template<class ForwardIt, class T>
 ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T &value) {
-for (ForwardIt it = first; it < last; ++it) {
-	if (*it > value)
-		return it;
-}
+	for (ForwardIt it = first; it < last; ++it) {
+		if (*it > value)
+			return it;
+	}
 
-return last;
+	return last;
 }
 
 template<class ForwardIt, class T, class Compare>
 ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T &value, Compare comp) {
-for (ForwardIt it = first; it < last; ++it) {
-	if (comp(value, *it))
-		return it;
-}
+	for (ForwardIt it = first; it < last; ++it) {
+		if (comp(value, *it))
+			return it;
+	}
 
-return last;
+	return last;
 }
 
 } // namespace std
diff --git a/engines/ags/lib/std/array.h b/engines/ags/lib/std/array.h
index d38ad928b5..4505a669f6 100644
--- a/engines/ags/lib/std/array.h
+++ b/engines/ags/lib/std/array.h
@@ -31,11 +31,11 @@ namespace std {
 template<class T>
 class array : public Common::Array<T> {
 public:
-array() : Common::Array<T>() {
-}
-array(size_t size) : Common::Array<T>() {
-	Common::Array<T>::resize(size);
-}
+	array() : Common::Array<T>() {
+	}
+	array(size_t size) : Common::Array<T>() {
+		Common::Array<T>::resize(size);
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/chrono.h b/engines/ags/lib/std/chrono.h
index 3ea5202ce7..50fdf3f6da 100644
--- a/engines/ags/lib/std/chrono.h
+++ b/engines/ags/lib/std/chrono.h
@@ -32,41 +32,41 @@ namespace chrono {
 
 class duration {
 private:
-uint32 _value;
+	uint32 _value;
 public:
-duration() : _value(0) {
-}
-duration(uint32 value) : _value(value) {
-}
-
-size_t count() const {
-	// durations for ScummVM are hardcoded to be in milliseconds
-	return 1000;
-}
-
-operator uint32() const {
-	return _value;
-}
-
-inline bool operator>=(const duration &rhs) const {
-	return _value >= rhs._value;
-}
+	duration() : _value(0) {
+	}
+	duration(uint32 value) : _value(value) {
+	}
+
+	size_t count() const {
+		// durations for ScummVM are hardcoded to be in milliseconds
+		return 1000;
+	}
+
+	operator uint32() const {
+		return _value;
+	}
+
+	inline bool operator>=(const duration &rhs) const {
+		return _value >= rhs._value;
+	}
 };
 
 class milliseconds : public duration {
 public:
-milliseconds() : duration(0) {}
-milliseconds(uint32 val) : duration(val) {}
+	milliseconds() : duration(0) {}
+	milliseconds(uint32 val) : duration(val) {}
 
-static milliseconds zero() {
-	return milliseconds();
-}
+	static milliseconds zero() {
+		return milliseconds();
+	}
 };
 
 class microseconds : public duration {
 public:
-microseconds() : duration(0) {}
-microseconds(long val) : duration(val / 1000) {}
+	microseconds() : duration(0) {}
+	microseconds(long val) : duration(val / 1000) {}
 };
 
 
@@ -75,15 +75,15 @@ struct system_clock {
 
 
 struct steady_clock { // wraps QueryPerformanceCounter
-using rep = uint32;
-using period = milliseconds;
-using duration = milliseconds;
-using time_point = uint32;
-static constexpr bool is_steady = true;
-
-static time_point now() { // get current time
-	return g_system->getMillis();
-}
+	using rep = uint32;
+	using period = milliseconds;
+	using duration = milliseconds;
+	using time_point = uint32;
+	static constexpr bool is_steady = true;
+
+	static time_point now() { // get current time
+		return g_system->getMillis();
+	}
 };
 
 using high_resolution_clock = steady_clock;
@@ -93,7 +93,7 @@ duration duration_cast(T param);
 
 template<class T>
 duration duration_cast(T param) {
-return duration(param);
+	return duration(param);
 }
 
 } // namespace chrono
diff --git a/engines/ags/lib/std/functional.h b/engines/ags/lib/std/functional.h
index d4625a7321..0827900113 100644
--- a/engines/ags/lib/std/functional.h
+++ b/engines/ags/lib/std/functional.h
@@ -28,27 +28,27 @@ namespace std {
 
 template <class _Arg, class _Result>
 struct unary_function { // base class for unary functions
-using argument_type = _Arg;
-using result_type = _Result;
+	using argument_type = _Arg;
+	using result_type = _Result;
 };
 
 template <class _Arg1, class _Arg2, class _Result>
 struct binary_function { // base class for binary functions
-using first_argument_type = _Arg1;
-using second_argument_type = _Arg2;
-using result_type = _Result;
+	using first_argument_type = _Arg1;
+	using second_argument_type = _Arg2;
+	using result_type = _Result;
 };
 
 template <typename _Fty>
 struct function {
-_Fty *_fn;
+	_Fty *_fn;
 
-function() : _fn(nullptr) {}
-function(_Fty *fn) : _fn(fn) {}
+	function() : _fn(nullptr) {}
+	function(_Fty *fn) : _fn(fn) {}
 
-operator _Fty &() {
-	return *_fn;
-}
+	operator _Fty &() {
+		return *_fn;
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/limits.h b/engines/ags/lib/std/limits.h
index 8767068d4f..97448d50f7 100644
--- a/engines/ags/lib/std/limits.h
+++ b/engines/ags/lib/std/limits.h
@@ -35,37 +35,36 @@ class _Num_base {
 template <class _Ty>
 class numeric_limits : public _Num_base {
 public:
-static constexpr _Ty(min)() {
-	return _Ty();
-}
-
-static constexpr _Ty(max)() {
-	return _Ty();
-}
+	static constexpr _Ty(min)() {
+		return _Ty();
+	}
 
+	static constexpr _Ty(max)() {
+		return _Ty();
+	}
 };
 
 template <>
 class numeric_limits<float> {
 public:
-static constexpr float quiet_undefined() {
-	return FLOAT_UNASSIGNED;
-}
+	static constexpr float quiet_undefined() {
+		return FLOAT_UNASSIGNED;
+	}
 };
 
 template <>
 class numeric_limits<uint16_t> {
 public:
-static constexpr uint16_t quiet_undefined() {
-	return 0;
-}
+	static constexpr uint16_t quiet_undefined() {
+		return 0;
+	}
 
-static constexpr uint16_t min() {
-	return 0;
-}
-static constexpr uint16_t max() {
-	return UINT16_MAX;
-}
+	static constexpr uint16_t min() {
+		return 0;
+	}
+	static constexpr uint16_t max() {
+		return UINT16_MAX;
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/list.h b/engines/ags/lib/std/list.h
index 22f99e9a25..f153118275 100644
--- a/engines/ags/lib/std/list.h
+++ b/engines/ags/lib/std/list.h
@@ -57,18 +57,18 @@ public:
 	}
 };
 public:
-typename Common::List<T>::iterator insert(typename Common::List<T>::iterator pos,
-        const T &element) {
-	Common::List<T>::insert(pos, element);
-	return pos;
-}
+	typename Common::List<T>::iterator insert(typename Common::List<T>::iterator pos,
+			const T &element) {
+		Common::List<T>::insert(pos, element);
+		return pos;
+	}
 
-reverse_iterator rbegin() {
-	return reverse_iterator(Common::List<T>::reverse_begin());
-}
-reverse_iterator rend() {
-	return reverse_iterator(Common::List<T>::end());
-}
+	reverse_iterator rbegin() {
+		return reverse_iterator(Common::List<T>::reverse_begin());
+	}
+	reverse_iterator rend() {
+		return reverse_iterator(Common::List<T>::end());
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/map.h b/engines/ags/lib/std/map.h
index 7333badd1c..15bbbe012c 100644
--- a/engines/ags/lib/std/map.h
+++ b/engines/ags/lib/std/map.h
@@ -31,184 +31,184 @@ namespace std {
 
 template<class Key, class Val, class CompFunc = Common::Less<Key> >
 class map {
-struct KeyValue {
-	Key _key;
-	Val _value;
-};
+	struct KeyValue {
+		Key _key;
+		Val _value;
+	};
 private:
-Common::Array<KeyValue> _items;
-CompFunc _comp;
-public:
-using iterator = typename Common::Array<KeyValue>::iterator;
-using const_iterator = typename Common::Array<KeyValue>::const_iterator;
+	Common::Array<KeyValue> _items;
+	CompFunc _comp;
+	public:
+	using iterator = typename Common::Array<KeyValue>::iterator;
+	using const_iterator = typename Common::Array<KeyValue>::const_iterator;
+
+	/**
+	 * Clears the map
+	 */
+	void clear() {
+		_items.clear();
+	}
 
-/**
- * Clears the map
- */
-void clear() {
-	_items.clear();
-}
+	/**
+	 * Gets the iterator start
+	 */
+	iterator begin() {
+		return _items.begin();
+	}
 
-/**
- * Gets the iterator start
- */
-iterator begin() {
-	return _items.begin();
-}
+	/**
+	 * Get the iterator end
+	 */
+	iterator end() {
+		return _items.end();
+	}
 
-/**
- * Get the iterator end
- */
-iterator end() {
-	return _items.end();
-}
+	/**
+	 * Get the const iterator start
+	 */
+	const_iterator begin() const {
+		return _items.begin();
+	}
 
-/**
- * Get the const iterator start
- */
-const_iterator begin() const {
-	return _items.begin();
-}
+	/**
+	 * Get the const iterator end
+	 */
+	const_iterator end() const {
+		return _items.end();
+	}
 
-/**
- * Get the const iterator end
- */
-const_iterator end() const {
-	return _items.end();
-}
+	/**
+	 * Returns an iterator for the first element of the map that is
+	 * not less than the given key
+	 */
+	const_iterator lower_bound(const Key &theKey) const {
+		const_iterator first = this->begin();
+		const_iterator it;
+		int count_ = _items.size(), step;
+
+		while (count_ > 0) {
+			it = first;
+			step = count_ / 2;
+			it += step;
+
+			if (_comp(it->_key, theKey)) {
+				first = ++it;
+				count_ -= step + 1;
+			} else {
+				count_ = step;
+			}
+		}
 
-/**
- * Returns an iterator for the first element of the map that is
- * not less than the given key
- */
-const_iterator lower_bound(const Key &theKey) const {
-	const_iterator first = this->begin();
-	const_iterator it;
-	int count_ = _items.size(), step;
-
-	while (count_ > 0) {
-		it = first;
-		step = count_ / 2;
-		it += step;
-
-		if (_comp(it->_key, theKey)) {
-			first = ++it;
-			count_ -= step + 1;
-		} else {
-			count_ = step;
+		return first;
+	}
+
+	iterator lower_bound(const Key &theKey) {
+		iterator first = this->begin();
+		iterator it;
+		int count_ = _items.size(), step;
+
+		while (count_ > 0) {
+			it = first;
+			step = count_ / 2;
+			it += step;
+
+			if (_comp(it->_key, theKey)) {
+				first = ++it;
+				count_ -= step + 1;
+			} else {
+				count_ = step;
+			}
 		}
+
+		return first;
 	}
 
-	return first;
-}
+	/**
+	 * Find the entry with the given key
+	 */
+	iterator find(const Key &theKey) {
+		iterator it = this->lower_bound(theKey);
 
-iterator lower_bound(const Key &theKey) {
-	iterator first = this->begin();
-	iterator it;
-	int count_ = _items.size(), step;
+		if (it != this->end() && it->_key == theKey)
+			return it;
+		return this->end();
+	}
+
+	const_iterator find(const Key &theKey) const {
+		const_iterator it = this->lower_bound(theKey);
 
-	while (count_ > 0) {
-		it = first;
-		step = count_ / 2;
-		it += step;
+		if (it != this->end() && it->_key == theKey)
+			return it;
+		return this->end();
+	}
 
-		if (_comp(it->_key, theKey)) {
-			first = ++it;
-			count_ -= step + 1;
+	/**
+	 * Square brackets operator accesses items by key, creating if necessary
+	 */
+	Val &operator[](const Key &theKey) {
+		iterator it = this->lower_bound(theKey);
+		if (it == this->end() || it->_key != theKey) {
+			size_t idx = it - this->begin();
+			_items.insert_at(idx, KeyValue());
+			_items[idx]._key = theKey;
+			return _items[idx]._value;
 		} else {
-			count_ = step;
+			return _items[it - this->begin()]._value;
 		}
 	}
 
-	return first;
-}
-
-/**
- * Find the entry with the given key
- */
-iterator find(const Key &theKey) {
-	iterator it = this->lower_bound(theKey);
-
-	if (it != this->end() && it->_key == theKey)
-		return it;
-	return this->end();
-}
+	/**
+	 * Erases an entry in the map
+	 */
+	iterator erase(iterator it) {
+		iterator next = it;
+		++next;
+		_items.remove_at(it - begin());
+		return next;
+	}
 
-const_iterator find(const Key &theKey) const {
-	const_iterator it = this->lower_bound(theKey);
+	iterator erase(const Key &theKey) {
+		return erase(find(theKey));
+	}
 
-	if (it != this->end() && it->_key == theKey)
-		return it;
-	return this->end();
-}
+	/**
+	 * Returns the size of the map
+	 */
+	size_t size() const {
+		return _items.size();
+	}
 
-/**
- * Square brackets operator accesses items by key, creating if necessary
- */
-Val &operator[](const Key &theKey) {
-	iterator it = this->lower_bound(theKey);
-	if (it == this->end() || it->_key != theKey) {
-		size_t idx = it - this->begin();
-		_items.insert_at(idx, KeyValue());
-		_items[idx]._key = theKey;
-		return _items[idx]._value;
-	} else {
-		return _items[it - this->begin()]._value;
-	}
-}
-
-/**
- * Erases an entry in the map
- */
-iterator erase(iterator it) {
-	iterator next = it;
-	++next;
-	_items.remove_at(it - begin());
-	return next;
-}
-
-iterator erase(const Key &theKey) {
-	return erase(find(theKey));
-}
-
-/**
- * Returns the size of the map
- */
-size_t size() const {
-	return _items.size();
-}
+	/**
+	 * Returns the number of elements with a matching key
+	 */
+	size_t count(const Key &theKey) {
+		int count_ = 0;
+		for (iterator it = this->begin(); it != this->end(); ++it) {
+			if (it->_key == theKey)
+				++count_;
+		}
 
-/**
- * Returns the number of elements with a matching key
- */
-size_t count(const Key &theKey) {
-	int count_ = 0;
-	for (iterator it = this->begin(); it != this->end(); ++it) {
-		if (it->_key == theKey)
-			++count_;
+		return count_;
 	}
-
-	return count_;
-}
 };
 
 template<class Key, class Val, class HashFunc = Common::Hash<Key>,
          class EqualFunc = Common::EqualTo<Key> >
 class unordered_map : public Common::HashMap<Key, Val, HashFunc, EqualFunc> {
 public:
-pair<Key, Val> insert(pair<Key, Val> elem) {
-	// unordered_map doesn't replace already existing keys
-	if (this->contains(elem.first))
-		return pair<Key, Val>(elem.first, this->operator[](elem.first));
-
-	// Add item to map
-	this->operator[](elem.first) = elem.second;
-	return elem;
-}
-
-void reserve(size_t size) {
-	// No implementation
-}
+	pair<Key, Val> insert(pair<Key, Val> elem) {
+		// unordered_map doesn't replace already existing keys
+		if (this->contains(elem.first))
+			return pair<Key, Val>(elem.first, this->operator[](elem.first));
+
+		// Add item to map
+		this->operator[](elem.first) = elem.second;
+		return elem;
+	}
+
+	void reserve(size_t size) {
+		// No implementation
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/math.h b/engines/ags/lib/std/math.h
index f3e5990dbc..706d9d7c3a 100644
--- a/engines/ags/lib/std/math.h
+++ b/engines/ags/lib/std/math.h
@@ -38,7 +38,7 @@ namespace std {
 
 template<class T>
 inline bool isUndefined(T val) {
-return val == FLOAT_UNASSIGNED;
+	return val == FLOAT_UNASSIGNED;
 }
 
 } // namespace std
diff --git a/engines/ags/lib/std/memory.h b/engines/ags/lib/std/memory.h
index ae5a1a7161..7efe2c16f6 100644
--- a/engines/ags/lib/std/memory.h
+++ b/engines/ags/lib/std/memory.h
@@ -40,13 +40,13 @@ using unique_ptr = Common::ScopedPtr<T, DL>;
 
 template<class T>
 T *memcpy(T *dest, const T *src, size_t n) {
-return (T *)::memcpy(dest, src, n);
+	return (T *)::memcpy(dest, src, n);
 }
 
 template<class T>
 shared_ptr<T> static_pointer_cast(const shared_ptr<T> &src) {
-T *ptr = src.get();
-return shared_ptr<T>(ptr);
+	T *ptr = src.get();
+	return shared_ptr<T>(ptr);
 }
 
 } // namespace std
diff --git a/engines/ags/lib/std/queue.h b/engines/ags/lib/std/queue.h
index b0803ba527..2dfe76ccb0 100644
--- a/engines/ags/lib/std/queue.h
+++ b/engines/ags/lib/std/queue.h
@@ -36,27 +36,27 @@ using queue = Common::Queue<T>;
 template<class T, class Container = vector<T>, class Comparitor = typename Common::Less<T> >
 class priority_queue {
 private:
-Container _container;
-Comparitor _comparitor;
+	Container _container;
+	Comparitor _comparitor;
 public:
-priority_queue() {}
+	priority_queue() {}
 
-bool empty() const {
-	return _container.empty();
-}
+	bool empty() const {
+		return _container.empty();
+	}
 
-const T &top() const {
-	return _container.front();
-}
+	const T &top() const {
+		return _container.front();
+	}
 
-void push(const T &item) {
-	_container.push_back(item);
-	Common::sort(_container.begin(), _container.end(), _comparitor);
-}
+	void push(const T &item) {
+		_container.push_back(item);
+		Common::sort(_container.begin(), _container.end(), _comparitor);
+	}
 
-void pop() {
-	_container.remove_at(0);
-}
+	void pop() {
+		_container.remove_at(0);
+	}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/set.h b/engines/ags/lib/std/set.h
index bfa1b7e511..0d5b941d92 100644
--- a/engines/ags/lib/std/set.h
+++ b/engines/ags/lib/std/set.h
@@ -34,58 +34,58 @@ namespace std {
 template<class T, class Comparitor = Common::Less<T> >
 class set : public Common::SortedArray<T, const T &> {
 private:
-static int ComparatorFn(const T &a, const T &b) {
-	return Comparitor().operator()(a, b) ? -1 : 0;
-}
-public:
-struct Entry {
-	const T &_value;
-	Entry(const T &item) : _value(item) {
+	static int ComparatorFn(const T &a, const T &b) {
+		return Comparitor().operator()(a, b) ? -1 : 0;
 	}
-};
 public:
-using iterator = typename Common::SortedArray<T, const T &>::iterator;
-using const_iterator = typename Common::SortedArray<T, const T &>::const_iterator;
+	struct Entry {
+		const T &_value;
+		Entry(const T &item) : _value(item) {
+		}
+	};
+public:
+	using iterator = typename Common::SortedArray<T, const T &>::iterator;
+	using const_iterator = typename Common::SortedArray<T, const T &>::const_iterator;
 
-/**
- * Constructor
- */
-set() : Common::SortedArray<T, const T & >(ComparatorFn) {}
+	/**
+	 * Constructor
+	 */
+	set() : Common::SortedArray<T, const T & >(ComparatorFn) {}
 
-/**
- * Locate an item in the set
- */
-iterator find(const T &item) {
-	iterator it;
-	for (it = this->begin(); it != this->end() && *it != item; ++it) {
+	/**
+	 * Locate an item in the set
+	 */
+	iterator find(const T &item) {
+		iterator it;
+		for (it = this->begin(); it != this->end() && *it != item; ++it) {
+		}
+
+		return it;
 	}
 
-	return it;
-}
+	/**
+	 * Insert an element at the sorted position.
+	 */
+	Entry insert(const T &item) {
+		Common::SortedArray<T, const T &>::insert(item);
+		return Entry(item);
+	}
 
-/**
- * Insert an element at the sorted position.
- */
-Entry insert(const T &item) {
-	Common::SortedArray<T, const T &>::insert(item);
-	return Entry(item);
-}
+	/**
+	 * Returns the number of keys that match the specified key
+	 */
+	size_t count(const T item) const {
+		size_t total = 0;
+		for (const_iterator it = this->begin(); it != this->end(); ++it) {
+			if (*it == item)
+				++total;
+			else if (!ComparatorFn(item, *it))
+				// Passed beyond possibility of matches
+				break;
+		}
 
-/**
- * Returns the number of keys that match the specified key
- */
-size_t count(const T item) const {
-	size_t total = 0;
-	for (const_iterator it = this->begin(); it != this->end(); ++it) {
-		if (*it == item)
-			++total;
-		else if (!ComparatorFn(item, *it))
-			// Passed beyond possibility of matches
-			break;
+		return total;
 	}
-
-	return total;
-}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/type_traits.h b/engines/ags/lib/std/type_traits.h
index 9edac398d0..cc33200a82 100644
--- a/engines/ags/lib/std/type_traits.h
+++ b/engines/ags/lib/std/type_traits.h
@@ -31,17 +31,17 @@ namespace std {
 // STRUCT TEMPLATE remove_extent
 template <class _Ty>
 struct remove_extent { // remove array extent
-using type = _Ty;
+	using type = _Ty;
 };
 
 template <class _Ty, size_t _Ix>
 struct remove_extent<_Ty[_Ix]> {
-using type = _Ty;
+	using type = _Ty;
 };
 
 template <class _Ty>
 struct remove_extent<_Ty[]> {
-using type = _Ty;
+	using type = _Ty;
 };
 
 template <class _Ty>
diff --git a/engines/ags/lib/std/unordered_set.h b/engines/ags/lib/std/unordered_set.h
index 3f92ecbb5c..12a73026dc 100644
--- a/engines/ags/lib/std/unordered_set.h
+++ b/engines/ags/lib/std/unordered_set.h
@@ -36,53 +36,53 @@ namespace std {
 template <class T, class Hash = Common::Hash<T>, class Pred = Common::EqualTo<T> >
 class unordered_set : public Common::Array<T> {
 private:
-Hash _hash;
-Pred _comparitor;
+	Hash _hash;
+	Pred _comparitor;
+	public:
+	struct Entry {
+		const T &_value;
+		Entry(const T &item) : _value(item) {}
+	};
 public:
-struct Entry {
-	const T &_value;
-	Entry(const T &item) : _value(item) {}
-};
-public:
-using iterator = typename Common::Array<T>::iterator;
-using const_iterator = typename Common::Array<T>::const_iterator;
+	using iterator = typename Common::Array<T>::iterator;
+	using const_iterator = typename Common::Array<T>::const_iterator;
 
-unordered_set() {}
+	unordered_set() {}
 
-/**
- * Locate an item in the set
- */
-iterator find(const T &item) {
-	iterator it;
-	for (it = this->begin(); it != this->end() && *it != item; ++it) {
+	/**
+	 * Locate an item in the set
+	 */
+	iterator find(const T &item) {
+		iterator it;
+		for (it = this->begin(); it != this->end() && *it != item; ++it) {
+		}
+
+		return it;
 	}
 
-	return it;
-}
+	/**
+	 * Adds an item
+	 */
+	Entry insert(const T &item) {
+		this->push_back(item);
+		return Entry(item);
+	}
 
-/**
- * Adds an item
- */
-Entry insert(const T &item) {
-	this->push_back(item);
-	return Entry(item);
-}
+	/**
+	 * Returns the number of keys that match the specified key
+	 */
+	size_t count(const T item) const {
+		size_t total = 0;
+		for (const_iterator it = this->begin(); it != this->end(); ++it) {
+			if (*it == item)
+				++total;
+			else if (!_comparitor(item, *it))
+				// Passed beyond possibility of matches
+				break;
+		}
 
-/**
- * Returns the number of keys that match the specified key
- */
-size_t count(const T item) const {
-	size_t total = 0;
-	for (const_iterator it = this->begin(); it != this->end(); ++it) {
-		if (*it == item)
-			++total;
-		else if (!_comparitor(item, *it))
-			// Passed beyond possibility of matches
-			break;
+		return total;
 	}
-
-	return total;
-}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/utility.h b/engines/ags/lib/std/utility.h
index 7ad169d04c..41c43d09ac 100644
--- a/engines/ags/lib/std/utility.h
+++ b/engines/ags/lib/std/utility.h
@@ -28,23 +28,23 @@ namespace std {
 
 template<class T1, class T2>
 struct pair {
-T1 first;
-T2 second;
+	T1 first;
+	T2 second;
 
-pair() {
-}
-pair(T1 first_, T2 second_) : first(first_), second(second_) {
-}
+	pair() {
+	}
+	pair(T1 first_, T2 second_) : first(first_), second(second_) {
+	}
 };
 
 template< class T1, class T2 >
 pair<T1, T2> make_pair(T1 first, T2 second) {
-return pair<T1, T2>(first, second);
+	return pair<T1, T2>(first, second);
 }
 
 template<class T>
 T move(const T &v) {
-return v;
+	return v;
 }
 
 } // namespace std
diff --git a/engines/ags/lib/std/vector.h b/engines/ags/lib/std/vector.h
index 76e5b9ea5a..0c5b01f352 100644
--- a/engines/ags/lib/std/vector.h
+++ b/engines/ags/lib/std/vector.h
@@ -31,173 +31,173 @@ namespace std {
 template<class T>
 class vector : public Common::Array<T> {
 public:
-struct reverse_iterator {
-private:
-	vector<T> *_owner;
-	int _index;
+	struct reverse_iterator {
+	private:
+		vector<T> *_owner;
+		int _index;
+	public:
+		reverse_iterator(vector<T> *owner, int index) : _owner(owner), _index(index) {
+		}
+		reverse_iterator() : _owner(0), _index(-1) {
+		}
+
+		T &operator*() {
+			return (*_owner)[_index];
+		}
+
+		reverse_iterator &operator++() {
+			--_index;
+			return *this;
+		}
+
+		bool operator==(const reverse_iterator &rhs) {
+			return _owner == rhs._owner && _index == rhs._index;
+		}
+		bool operator!=(const reverse_iterator &rhs) {
+			return !operator==(rhs);
+		}
+	};
+
+	struct const_reverse_iterator {
+	private:
+		const vector<T> *_owner;
+		int _index;
+	public:
+		const_reverse_iterator(const vector<T> *owner, int index) : _owner(owner), _index(index) {
+		}
+		const_reverse_iterator() : _owner(0), _index(-1) {
+		}
+
+		const T operator*() const {
+			return (*_owner)[_index];
+		}
+
+		const_reverse_iterator &operator++() {
+			--_index;
+			return *this;
+		}
+
+		bool operator==(const const_reverse_iterator &rhs) {
+			return _owner == rhs._owner && _index == rhs._index;
+		}
+		bool operator!=(const const_reverse_iterator &rhs) {
+			return !operator==(rhs);
+		}
+	};
+
+	using iterator = typename Common::Array<T>::iterator;
+	using const_iterator = typename Common::Array<T>::const_iterator;
 public:
-	reverse_iterator(vector<T> *owner, int index) : _owner(owner), _index(index) {
+	typedef T reference;
+	typedef const T const_reference;
+
+	vector() : Common::Array<T>() {
 	}
-	reverse_iterator() : _owner(0), _index(-1) {
+	vector(size_t newSize) : Common::Array<T>() {
+		Common::Array<T>::resize(newSize);
+	}
+	vector(size_t newSize, const T elem) {
+		resize(newSize, elem);
 	}
 
-	T &operator*() {
-		return (*_owner)[_index];
+	iterator erase(iterator pos) {
+		return Common::Array<T>::erase(pos);
 	}
 
-	reverse_iterator &operator++() {
-		--_index;
-		return *this;
+	iterator erase(iterator first,
+				   iterator last) {
+		Common::copy(last, this->_storage + this->_size, first);
+
+		int count = (last - first);
+		this->_size -= count;
+
+		// We also need to destroy the objects beyond the new size
+		for (uint idx = this->_size; idx < (this->_size + count); ++idx)
+			this->_storage[idx].~T();
+
+		return first;
 	}
 
-	bool operator==(const reverse_iterator &rhs) {
-		return _owner == rhs._owner && _index == rhs._index;
+	void swap(vector &arr) {
+		SWAP(this->_capacity, arr._capacity);
+		SWAP(this->_size, arr._size);
+		SWAP(this->_storage, arr._storage);
 	}
-	bool operator!=(const reverse_iterator &rhs) {
-		return !operator==(rhs);
+
+	/**
+	 * Rotates the array so that the item pointed to by the iterator becomes
+	 * the first item, and the predeceding item becomes the last one
+	 */
+	void rotate(iterator it) {
+		if (it != Common::Array<T>::end()) {
+			size_t count = it - Common::Array<T>::begin();
+			for (size_t ctr = 0; ctr < count; ++ctr) {
+				Common::Array<T>::push_back(Common::Array<T>::front());
+				Common::Array<T>::remove_at(0);
+			}
+		}
 	}
-};
 
-struct const_reverse_iterator {
-private:
-	const vector<T> *_owner;
-	int _index;
-public:
-	const_reverse_iterator(const vector<T> *owner, int index) : _owner(owner), _index(index) {
+	const_iterator cbegin() {
+		return this->begin();
 	}
-	const_reverse_iterator() : _owner(0), _index(-1) {
+	const_iterator cend() {
+		return this->end();
 	}
-
-	const T operator*() const {
-		return (*_owner)[_index];
+	reverse_iterator rbegin() {
+		return reverse_iterator(this, (int)Common::Array<T>::size() - 1);
+	}
+	reverse_iterator rend() {
+		return reverse_iterator(this, -1);
+	}
+	const_reverse_iterator rbegin() const {
+		return const_reverse_iterator(this, (int)Common::Array<T>::size() - 1);
+	}
+	const_reverse_iterator rend() const {
+		return const_reverse_iterator(this, -1);
 	}
 
-	const_reverse_iterator &operator++() {
-		--_index;
-		return *this;
+	void pop_front() {
+		Common::Array<T>::remove_at(0);
 	}
 
-	bool operator==(const const_reverse_iterator &rhs) {
-		return _owner == rhs._owner && _index == rhs._index;
+	void resize(size_t newSize) {
+		Common::Array<T>::resize(newSize);
 	}
-	bool operator!=(const const_reverse_iterator &rhs) {
-		return !operator==(rhs);
+	void resize(size_t newSize, const T elem) {
+		size_t oldSize = Common::Array<T>::size();
+		resize(newSize);
+		for (size_t idx = oldSize; idx < newSize; ++idx)
+			this->operator[](idx) = elem;
 	}
-};
 
-using iterator = typename Common::Array<T>::iterator;
-using const_iterator = typename Common::Array<T>::const_iterator;
-public:
-typedef T reference;
-typedef const T const_reference;
-
-vector() : Common::Array<T>() {
-}
-vector(size_t newSize) : Common::Array<T>() {
-	Common::Array<T>::resize(newSize);
-}
-vector(size_t newSize, const T elem) {
-	resize(newSize, elem);
-}
-
-iterator erase(iterator pos) {
-	return Common::Array<T>::erase(pos);
-}
-
-iterator erase(iterator first,
-               iterator last) {
-	Common::copy(last, this->_storage + this->_size, first);
-
-	int count = (last - first);
-	this->_size -= count;
-
-	// We also need to destroy the objects beyond the new size
-	for (uint idx = this->_size; idx < (this->_size + count); ++idx)
-		this->_storage[idx].~T();
-
-	return first;
-}
-
-void swap(vector &arr) {
-	SWAP(this->_capacity, arr._capacity);
-	SWAP(this->_size, arr._size);
-	SWAP(this->_storage, arr._storage);
-}
-
-/**
- * Rotates the array so that the item pointed to by the iterator becomes
- * the first item, and the predeceding item becomes the last one
- */
-void rotate(iterator it) {
-	if (it != Common::Array<T>::end()) {
-		size_t count = it - Common::Array<T>::begin();
-		for (size_t ctr = 0; ctr < count; ++ctr) {
-			Common::Array<T>::push_back(Common::Array<T>::front());
-			Common::Array<T>::remove_at(0);
-		}
+	T at(size_t index) const {
+		return (*this)[index];
 	}
-}
-
-const_iterator cbegin() {
-	return this->begin();
-}
-const_iterator cend() {
-	return this->end();
-}
-reverse_iterator rbegin() {
-	return reverse_iterator(this, (int)Common::Array<T>::size() - 1);
-}
-reverse_iterator rend() {
-	return reverse_iterator(this, -1);
-}
-const_reverse_iterator rbegin() const {
-	return const_reverse_iterator(this, (int)Common::Array<T>::size() - 1);
-}
-const_reverse_iterator rend() const {
-	return const_reverse_iterator(this, -1);
-}
-
-void pop_front() {
-	Common::Array<T>::remove_at(0);
-}
-
-void resize(size_t newSize) {
-	Common::Array<T>::resize(newSize);
-}
-void resize(size_t newSize, const T elem) {
-	size_t oldSize = Common::Array<T>::size();
-	resize(newSize);
-	for (size_t idx = oldSize; idx < newSize; ++idx)
-		this->operator[](idx) = elem;
-}
-
-T at(size_t index) const {
-	return (*this)[index];
-}
-
-/**
- * Adds an item to the array
- */
-void insert(const T &element) {
-	Common::Array<T>::push_back(element);
-}
 
-/**
- * Adds an item to the array at a specified index
- */
-void insert(iterator pos, const T &element) {
-	Common::Array<T>::insert(pos, element);
-}
+	/**
+	 * Adds an item to the array
+	 */
+	void insert(const T &element) {
+		Common::Array<T>::push_back(element);
+	}
 
-/**
- * Adds a range of items at the specified position in the array
- */
-void insert(iterator position, const_iterator first, const_iterator last) {
-	int destIndex = position - this->begin();
-	for (; first != last; ++first) {
-		this->insert_at(destIndex++, *first);
+	/**
+	 * Adds an item to the array at a specified index
+	 */
+	void insert(iterator pos, const T &element) {
+		Common::Array<T>::insert(pos, element);
+	}
+
+	/**
+	 * Adds a range of items at the specified position in the array
+	 */
+	void insert(iterator position, const_iterator first, const_iterator last) {
+		int destIndex = position - this->begin();
+		for (; first != last; ++first) {
+			this->insert_at(destIndex++, *first);
+		}
 	}
-}
 };
 
 } // namespace std
diff --git a/engines/ags/lib/std/xtr1common.h b/engines/ags/lib/std/xtr1common.h
index f8813c7583..c17c0ba663 100644
--- a/engines/ags/lib/std/xtr1common.h
+++ b/engines/ags/lib/std/xtr1common.h
@@ -29,12 +29,12 @@ namespace std {
 // STRUCT TEMPLATE conditional
 template <bool _Test, class _Ty1, class _Ty2>
 struct conditional { // Choose _Ty1 if _Test is true, and _Ty2 otherwise
-using type = _Ty1;
+	using type = _Ty1;
 };
 
 template <class _Ty1, class _Ty2>
 struct conditional<false, _Ty1, _Ty2> {
-using type = _Ty2;
+	using type = _Ty2;
 };
 
 template <bool _Test, class _Ty1, class _Ty2>
diff --git a/engines/ags/lib/std/xutility.h b/engines/ags/lib/std/xutility.h
index da838abdb7..519db3c054 100644
--- a/engines/ags/lib/std/xutility.h
+++ b/engines/ags/lib/std/xutility.h
@@ -31,9 +31,9 @@ namespace std {
 
 template <class T>
 void reverse(T *First, T *Last) {
-for (--Last; First < Last; ++First, --Last) {
-	SWAP(*First, *Last);
-}
+	for (--Last; First < Last; ++First, --Last) {
+		SWAP(*First, *Last);
+	}
 }
 
 } // namespace std


Commit: 7a1ee192e2663e53c8e7edbb1a3d59829f96f7dd
    https://github.com/scummvm/scummvm/commit/7a1ee192e2663e53c8e7edbb1a3d59829f96f7dd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:34-07:00

Commit Message:
AGS: Fixup character's view loop in update, prevent having no frame

>From upstream 2ac1b258db203b62ba0613c979d7a092b51e441f

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


diff --git a/engines/ags/engine/ac/character_info_engine.cpp b/engines/ags/engine/ac/character_info_engine.cpp
index 3fc262c0c6..560f334a3f 100644
--- a/engines/ags/engine/ac/character_info_engine.cpp
+++ b/engines/ags/engine/ac/character_info_engine.cpp
@@ -76,10 +76,15 @@ void CharacterInfo::UpdateMoveAndAnim(int &char_index, CharacterExtras *chex, in
 		return;                   //  must be careful not to screw things up
 	}
 
-	// Make sure it doesn't flash up a blue cup
-	if (view < 0);
-	else if (loop >= _G(views)[view].numLoops)
-		loop = 0;
+	// Fixup character's view when possible
+	if (view >= 0 &&
+		(loop >= _G(views)[view].numLoops || frame >= _G(views)[view].loops[loop].numFrames)) {
+		for (loop = 0;
+			(loop < _G(views)[view].numLoops) && (_G(views)[view].loops[loop].numFrames == 0); ++loop) {
+		}
+		if (loop == _G(views)[view].numLoops)
+			quitprintf("!Character %s is assigned view %d that has no frames!", name, view);
+	}
 
 	int doing_nothing = 1;
 


Commit: 69157077cff2d7c3f1a2019d044a120d579b8d5f
    https://github.com/scummvm/scummvm/commit/69157077cff2d7c3f1a2019d044a120d579b8d5f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:35-07:00

Commit Message:
AGS: Fixed Path::GetParent (now it actually works)

>From upstream a72e45f6ebb19e9da96cbe2d621f86ac57bffa8a

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


diff --git a/engines/ags/shared/util/path.cpp b/engines/ags/shared/util/path.cpp
index 56b894ea5c..b19ca3ecd6 100644
--- a/engines/ags/shared/util/path.cpp
+++ b/engines/ags/shared/util/path.cpp
@@ -70,6 +70,16 @@ bool IsFileOrDir(const String &filename) {
 	return ags_path_exists(fixed_path.GetCStr()) != 0;
 }
 
+String GetParent(const String &path) {
+	const char *cstr = path.GetCStr();
+	const char *ptr_end = cstr + path.GetLength();
+	for (const char *ptr = ptr_end; ptr > cstr; --ptr) {
+		if (*ptr == '/' || *ptr == PATH_ALT_SEPARATOR)
+			return String(cstr, ptr - cstr);
+	}
+	return ".";
+}
+
 String GetFilename(const String &path) {
 	return get_filename(path.GetCStr());
 }
diff --git a/engines/ags/shared/util/path.h b/engines/ags/shared/util/path.h
index 664beb8754..44c99dee11 100644
--- a/engines/ags/shared/util/path.h
+++ b/engines/ags/shared/util/path.h
@@ -51,7 +51,8 @@ bool    IsFile(const String &filename);
 // Tells if the given path is file or directory;
 // may be used to check if it's valid to use
 bool    IsFileOrDir(const String &filename);
-// Returns filename part out of the longer path
+// Returns parent directory of the given path;
+// returns "." (current dir) if the path does not contain a parent segment
 String  GetFilename(const String &path);
 // Returns file's extension; file may be a fully qualified path too
 String  GetFileExtension(const String &path);


Commit: 5e37a5515ba10088e0de1add06c2db553618b1b4
    https://github.com/scummvm/scummvm/commit/5e37a5515ba10088e0de1add06c2db553618b1b4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:35-07:00

Commit Message:
AGS: Implemented GetFiles and GetDirs through the same algorithm

>From upstream 187b8fde1350575e3d848355cba3aba928285c22

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


diff --git a/engines/ags/shared/util/directory.cpp b/engines/ags/shared/util/directory.cpp
index aea9cd7086..2b0dccfd04 100644
--- a/engines/ags/shared/util/directory.cpp
+++ b/engines/ags/shared/util/directory.cpp
@@ -89,6 +89,27 @@ String GetCurrentDirectory() {
 #endif
 }
 
+static bool GetFilesImpl(const String &dir_path, std::vector<String> &files, bool isDirectories) {
+	Common::FSNode fsNode(dir_path);
+	Common::FSList fsList;
+
+	fsNode.getChildren(fsList,
+		isDirectories ? Common::FSNode::kListDirectoriesOnly :
+		Common::FSNode::kListFilesOnly);
+
+	for (uint i = 0; i < fsList.size(); ++i)
+		files.push_back(fsList[i].getName());
+	return true;
+}
+
+bool GetDirs(const String &dir_path, std::vector<String> &dirs) {
+	return GetFilesImpl(dir_path, dirs, true);
+}
+
+bool GetFiles(const String &dir_path, std::vector<String> &files) {
+	return GetFilesImpl(dir_path, files, false);
+}
+
 } // namespace Directory
 
 } // namespace Shared
diff --git a/engines/ags/shared/util/directory.h b/engines/ags/shared/util/directory.h
index 0093193da2..80df2f0d16 100644
--- a/engines/ags/shared/util/directory.h
+++ b/engines/ags/shared/util/directory.h
@@ -50,6 +50,11 @@ String SetCurrentDirectory(const String &path);
 // Gets current working directory
 String GetCurrentDirectory();
 
+// Get list of subdirs found in the given directory
+bool   GetDirs(const String &dir_path, std::vector<String> &dirs);
+// Get list of files found in the given directory
+bool   GetFiles(const String &dir_path, std::vector<String> &files);
+
 } // namespace Directory
 
 } // namespace Shared


Commit: 00ade063b9ab75941562e616cc679547d0100a71
    https://github.com/scummvm/scummvm/commit/00ade063b9ab75941562e616cc679547d0100a71
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:35-07:00

Commit Message:
AGS: In File api functions replaced quit with a warning on error

>From upstream b703e7d25041e1b6bf99b76a89ca422351e04ace

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


diff --git a/engines/ags/engine/ac/file.cpp b/engines/ags/engine/ac/file.cpp
index 9ed36878a2..105a2c3ca4 100644
--- a/engines/ags/engine/ac/file.cpp
+++ b/engines/ags/engine/ac/file.cpp
@@ -118,12 +118,12 @@ void File_ReadRawLine(sc_File *fil, char *buffer) {
 	int i = 0;
 	while (i < _G(MAXSTRLEN) - 1) {
 		buffer[i] = in->ReadInt8();
-		if (buffer[i] == 13) {
+		if (buffer[i] == '\r') {
 			// CR -- skip LF and abort
 			in->ReadInt8();
 			break;
 		}
-		if (buffer[i] == 10)  // LF only -- abort
+		if (buffer[i] == '\n')  // LF only -- abort
 			break;
 		if (in->EOS())  // EOF -- abort
 			break;
@@ -148,9 +148,11 @@ const char *File_ReadStringBack(sc_File *fil) {
 		return CreateNewScriptString("");
 	}
 
-	int lle = in->ReadInt32();
-	if ((lle >= 20000) || (lle < 1))
-		quit("!File.ReadStringBack: file was not written by WriteString");
+	size_t lle = (uint32_t)in->ReadInt32();
+	if (lle == 0) {
+		debug_script_warn("File.ReadStringBack: file was not written by WriteString");
+		return CreateNewScriptString("");
+	}
 
 	char *retVal = (char *)malloc(lle);
 	in->Read(retVal, lle);
diff --git a/engines/ags/engine/ac/global_file.cpp b/engines/ags/engine/ac/global_file.cpp
index b18627ce03..204cd23771 100644
--- a/engines/ags/engine/ac/global_file.cpp
+++ b/engines/ags/engine/ac/global_file.cpp
@@ -101,14 +101,15 @@ void FileClose(int32_t handle) {
 }
 void FileWrite(int32_t handle, const char *towrite) {
 	Stream *out = get_valid_file_stream_from_handle(handle, "FileWrite");
-	out->WriteInt32(strlen(towrite) + 1);
-	out->Write(towrite, strlen(towrite) + 1);
+	size_t len = strlen(towrite);
+	out->WriteInt32(len + 1); // write with null-terminator
+	out->Write(towrite, len + 1);
 }
 void FileWriteRawLine(int32_t handle, const char *towrite) {
 	Stream *out = get_valid_file_stream_from_handle(handle, "FileWriteRawLine");
 	out->Write(towrite, strlen(towrite));
-	out->WriteInt8(13);
-	out->WriteInt8(10);
+	out->WriteInt8('\r');
+	out->WriteInt8('\n');
 }
 void FileRead(int32_t handle, char *toread) {
 	VALIDATE_STRING(toread);
@@ -117,10 +118,16 @@ void FileRead(int32_t handle, char *toread) {
 		toread[0] = 0;
 		return;
 	}
-	int lle = in->ReadInt32();
-	if ((lle >= 200) | (lle < 1)) quit("!FileRead: file was not written by FileWrite");
+
+	size_t lle = (uint32_t)in->ReadInt32();
+	// This tests for the legacy string (limited by 200 chars)
+	if ((lle >= 200) | (lle < 1)) {
+		debug_script_warn("FileRead: file was not written by FileWrite");
+		return;
+	}
 	in->Read(toread, lle);
 }
+
 int FileIsEOF(int32_t handle) {
 	Stream *stream = get_valid_file_stream_from_handle(handle, "FileIsEOF");
 	if (stream->EOS())
@@ -152,26 +159,32 @@ int FileReadInt(int32_t handle) {
 	Stream *in = get_valid_file_stream_from_handle(handle, "FileReadInt");
 	if (in->EOS())
 		return -1;
-	if (in->ReadInt8() != 'I')
-		quit("!FileReadInt: File read back in wrong order");
+	if (in->ReadInt8() != 'I') {
+		debug_script_warn("FileReadInt: File read back in wrong order");
+		return -1;
+	}
+
 	return in->ReadInt32();
 }
+
 char FileReadRawChar(int32_t handle) {
 	Stream *in = get_valid_file_stream_from_handle(handle, "FileReadRawChar");
 	if (in->EOS())
 		return -1;
 	return in->ReadInt8();
 }
+
 int FileReadRawInt(int32_t handle) {
 	Stream *in = get_valid_file_stream_from_handle(handle, "FileReadRawInt");
 	if (in->EOS())
 		return -1;
 	return in->ReadInt32();
 }
+
 void FileWriteRawChar(int32_t handle, int chartoWrite) {
 	Stream *out = get_valid_file_stream_from_handle(handle, "FileWriteRawChar");
 	if ((chartoWrite < 0) || (chartoWrite > 255))
-		quit("!FileWriteRawChar: can only write values 0-255");
+		debug_script_warn("!FileWriteRawChar: can only write values 0-255");
 
 	out->WriteInt8(chartoWrite);
 }


Commit: 5ccb07acf9d63f536e349120c07ee84bfebf8f90
    https://github.com/scummvm/scummvm/commit/5ccb07acf9d63f536e349120c07ee84bfebf8f90
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: implemented bool Room.Exists(int room)

>From upstream d676baaea0860ef1737019452d8e97b4aee12526

Changed paths:
    engines/ags/engine/ac/room.cpp
    engines/ags/engine/ac/room.h
    engines/ags/engine/script/script_api.h
    engines/ags/plugins/core/room.cpp
    engines/ags/plugins/core/room.h


diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index 9305c69a81..9cbf56cd7e 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -166,6 +166,11 @@ const char *Room_GetMessages(int index) {
 	return CreateNewScriptString(buffer);
 }
 
+bool Room_Exists(int room) {
+	String room_filename;
+	room_filename.Format("room%d.crm", room);
+	return _GP(AssetMgr)->DoesAssetExist(room_filename);
+}
 
 //=============================================================================
 
@@ -1158,25 +1163,30 @@ RuntimeScriptValue Sc_RoomProcessClick(const RuntimeScriptValue *params, int32_t
 	API_SCALL_VOID_PINT3(RoomProcessClick);
 }
 
+RuntimeScriptValue Sc_Room_Exists(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_BOOL_PINT(Room_Exists);
+}
+
 
 void RegisterRoomAPI() {
 	ccAddExternalStaticFunction("Room::GetDrawingSurfaceForBackground^1",   Sc_Room_GetDrawingSurfaceForBackground);
-	ccAddExternalStaticFunction("Room::GetProperty^1",                      Sc_Room_GetProperty);
-	ccAddExternalStaticFunction("Room::GetTextProperty^1",                  Sc_Room_GetTextProperty);
-	ccAddExternalStaticFunction("Room::SetProperty^2",                      Sc_Room_SetProperty);
-	ccAddExternalStaticFunction("Room::SetTextProperty^2",                  Sc_Room_SetTextProperty);
-	ccAddExternalStaticFunction("Room::ProcessClick^3",                     Sc_RoomProcessClick);
-	ccAddExternalStaticFunction("ProcessClick",                             Sc_RoomProcessClick);
-	ccAddExternalStaticFunction("Room::get_BottomEdge",                     Sc_Room_GetBottomEdge);
-	ccAddExternalStaticFunction("Room::get_ColorDepth",                     Sc_Room_GetColorDepth);
-	ccAddExternalStaticFunction("Room::get_Height",                         Sc_Room_GetHeight);
-	ccAddExternalStaticFunction("Room::get_LeftEdge",                       Sc_Room_GetLeftEdge);
-	ccAddExternalStaticFunction("Room::geti_Messages",                      Sc_Room_GetMessages);
-	ccAddExternalStaticFunction("Room::get_MusicOnLoad",                    Sc_Room_GetMusicOnLoad);
-	ccAddExternalStaticFunction("Room::get_ObjectCount",                    Sc_Room_GetObjectCount);
-	ccAddExternalStaticFunction("Room::get_RightEdge",                      Sc_Room_GetRightEdge);
-	ccAddExternalStaticFunction("Room::get_TopEdge",                        Sc_Room_GetTopEdge);
-	ccAddExternalStaticFunction("Room::get_Width",                          Sc_Room_GetWidth);
+	ccAddExternalStaticFunction("Room::GetProperty^1",      Sc_Room_GetProperty);
+	ccAddExternalStaticFunction("Room::GetTextProperty^1",  Sc_Room_GetTextProperty);
+	ccAddExternalStaticFunction("Room::SetProperty^2",      Sc_Room_SetProperty);
+	ccAddExternalStaticFunction("Room::SetTextProperty^2",  Sc_Room_SetTextProperty);
+	ccAddExternalStaticFunction("Room::ProcessClick^3",     Sc_RoomProcessClick);
+	ccAddExternalStaticFunction("ProcessClick",             Sc_RoomProcessClick);
+	ccAddExternalStaticFunction("Room::get_BottomEdge",     Sc_Room_GetBottomEdge);
+	ccAddExternalStaticFunction("Room::get_ColorDepth",     Sc_Room_GetColorDepth);
+	ccAddExternalStaticFunction("Room::get_Height",         Sc_Room_GetHeight);
+	ccAddExternalStaticFunction("Room::get_LeftEdge",       Sc_Room_GetLeftEdge);
+	ccAddExternalStaticFunction("Room::geti_Messages",      Sc_Room_GetMessages);
+	ccAddExternalStaticFunction("Room::get_MusicOnLoad",    Sc_Room_GetMusicOnLoad);
+	ccAddExternalStaticFunction("Room::get_ObjectCount",    Sc_Room_GetObjectCount);
+	ccAddExternalStaticFunction("Room::get_RightEdge",      Sc_Room_GetRightEdge);
+	ccAddExternalStaticFunction("Room::get_TopEdge",        Sc_Room_GetTopEdge);
+	ccAddExternalStaticFunction("Room::get_Width",          Sc_Room_GetWidth);
+	ccAddExternalStaticFunction("Room::Exists",             Sc_Room_Exists);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/room.h b/engines/ags/engine/ac/room.h
index 2e6116fa2b..cef464acd0 100644
--- a/engines/ags/engine/ac/room.h
+++ b/engines/ags/engine/ac/room.h
@@ -43,6 +43,7 @@ int Room_GetMusicOnLoad();
 const char *Room_GetTextProperty(const char *property);
 int Room_GetProperty(const char *property);
 const char *Room_GetMessages(int index);
+bool Room_Exists(int room);
 RuntimeScriptValue Sc_Room_GetProperty(const RuntimeScriptValue *params, int32_t param_count);
 
 //=============================================================================
diff --git a/engines/ags/engine/script/script_api.h b/engines/ags/engine/script/script_api.h
index 0ffbe8a705..18bac43cb9 100644
--- a/engines/ags/engine/script/script_api.h
+++ b/engines/ags/engine/script/script_api.h
@@ -285,6 +285,10 @@ inline const char *ScriptVSprintf(char *buffer, size_t buf_length, const char *f
 	ASSERT_PARAM_COUNT(FUNCTION, 1); \
 	return RuntimeScriptValue().SetInt32AsBool(FUNCTION((P1CLASS*)params[0].Ptr))
 
+#define API_SCALL_BOOL_PINT(FUNCTION) \
+    ASSERT_PARAM_COUNT(FUNCTION, 1); \
+    return RuntimeScriptValue().SetInt32AsBool(FUNCTION(params[0].IValue))
+
 #define API_SCALL_BOOL_POBJ_PINT(FUNCTION, P1CLASS) \
 	ASSERT_PARAM_COUNT(FUNCTION, 2); \
 	return RuntimeScriptValue().SetInt32AsBool(FUNCTION((P1CLASS*)params[0].Ptr, params[1].IValue))
diff --git a/engines/ags/plugins/core/room.cpp b/engines/ags/plugins/core/room.cpp
index 4917c05685..f98c56279f 100644
--- a/engines/ags/plugins/core/room.cpp
+++ b/engines/ags/plugins/core/room.cpp
@@ -101,6 +101,11 @@ void Room::GetWidth(ScriptMethodParams &params) {
 	params._result = AGS3::Room_GetWidth();
 }
 
+void Room::RoomExists(ScriptMethodParams &params) {
+	PARAMS1(int, room);
+	params._result = AGS3::Room_Exists(room);
+}
+
 } // namespace Core
 } // namespace Plugins
 } // namespace AGS3
diff --git a/engines/ags/plugins/core/room.h b/engines/ags/plugins/core/room.h
index f891e9f77e..d617953549 100644
--- a/engines/ags/plugins/core/room.h
+++ b/engines/ags/plugins/core/room.h
@@ -48,6 +48,7 @@ public:
 	void GetRightEdge(ScriptMethodParams &params);
 	void GetTopEdge(ScriptMethodParams &params);
 	void GetWidth(ScriptMethodParams &params);
+	void RoomExists(ScriptMethodParams &params);
 };
 
 } // namespace Core


Commit: 47928c39aaf1a3b8523a031fbea02fc34b6103e4
    https://github.com/scummvm/scummvm/commit/47928c39aaf1a3b8523a031fbea02fc34b6103e4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: changed Object.SetView default loop & frame values to 0

>From upstream eb376e63f95b09fd75ca7f96591aca20d0564072

Changed paths:
    engines/ags/engine/ac/global_object.cpp
    engines/ags/engine/ac/object.cpp


diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index 7d00eeace5..39e424ef3d 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -153,13 +153,19 @@ void SetObjectView(int obn, int vii) {
 void SetObjectFrame(int obn, int viw, int lop, int fra) {
 	if (!is_valid_object(obn)) quit("!SetObjectFrame: invalid object number specified");
 	viw--;
-	if (viw >= _GP(game).numviews) quit("!SetObjectFrame: invalid view number used");
-	if (_G(views)[viw].numLoops == 0) quit("!SetObjectFrame: specified view has no loops");
-	if (lop >= _G(views)[viw].numLoops) quit("!SetObjectFrame: invalid loop number used");
-
+	if (viw < 0 || viw >= _GP(game).numviews) quitprintf("!SetObjectFrame: invalid view number used (%d, range is 0 - %d)", viw, _GP(game).numviews - 1);
+	if (lop < 0 || lop >= _G(views)[viw].numLoops) quitprintf("!SetObjectFrame: invalid loop number used (%d, range is 0 - %d)", lop, _G(views)[viw].numLoops - 1);
+	// AGS < 3.6.0 let user to pass literally any positive invalid frame value by silently reassigning it to zero...
+	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v360) {
+		if (fra >= _G(views)[viw].loops[lop].numFrames) {
+			debug_script_warn("SetObjectFrame: frame index out of range (%d, must be 0 - %d), set to 0", fra, _G(views)[viw].loops[lop].numFrames - 1);
+			fra = 0;
+		}
+	}
+	if (fra < 0 || fra >= _G(views)[viw].loops[lop].numFrames) quitprintf("!SetObjectFrame: invalid frame number used (%d, range is 0 - %d)", fra, _G(views)[viw].loops[lop].numFrames - 1);
 	if (viw > UINT16_MAX || lop > UINT16_MAX || fra > UINT16_MAX) {
 		debug_script_warn("Warning: object's (id %d) view/loop/frame (%d/%d/%d) is outside of internal range (%d/%d/%d), reset to no view",
-		                  obn, viw + 1, lop, fra, UINT16_MAX + 1, UINT16_MAX, UINT16_MAX);
+			obn, viw + 1, lop, fra, UINT16_MAX + 1, UINT16_MAX, UINT16_MAX);
 		SetObjectGraphic(obn, 0);
 		return;
 	}
@@ -169,20 +175,17 @@ void SetObjectFrame(int obn, int viw, int lop, int fra) {
 		_G(objs)[obn].loop = (uint16_t)lop;
 	if (fra >= 0)
 		_G(objs)[obn].frame = (uint16_t)fra;
-	if (_G(objs)[obn].loop >= _G(views)[viw].numLoops)
-		_G(objs)[obn].loop = 0;
-	if (_G(objs)[obn].frame >= _G(views)[viw].loops[_G(objs)[obn].loop].numFrames)
-		_G(objs)[obn].frame = 0;
-
 	// AGS >= 3.2.0 do not let assign an empty loop
 	// NOTE: pre-3.2.0 games are converting views from ViewStruct272 struct, always has at least 1 frame
 	if (_G(loaded_game_file_version) >= kGameVersion_320) {
-		if (_G(views)[viw].loops[_G(objs)[obn].loop].numFrames == 0)
+		if (_G(views)[viw].loops[lop].numFrames == 0)
 			quit("!SetObjectFrame: specified loop has no frames");
 	}
-
+	_G(objs)[obn].view = viw;
+	_G(objs)[obn].loop = lop;
+	_G(objs)[obn].frame = fra;
 	_G(objs)[obn].cycling = 0;
-	int pic = _G(views)[viw].loops[_G(objs)[obn].loop].frames[_G(objs)[obn].frame].pic;
+	int pic = _G(views)[viw].loops[lop].frames[fra].pic;
 	_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);
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index d55a27d41f..cc04f39096 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -40,6 +40,7 @@
 #include "ags/engine/main/game_run.h"
 #include "ags/engine/ac/route_finder.h"
 #include "ags/engine/gfx/graphics_driver.h"
+#include "ags/shared/ac/view.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/shared/gfx/gfx_def.h"
 #include "ags/engine/script/runtime_script_value.h"
@@ -87,6 +88,16 @@ void Object_RemoveTint(ScriptObject *objj) {
 }
 
 void Object_SetView(ScriptObject *objj, int view, int loop, int frame) {
+	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v360) { // Previous version of SetView had negative loop and frame mean "use latest values"
+		auto &obj = _G(objs)[objj->id];
+		if (loop < 0) loop = obj.loop;
+		if (frame < 0) frame = obj.frame;
+		const int vidx = view - 1;
+		if (vidx < 0 || vidx >= _GP(game).numviews) quit("!Object_SetView: invalid view number used");
+		loop = CLIP(loop, 0, (int)_G(views)[vidx].numLoops - 1);
+		frame = CLIP(frame, 0, (int)_G(views)[vidx].loops[loop].numFrames - 1);
+	}
+
 	SetObjectFrame(objj->id, view, loop, frame);
 }
 


Commit: 5b4ce2d365a9764afbfdfff3639ae845e5e5fb7e
    https://github.com/scummvm/scummvm/commit/5b4ce2d365a9764afbfdfff3639ae845e5e5fb7e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: support source rectangle for DrawImage

>From upstream 27e2f431ed892a0dd9bea8c1831846ca0ca493e1

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


diff --git a/engines/ags/engine/ac/drawing_surface.cpp b/engines/ags/engine/ac/drawing_surface.cpp
index 731faffd66..b2ec3effe0 100644
--- a/engines/ags/engine/ac/drawing_surface.cpp
+++ b/engines/ags/engine/ac/drawing_surface.cpp
@@ -140,56 +140,91 @@ void DrawingSurface_DrawSurface(ScriptDrawingSurface *target, ScriptDrawingSurfa
 	target->FinishedDrawing();
 }
 
-void DrawingSurface_DrawImage(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height) {
+void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y, int slot, int trans, int dst_width, int dst_height,
+	int src_x, int src_y, int src_width, int src_height) {
 	if ((slot < 0) || (_GP(spriteset)[slot] == nullptr))
 		quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
-
 	if ((trans < 0) || (trans > 100))
 		quit("!DrawingSurface.DrawImage: invalid transparency setting");
-
-	// 100% transparency, don't draw anything
 	if (trans == 100)
-		return;
-
-	Bitmap *sourcePic = _GP(spriteset)[slot];
-	bool needToFreeBitmap = false;
-
-	if (width != SCR_NO_VALUE) {
-		// Resize specified
-
-		if ((width < 1) || (height < 1))
-			return;
-
-		sds->SizeToGameResolution(&width, &height);
+		return; // fully transparent
+	if (dst_width < 1 || dst_height < 1 || src_width < 1 || src_height < 1)
+		return; // invalid src or dest rectangles
+
+	// Setup uninitialized arguments; convert coordinates for legacy script mode
+	Bitmap *ds = sds->GetBitmapSurface();
+	Bitmap *src = _GP(spriteset)[slot];
+	if (dst_width == SCR_NO_VALUE) {
+		dst_width = src->GetWidth();
+	} else {
+		sds->SizeToGameResolution(&dst_width);
+	}
+	if (dst_height == SCR_NO_VALUE) {
+		dst_height = src->GetHeight();
+	} else {
+		sds->SizeToGameResolution(&dst_height);
+	}
 
-		// resize the sprite to the requested size
-		Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, sourcePic->GetColorDepth());
+	if (src_x == SCR_NO_VALUE) {
+		src_x = 0;
+	}
+	if (src_y == SCR_NO_VALUE) {
+		src_y = 0;
+	}
+	sds->PointToGameResolution(&src_x, &src_y);
+	if (src_width == SCR_NO_VALUE) {
+		src_width = src->GetWidth();
+	} else {
+		sds->SizeToGameResolution(&src_width);
+	}
+	if (src_height == SCR_NO_VALUE) {
+		src_height = src->GetHeight();
+	} else {
+		sds->SizeToGameResolution(&src_height);
+	}
 
-		newPic->StretchBlt(sourcePic,
-		                   RectWH(0, 0, _GP(game).SpriteInfos[slot].Width, _GP(game).SpriteInfos[slot].Height),
-		                   RectWH(0, 0, width, height));
+	if (dst_x >= ds->GetWidth() || dst_x + dst_width <= 0 || dst_y >= ds->GetHeight() || dst_y + dst_height <= 0 ||
+		src_x >= src->GetWidth() || src_x + src_width <= 0 || src_y >= src->GetHeight() || src_y + src_height <= 0)
+		return; // source or destination rects lie completely off surface
+	// Clamp the source rect to the valid limits to prevent exceptions (ignore dest, bitmap drawing deals with that)
+	Math::ClampLength(src_x, src_width, 0, src->GetWidth());
+	Math::ClampLength(src_y, src_height, 0, src->GetHeight());
 
-		sourcePic = newPic;
+	// TODO: possibly optimize by not making a stretched intermediate bitmap
+	// if simplier blit/draw_sprite could be called (no translucency with alpha channel).
+	bool needToFreeBitmap = false;
+	if (dst_width != src->GetWidth() || dst_height != src->GetHeight() ||
+		src_width != src->GetWidth() || src_height != src->GetHeight()) {
+		// Resize and/or partial copy specified
+		Bitmap *newPic = BitmapHelper::CreateBitmap(dst_width, dst_height, src->GetColorDepth());
+		newPic->StretchBlt(src,
+			RectWH(src_x, src_y, src_width, src_height),
+			RectWH(0, 0, dst_width, dst_height));
+
+		src = newPic;
 		needToFreeBitmap = true;
 		update_polled_stuff_if_runtime();
 	}
 
-	Bitmap *ds = sds->StartDrawing();
-	sds->PointToGameResolution(&xx, &yy);
+	ds = sds->StartDrawing();
+	sds->PointToGameResolution(&dst_x, &dst_y);
 
-	if (sourcePic->GetColorDepth() != ds->GetColorDepth()) {
+	if (src->GetColorDepth() != ds->GetColorDepth()) {
 		debug_script_warn("RawDrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", slot, _GP(spriteset)[slot]->GetColorDepth(), ds->GetColorDepth());
 	}
 
-	draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, xx, yy, sourcePic, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0,
-	                          kBlendMode_Alpha, GfxDef::Trans100ToAlpha255(trans));
+	draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, dst_x, dst_y, src, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0,
+		kBlendMode_Alpha, GfxDef::Trans100ToAlpha255(trans));
 
 	sds->FinishedDrawing();
 
 	if (needToFreeBitmap)
-		delete sourcePic;
+		delete src;
 }
 
+void DrawingSurface_DrawImage(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height) {
+	DrawingSurface_DrawImageEx(sds, xx, yy, slot, trans, width, height, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
+}
 
 void DrawingSurface_SetDrawingColor(ScriptDrawingSurface *sds, int newColour) {
 	sds->currentColourScript = newColour;
@@ -404,10 +439,17 @@ RuntimeScriptValue Sc_DrawingSurface_DrawCircle(void *self, const RuntimeScriptV
 }
 
 // void (ScriptDrawingSurface* sds, int xx, int yy, int slot, int trans, int width, int height)
-RuntimeScriptValue Sc_DrawingSurface_DrawImage(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+RuntimeScriptValue Sc_DrawingSurface_DrawImage_6(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_VOID_PINT6(ScriptDrawingSurface, DrawingSurface_DrawImage);
 }
 
+RuntimeScriptValue Sc_DrawingSurface_DrawImage(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
+	DrawingSurface_DrawImageEx((ScriptDrawingSurface *)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, params[8].IValue, params[9].IValue);
+	return RuntimeScriptValue((int32_t)0);
+}
+
 // void (ScriptDrawingSurface *sds, int fromx, int fromy, int tox, int toy, int thickness)
 RuntimeScriptValue Sc_DrawingSurface_DrawLine(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_VOID_PINT5(ScriptDrawingSurface, DrawingSurface_DrawLine);
@@ -504,7 +546,8 @@ void RegisterDrawingSurfaceAPI(ScriptAPIVersion base_api, ScriptAPIVersion compa
 	ccAddExternalObjectFunction("DrawingSurface::Clear^1", Sc_DrawingSurface_Clear);
 	ccAddExternalObjectFunction("DrawingSurface::CreateCopy^0", Sc_DrawingSurface_CreateCopy);
 	ccAddExternalObjectFunction("DrawingSurface::DrawCircle^3", Sc_DrawingSurface_DrawCircle);
-	ccAddExternalObjectFunction("DrawingSurface::DrawImage^6", Sc_DrawingSurface_DrawImage);
+	ccAddExternalObjectFunction("DrawingSurface::DrawImage^6", Sc_DrawingSurface_DrawImage_6);
+	ccAddExternalObjectFunction("DrawingSurface::DrawImage^10", Sc_DrawingSurface_DrawImage);
 	ccAddExternalObjectFunction("DrawingSurface::DrawLine^5", Sc_DrawingSurface_DrawLine);
 	ccAddExternalObjectFunction("DrawingSurface::DrawMessageWrapped^5", Sc_DrawingSurface_DrawMessageWrapped);
 	ccAddExternalObjectFunction("DrawingSurface::DrawPixel^2", Sc_DrawingSurface_DrawPixel);


Commit: 37c51eeac51dc2c9ecd8bc849ab16efb9be1dcb5
    https://github.com/scummvm/scummvm/commit/37c51eeac51dc2c9ecd8bc849ab16efb9be1dcb5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: Support extended params for DrawSurface

>From upstream 67810b264d60f55571b1fb604ee5de833a08bfde

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


diff --git a/engines/ags/engine/ac/drawing_surface.cpp b/engines/ags/engine/ac/drawing_surface.cpp
index b2ec3effe0..33ab8ff735 100644
--- a/engines/ags/engine/ac/drawing_surface.cpp
+++ b/engines/ags/engine/ac/drawing_surface.cpp
@@ -114,46 +114,21 @@ ScriptDrawingSurface *DrawingSurface_CreateCopy(ScriptDrawingSurface *sds) {
 	return nullptr;
 }
 
-void DrawingSurface_DrawSurface(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int translev) {
-	if ((translev < 0) || (translev > 99))
-		quit("!DrawingSurface.DrawSurface: invalid parameter (transparency must be 0-99)");
-
-	Bitmap *ds = target->StartDrawing();
-	Bitmap *surfaceToDraw = source->GetBitmapSurface();
-
-	if (surfaceToDraw == target->GetBitmapSurface())
-		quit("!DrawingSurface.DrawSurface: cannot draw surface onto itself");
-
-	if (translev == 0) {
-		// just draw it over the top, no transparency
-		ds->Blit(surfaceToDraw, 0, 0, 0, 0, surfaceToDraw->GetWidth(), surfaceToDraw->GetHeight());
-		target->FinishedDrawing();
-		return;
-	}
-
-	if (surfaceToDraw->GetColorDepth() <= 8)
-		quit("!DrawingSurface.DrawSurface: 256-colour surfaces cannot be drawn transparently");
-
-	// Draw it transparently
-	GfxUtil::DrawSpriteWithTransparency(ds, surfaceToDraw, 0, 0,
-	                                    GfxDef::Trans100ToAlpha255(translev));
-	target->FinishedDrawing();
-}
-
-void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y, int slot, int trans, int dst_width, int dst_height,
-	int src_x, int src_y, int src_width, int src_height) {
-	if ((slot < 0) || (_GP(spriteset)[slot] == nullptr))
-		quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
+void DrawingSurface_DrawImageImpl(ScriptDrawingSurface *sds, Bitmap *src,
+	int dst_x, int dst_y, int trans, int dst_width, int dst_height,
+	int src_x, int src_y, int src_width, int src_height, int sprite_id, bool src_has_alpha) {
+	Bitmap *ds = sds->GetBitmapSurface();
+	if (src == ds)
+		quit("!DrawingSurface.DrawImage: cannot draw onto itself");
 	if ((trans < 0) || (trans > 100))
 		quit("!DrawingSurface.DrawImage: invalid transparency setting");
+
 	if (trans == 100)
 		return; // fully transparent
 	if (dst_width < 1 || dst_height < 1 || src_width < 1 || src_height < 1)
 		return; // invalid src or dest rectangles
 
-	// Setup uninitialized arguments; convert coordinates for legacy script mode
-	Bitmap *ds = sds->GetBitmapSurface();
-	Bitmap *src = _GP(spriteset)[slot];
+				// Setup uninitialized arguments; convert coordinates for legacy script mode
 	if (dst_width == SCR_NO_VALUE) {
 		dst_width = src->GetWidth();
 	} else {
@@ -186,7 +161,7 @@ void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y,
 	if (dst_x >= ds->GetWidth() || dst_x + dst_width <= 0 || dst_y >= ds->GetHeight() || dst_y + dst_height <= 0 ||
 		src_x >= src->GetWidth() || src_x + src_width <= 0 || src_y >= src->GetHeight() || src_y + src_height <= 0)
 		return; // source or destination rects lie completely off surface
-	// Clamp the source rect to the valid limits to prevent exceptions (ignore dest, bitmap drawing deals with that)
+				// Clamp the source rect to the valid limits to prevent exceptions (ignore dest, bitmap drawing deals with that)
 	Math::ClampLength(src_x, src_width, 0, src->GetWidth());
 	Math::ClampLength(src_y, src_height, 0, src->GetHeight());
 
@@ -210,10 +185,13 @@ void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y,
 	sds->PointToGameResolution(&dst_x, &dst_y);
 
 	if (src->GetColorDepth() != ds->GetColorDepth()) {
-		debug_script_warn("RawDrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", slot, _GP(spriteset)[slot]->GetColorDepth(), ds->GetColorDepth());
+		if (sprite_id >= 0)
+			debug_script_warn("DrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", sprite_id, src->GetColorDepth(), ds->GetColorDepth());
+		else
+			debug_script_warn("DrawImage: Source image colour depth %d-bit not same as background depth %d-bit", src->GetColorDepth(), ds->GetColorDepth());
 	}
 
-	draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, dst_x, dst_y, src, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0,
+	draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, dst_x, dst_y, src, src_has_alpha,
 		kBlendMode_Alpha, GfxDef::Trans100ToAlpha255(trans));
 
 	sds->FinishedDrawing();
@@ -222,10 +200,31 @@ void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y,
 		delete src;
 }
 
+void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds,
+		int dst_x, int dst_y, int slot, int trans,
+		int dst_width, int dst_height,
+		int src_x, int src_y, int src_width, int src_height) {
+	if ((slot < 0) || (_GP(spriteset)[slot] == nullptr))
+		quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
+	DrawingSurface_DrawImageImpl(sds, _GP(spriteset)[slot], dst_x, dst_y, trans, dst_width, dst_height,
+		src_x, src_y, src_width, src_height, slot, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
+}
+
 void DrawingSurface_DrawImage(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height) {
 	DrawingSurface_DrawImageEx(sds, xx, yy, slot, trans, width, height, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
 }
 
+void DrawingSurface_DrawSurfaceEx(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans,
+		int dst_x, int dst_y, int dst_width, int dst_height,
+		int src_x, int src_y, int src_width, int src_height) {
+	DrawingSurface_DrawImageImpl(target, source->GetBitmapSurface(), dst_x, dst_y, trans, dst_width, dst_height,
+		src_x, src_y, src_width, src_height, -1, source->hasAlphaChannel);
+}
+
+void DrawingSurface_DrawSurface(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans) {
+	DrawingSurface_DrawSurfaceEx(target, source, trans, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
+}
+
 void DrawingSurface_SetDrawingColor(ScriptDrawingSurface *sds, int newColour) {
 	sds->currentColourScript = newColour;
 	// StartDrawing to set up ds to set the colour at the appropriate
@@ -487,10 +486,18 @@ RuntimeScriptValue Sc_DrawingSurface_DrawStringWrapped(void *self, const Runtime
 }
 
 // void (ScriptDrawingSurface* target, ScriptDrawingSurface* source, int translev)
-RuntimeScriptValue Sc_DrawingSurface_DrawSurface(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+RuntimeScriptValue Sc_DrawingSurface_DrawSurface_2(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_VOID_POBJ_PINT(ScriptDrawingSurface, DrawingSurface_DrawSurface, ScriptDrawingSurface);
 }
 
+RuntimeScriptValue Sc_DrawingSurface_DrawSurface(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
+	DrawingSurface_DrawSurfaceEx((ScriptDrawingSurface *)self, (ScriptDrawingSurface *)params[0].Ptr,
+		params[1].IValue, params[2].IValue, params[3].IValue, params[4].IValue, params[5].IValue,
+		params[6].IValue, params[7].IValue, params[8].IValue, params[9].IValue);
+	return RuntimeScriptValue((int32_t)0);
+}
+
 // void (ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2, int x3, int y3)
 RuntimeScriptValue Sc_DrawingSurface_DrawTriangle(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_VOID_PINT6(ScriptDrawingSurface, DrawingSurface_DrawTriangle);
@@ -557,7 +564,8 @@ void RegisterDrawingSurfaceAPI(ScriptAPIVersion base_api, ScriptAPIVersion compa
 		ccAddExternalObjectFunction("DrawingSurface::DrawStringWrapped^6", Sc_DrawingSurface_DrawStringWrapped_Old);
 	else
 		ccAddExternalObjectFunction("DrawingSurface::DrawStringWrapped^6", Sc_DrawingSurface_DrawStringWrapped);
-	ccAddExternalObjectFunction("DrawingSurface::DrawSurface^2", Sc_DrawingSurface_DrawSurface);
+	ccAddExternalObjectFunction("DrawingSurface::DrawSurface^2", Sc_DrawingSurface_DrawSurface_2);
+	ccAddExternalObjectFunction("DrawingSurface::DrawSurface^10", Sc_DrawingSurface_DrawSurface);
 	ccAddExternalObjectFunction("DrawingSurface::DrawTriangle^6", Sc_DrawingSurface_DrawTriangle);
 	ccAddExternalObjectFunction("DrawingSurface::GetPixel^2", Sc_DrawingSurface_GetPixel);
 	ccAddExternalObjectFunction("DrawingSurface::Release^0", Sc_DrawingSurface_Release);


Commit: 9f78c2f22cf55ac4c44143e5f1eb967c288e1189
    https://github.com/scummvm/scummvm/commit/9f78c2f22cf55ac4c44143e5f1eb967c288e1189
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: Added WaitMouse() to complement existing Wait funcs

>From upstream b623980549cc7355c5ca3db9adf4ef29463d65d6

Changed paths:
    engines/ags/engine/ac/global_api.cpp
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_game.h


diff --git a/engines/ags/engine/ac/global_api.cpp b/engines/ags/engine/ac/global_api.cpp
index 5cc1c35994..dc6f1f8d3c 100644
--- a/engines/ags/engine/ac/global_api.cpp
+++ b/engines/ags/engine/ac/global_api.cpp
@@ -1862,6 +1862,10 @@ RuntimeScriptValue Sc_WaitKey(const RuntimeScriptValue *params, int32_t param_co
 	API_SCALL_INT_PINT(WaitKey);
 }
 
+RuntimeScriptValue Sc_WaitMouse(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_INT_PINT(WaitMouse);
+}
+
 // int (int nloops)
 RuntimeScriptValue Sc_WaitMouseKey(const RuntimeScriptValue *params, int32_t param_count) {
 	API_SCALL_INT_PINT(WaitMouseKey);
@@ -2235,6 +2239,7 @@ void RegisterGlobalAPI() {
 	ccAddExternalStaticFunction("UpdatePalette",            Sc_UpdatePalette);
 	ccAddExternalStaticFunction("Wait",                     Sc_scrWait);
 	ccAddExternalStaticFunction("WaitKey",                  Sc_WaitKey);
+	ccAddExternalStaticFunction("WaitMouse",                Sc_WaitMouse);
 	ccAddExternalStaticFunction("WaitMouseKey",             Sc_WaitMouseKey);
 }
 
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 6dea34994e..27ebd78253 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -792,6 +792,10 @@ int WaitKey(int nloops) {
 	return WaitImpl(SKIP_KEYPRESS | SKIP_AUTOTIMER, nloops);
 }
 
+int WaitMouse(int nloops) {
+	return WaitImpl(SKIP_MOUSECLICK | SKIP_AUTOTIMER, nloops);
+}
+
 int WaitMouseKey(int nloops) {
 	return WaitImpl(SKIP_KEYPRESS | SKIP_MOUSECLICK | SKIP_AUTOTIMER, nloops);
 }
diff --git a/engines/ags/engine/ac/global_game.h b/engines/ags/engine/ac/global_game.h
index 35902055cc..a250ab8dbd 100644
--- a/engines/ags/engine/ac/global_game.h
+++ b/engines/ags/engine/ac/global_game.h
@@ -106,6 +106,7 @@ int GetGraphicalVariable(const char *varName);
 void SetGraphicalVariable(const char *varName, int p_value);
 void scrWait(int nloops);
 int WaitKey(int nloops);
+int WaitMouse(int nloops);
 int WaitMouseKey(int nloops);
 
 } // namespace AGS3


Commit: b4997729cd36ccc4eaba7f1ecb7e54922acf4b57
    https://github.com/scummvm/scummvm/commit/b4997729cd36ccc4eaba7f1ecb7e54922acf4b57
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:36-07:00

Commit Message:
AGS: Wait functions return the actual reason they were skipped

>From upstream 5a9a32348659f421115a951155405d431f8f3234

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


diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 1b1bee1db1..babff172be 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -157,6 +157,8 @@ struct GameState {
 	int   bg_frame = 0, bg_anim_delay = 0;  // for animating backgrounds
 	int   music_vol_was = 0;  // before the volume drop
 	short wait_counter = 0;
+	char  wait_skipped_by = 0; // tells how last wait was skipped [not serialized]
+	int   wait_skipped_by_data = 0; // extended data telling how last wait was skipped [not serialized]
 	short mboundx1 = 0, mboundx2 = 0, mboundy1 = 0, mboundy2 = 0;
 	int   fade_effect = 0;
 	int   bg_frame_locked = 0;
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 27ebd78253..51b685d7a5 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -775,13 +775,22 @@ int WaitImpl(int skip_type, int nloops) {
 		quit("!Wait: must wait at least 1 loop");
 
 	_GP(play).wait_counter = nloops;
+	_GP(play).wait_skipped_by = SKIP_AUTOTIMER; // we set timer flag by default to simplify that case
+	_GP(play).wait_skipped_by_data = 0;
 	_GP(play).key_skip_wait = skip_type;
 
 	GameLoopUntilValueIsZeroOrLess(&_GP(play).wait_counter);
 
-	if (_GP(play).wait_counter < 0)
-		return 1;
-	return 0;
+	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v360) {
+		// < 3.6.0 return 1 is skipped by user input, otherwise 0
+		return (_GP(play).wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK) != 0) ? 1 : 0;
+	}
+	// >= 3.6.0 return positive keycode, negative mouse button code, or 0 as time-out
+	switch (_GP(play).wait_skipped_by) {
+	case SKIP_KEYPRESS: return _GP(play).wait_skipped_by_data;
+	case SKIP_MOUSECLICK: return -(_GP(play).wait_skipped_by_data + 1); // convert to 1-based code and negate
+	default: return 0;
+	}
 }
 
 void scrWait(int nloops) {
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index 02ef458ed5..b74f345761 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -209,9 +209,11 @@ static void check_mouse_controls() {
 		check_skip_cutscene_mclick(mbut);
 
 		if (_GP(play).fast_forward || _GP(play).IsIgnoringInput()) { /* do nothing if skipping cutscene or input disabled */
-		} else if ((_GP(play).wait_counter > 0) && (_GP(play).key_skip_wait & SKIP_MOUSECLICK) != 0)
-			_GP(play).wait_counter = -1;
-		else if (_G(is_text_overlay) > 0) {
+		} else if ((_GP(play).wait_counter > 0) && (_GP(play).key_skip_wait & SKIP_MOUSECLICK) != 0) {
+			_GP(play).wait_counter = 0;
+			_GP(play).wait_skipped_by = SKIP_MOUSECLICK;
+			_GP(play).wait_skipped_by_data = mbut;
+		} else if (_G(is_text_overlay) > 0) {
 			if (_GP(play).cant_skip_speech & SKIP_MOUSECLICK)
 				remove_screen_overlay(OVER_TEXTMSG);
 		} else if (!IsInterfaceEnabled());  // blocking cutscene, ignore mouse


Commit: 0b4b055d6f243e5c05d776627d5861cad747bf51
    https://github.com/scummvm/scummvm/commit/0b4b055d6f243e5c05d776627d5861cad747bf51
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:37-07:00

Commit Message:
AGS: Wait functions may have infinite timeout with <0 time arg

>From upstream 53c8b50559f6e8241ba7dbedbe1a8ff860522590

Changed paths:
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/main/game_run.cpp


diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 51b685d7a5..5fee4426ff 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -771,19 +771,16 @@ void SetGraphicalVariable(const char *varName, int p_value) {
 }
 
 int WaitImpl(int skip_type, int nloops) {
-	if ((nloops < 1) && (_G(loaded_game_file_version) >= kGameVersion_262)) // 2.62+
-		quit("!Wait: must wait at least 1 loop");
-
 	_GP(play).wait_counter = nloops;
 	_GP(play).wait_skipped_by = SKIP_AUTOTIMER; // we set timer flag by default to simplify that case
 	_GP(play).wait_skipped_by_data = 0;
 	_GP(play).key_skip_wait = skip_type;
 
-	GameLoopUntilValueIsZeroOrLess(&_GP(play).wait_counter);
+    GameLoopUntilValueIsZero(&_GP(play).wait_counter);
 
 	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v360) {
 		// < 3.6.0 return 1 is skipped by user input, otherwise 0
-		return (_GP(play).wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK) != 0) ? 1 : 0;
+		return (_GP(play).wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK)) != 0 ? 1 : 0;
 	}
 	// >= 3.6.0 return positive keycode, negative mouse button code, or 0 as time-out
 	switch (_GP(play).wait_skipped_by) {
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index b74f345761..b435e7f995 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -209,7 +209,7 @@ static void check_mouse_controls() {
 		check_skip_cutscene_mclick(mbut);
 
 		if (_GP(play).fast_forward || _GP(play).IsIgnoringInput()) { /* do nothing if skipping cutscene or input disabled */
-		} else if ((_GP(play).wait_counter > 0) && (_GP(play).key_skip_wait & SKIP_MOUSECLICK) != 0) {
+		} else if ((_GP(play).wait_counter != 0) && (_GP(play).key_skip_wait & SKIP_MOUSECLICK) != 0) {
 			_GP(play).wait_counter = 0;
 			_GP(play).wait_skipped_by = SKIP_MOUSECLICK;
 			_GP(play).wait_skipped_by_data = mbut;
@@ -445,7 +445,7 @@ static void check_keyboard_controls() {
 		return;
 	}
 
-	if ((_GP(play).wait_counter > 0) && (_GP(play).key_skip_wait & SKIP_KEYPRESS) != 0) {
+	if ((_GP(play).wait_counter != 0) && (_GP(play).key_skip_wait & SKIP_KEYPRESS) != 0) {
 		_GP(play).wait_counter = -1;
 		debug_script_log("Keypress code %d ignored - in Wait", kgn);
 		return;


Commit: 529362a2d70a86cd21e6636e811f8e815f550bb4
    https://github.com/scummvm/scummvm/commit/529362a2d70a86cd21e6636e811f8e815f550bb4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:37-07:00

Commit Message:
AGS: implemented SkipWait()

>From upstream 3b3aed5b4e33d1791d8eac922c9d530e5796d984

Changed paths:
    engines/ags/engine/ac/global_api.cpp
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_game.h


diff --git a/engines/ags/engine/ac/global_api.cpp b/engines/ags/engine/ac/global_api.cpp
index dc6f1f8d3c..81437c619e 100644
--- a/engines/ags/engine/ac/global_api.cpp
+++ b/engines/ags/engine/ac/global_api.cpp
@@ -1871,6 +1871,10 @@ RuntimeScriptValue Sc_WaitMouseKey(const RuntimeScriptValue *params, int32_t par
 	API_SCALL_INT_PINT(WaitMouseKey);
 }
 
+RuntimeScriptValue Sc_SkipWait(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_VOID(SkipWait);
+}
+
 void RegisterGlobalAPI() {
 	ccAddExternalStaticFunction("AbortGame",                Sc_sc_AbortGame);
 	ccAddExternalStaticFunction("AddInventory",             Sc_add_inventory);
@@ -2241,6 +2245,7 @@ void RegisterGlobalAPI() {
 	ccAddExternalStaticFunction("WaitKey",                  Sc_WaitKey);
 	ccAddExternalStaticFunction("WaitMouse",                Sc_WaitMouse);
 	ccAddExternalStaticFunction("WaitMouseKey",             Sc_WaitMouseKey);
+	ccAddExternalStaticFunction("SkipWait",                 Sc_SkipWait);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 5fee4426ff..4c9bc30f6e 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -806,4 +806,8 @@ int WaitMouseKey(int nloops) {
 	return WaitImpl(SKIP_KEYPRESS | SKIP_MOUSECLICK | SKIP_AUTOTIMER, nloops);
 }
 
+void SkipWait() {
+	_GP(play).wait_counter = 0;
+}
+
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_game.h b/engines/ags/engine/ac/global_game.h
index a250ab8dbd..6cf7246e87 100644
--- a/engines/ags/engine/ac/global_game.h
+++ b/engines/ags/engine/ac/global_game.h
@@ -108,6 +108,7 @@ void scrWait(int nloops);
 int WaitKey(int nloops);
 int WaitMouse(int nloops);
 int WaitMouseKey(int nloops);
+void SkipWait();
 
 } // namespace AGS3
 


Commit: 9612b5cb35d7f852e1cde03e1f5eb1fe9a1f776f
    https://github.com/scummvm/scummvm/commit/9612b5cb35d7f852e1cde03e1f5eb1fe9a1f776f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:37-07:00

Commit Message:
AGS: distinct overlay types of speech and messagebox

>From upstream d7c091890d2cde07776cca4ebbed7352d379612d

Changed paths:
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/display.cpp
    engines/ags/engine/ac/display.h
    engines/ags/engine/ac/draw.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/game_state.h
    engines/ags/engine/ac/gui.cpp
    engines/ags/engine/ac/overlay.cpp
    engines/ags/engine/ac/runtime_defines.h
    engines/ags/engine/game/savegame.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/engine/main/update.cpp
    engines/ags/globals.h


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index e896818f0c..da82cf95b6 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -2253,7 +2253,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	if ((speakingChar->view < 0) || (speakingChar->view >= _GP(game).numviews))
 		quit("!DisplaySpeech: character has invalid view");
 
-	if (_G(is_text_overlay) > 0) {
+	if (_GP(play).text_overlay_on > 0) {
 		debug_script_warn("DisplaySpeech: speech was already displayed (nested DisplaySpeech, perhaps room script and global script conflict?)");
 		return;
 	}
diff --git a/engines/ags/engine/ac/display.cpp b/engines/ags/engine/ac/display.cpp
index 59671a472c..0a1b94be89 100644
--- a/engines/ags/engine/ac/display.cpp
+++ b/engines/ags/engine/ac/display.cpp
@@ -173,7 +173,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 	int extraHeight = paddingDoubledScaled;
 	color_t text_color = MakeColor(15);
 	if (disp_type < DISPLAYTEXT_NORMALOVERLAY)
-		remove_screen_overlay(OVER_TEXTMSG); // remove any previous blocking texts
+		remove_screen_overlay(_GP(play).text_overlay_on); // remove any previous blocking texts
 
 	const int bmp_width = std::max(2, wii);
 	const int bmp_height = std::max(2, disp.fulltxtheight + extraHeight);
@@ -246,9 +246,13 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			wouttext_aligned(text_window_ds, xoffs, yoffs + ee * disp.linespacing, oriwid, usingfont, text_color, _GP(Lines)[ee].GetCStr(), _GP(play).text_align);
 	}
 
-	int ovrtype = OVER_TEXTMSG;
-	if (disp_type == DISPLAYTEXT_NORMALOVERLAY) ovrtype = OVER_CUSTOM;
-	else if (disp_type >= OVER_CUSTOM) ovrtype = disp_type;
+	int ovrtype;
+	switch (disp_type) {
+	case DISPLAYTEXT_SPEECH: ovrtype = OVER_TEXTSPEECH; break;
+	case DISPLAYTEXT_MESSAGEBOX: ovrtype = OVER_TEXTMSG; break;
+	case DISPLAYTEXT_NORMALOVERLAY: ovrtype = OVER_CUSTOM; break;
+	default: ovrtype = disp_type; break; // must be precreated overlay id
+	}
 
 	int nse = add_screen_overlay(xx, yy, ovrtype, text_window_ds, adjustedXX - xx, adjustedYY - yy, alphaChannel);
 	// we should not delete text_window_ds here, because it is now owned by Overlay
@@ -329,6 +333,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 		remove_screen_overlay(OVER_TEXTMSG);
 		invalidate_screen();
 	} else {
+		/* DISPLAYTEXT_SPEECH */
 		// if the speech does not time out, but we are skipping a cutscene,
 		// allow it to time out
 		if ((_GP(play).messagetime < 0) && (_GP(play).fast_forward))
diff --git a/engines/ags/engine/ac/display.h b/engines/ags/engine/ac/display.h
index 5928dff6f9..aa7395508d 100644
--- a/engines/ags/engine/ac/display.h
+++ b/engines/ags/engine/ac/display.h
@@ -30,8 +30,11 @@ namespace AGS3 {
 using AGS::Shared::GUIMain;
 
 // options for 'disp_type' parameter
+// blocking speech
 #define DISPLAYTEXT_SPEECH        0
+// super-blocking message box
 #define DISPLAYTEXT_MESSAGEBOX    1
+// regular non-blocking overlay
 #define DISPLAYTEXT_NORMALOVERLAY 2
 // also accepts explicit overlay ID >= OVER_CUSTOM
 
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 6fb675d8aa..1a76213273 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2099,7 +2099,7 @@ void construct_game_scene(bool full_redraw) {
 		_GP(play).UpdateRoomCameras();
 
 	// Stage: room viewports
-	if (_GP(play).screen_is_faded_out == 0 && _G(is_complete_overlay) == 0) {
+	if (_GP(play).screen_is_faded_out == 0 && _GP(play).complete_overlay_on == 0) {
 		if (_G(displayed_room) >= 0) {
 			construct_room_view();
 		} else if (!_G(gfxDriver)->RequiresFullRedrawEachFrame()) {
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index 07bdaa31bb..9546948a0d 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -1093,9 +1093,8 @@ void start_skipping_cutscene() {
 		remove_popup_interface(_G(ifacepopped));
 
 	// if a text message is currently displayed, remove it
-	if (_G(is_text_overlay) > 0)
-		remove_screen_overlay(OVER_TEXTMSG);
-
+	if (_GP(play).text_overlay_on > 0)
+		remove_screen_overlay(_GP(play).text_overlay_on);
 }
 
 bool check_skip_cutscene_keypress(int kgn) {
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index babff172be..50d77cb66d 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -246,6 +246,13 @@ struct GameState {
 	// Tells whether character speech stays on screen not animated for additional time
 	bool  speech_in_post_state = false;
 
+	// Special overlays
+	//
+	// Is there a QFG4-style dialog overlay on screen (contains overlay ID)
+	int  complete_overlay_on = 0;
+	// Is there a blocking text overlay on screen (contains overlay ID)
+	int  text_overlay_on = 0;
+
 	int shake_screen_yoff = 0; // y offset of the shaking screen
 
 
diff --git a/engines/ags/engine/ac/gui.cpp b/engines/ags/engine/ac/gui.cpp
index 4c55450547..7df7200c55 100644
--- a/engines/ags/engine/ac/gui.cpp
+++ b/engines/ags/engine/ac/gui.cpp
@@ -20,7 +20,6 @@
  *
  */
 
-//include <cstdio>
 #include "ags/engine/ac/gui.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/draw.h"
@@ -584,8 +583,7 @@ int gui_on_mouse_move() {
 			if (_GP(guis)[guin].IsInteractableAt(_G(mousex), _G(mousey))) mouse_over_gui = guin;
 
 			if (_GP(guis)[guin].PopupStyle != kGUIPopupMouseY) continue;
-			if (_G(is_complete_overlay) > 0) break;  // interfaces disabled
-			//    if (_GP(play).disabled_user_interface>0) break;
+			if (_GP(play).complete_overlay_on > 0) break;  // interfaces disabled			//    if (_GP(play).disabled_user_interface>0) break;
 			if (_G(ifacepopped) == guin) continue;
 			if (!_GP(guis)[guin].IsVisible()) continue;
 			// Don't allow it to be popped up while skipping cutscene
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index b3cccac2e9..f7d1f8cc81 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -160,8 +160,8 @@ void dispose_overlay(ScreenOverlay &over) {
 void remove_screen_overlay_index(int over_idx) {
 	ScreenOverlay &over = _G(screenover)[over_idx];
 	dispose_overlay(over);
-	if (over.type == OVER_COMPLETE) _G(is_complete_overlay)--;
-	if (over.type == OVER_TEXTMSG) _G(is_text_overlay)--;
+	if (over.type == _GP(play).complete_overlay_on) _GP(play).complete_overlay_on = 0;
+	if (over.type == _GP(play).text_overlay_on) _GP(play).text_overlay_on = 0;
 	_G(numscreenover)--;
 	for (int i = over_idx; i < _G(numscreenover); ++i)
 		_G(screenover)[i] = _G(screenover)[i + 1];
@@ -192,8 +192,8 @@ int add_screen_overlay(int x, int y, int type, Bitmap *piccy, bool alphaChannel)
 }
 
 int add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_offx, int pic_offy, bool alphaChannel) {
-	if (type == OVER_COMPLETE) _G(is_complete_overlay)++;
-	if (type == OVER_TEXTMSG) _G(is_text_overlay)++;
+	if (type == OVER_COMPLETE) _GP(play).complete_overlay_on = type;
+	if (type == OVER_TEXTMSG || type == OVER_TEXTSPEECH) _GP(play).text_overlay_on = type;
 	if (type == OVER_CUSTOM) {
 		// find an unused custom ID; TODO: find a better approach!
 		for (int id = OVER_CUSTOM + 1; id < OVER_CUSTOM + 100; ++id) {
diff --git a/engines/ags/engine/ac/runtime_defines.h b/engines/ags/engine/ac/runtime_defines.h
index ff623cf760..cb29b9ba5d 100644
--- a/engines/ags/engine/ac/runtime_defines.h
+++ b/engines/ags/engine/ac/runtime_defines.h
@@ -112,6 +112,7 @@ const int LegacyRoomVolumeFactor = 30;
 #define OVER_TEXTMSG  1
 #define OVER_COMPLETE 2
 #define OVER_PICTURE  3
+#define OVER_TEXTSPEECH 4
 #define OVER_CUSTOM   100
 #define OVR_AUTOPLACE 30000
 #define FOR_ANIMATION 1
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 3875852c1c..83e4a0e132 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -332,8 +332,8 @@ void DoBeforeRestore(PreservedParams &pp) {
 	delete _G(raw_saved_screen);
 	_G(raw_saved_screen) = nullptr;
 	remove_screen_overlay(-1);
-	_G(is_complete_overlay) = 0;
-	_G(is_text_overlay) = 0;
+	_GP(play).complete_overlay_on = 0;
+	_GP(play).text_overlay_on = 0;
 
 	// cleanup dynamic sprites
 	// NOTE: sprite 0 is a special constant sprite that cannot be dynamic
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index ccb98eef87..b381178381 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -807,6 +807,8 @@ void engine_init_game_settings() {
 	_GP(play).speech_has_voice = false;
 	_GP(play).speech_voice_blocking = false;
 	_GP(play).speech_in_post_state = false;
+	_GP(play).complete_overlay_on = 0;
+	_GP(play).text_overlay_on = 0;
 	_GP(play).narrator_speech = _GP(game).playercharacter;
 	_GP(play).crossfading_out_channel = 0;
 	_GP(play).speech_textwindow_gui = _GP(game).options[OPT_TWCUSTOM];
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index b435e7f995..e275862a03 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -25,8 +25,6 @@
 //
 
 #include "ags/lib/std/limits.h"
-//include <chrono>
-//include <SDL.h>
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/character_extras.h"
 #include "ags/shared/ac/character_info.h"
@@ -213,9 +211,9 @@ static void check_mouse_controls() {
 			_GP(play).wait_counter = 0;
 			_GP(play).wait_skipped_by = SKIP_MOUSECLICK;
 			_GP(play).wait_skipped_by_data = mbut;
-		} else if (_G(is_text_overlay) > 0) {
+		} else if (_GP(play).text_overlay_on > 0) {
 			if (_GP(play).cant_skip_speech & SKIP_MOUSECLICK)
-				remove_screen_overlay(OVER_TEXTMSG);
+				remove_screen_overlay(_GP(play).text_overlay_on);
 		} else if (!IsInterfaceEnabled());  // blocking cutscene, ignore mouse
 		else if (pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut + 1)) {
 			// plugin took the click
@@ -383,7 +381,7 @@ bool run_service_key_controls(KeyInput &out_key) {
 	}
 
 	if (((agskey == eAGSKeyCodeCtrlV) && (cur_key_mods & Common::KBD_ALT) != 0)
-	        && (_GP(play).wait_counter < 1) && (_G(is_text_overlay) == 0) && (_G(restrict_until) == 0)) {
+	        && (_GP(play).wait_counter < 1) && (_GP(play).text_overlay_on == 0) && (_G(restrict_until) == 0)) {
 		// make sure we can't interrupt a Wait()
 		// and desync the music to cutscene
 		_GP(play).debug_mode++;
@@ -432,14 +430,14 @@ static void check_keyboard_controls() {
 	}
 
 	// skip speech if desired by Speech.SkipStyle
-	if ((_G(is_text_overlay) > 0) && (_GP(play).cant_skip_speech & SKIP_KEYPRESS)) {
+	if ((_GP(play).text_overlay_on > 0) && (_GP(play).cant_skip_speech & SKIP_KEYPRESS)) {
 		// only allow a key to remove the overlay if the icon bar isn't up
 		if (IsGamePaused() == 0) {
 			// check if it requires a specific keypress
 			if ((_GP(play).skip_speech_specific_key > 0) &&
-			        (kgn != _GP(play).skip_speech_specific_key)) {
+				(kgn != _GP(play).skip_speech_specific_key)) {
 			} else
-				remove_screen_overlay(OVER_TEXTMSG);
+				remove_screen_overlay(_GP(play).text_overlay_on);
 		}
 
 		return;
@@ -835,7 +833,7 @@ static int ShouldStayInWaitMode() {
 		const int *wkptr = (const int *)_G(user_disabled_data);
 		if (wkptr[0] < 0) retval = 0;
 	} else if (_G(restrict_until) == UNTIL_NOOVERLAY) {
-		if (_G(is_text_overlay) < 1) retval = 0;
+		if (_GP(play).text_overlay_on == 0) retval = 0;
 	} else if (_G(restrict_until) == UNTIL_INTIS0) {
 		const int *wkptr = (const int *)_G(user_disabled_data);
 		if (wkptr[0] == 0) retval = 0;
diff --git a/engines/ags/engine/main/update.cpp b/engines/ags/engine/main/update.cpp
index 2572b2a1a7..a7ae9981fe 100644
--- a/engines/ags/engine/main/update.cpp
+++ b/engines/ags/engine/main/update.cpp
@@ -260,9 +260,9 @@ void update_speech_and_messages() {
 
 		if (_GP(play).messagetime < 1) {
 			if (_GP(play).fast_forward > 0) {
-				remove_screen_overlay(OVER_TEXTMSG);
+				remove_screen_overlay(_GP(play).text_overlay_on);
 			} else if (_GP(play).cant_skip_speech & SKIP_AUTOTIMER) {
-				remove_screen_overlay(OVER_TEXTMSG);
+				remove_screen_overlay(_GP(play).text_overlay_on);
 				_GP(play).SetIgnoreInput(_GP(play).ignore_user_input_after_text_timeout_ms);
 			}
 		}
@@ -371,7 +371,7 @@ void update_sierra_speech() {
 		}
 
 		// _G(is_text_overlay) might be 0 if it was only just destroyed this loop
-		if ((updatedFrame) && (_G(is_text_overlay) > 0)) {
+		if ((updatedFrame) && (_GP(play).text_overlay_on > 0)) {
 
 			if (updatedFrame & 1)
 				CheckViewFrame(_G(facetalkview), _G(facetalkloop), _G(facetalkframe));
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 60c51933fc..04b6635430 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -1144,7 +1144,7 @@ public:
 	 */
 
 	ScreenOverlay *_screenover;
-	int _is_complete_overlay = 0, _is_text_overlay = 0;
+	int _is_complete_overlay = 0;
 	int _numscreenover = 0;
 
 	/**@}*/


Commit: c133e516209f6e0f0edcb1429c9ff18135b5f367
    https://github.com/scummvm/scummvm/commit/c133e516209f6e0f0edcb1429c9ff18135b5f367
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:37-07:00

Commit Message:
AGS: Speech.TextOverlay for accessing blocking speech overlay

>From upstream 1affbd4d57686e3080ebdb21a0cd33ee4af04b75

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


diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index da82cf95b6..5433b8cc70 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -708,14 +708,10 @@ ScriptOverlay *Character_SayBackground(CharacterInfo *chaa, const char *texx) {
 	if (ovri < 0)
 		quit("!SayBackground internal error: no overlay");
 
-	// Convert the overlay ID to an Overlay object
-	ScriptOverlay *scOver = new ScriptOverlay();
-	scOver->overlayId = ovltype;
+	ScriptOverlay *scOver = create_scriptobj_for_overlay(_G(screenover)[ovri]);
 	scOver->borderHeight = 0;
 	scOver->borderWidth = 0;
 	scOver->isBackgroundSpeech = 1;
-	int handl = ccRegisterManagedObject(scOver, scOver);
-	_G(screenover)[ovri].associatedOverlayHandle = handl;
 
 	return scOver;
 }
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 50d77cb66d..2ffc72ec46 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -53,6 +53,7 @@ struct RestoredData;
 using namespace AGS; // FIXME later
 struct ScriptViewport;
 struct ScriptCamera;
+struct ScriptOverlay;
 
 #define GAME_STATE_RESERVED_INTS 5
 
@@ -252,6 +253,8 @@ struct GameState {
 	int  complete_overlay_on = 0;
 	// Is there a blocking text overlay on screen (contains overlay ID)
 	int  text_overlay_on = 0;
+	// Blocking speech overlay managed object, for accessing in scripts
+	ScriptOverlay *speech_text_scover = nullptr;
 
 	int shake_screen_yoff = 0; // y offset of the shaking screen
 
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index f7d1f8cc81..e6466d6e6e 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -145,28 +145,56 @@ ScriptOverlay *Overlay_CreateTextual(int x, int y, int width, int font, int colo
 
 //=============================================================================
 
-void dispose_overlay(ScreenOverlay &over) {
+// Creates and registers a managed script object for existing overlay object
+ScriptOverlay *create_scriptobj_for_overlay(ScreenOverlay &over) {
+	ScriptOverlay *scover = new ScriptOverlay();
+	scover->overlayId = over.type;
+	int handl = ccRegisterManagedObject(scover, scover);
+	over.associatedOverlayHandle = handl;
+	return scover;
+}
+
+// Creates managed script object for overlay and adds internal engine's reference to it,
+// so that it does not get disposed even if there are no user references in script.
+static ScriptOverlay *create_scriptobj_addref(ScreenOverlay &over) {
+	ScriptOverlay *scover = create_scriptobj_for_overlay(over);
+	ccAddObjectReference(over.associatedOverlayHandle);
+	return scover;
+}
+
+// Invalidates existing script object to let user know that previous overlay is gone,
+// and releases engine's internal reference (script object may exist while there are user refs)
+static void invalidate_and_subref(ScreenOverlay &over, ScriptOverlay *&scover) {
+	scover->overlayId = -1;
+	scover = nullptr;
+	ccReleaseObjectReference(over.associatedOverlayHandle);
+}
+
+// Frees overlay resources and disposes script object if there are no more refs
+static void dispose_overlay(ScreenOverlay &over) {
 	delete over.pic;
 	over.pic = nullptr;
 	if (over.bmp != nullptr)
 		_G(gfxDriver)->DestroyDDB(over.bmp);
 	over.bmp = nullptr;
-	// if the script didn't actually use the Overlay* return
-	// value, dispose of the pointer
-	if (over.associatedOverlayHandle)
+	if (over.associatedOverlayHandle) // dispose script object if there are no more refs
 		ccAttemptDisposeObject(over.associatedOverlayHandle);
 }
 
 void remove_screen_overlay_index(int over_idx) {
 	ScreenOverlay &over = _G(screenover)[over_idx];
+	if (over.type == _GP(play).complete_overlay_on) {
+		_GP(play).complete_overlay_on = 0;
+	} else if (over.type == _GP(play).text_overlay_on) {
+		_GP(play).text_overlay_on = 0;
+		if (_GP(play).speech_text_scover)
+			invalidate_and_subref(over, _GP(play).speech_text_scover);
+	}
 	dispose_overlay(over);
-	if (over.type == _GP(play).complete_overlay_on) _GP(play).complete_overlay_on = 0;
-	if (over.type == _GP(play).text_overlay_on) _GP(play).text_overlay_on = 0;
 	_G(numscreenover)--;
 	for (int i = over_idx; i < _G(numscreenover); ++i)
 		_G(screenover)[i] = _G(screenover)[i + 1];
-	// if an overlay before the sierra-style speech one is removed,
-	// update the index
+	// if an overlay before the sierra-style speech one is removed, update the index
 	if (_G(face_talking) > over_idx)
 		_G(face_talking)--;
 }
@@ -192,8 +220,6 @@ int add_screen_overlay(int x, int y, int type, Bitmap *piccy, bool alphaChannel)
 }
 
 int add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_offx, int pic_offy, bool alphaChannel) {
-	if (type == OVER_COMPLETE) _GP(play).complete_overlay_on = type;
-	if (type == OVER_TEXTMSG || type == OVER_TEXTSPEECH) _GP(play).text_overlay_on = type;
 	if (type == OVER_CUSTOM) {
 		// find an unused custom ID; TODO: find a better approach!
 		for (int id = OVER_CUSTOM + 1; id < OVER_CUSTOM + 100; ++id) {
@@ -203,6 +229,7 @@ int add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_of
 			}
 		}
 	}
+
 	ScreenOverlay &over = _G(screenover)[_G(numscreenover)++];
 	over.pic = piccy;
 	over.bmp = _G(gfxDriver)->CreateDDBFromBitmap(piccy, alphaChannel);
@@ -216,11 +243,20 @@ int add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_of
 	over.associatedOverlayHandle = 0;
 	over.hasAlphaChannel = alphaChannel;
 	over.positionRelativeToScreen = true;
+	// TODO: move these custom settings outside of this function
+	if (type == OVER_COMPLETE) _GP(play).complete_overlay_on = type;
+	else if (type == OVER_TEXTMSG || type == OVER_TEXTSPEECH) {
+		_GP(play).text_overlay_on = type;
+		// only make script object for blocking speech now, because messagebox blocks all script
+		// and therefore cannot be accessed, so no practical reason for that atm
+		if (type == OVER_TEXTSPEECH)
+			_GP(play).speech_text_scover = create_scriptobj_addref(over);
+	} else if (type == OVER_PICTURE) {
+		_GP(play).speech_text_scover = create_scriptobj_addref(over);
+	}
 	return _G(numscreenover) - 1;
 }
 
-
-
 void get_overlay_position(const ScreenOverlay &over, int *x, int *y) {
 	int tdxp, tdyp;
 	const Rect &ui_view = _GP(play).GetUIViewport();
diff --git a/engines/ags/engine/ac/overlay.h b/engines/ags/engine/ac/overlay.h
index 0bc07f0985..c6e8ccfecd 100644
--- a/engines/ags/engine/ac/overlay.h
+++ b/engines/ags/engine/ac/overlay.h
@@ -54,6 +54,8 @@ void get_overlay_position(const ScreenOverlay &over, int *x, int *y);
 int  add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, bool alphaChannel = false);
 int  add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_offx, int pic_offy, bool alphaChannel = false);
 void remove_screen_overlay_index(int over_idx);
+// Creates and registers a managed script object for existing overlay object
+ScriptOverlay *create_scriptobj_for_overlay(ScreenOverlay &over);
 void recreate_overlay_ddbs();
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/speech.cpp b/engines/ags/engine/ac/speech.cpp
index a3eb1b035a..56ec8e0747 100644
--- a/engines/ags/engine/ac/speech.cpp
+++ b/engines/ags/engine/ac/speech.cpp
@@ -31,6 +31,7 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/engine/ac/dynobj/script_overlay.h"
 #include "ags/globals.h"
 
 namespace AGS3 {
@@ -86,6 +87,10 @@ SkipSpeechStyle internal_skip_speech_to_user(int internal_val) {
 //
 //=============================================================================
 
+ScriptOverlay *Speech_GetTextOverlay() {
+	return _GP(play).speech_text_scover;
+}
+
 RuntimeScriptValue Sc_Speech_GetAnimationStopTimeMargin(const RuntimeScriptValue *params, int32_t param_count) {
 	API_VARGET_INT(_GP(play).close_mouth_speech_time);
 }
@@ -186,6 +191,10 @@ RuntimeScriptValue Sc_Speech_GetVoiceMode(const RuntimeScriptValue *params, int3
 	API_SCALL_INT(GetVoiceMode);
 }
 
+RuntimeScriptValue Sc_Speech_GetTextOverlay(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_OBJAUTO(ScriptOverlay, Speech_GetTextOverlay);
+}
+
 extern RuntimeScriptValue Sc_SetVoiceMode(const RuntimeScriptValue *params, int32_t param_count);
 
 void RegisterSpeechAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api) {
@@ -212,6 +221,7 @@ void RegisterSpeechAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api) {
 		ccAddExternalStaticFunction("Speech::set_TextAlignment", Sc_Speech_SetTextAlignment_Old);
 	else
 		ccAddExternalStaticFunction("Speech::set_TextAlignment", Sc_Speech_SetTextAlignment);
+	ccAddExternalStaticFunction("Speech::get_TextOverlay", Sc_Speech_GetTextOverlay);
 	ccAddExternalStaticFunction("Speech::get_UseGlobalSpeechAnimationDelay", Sc_Speech_GetUseGlobalSpeechAnimationDelay);
 	ccAddExternalStaticFunction("Speech::set_UseGlobalSpeechAnimationDelay", Sc_Speech_SetUseGlobalSpeechAnimationDelay);
 	ccAddExternalStaticFunction("Speech::get_VoiceMode", Sc_Speech_GetVoiceMode);


Commit: 217e55e2d92b10c95a6c8a992f0ccaf3863a0243
    https://github.com/scummvm/scummvm/commit/217e55e2d92b10c95a6c8a992f0ccaf3863a0243
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:37-07:00

Commit Message:
AGS: Speech.PortraitOverlay for accessing speech portrait overlay

>From upstream 7e9d785262915112d5c4d3f435ef33e22de95fc7

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


diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 2ffc72ec46..e9c9a6d32f 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -255,6 +255,8 @@ struct GameState {
 	int  text_overlay_on = 0;
 	// Blocking speech overlay managed object, for accessing in scripts
 	ScriptOverlay *speech_text_scover = nullptr;
+	// Speech portrait overlay managed object
+	ScriptOverlay *speech_face_scover = nullptr;
 
 	int shake_screen_yoff = 0; // y offset of the shaking screen
 
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index e6466d6e6e..cc858967dd 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -183,18 +183,24 @@ static void dispose_overlay(ScreenOverlay &over) {
 
 void remove_screen_overlay_index(int over_idx) {
 	ScreenOverlay &over = _G(screenover)[over_idx];
+	// TODO: move these custom settings outside of this function
 	if (over.type == _GP(play).complete_overlay_on) {
 		_GP(play).complete_overlay_on = 0;
 	} else if (over.type == _GP(play).text_overlay_on) {
-		_GP(play).text_overlay_on = 0;
 		if (_GP(play).speech_text_scover)
 			invalidate_and_subref(over, _GP(play).speech_text_scover);
+		_GP(play).text_overlay_on = 0;
+	} else if (over.type == OVER_PICTURE) {
+		if (_GP(play).speech_face_scover)
+			invalidate_and_subref(over, _GP(play).speech_face_scover);
+		_G(face_talking) = -1;
 	}
 	dispose_overlay(over);
 	_G(numscreenover)--;
 	for (int i = over_idx; i < _G(numscreenover); ++i)
 		_G(screenover)[i] = _G(screenover)[i + 1];
 	// if an overlay before the sierra-style speech one is removed, update the index
+	// TODO: this is bad, need more generic system to store overlay references
 	if (_G(face_talking) > over_idx)
 		_G(face_talking)--;
 }
@@ -252,7 +258,7 @@ int add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic_of
 		if (type == OVER_TEXTSPEECH)
 			_GP(play).speech_text_scover = create_scriptobj_addref(over);
 	} else if (type == OVER_PICTURE) {
-		_GP(play).speech_text_scover = create_scriptobj_addref(over);
+		_GP(play).speech_face_scover = create_scriptobj_addref(over);
 	}
 	return _G(numscreenover) - 1;
 }
diff --git a/engines/ags/engine/ac/speech.cpp b/engines/ags/engine/ac/speech.cpp
index 56ec8e0747..ab6cb0178d 100644
--- a/engines/ags/engine/ac/speech.cpp
+++ b/engines/ags/engine/ac/speech.cpp
@@ -91,6 +91,10 @@ ScriptOverlay *Speech_GetTextOverlay() {
 	return _GP(play).speech_text_scover;
 }
 
+ScriptOverlay *Speech_GetPortraitOverlay() {
+	return _GP(play).speech_face_scover;
+}
+
 RuntimeScriptValue Sc_Speech_GetAnimationStopTimeMargin(const RuntimeScriptValue *params, int32_t param_count) {
 	API_VARGET_INT(_GP(play).close_mouth_speech_time);
 }
@@ -195,6 +199,10 @@ RuntimeScriptValue Sc_Speech_GetTextOverlay(const RuntimeScriptValue *params, in
 	API_SCALL_OBJAUTO(ScriptOverlay, Speech_GetTextOverlay);
 }
 
+RuntimeScriptValue Sc_Speech_GetPortraitOverlay(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_OBJAUTO(ScriptOverlay, Speech_GetPortraitOverlay);
+}
+
 extern RuntimeScriptValue Sc_SetVoiceMode(const RuntimeScriptValue *params, int32_t param_count);
 
 void RegisterSpeechAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api) {
@@ -206,6 +214,7 @@ void RegisterSpeechAPI(ScriptAPIVersion base_api, ScriptAPIVersion compat_api) {
 	ccAddExternalStaticFunction("Speech::set_DisplayPostTimeMs", Sc_Speech_SetDisplayPostTimeMs);
 	ccAddExternalStaticFunction("Speech::get_GlobalSpeechAnimationDelay", Sc_Speech_GetGlobalSpeechAnimationDelay);
 	ccAddExternalStaticFunction("Speech::set_GlobalSpeechAnimationDelay", Sc_Speech_SetGlobalSpeechAnimationDelay);
+	ccAddExternalStaticFunction("Speech::get_PortraitOverlay", Sc_Speech_GetPortraitOverlay);
 	ccAddExternalStaticFunction("Speech::get_PortraitXOffset", Sc_Speech_GetPortraitXOffset);
 	ccAddExternalStaticFunction("Speech::set_PortraitXOffset", Sc_Speech_SetPortraitXOffset);
 	ccAddExternalStaticFunction("Speech::get_PortraitY", Sc_Speech_GetPortraitY);


Commit: 65f992979e99590b0da44dc4ecfc26a50b8549b8
    https://github.com/scummvm/scummvm/commit/65f992979e99590b0da44dc4ecfc26a50b8549b8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:38-07:00

Commit Message:
AGS: Implemented Game.BlockingWaitSkipped

>From upstream ce6bd0173f668932a0a5cab41119d2a476f7e73c

Changed paths:
    engines/ags/engine/ac/display.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/game_state.cpp
    engines/ags/engine/ac/game_state.h
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/engine/main/update.cpp


diff --git a/engines/ags/engine/ac/display.cpp b/engines/ags/engine/ac/display.cpp
index 0a1b94be89..d1baabd78d 100644
--- a/engines/ags/engine/ac/display.cpp
+++ b/engines/ags/engine/ac/display.cpp
@@ -268,6 +268,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 		// If fast-forwarding, then skip immediately
 		if (_GP(play).fast_forward) {
 			remove_screen_overlay(OVER_TEXTMSG);
+			_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
 			_GP(play).messagetime = -1;
 			return 0;
 		}
@@ -290,16 +291,20 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 				check_skip_cutscene_mclick(mbut);
 				if (_GP(play).fast_forward)
 					break;
-				if (skip_setting & SKIP_MOUSECLICK && !_GP(play).IsIgnoringInput())
+				if (skip_setting & SKIP_MOUSECLICK && !_GP(play).IsIgnoringInput()) {
+					_GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut);
 					break;
+				}
 			}
 			KeyInput kp;
 			if (run_service_key_controls(kp)) {
 				check_skip_cutscene_keypress(kp.Key);
 				if (_GP(play).fast_forward)
 					break;
-				if ((skip_setting & SKIP_KEYPRESS) && !_GP(play).IsIgnoringInput())
+				if ((skip_setting & SKIP_KEYPRESS) && !_GP(play).IsIgnoringInput()) {
+					_GP(play).SetWaitSkipResult(SKIP_KEYPRESS, kp.Key);
 					break;
+				}
 			}
 
 			update_polled_stuff_if_runtime();
@@ -321,6 +326,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			}
 			// Test for the timed auto-skip
 			if ((countdown < 1) && (skip_setting & SKIP_AUTOTIMER)) {
+				_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
 				_GP(play).SetIgnoreInput(_GP(play).ignore_user_input_after_text_timeout_ms);
 				break;
 			}
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index 9546948a0d..ddc28902a4 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -752,6 +752,10 @@ void Game_SimulateKeyPress(int key) {
 	ags_simulate_keypress(static_cast<eAGSKeyCode>(key));
 }
 
+int Game_BlockingWaitSkipped() {
+	return _GP(play).GetWaitSkipResult();
+}
+
 //=============================================================================
 
 // save game functions
@@ -1093,8 +1097,10 @@ void start_skipping_cutscene() {
 		remove_popup_interface(_G(ifacepopped));
 
 	// if a text message is currently displayed, remove it
-	if (_GP(play).text_overlay_on > 0)
+	if (_GP(play).text_overlay_on > 0) {
 		remove_screen_overlay(_GP(play).text_overlay_on);
+		_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
+	}
 }
 
 bool check_skip_cutscene_keypress(int kgn) {
@@ -1722,6 +1728,10 @@ RuntimeScriptValue Sc_Game_SimulateKeyPress(const RuntimeScriptValue *params, in
 	API_SCALL_VOID_PINT(Game_SimulateKeyPress);
 }
 
+RuntimeScriptValue Sc_Game_BlockingWaitSkipped(const RuntimeScriptValue *params, int32_t param_count) {
+	API_SCALL_INT(Game_BlockingWaitSkipped);
+}
+
 void RegisterGameAPI() {
 	ccAddExternalStaticFunction("Game::IsAudioPlaying^1",                       Sc_Game_IsAudioPlaying);
 	ccAddExternalStaticFunction("Game::SetAudioTypeSpeechVolumeDrop^2",         Sc_Game_SetAudioTypeSpeechVolumeDrop);
@@ -1774,6 +1784,7 @@ void RegisterGameAPI() {
 	ccAddExternalStaticFunction("Game::IsPluginLoaded",                         Sc_Game_IsPluginLoaded);
 	ccAddExternalStaticFunction("Game::PlayVoiceClip",                          Sc_Game_PlayVoiceClip);
 	ccAddExternalStaticFunction("Game::SimulateKeyPress",                       Sc_Game_SimulateKeyPress);
+	ccAddExternalStaticFunction("Game::get_BlockingWaitSkipped",                Sc_Game_BlockingWaitSkipped);
 
 	ccAddExternalStaticFunction("Game::get_Camera",                             Sc_Game_GetCamera);
 	ccAddExternalStaticFunction("Game::get_CameraCount",                        Sc_Game_GetCameraCount);
diff --git a/engines/ags/engine/ac/game_state.cpp b/engines/ags/engine/ac/game_state.cpp
index 42d06aacde..ed84c5e33a 100644
--- a/engines/ags/engine/ac/game_state.cpp
+++ b/engines/ags/engine/ac/game_state.cpp
@@ -370,6 +370,20 @@ void GameState::ClearIgnoreInput() {
 	_ignoreUserInputUntilTime = AGS_Clock::now();
 }
 
+void GameState::SetWaitSkipResult(int how, int data) {
+	wait_counter = 0;
+	wait_skipped_by = how;
+	wait_skipped_by_data = data;
+}
+
+int GameState::GetWaitSkipResult() const {
+	switch (wait_skipped_by) {
+	case SKIP_KEYPRESS: return wait_skipped_by_data;
+	case SKIP_MOUSECLICK: return -(wait_skipped_by_data + 1); // convert to 1-based code and negate
+	default: return 0;
+	}
+}
+
 bool GameState::IsBlockingVoiceSpeech() const {
 	return speech_has_voice && speech_voice_blocking;
 }
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index e9c9a6d32f..370f1ceddf 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -158,8 +158,8 @@ struct GameState {
 	int   bg_frame = 0, bg_anim_delay = 0;  // for animating backgrounds
 	int   music_vol_was = 0;  // before the volume drop
 	short wait_counter = 0;
-	char  wait_skipped_by = 0; // tells how last wait was skipped [not serialized]
-	int   wait_skipped_by_data = 0; // extended data telling how last wait was skipped [not serialized]
+	char  wait_skipped_by = 0; // tells how last blocking wait was skipped [not serialized]
+	int   wait_skipped_by_data = 0; // extended data telling how last blocking wait was skipped [not serialized]
 	short mboundx1 = 0, mboundx2 = 0, mboundy1 = 0, mboundy2 = 0;
 	int   fade_effect = 0;
 	int   bg_frame_locked = 0;
@@ -354,6 +354,14 @@ struct GameState {
 	// Clears ignore input state
 	void ClearIgnoreInput();
 
+	// Set how the last blocking wait was skipped
+	void SetWaitSkipResult(int how, int data = 0);
+	// Returns the code of the latest blocking wait skip method.
+	// * positive value means a key code;
+	// * negative value means a -(mouse code + 1);
+	// * 0 means timeout.
+	int GetWaitSkipResult() const;
+
 	//
 	// Voice speech management
 	//
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index 4c9bc30f6e..36a36df955 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -772,6 +772,7 @@ void SetGraphicalVariable(const char *varName, int p_value) {
 
 int WaitImpl(int skip_type, int nloops) {
 	_GP(play).wait_counter = nloops;
+	_GP(play).wait_skipped_by = SKIP_NONE;
 	_GP(play).wait_skipped_by = SKIP_AUTOTIMER; // we set timer flag by default to simplify that case
 	_GP(play).wait_skipped_by_data = 0;
 	_GP(play).key_skip_wait = skip_type;
@@ -783,11 +784,7 @@ int WaitImpl(int skip_type, int nloops) {
 		return (_GP(play).wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK)) != 0 ? 1 : 0;
 	}
 	// >= 3.6.0 return positive keycode, negative mouse button code, or 0 as time-out
-	switch (_GP(play).wait_skipped_by) {
-	case SKIP_KEYPRESS: return _GP(play).wait_skipped_by_data;
-	case SKIP_MOUSECLICK: return -(_GP(play).wait_skipped_by_data + 1); // convert to 1-based code and negate
-	default: return 0;
-	}
+	return _GP(play).GetWaitSkipResult();
 }
 
 void scrWait(int nloops) {
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index b381178381..53d7932bff 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -738,6 +738,7 @@ void engine_init_game_settings() {
 	_GP(play).music_queue_size = 0;
 	_GP(play).shakesc_length = 0;
 	_GP(play).wait_counter = 0;
+	_GP(play).SetWaitSkipResult(SKIP_NONE);
 	_GP(play).key_skip_wait = SKIP_NONE;
 	_GP(play).cur_music_number = -1;
 	_GP(play).music_repeat = 1;
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index e275862a03..6054dd0f27 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -208,12 +208,12 @@ static void check_mouse_controls() {
 
 		if (_GP(play).fast_forward || _GP(play).IsIgnoringInput()) { /* do nothing if skipping cutscene or input disabled */
 		} else if ((_GP(play).wait_counter != 0) && (_GP(play).key_skip_wait & SKIP_MOUSECLICK) != 0) {
-			_GP(play).wait_counter = 0;
-			_GP(play).wait_skipped_by = SKIP_MOUSECLICK;
-			_GP(play).wait_skipped_by_data = mbut;
+			_GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut);
 		} else if (_GP(play).text_overlay_on > 0) {
-			if (_GP(play).cant_skip_speech & SKIP_MOUSECLICK)
+			if (_GP(play).cant_skip_speech & SKIP_MOUSECLICK) {
 				remove_screen_overlay(_GP(play).text_overlay_on);
+				_GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut);
+			}
 		} else if (!IsInterfaceEnabled());  // blocking cutscene, ignore mouse
 		else if (pl_run_plugin_hooks(AGSE_MOUSECLICK, mbut + 1)) {
 			// plugin took the click
@@ -436,16 +436,17 @@ static void check_keyboard_controls() {
 			// check if it requires a specific keypress
 			if ((_GP(play).skip_speech_specific_key > 0) &&
 				(kgn != _GP(play).skip_speech_specific_key)) {
-			} else
+			} else {
 				remove_screen_overlay(_GP(play).text_overlay_on);
+				_GP(play).SetWaitSkipResult(SKIP_KEYPRESS, kgn);
+			}
 		}
 
 		return;
 	}
 
 	if ((_GP(play).wait_counter != 0) && (_GP(play).key_skip_wait & SKIP_KEYPRESS) != 0) {
-		_GP(play).wait_counter = -1;
-		debug_script_log("Keypress code %d ignored - in Wait", kgn);
+		_GP(play).SetWaitSkipResult(SKIP_KEYPRESS, kgn);
 		return;
 	}
 
diff --git a/engines/ags/engine/main/update.cpp b/engines/ags/engine/main/update.cpp
index a7ae9981fe..88b4911cdd 100644
--- a/engines/ags/engine/main/update.cpp
+++ b/engines/ags/engine/main/update.cpp
@@ -261,8 +261,10 @@ void update_speech_and_messages() {
 		if (_GP(play).messagetime < 1) {
 			if (_GP(play).fast_forward > 0) {
 				remove_screen_overlay(_GP(play).text_overlay_on);
+				_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
 			} else if (_GP(play).cant_skip_speech & SKIP_AUTOTIMER) {
 				remove_screen_overlay(_GP(play).text_overlay_on);
+				_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
 				_GP(play).SetIgnoreInput(_GP(play).ignore_user_input_after_text_timeout_ms);
 			}
 		}


Commit: e93845cb0ca66a548f0e498a87b4055c34241bc8
    https://github.com/scummvm/scummvm/commit/e93845cb0ca66a548f0e498a87b4055c34241bc8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:38-07:00

Commit Message:
AGS: added eSkipNone to SkipSpeechStyle

>From upstream 67f88aed90de1c32fb415e8d0826836fae919bfa

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


diff --git a/engines/ags/engine/ac/speech.cpp b/engines/ags/engine/ac/speech.cpp
index ab6cb0178d..e04ea79a59 100644
--- a/engines/ags/engine/ac/speech.cpp
+++ b/engines/ags/engine/ac/speech.cpp
@@ -38,6 +38,8 @@ namespace AGS3 {
 
 int user_to_internal_skip_speech(SkipSpeechStyle userval) {
 	switch (userval) {
+	case kSkipSpeechNone:
+		return SKIP_NONE;
 	case kSkipSpeechKeyMouseTime:
 		return SKIP_AUTOTIMER | SKIP_KEYPRESS | SKIP_MOUSECLICK;
 	case kSkipSpeechKeyTime:
@@ -54,7 +56,7 @@ int user_to_internal_skip_speech(SkipSpeechStyle userval) {
 		return SKIP_MOUSECLICK;
 	default:
 		quit("user_to_internal_skip_speech: unknown userval");
-		return 0;
+		return SKIP_NONE;
 	}
 }
 
@@ -78,7 +80,7 @@ SkipSpeechStyle internal_skip_speech_to_user(int internal_val) {
 			return kSkipSpeechMouse;
 		}
 	}
-	return kSkipSpeechUndefined;
+	return kSkipSpeechNone;
 }
 
 //=============================================================================
diff --git a/engines/ags/engine/ac/speech.h b/engines/ags/engine/ac/speech.h
index dd5e3dc1e9..3d2d46edd2 100644
--- a/engines/ags/engine/ac/speech.h
+++ b/engines/ags/engine/ac/speech.h
@@ -26,7 +26,7 @@
 namespace AGS3 {
 
 enum SkipSpeechStyle {
-	kSkipSpeechUndefined = -1,
+	kSkipSpeechNone = -1,
 	kSkipSpeechKeyMouseTime = 0,
 	kSkipSpeechKeyTime = 1,
 	kSkipSpeechTime = 2,
@@ -35,7 +35,7 @@ enum SkipSpeechStyle {
 	kSkipSpeechKey = 5,
 	kSkipSpeechMouse = 6,
 
-	kSkipSpeechFirst = kSkipSpeechKeyMouseTime,
+	kSkipSpeechFirst = kSkipSpeechNone,
 	kSkipSpeechLast = kSkipSpeechMouse
 };
 


Commit: cf36b34f0d16e17b2a2c96d06c159ca366e430bd
    https://github.com/scummvm/scummvm/commit/cf36b34f0d16e17b2a2c96d06c159ca366e430bd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:38-07:00

Commit Message:
AGS: Implemented Object.ManualScaling and Object.Scaling

>From upstream fe9bf3707afb4c36effc358d8e3eb7834d333fb5

Changed paths:
    engines/ags/engine/ac/draw.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


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 1a76213273..f85c813cf7 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1240,22 +1240,22 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 	int zoom_level = 100;
 
 	// calculate the zoom level
-	if (_G(objs)[aa].flags & OBJF_USEROOMSCALING) {
+	if ((_G(objs)[aa].flags & OBJF_USEROOMSCALING) == 0) {
+		zoom_level = _G(objs)[aa].zoom;
+	} else {
 		int onarea = get_walkable_area_at_location(_G(objs)[aa].x, _G(objs)[aa].y);
 
 		if ((onarea <= 0) && (_GP(thisroom).WalkAreas[0].ScalingFar == 0)) {
 			// just off the edge of an area -- use the scaling we had
 			// while on the area
-			zoom_level = _G(objs)[aa].last_zoom;
+			zoom_level = _G(objs)[aa].zoom;
 		} else
 			zoom_level = get_area_scaling(onarea, _G(objs)[aa].x, _G(objs)[aa].y);
-
-		if (zoom_level != 100)
-			scale_sprite_size(_G(objs)[aa].num, zoom_level, &sprwidth, &sprheight);
-
 	}
-	// save the zoom level for next time
-	_G(objs)[aa].last_zoom = zoom_level;
+
+	if (zoom_level != 100)
+		scale_sprite_size(_G(objs)[aa].num, zoom_level, &sprwidth, &sprheight);
+	_G(objs)[aa].zoom = zoom_level;
 
 	// save width/height into parameters if requested
 	if (drawnWidth)
@@ -1423,7 +1423,7 @@ void prepare_objects_for_drawing() {
 				usebasel += _GP(thisroom).Height;
 			}
 		} else if (_G(walkBehindMethod) == DrawAsSeparateCharSprite) {
-			sort_out_char_sprite_walk_behind(useindx, atxp, atyp, usebasel, _G(objs)[aa].last_zoom, _G(objs)[aa].last_width, _G(objs)[aa].last_height);
+			sort_out_char_sprite_walk_behind(useindx, atxp, atyp, usebasel, _G(objs)[aa].zoom, _G(objs)[aa].last_width, _G(objs)[aa].last_height);
 		} else if ((!actspsIntact) && (_G(walkBehindMethod) == DrawOverCharSprite)) {
 			sort_out_walk_behinds(_G(actsps)[useindx], atxp, atyp, usebasel);
 		}
@@ -1546,10 +1546,12 @@ void prepare_characters_for_drawing() {
 		onarea = get_walkable_area_at_character(aa);
 		_G(our_eip) = 332;
 
+		// calculates the zoom level
 		if (chin->flags & CHF_MANUALSCALING)  // character ignores scaling
 			zoom_level = _G(charextra)[aa].zoom;
 		else if ((onarea <= 0) && (_GP(thisroom).WalkAreas[0].ScalingFar == 0)) {
 			zoom_level = _G(charextra)[aa].zoom;
+			// NOTE: room objects don't have this fix
 			if (zoom_level == 0)
 				zoom_level = 100;
 		} else
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index cc04f39096..a15cc5ddf1 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -321,16 +321,19 @@ int Object_GetClickable(ScriptObject *objj) {
 	return 1;
 }
 
+void Object_SetManualScaling(ScriptObject *objj, bool on) {
+	if (on) _G(objs)[objj->id].flags &= ~OBJF_USEROOMSCALING;
+	else _G(objs)[objj->id].flags |= OBJF_USEROOMSCALING;
+	// clear the cache
+	_G(objcache)[objj->id].ywas = -9999;
+}
+
 void Object_SetIgnoreScaling(ScriptObject *objj, int newval) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.IgnoreScaling: Invalid object specified");
-
-	_G(objs)[objj->id].flags &= ~OBJF_USEROOMSCALING;
-	if (!newval)
-		_G(objs)[objj->id].flags |= OBJF_USEROOMSCALING;
-
-	// clear the cache
-	_G(objcache)[objj->id].ywas = -9999;
+	if (newval)
+		_G(objs)[objj->id].zoom = 100; // compatibility, for before manual scaling existed
+	Object_SetManualScaling(objj, newval != 0);
 }
 
 int Object_GetIgnoreScaling(ScriptObject *objj) {
@@ -342,6 +345,22 @@ int Object_GetIgnoreScaling(ScriptObject *objj) {
 	return 1;
 }
 
+int Object_GetScaling(ScriptObject *objj) {
+	return _G(objs)[objj->id].zoom;
+}
+
+void Object_SetScaling(ScriptObject *objj, int zoomlevel) {
+	if ((_G(objs)[objj->id].flags & OBJF_USEROOMSCALING) != 0) {
+		debug_script_warn("Object.Scaling: cannot set property unless ManualScaling is enabled");
+		return;
+	}
+	int zoom_fixed = Math::Clamp(zoomlevel, 1, (int)(INT16_MAX)); // RoomObject.zoom is int16
+	if (zoomlevel != zoom_fixed)
+		debug_script_warn("Object.Scaling: scaling level must be between 1 and %d%%, asked for: %d",
+		(int)(INT16_MAX), zoomlevel);
+	_G(objs)[objj->id].zoom = zoom_fixed;
+}
+
 void Object_SetSolid(ScriptObject *objj, int solid) {
 	_G(objs)[objj->id].flags &= ~OBJF_SOLID;
 	if (solid)
@@ -758,6 +777,10 @@ RuntimeScriptValue Sc_Object_GetLoop(void *self, const RuntimeScriptValue *param
 	API_OBJCALL_INT(ScriptObject, Object_GetLoop);
 }
 
+RuntimeScriptValue Sc_Object_SetManualScaling(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PBOOL(ScriptObject, Object_SetManualScaling);
+}
+
 // int (ScriptObject *objj)
 RuntimeScriptValue Sc_Object_GetMoving(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(ScriptObject, Object_GetMoving);
@@ -768,6 +791,14 @@ 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_GetScaling(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_INT(ScriptObject, Object_GetScaling);
+}
+
+RuntimeScriptValue Sc_Object_SetScaling(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+	API_OBJCALL_VOID_PINT(ScriptObject, Object_SetScaling);
+}
+
 // int (ScriptObject *objj)
 RuntimeScriptValue Sc_Object_GetSolid(void *self, const RuntimeScriptValue *params, int32_t param_count) {
 	API_OBJCALL_INT(ScriptObject, Object_GetSolid);
@@ -869,9 +900,12 @@ void RegisterObjectAPI() {
 	ccAddExternalObjectFunction("Object::get_IgnoreWalkbehinds", Sc_Object_GetIgnoreWalkbehinds);
 	ccAddExternalObjectFunction("Object::set_IgnoreWalkbehinds", Sc_Object_SetIgnoreWalkbehinds);
 	ccAddExternalObjectFunction("Object::get_Loop", Sc_Object_GetLoop);
+	ccAddExternalObjectFunction("Object::get_ManualScaling", Sc_Object_GetIgnoreScaling);
+	ccAddExternalObjectFunction("Object::set_ManualScaling", Sc_Object_SetManualScaling);
 	ccAddExternalObjectFunction("Object::get_Moving", Sc_Object_GetMoving);
 	ccAddExternalObjectFunction("Object::get_Name", Sc_Object_GetName_New);
-	ccAddExternalObjectFunction("Object::get_Solid", Sc_Object_GetSolid);
+	ccAddExternalObjectFunction("Object::get_Scaling", Sc_Object_GetScaling);
+	ccAddExternalObjectFunction("Object::set_Scaling", Sc_Object_SetScaling);
 	ccAddExternalObjectFunction("Object::set_Solid", Sc_Object_SetSolid);
 	ccAddExternalObjectFunction("Object::get_Transparency", Sc_Object_GetTransparency);
 	ccAddExternalObjectFunction("Object::set_Transparency", Sc_Object_SetTransparency);
diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index 9cbf56cd7e..8725c36686 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -573,7 +573,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 			_G(croom)->obj[cc].moving = -1;
 			_G(croom)->obj[cc].flags = _GP(thisroom).Objects[cc].Flags;
 			_G(croom)->obj[cc].baseline = -1;
-			_G(croom)->obj[cc].last_zoom = 100;
+			_G(croom)->obj[cc].zoom = 100;
 			_G(croom)->obj[cc].last_width = 0;
 			_G(croom)->obj[cc].last_height = 0;
 			_G(croom)->obj[cc].blocking_width = 0;
diff --git a/engines/ags/engine/ac/room_object.cpp b/engines/ags/engine/ac/room_object.cpp
index f311d49d01..6b1dd69372 100644
--- a/engines/ags/engine/ac/room_object.cpp
+++ b/engines/ags/engine/ac/room_object.cpp
@@ -36,17 +36,13 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-
-
-
 RoomObject::RoomObject() {
 	x = y = 0;
 	transparent = 0;
 	tint_r = tint_g = 0;
 	tint_b = tint_level = 0;
 	tint_light = 0;
-	last_zoom = 0;
+	zoom = 0;
 	last_width = last_height = 0;
 	num = 0;
 	baseline = 0;
diff --git a/engines/ags/engine/ac/room_object.h b/engines/ags/engine/ac/room_object.h
index 1c8b9697e3..912a8d3e1f 100644
--- a/engines/ags/engine/ac/room_object.h
+++ b/engines/ags/engine/ac/room_object.h
@@ -51,7 +51,7 @@ struct RoomObject {
 	short tint_r, tint_g;   // specific object tint
 	short tint_b, tint_level;
 	short tint_light;
-	short last_zoom;      // zoom level last time
+	short zoom;           // zoom level, either manual or from the current area
 	short last_width, last_height;   // width/height last time drawn
 	uint16_t num;            // sprite slot number
 	short baseline;       // <=0 to use Y co-ordinate; >0 for specific baseline


Commit: 28102f13ab3f6fe4979f272e8e8500b8d3d47fc7
    https://github.com/scummvm/scummvm/commit/28102f13ab3f6fe4979f272e8e8500b8d3d47fc7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:38-07:00

Commit Message:
AGS: allow Character.Scaling full range (1-32767)

>From upstream fe9b19e2d9868b3c953aa4b71c44be3c712987b7

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 5433b8cc70..114219c485 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -1384,10 +1384,12 @@ void Character_SetScaling(CharacterInfo *chaa, int zoomlevel) {
 		debug_script_warn("Character.Scaling: cannot set property unless ManualScaling is enabled");
 		return;
 	}
-	if ((zoomlevel < 5) || (zoomlevel > 200))
-		quit("!Character.Scaling: scaling level must be between 5 and 200%");
+	int zoom_fixed = Math::Clamp(zoomlevel, 1, (int)(INT16_MAX)); // CharacterExtras.zoom is int16
+	if (zoomlevel != zoom_fixed)
+		debug_script_warn("Character.Scaling: scaling level must be between 1 and %d%%, asked for: %d",
+			(int)(INT16_MAX), zoomlevel);
 
-	_G(charextra)[chaa->index_id].zoom = zoomlevel;
+	_G(charextra)[chaa->index_id].zoom = zoom_fixed;
 }
 
 int Character_GetSolid(CharacterInfo *chaa) {


Commit: 60c7f3351610e5794e0cb8dcf8187ced3bf51b39
    https://github.com/scummvm/scummvm/commit/60c7f3351610e5794e0cb8dcf8187ced3bf51b39
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-27T22:03:39-07:00

Commit Message:
AGS: Update engine sync point comments

>From upstream 4bb97d6d318fdd1a8d2e86e0b8b0457bd5f939d0

Changed paths:
    engines/ags/ags.h


diff --git a/engines/ags/ags.h b/engines/ags/ags.h
index 4f009fb6dd..146de292c1 100644
--- a/engines/ags/ags.h
+++ b/engines/ags/ags.h
@@ -50,8 +50,8 @@ namespace AGS {
  * @brief Engine to run Adventure Game Studio games.
  */
 
-/* Synced up to upstream:
- * 4e2df949ff36bbb6d08e402586dc8c2bb02ecad9
+/* Synced up to upstream: 3.6.0.5
+ * 4bb97d6d318fdd1a8d2e86e0b8b0457bd5f939d0
  */
 #define SCREEN_WIDTH 320
 #define SCREEN_HEIGHT 200




More information about the Scummvm-git-logs mailing list