[Scummvm-git-logs] scummvm master -> e7aac61340935b930cf9b8d50a85d51d8e7303cd

aquadran noreply at scummvm.org
Fri Aug 15 12:57:42 UTC 2025


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

Summary:
e7aac61340 WINTERMUTE: Added W/A for 'Face Noir' in game mini puzzle


Commit: e7aac61340935b930cf9b8d50a85d51d8e7303cd
    https://github.com/scummvm/scummvm/commit/e7aac61340935b930cf9b8d50a85d51d8e7303cd
Author: Paweł Kołodziejski (aquadran at gmail.com)
Date: 2025-08-15T14:57:20+02:00

Commit Message:
WINTERMUTE: Added W/A for 'Face Noir' in game mini puzzle

Changed paths:
    engines/wintermute/base/scriptables/script.cpp
    engines/wintermute/base/scriptables/script.h
    engines/wintermute/base/scriptables/script_value.cpp
    engines/wintermute/base/scriptables/script_value.h
    engines/wintermute/debugger/watch_instance.cpp


diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp
index e125826ae07..b91bc9d01b1 100644
--- a/engines/wintermute/base/scriptables/script.cpp
+++ b/engines/wintermute/base/scriptables/script.cpp
@@ -107,6 +107,10 @@ ScScript::ScScript(BaseGame *inGame, ScEngine *engine) : BaseClass(inGame) {
 #ifdef ENABLE_FOXTAIL
 	initOpcodesType();
 #endif
+	// W/A for 'Face Noir' game. See comment in script_value.cpp
+	if (BaseEngine::instance().getGameId() == "facenoir") {
+		_enableFloatCompareWA = true;
+	}
 }
 
 
@@ -1019,7 +1023,7 @@ bool ScScript::executeInstruction() {
 		}
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) == 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) == 0);
 		_stack->push(_operand);
 		break;
 
@@ -1043,7 +1047,7 @@ bool ScScript::executeInstruction() {
 		}
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) != 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) != 0);
 		_stack->push(_operand);
 		break;
 
@@ -1058,7 +1062,7 @@ bool ScScript::executeInstruction() {
 		else _operand->setBool(op1->getInt() < op2->getInt());
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) < 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) < 0);
 		_stack->push(_operand);
 		break;
 
@@ -1073,7 +1077,7 @@ bool ScScript::executeInstruction() {
 		else _operand->setBool(op1->getInt() > op2->getInt());
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) > 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) > 0);
 		_stack->push(_operand);
 		break;
 
@@ -1088,7 +1092,7 @@ bool ScScript::executeInstruction() {
 		else _operand->setBool(op1->getInt() <= op2->getInt());
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) <= 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) <= 0);
 		_stack->push(_operand);
 		break;
 
@@ -1103,7 +1107,7 @@ bool ScScript::executeInstruction() {
 		else _operand->setBool(op1->getInt() >= op2->getInt());
 		*/
 
-		_operand->setBool(ScValue::compare(op1, op2) >= 0);
+		_operand->setBool(ScValue::compare(op1, op2, _enableFloatCompareWA) >= 0);
 		_stack->push(_operand);
 		break;
 
@@ -1112,7 +1116,7 @@ bool ScScript::executeInstruction() {
 		op1 = _stack->pop();
 
 		//_operand->setBool(op1->getType()==op2->getType() && op1->getFloat()==op2->getFloat());
-		_operand->setBool(ScValue::compareStrict(op1, op2) == 0);
+		_operand->setBool(ScValue::compareStrict(op1, op2, _enableFloatCompareWA) == 0);
 		_stack->push(_operand);
 
 		break;
@@ -1122,7 +1126,7 @@ bool ScScript::executeInstruction() {
 		op1 = _stack->pop();
 
 		//_operand->setBool(op1->getType()!=op2->getType() || op1->getFloat()!=op2->getFloat());
-		_operand->setBool(ScValue::compareStrict(op1, op2) != 0);
+		_operand->setBool(ScValue::compareStrict(op1, op2, _enableFloatCompareWA) != 0);
 		_stack->push(_operand);
 		break;
 
@@ -1352,6 +1356,12 @@ bool ScScript::persist(BasePersistenceManager *persistMgr) {
 #ifdef ENABLE_FOXTAIL
 		initOpcodesType();
 #endif
+		// W/A for 'Face Noir' game. See comment in script_value.cpp
+		if (BaseEngine::instance().getGameId() == "facenoir") {
+			_enableFloatCompareWA = true;
+		} else {
+			_enableFloatCompareWA = false;
+		}
 	}
 
 	return STATUS_OK;
diff --git a/engines/wintermute/base/scriptables/script.h b/engines/wintermute/base/scriptables/script.h
index ae175191b0e..a48b57e68f1 100644
--- a/engines/wintermute/base/scriptables/script.h
+++ b/engines/wintermute/base/scriptables/script.h
@@ -168,6 +168,8 @@ private:
 	void initOpcodesType();
 	uint32 decodeAltOpcodes(uint32 inst);
 #endif
+
+	bool _enableFloatCompareWA{};
 };
 
 } // End of namespace Wintermute
diff --git a/engines/wintermute/base/scriptables/script_value.cpp b/engines/wintermute/base/scriptables/script_value.cpp
index 6e356914fce..62b5a0220ea 100644
--- a/engines/wintermute/base/scriptables/script_value.cpp
+++ b/engines/wintermute/base/scriptables/script_value.cpp
@@ -892,7 +892,7 @@ bool ScValue::saveAsText(BaseDynamicBuffer *buffer, int indent) {
 
 //////////////////////////////////////////////////////////////////////////
 // -1 ... left is less, 0 ... equals, 1 ... left is greater
-int ScValue::compare(ScValue *val1, ScValue *val2) {
+int ScValue::compare(ScValue *val1, ScValue *val2, bool enableFloatCompareWA) {
 	// both natives?
 	if (val1->isNative() && val2->isNative()) {
 		// same class?
@@ -925,12 +925,32 @@ int ScValue::compare(ScValue *val1, ScValue *val2) {
 
 	// one of them is float?
 	if (val1->isFloat() || val2->isFloat()) {
-		if (val1->getFloat() < val2->getFloat()) {
-			return -1;
-		} else if (val1->getFloat() > val2->getFloat()) {
-			return 1;
+		if (enableFloatCompareWA) {
+			// W/A:
+			// The engine uses double precision for script values,
+			// while other parts use single precision.
+			// Conversion between them may not always be exactly
+			// the same across platforms.
+			// Some games maye rely on the higher precision of doubles.
+			// As a result, calculated values may not match the
+			// expectations of the game scripts.
+			// The solution is to cast to single precision before comparison.
+			// This helps fix the in-game 'Face Noir' mini puzzle.
+			if ((float)val1->getFloat() < (float)val2->getFloat()) {
+				return -1;
+			} else if ((float)val1->getFloat() > (float)val2->getFloat()) {
+				return 1;
+			} else {
+				return 0;
+			}
 		} else {
-			return 0;
+			if (val1->getFloat() < val2->getFloat()) {
+				return -1;
+			} else if (val1->getFloat() > val2->getFloat()) {
+				return 1;
+			} else {
+				return 0;
+			}
 		}
 	}
 
@@ -946,11 +966,11 @@ int ScValue::compare(ScValue *val1, ScValue *val2) {
 
 
 //////////////////////////////////////////////////////////////////////////
-int ScValue::compareStrict(ScValue *val1, ScValue *val2) {
+int ScValue::compareStrict(ScValue *val1, ScValue *val2, bool enableFloatCompareWA) {
 	if (val1->getTypeTolerant() != val2->getTypeTolerant()) {
 		return -1;
 	} else {
-		return ScValue::compare(val1, val2);
+		return ScValue::compare(val1, val2, enableFloatCompareWA);
 	}
 }
 
diff --git a/engines/wintermute/base/scriptables/script_value.h b/engines/wintermute/base/scriptables/script_value.h
index e4074e977e7..0cd9cea58c7 100644
--- a/engines/wintermute/base/scriptables/script_value.h
+++ b/engines/wintermute/base/scriptables/script_value.h
@@ -41,8 +41,8 @@ class BaseScriptable;
 
 class ScValue : public BaseClass {
 public:
-	static int compare(ScValue *val1, ScValue *val2);
-	static int compareStrict(ScValue *val1, ScValue *val2);
+	static int compare(ScValue *val1, ScValue *val2, bool enableFloatCompareWA);
+	static int compareStrict(ScValue *val1, ScValue *val2, bool enableFloatCompareWA);
 	TValType getTypeTolerant();
 	void cleanup(bool ignoreNatives = false);
 	DECLARE_PERSISTENT(ScValue, BaseClass)
diff --git a/engines/wintermute/debugger/watch_instance.cpp b/engines/wintermute/debugger/watch_instance.cpp
index e4d1f74be5f..7a83e1360d5 100644
--- a/engines/wintermute/debugger/watch_instance.cpp
+++ b/engines/wintermute/debugger/watch_instance.cpp
@@ -38,10 +38,7 @@ void WatchInstance::evaluate() {
 				// ^^ This here is NULL by default
 			}
 			ScValue* currentValue = _script->resolveName(_watch->getSymbol());
-			if(ScValue::compare(
-					currentValue,
-					_lastValue
-					)) {
+			if(ScValue::compare(currentValue, _lastValue, false)) {
 				_lastValue->copy(currentValue);
 				_watch->trigger(this);
 			}




More information about the Scummvm-git-logs mailing list