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

sev- noreply at scummvm.org
Thu Sep 25 19:50:10 UTC 2025


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

Summary:
1f7f0a4c14 DIRECTOR: LINGO: Add Versions and OSCheck xlibs
37b60467a3 DIRECTOR: LINGO: Don't use global store for b_xtra
81307127ba DIRECTOR: Fix several issues with sprite behaviors
b5a1fad171 DIRECTOR: Move video palette hack into quirk


Commit: 1f7f0a4c146ed506bc42648e4aada1ed9ecc426a
    https://github.com/scummvm/scummvm/commit/1f7f0a4c146ed506bc42648e4aada1ed9ecc426a
Author: Scott Percival (code at moral.net.au)
Date: 2025-09-25T21:50:06+02:00

Commit Message:
DIRECTOR: LINGO: Add Versions and OSCheck xlibs

Changed paths:
  A engines/director/lingo/xlibs/versions.cpp
  A engines/director/lingo/xlibs/versions.h
  A engines/director/lingo/xtras/oscheck.cpp
  A engines/director/lingo/xtras/oscheck.h
    engines/director/detection_tables.h
    engines/director/lingo/lingo-object.cpp
    engines/director/module.mk


diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index 9260b8b1d1c..4c17175ac3d 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -7781,10 +7781,10 @@ static const DirectorGameDescription gameDescriptions[] = {
 	// French version from covermount of PC Fun Nº38 from PressImage, 10ᵉ Paris
 	// Mac filename is ' Sinkha '
 	MACGAME1("sinkha", "",	 "xn-- Sinkha -", "cb91232ecece0045461d236d5914c03d", 719033, 501),
-	WINGAME2("sinkha", "",	 "SINKHA.EXE",	  "3460ad87d2ba57104e2810a77b53c220", 1393825,
-							 "SINKHA.DXR",	  "b8516633b5124711a8c550a2ed539255", 745484, 500),
-	WINGAME2_l("sinkha", "", "SINKHA.EXE",	  "3460ad87d2ba57104e2810a77b53c220", 1393825,
-							 "SINKHA.DXR",	  "363580346c873a70fe1098175b99aa81", 709524, Common::FR_FRA, 500),
+	WINGAME2tf("sinkha", "",	 "SINKHA.EXE",	  "t:b7c21569f21e9b7e8e9e996264e41827", 1393825,
+							 "SINKHA.DXR",	  "t:206c7f91d9dd1593e90e468c4e80c36d", 745484, 500, GF_32BPP),
+	WINGAME2f_l("sinkha", "", "SINKHA.EXE",	  "t:b7c21569f21e9b7e8e9e996264e41827", 1393825,
+							 "SINKHA.DXR",	  "t:206c7f91d9dd1593e90e468c4e80c36d", 709524, Common::FR_FRA, 500, GF_32BPP),
 
 	MACGAME1("sinkha", "Music and Animation", "Music&Animation", "08d6f6e39fbd8388faf57f602acaebcc", 705445, 500),
 	WINGAME2("sinkha", "Music and Animation", "MUSIC.EXE",		 "3460ad87d2ba57104e2810a77b53c220", 1393827,
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 2319fe1b671..afe4085b3d8 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -126,6 +126,7 @@
 #include "director/lingo/xlibs/tengu.h"
 #include "director/lingo/xlibs/unittest.h"
 #include "director/lingo/xlibs/valkyrie.h"
+#include "director/lingo/xlibs/versions.h"
 #include "director/lingo/xlibs/videodiscxobj.h"
 #include "director/lingo/xlibs/vmisonxfcn.h"
 #include "director/lingo/xlibs/vmpresent.h"
@@ -147,6 +148,7 @@
 #include "director/lingo/xtras/keypoll.h"
 #include "director/lingo/xtras/masterapp.h"
 #include "director/lingo/xtras/openurl.h"
+#include "director/lingo/xtras/oscheck.h"
 #include "director/lingo/xtras/qtvrxtra.h"
 #include "director/lingo/xtras/rtk.h"
 #include "director/lingo/xtras/scrnutil.h"
@@ -300,6 +302,7 @@ static const struct XLibProto {
 	XLIBDEF(MovUtilsXObj,		kXObj,			400),	// D4
 	XLIBDEF(MSFile,             kXObj,          400),   // D4
 	XLIBDEF(MystIsleXObj,		kXObj,			400),	// D4
+	XLIBDEF(OSCheckXtra,			kXtraObj,					400),	// D4
 	XLIBDEF(OpenBleedWindowXCMD,kXObj,			300),	// D3
 	XLIBDEF(OpenURLXtra,		kXtraObj,		500),	// D5
 	XLIBDEF(OrthoPlayXObj,		kXObj,			400),	// D4
@@ -334,6 +337,7 @@ static const struct XLibProto {
 	XLIBDEF(VMPresentXObj,		kXObj,			400),	// D4
 	XLIBDEF(VMisOnXFCN,			kXObj,			400),	// D4
 	XLIBDEF(ValkyrieXObj,		kXObj,			400),	// D4
+	XLIBDEF(VersionsXObj,			kXObj,					400),	// D4
 	XLIBDEF(VideodiscXObj,		kXObj,			200),	// D2
 	XLIBDEF(VolumeList,			kXObj,			300),	// D3
 	XLIBDEF(VoyagerXSoundXObj,	kXObj,			400),	// D4
diff --git a/engines/director/lingo/xlibs/versions.cpp b/engines/director/lingo/xlibs/versions.cpp
new file mode 100644
index 00000000000..5c8fae89853
--- /dev/null
+++ b/engines/director/lingo/xlibs/versions.cpp
@@ -0,0 +1,256 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xlibs/versions.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * [insert game here]
+ *
+ **************************************************/
+
+/*
+-- Versions XObject, version 1.1, 8/9/96
+--Versions
+-- Copyright © 1996 Glenn M. Picher, Dirigo Multimedia
+-- Email: gpicher at maine.com
+-- Web: http://www.maine.com/shops/gpicher
+-- Phone: (207)767-8015 (South Portland, Maine, USA)
+--
+-- Distributors: g/matter, inc.
+-- Email: support at gmatter.com
+-- Web: http://www.gmatter.com
+-- Phone: (415)243-0394 (San Francisco, California USA)
+--
+-- License granted to use and redistribute for any purpose,
+-- as long as copyright and contact information remains intact.
+-- Each instance of the XObject will present a copyright alert
+-- box once if you use any methods other than the QuickTime version
+-- checking functions. The registered version does not present any
+-- alert boxes.
+--
+I mNew           -- Standard creation method
+X mDispose       -- Standard dispose method
+S mQuickTimeVersion
+--  Get string of QuickTime version ('000000.000000.000000.000000' if QTW
+--  is not installed). Suitable for string comparisons (<, =, >). Example:
+--  Your title includes the QTW v2.1.1.57 installer, and you're running on
+--  a machine with QTW v2.0.1.41 already installed.  QTW v. 2.1.1.57 becomes
+--  '000002.000001.000001.000057' . Alphabetically, this comes after QTW
+--  v. 2.0.1.41 ('000002.000000.000001.000041'). Thus you can conclude
+--  that QuickTime needs to be updated to the version supplied with your
+--  title. This is a workaround for a bug in MCI 'info qtwvideo version'
+--  reporting, which does not always produce valid numeric comparisons. Only
+--  reports the 16-bit QuickTime version. Works by initializing QuickTime,
+--  so the first use may take much longer than subsequent uses.
+--  Number is formatted to be compatible with file version numbers.
+--  Note: requires ASK16.EXE and VERS16.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if ASK16.EXE can't load; Returns string with word 1 'Error:'
+--  if ASK16.EXE fails. ***Note: version 1.0 of this XObject did not use
+--  ASK16.EXE and VERS16.DLL . To avoid occasional crashes when 16-bit Director
+--  got confused about the state of QuickTime, this new version keeps
+--  Director's QuickTime code isolated from this XObject's QuickTime
+--  code. Be sure to add ASK16.EXE and VERS16.DLL to your
+--  distributed projects when upgrading to this version of this XObject.
+S mWin32QuickTimeVersion
+--  Reports the 32-bit QuickTime version. Requires ASK32.EXE and VERS32.DLL
+--  in the same directory as this XObject .DLL . These files are
+--  distributed with this XObject .DLL file. Returns EMPTY if 32-bit
+--  environment is unavailable, or ASK32.EXE can't load; Returns
+--  string with word 1 'Error:' if ASK32.EXE fails.
+SS mFileVersion, fileName
+--  Get string of file version number. Allows checking versions of
+--  QuickTime compressor files, even 32-bit versions. Suitable for string
+--  comparisons. Example: QTIM32.DLL in the System folder, v. 2.1.1.57 becomes
+--  '000002.000001.000001.000057' . The extra digits are the minimum required to
+--  represent the maximum 64-bit version number. Can be used with any file that
+--  contains a version resource, not just QuickTime files. If file is missing
+--  or does not contain version info, result is '000000.000000.000000.000000' .
+--  Works whether 32-bit environment is available or not; however,
+--  ASK32.EXE and VERS32.DLL are required in the same directory as this
+--  XObject .DLL to get Win32 version numbers under Windows NT or 95. These
+--  files are distributed with this XObject .DLL file. Further note: Windows
+--  NT uses a different system directory for 32-bit .DLLs. See below.
+S mWindowsDirectory
+--  Returns full path to Windows directory (including trailing '\').
+--  Useful for building full path names for use with mFileVersion.
+--  Word 1 of the returned string will be 'Error:' in the unlikely
+--  event of an error, followed by a description of the error.
+--  Note: returns the Win16 answer (see below).
+S mWin32WindowsDirectory
+--  Returns full path to Windows directory (including trailing '\').
+--  Should be the same answer as mWindowsDirectory for all current
+--  Windows versions, but this may change in future Win versions.
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+S mSystemDirectory
+--  Returns full path to System directory (including trailing '\').
+--  Useful for building full path names for use with mFileVersion.
+--  Word 1 of the returned string will be 'Error:' in the unlikely
+--  event of an error, followed by a description of the error.
+--  Note: returns the Win16 answer (see below).
+S mWin32SystemDirectory
+--  Returns full path to System directory (including trailing '\').
+--  Under Windows NT, this is a different answer than mSystemDirectory.
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+S mDOSVersion
+--  Returns the DOS version reported to 16-bit apps. No Win32 equivalent.
+S mWindowsVersion
+--  Returns the Windows version reported to 16-bit apps. This is
+--  not the same answer as mWin32Version under Windows 95.
+S mWin32Version
+--  Returns the Win32 version (a different answer than mWindowsVersion)
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+--  Note the lack of ability to check for Win32-specific DOS version.
+S mWin32Platform
+--  Returns the Win32 platform ('Win32s on Windows 3.1',
+--  'Win32 on Windows 95', or 'Windows NT').
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+S mWin32Build
+--  Returns the Win32 build. This is useful because Director requires
+--  at least Windows NT v3.51 with Service Pack 4 applied (build 1057).
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+S mWinNTVersion
+--  Tells you what verison of Windows NT you're running under-- 'Workstation',
+--  'Server', 'Advanced Server', 'Unknown', or 'Error' is there's a problem.
+--  Note: requires ASK32.EXE and VERS32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+SS mGetShortFileName, theFile
+--  Returns the MS-DOS style filename of a Windows 95 or Windows NT long
+--  file name which might contain spaces or other DOS-illegal characters.
+--  This method can also accept file names that are already DOS-legal.
+--  This method is helpful when an XObject only works with DOS filenames.
+--  Note: requires ASK32.EXE and FNAME32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+SS mGetLongFileName, theFile
+--  Returns the Windows 95 or Windows NT long file name, which might contain
+--  spaces or other DOS-illegal characters, given a DOS short file name.
+--  This method can also accept file names that are already long.
+--  Note: requires ASK32.EXE and FNAME32.DLL in the same directory as this
+--  XObject .DLL (these files are distributed with this XObject).
+--  Returns EMPTY if 32-bit environment is unavailable, or ASK32.EXE
+--  can't load; Returns string with word 1 'Error:' if ASK32.EXE fails.
+-- 
+ */
+
+namespace Director {
+
+const char *VersionsXObj::xlibName = "Versions";
+const XlibFileDesc VersionsXObj::fileNames[] = {
+	{ "VERSIONS",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				VersionsXObj::m_new,		 0, 0,	400 },
+	{ "dispose",				VersionsXObj::m_dispose,		 0, 0,	400 },
+	{ "quickTimeVersion",				VersionsXObj::m_quickTimeVersion,		 0, 0,	400 },
+	{ "win32QuickTimeVersion",				VersionsXObj::m_win32QuickTimeVersion,		 0, 0,	400 },
+	{ "fileVersion",				VersionsXObj::m_fileVersion,		 1, 1,	400 },
+	{ "windowsDirectory",				VersionsXObj::m_windowsDirectory,		 0, 0,	400 },
+	{ "win32WindowsDirectory",				VersionsXObj::m_win32WindowsDirectory,		 0, 0,	400 },
+	{ "systemDirectory",				VersionsXObj::m_systemDirectory,		 0, 0,	400 },
+	{ "win32SystemDirectory",				VersionsXObj::m_win32SystemDirectory,		 0, 0,	400 },
+	{ "dOSVersion",				VersionsXObj::m_dOSVersion,		 0, 0,	400 },
+	{ "windowsVersion",				VersionsXObj::m_windowsVersion,		 0, 0,	400 },
+	{ "win32Version",				VersionsXObj::m_win32Version,		 0, 0,	400 },
+	{ "win32Platform",				VersionsXObj::m_win32Platform,		 0, 0,	400 },
+	{ "win32Build",				VersionsXObj::m_win32Build,		 0, 0,	400 },
+	{ "winNTVersion",				VersionsXObj::m_winNTVersion,		 0, 0,	400 },
+	{ "getShortFileName",				VersionsXObj::m_getShortFileName,		 1, 1,	400 },
+	{ "getLongFileName",				VersionsXObj::m_getLongFileName,		 1, 1,	400 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+VersionsXObject::VersionsXObject(ObjectType ObjectType) :Object<VersionsXObject>("Versions") {
+	_objType = ObjectType;
+}
+
+void VersionsXObj::open(ObjectType type, const Common::Path &path) {
+    VersionsXObject::initMethods(xlibMethods);
+    VersionsXObject *xobj = new VersionsXObject(type);
+    if (type == kXtraObj)
+        g_lingo->_openXtras.push_back(xlibName);
+    g_lingo->exposeXObject(xlibName, xobj);
+    g_lingo->initBuiltIns(xlibBuiltins);
+}
+
+void VersionsXObj::close(ObjectType type) {
+    VersionsXObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void VersionsXObj::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("VersionsXObj::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUBNR(VersionsXObj::m_dispose)
+XOBJSTUB(VersionsXObj::m_quickTimeVersion, "000003.000000.000000.000000")
+XOBJSTUB(VersionsXObj::m_win32QuickTimeVersion, "000003.000000.000000.000000")
+XOBJSTUB(VersionsXObj::m_fileVersion, "000003.000000.000000.000000")
+XOBJSTUB(VersionsXObj::m_windowsDirectory, "")
+XOBJSTUB(VersionsXObj::m_win32WindowsDirectory, "")
+XOBJSTUB(VersionsXObj::m_systemDirectory, "")
+XOBJSTUB(VersionsXObj::m_win32SystemDirectory, "")
+XOBJSTUB(VersionsXObj::m_dOSVersion, "")
+XOBJSTUB(VersionsXObj::m_windowsVersion, "")
+XOBJSTUB(VersionsXObj::m_win32Version, "")
+XOBJSTUB(VersionsXObj::m_win32Platform, "")
+XOBJSTUB(VersionsXObj::m_win32Build, "")
+XOBJSTUB(VersionsXObj::m_winNTVersion, "")
+XOBJSTUB(VersionsXObj::m_getShortFileName, "")
+XOBJSTUB(VersionsXObj::m_getLongFileName, "")
+
+}
diff --git a/engines/director/lingo/xlibs/versions.h b/engines/director/lingo/xlibs/versions.h
new file mode 100644
index 00000000000..6cb72995ea7
--- /dev/null
+++ b/engines/director/lingo/xlibs/versions.h
@@ -0,0 +1,62 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_LINGO_XLIBS_VERSIONS_H
+#define DIRECTOR_LINGO_XLIBS_VERSIONS_H
+
+namespace Director {
+
+class VersionsXObject : public Object<VersionsXObject> {
+public:
+	VersionsXObject(ObjectType objType);
+};
+
+namespace VersionsXObj {
+
+extern const char *xlibName;
+extern const XlibFileDesc fileNames[];
+
+void open(ObjectType type, const Common::Path &path);
+void close(ObjectType type);
+
+void m_new(int nargs);
+void m_dispose(int nargs);
+void m_quickTimeVersion(int nargs);
+void m_win32QuickTimeVersion(int nargs);
+void m_fileVersion(int nargs);
+void m_windowsDirectory(int nargs);
+void m_win32WindowsDirectory(int nargs);
+void m_systemDirectory(int nargs);
+void m_win32SystemDirectory(int nargs);
+void m_dOSVersion(int nargs);
+void m_windowsVersion(int nargs);
+void m_win32Version(int nargs);
+void m_win32Platform(int nargs);
+void m_win32Build(int nargs);
+void m_winNTVersion(int nargs);
+void m_getShortFileName(int nargs);
+void m_getLongFileName(int nargs);
+
+} // End of namespace VersionsXObj
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xtras/oscheck.cpp b/engines/director/lingo/xtras/oscheck.cpp
new file mode 100644
index 00000000000..0a95b420cad
--- /dev/null
+++ b/engines/director/lingo/xtras/oscheck.cpp
@@ -0,0 +1,101 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xtras/oscheck.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * sinkha
+ *
+ **************************************************/
+
+/*
+-- xtra osCheck
+new object me
+-- Template handlers --
+* chos -- returns true if Japan OS
+
+ */
+
+namespace Director {
+
+const char *OSCheckXtra::xlibName = "OSCheck";
+const XlibFileDesc OSCheckXtra::fileNames[] = {
+	{ "oscheck",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				OSCheckXtra::m_new,		 0, 0,	400 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "chos", OSCheckXtra::m_chos, 0, 0, 400, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+OSCheckXtraObject::OSCheckXtraObject(ObjectType ObjectType) :Object<OSCheckXtraObject>("OSCheck") {
+	_objType = ObjectType;
+}
+
+bool OSCheckXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum OSCheckXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(OSCheckXtra::xlibName);
+	warning("OSCheckXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void OSCheckXtra::open(ObjectType type, const Common::Path &path) {
+    OSCheckXtraObject::initMethods(xlibMethods);
+    OSCheckXtraObject *xobj = new OSCheckXtraObject(type);
+    if (type == kXtraObj)
+        g_lingo->_openXtras.push_back(xlibName);
+    g_lingo->exposeXObject(xlibName, xobj);
+    g_lingo->initBuiltIns(xlibBuiltins);
+}
+
+void OSCheckXtra::close(ObjectType type) {
+    OSCheckXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void OSCheckXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("OSCheckXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(OSCheckXtra::m_chos, 0)
+
+}
diff --git a/engines/director/lingo/xtras/oscheck.h b/engines/director/lingo/xtras/oscheck.h
new file mode 100644
index 00000000000..049ec88da22
--- /dev/null
+++ b/engines/director/lingo/xtras/oscheck.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_LINGO_XTRAS_OSCHECK_H
+#define DIRECTOR_LINGO_XTRAS_OSCHECK_H
+
+namespace Director {
+
+class OSCheckXtraObject : public Object<OSCheckXtraObject> {
+public:
+	OSCheckXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace OSCheckXtra {
+
+extern const char *xlibName;
+extern const XlibFileDesc fileNames[];
+
+void open(ObjectType type, const Common::Path &path);
+void close(ObjectType type);
+
+void m_new(int nargs);
+void m_chos(int nargs);
+
+} // End of namespace OSCheckXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index eb740dcef1a..b6454071e40 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -157,6 +157,7 @@ MODULE_OBJS = \
 	lingo/xlibs/tengu.o \
 	lingo/xlibs/unittest.o \
 	lingo/xlibs/valkyrie.o \
+	lingo/xlibs/versions.o \
 	lingo/xlibs/videodiscxobj.o \
 	lingo/xlibs/vmisonxfcn.o \
 	lingo/xlibs/vmpresent.o \
@@ -178,6 +179,7 @@ MODULE_OBJS = \
 	lingo/xtras/keypoll.o \
 	lingo/xtras/masterapp.o \
 	lingo/xtras/openurl.o \
+	lingo/xtras/oscheck.o \
 	lingo/xtras/qtvrxtra.o \
 	lingo/xtras/rtk.o \
 	lingo/xtras/scrnutil.o \


Commit: 37b60467a352c38312500b1c57ecce43bbb6173f
    https://github.com/scummvm/scummvm/commit/37b60467a352c38312500b1c57ecce43bbb6173f
Author: Scott Percival (code at moral.net.au)
Date: 2025-09-25T21:50:06+02:00

Commit Message:
DIRECTOR: LINGO: Don't use global store for b_xtra

Fixes crash on save screen of GADGET: Past as Future.

Changed paths:
    devtools/director-generate-xobj-stub.py
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo.h
    engines/director/lingo/xlibs/fileio.cpp
    engines/director/lingo/xtras/directsound.cpp
    engines/director/lingo/xtras/filextra.cpp
    engines/director/lingo/xtras/keypoll.cpp
    engines/director/lingo/xtras/masterapp.cpp
    engines/director/lingo/xtras/openurl.cpp
    engines/director/lingo/xtras/oscheck.cpp
    engines/director/lingo/xtras/qtvrxtra.cpp
    engines/director/lingo/xtras/rtk.cpp
    engines/director/lingo/xtras/scrnutil.cpp
    engines/director/lingo/xtras/timextra.cpp
    engines/director/lingo/xtras/xsound.cpp
    engines/director/score.cpp


diff --git a/devtools/director-generate-xobj-stub.py b/devtools/director-generate-xobj-stub.py
index 9fd897b0549..6331377c1dd 100755
--- a/devtools/director-generate-xobj-stub.py
+++ b/devtools/director-generate-xobj-stub.py
@@ -137,8 +137,10 @@ static BuiltinProto xlibBuiltins[] = {{
 void {xobj_class}::open(ObjectType type, const Common::Path &path) {{
     {xobject_class}::initMethods(xlibMethods);
     {xobject_class} *xobj = new {xobject_class}(type);
-    if (type == kXtraObj)
+    if (type == kXtraObj) {
         g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }}
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index b8bf4094140..2728e7d3abd 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1670,16 +1670,16 @@ void LB::b_xtra(int nargs) {
 	Datum d = g_lingo->pop();
 	if (d.type == INT) {
 		int i = d.asInt() -1; // Lingo index for XTRAs start at 1
-		if (i >=0 && (uint)i < g_lingo->_openXtras.size()) {
-			Datum var = g_lingo->_globalvars[g_lingo->_openXtras[i]];
+		if (i >=0 && (uint)i < g_lingo->_openXtraObjects.size()) {
+			Datum var = g_lingo->_openXtraObjects[i];
 			g_lingo->push(var);
 			return;
 		}
 	} else {
 		Common::String name = d.asString();
-		if (g_lingo->_globalvars.contains(name)) {
-			Datum var = g_lingo->_globalvars[name];
-			if (var.type == OBJECT && var.u.obj->getObjType() == kXtraObj) {
+		for (int i = 0; i < g_lingo->_openXtras.size(); i++) {
+			if (name.equalsIgnoreCase(g_lingo->_openXtras[i])) {
+				Datum var = g_lingo->_openXtraObjects[i];
 				g_lingo->push(var);
 				return;
 			}
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 071a6e9ddfd..9c6b471ca11 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -728,7 +728,7 @@ Datum Score::createScriptInstance(BehaviorElement *behavior) {
 	Datum inst = g_lingo->pop();
 
 	if (inst.type != OBJECT) {
-		warning("Score::createScriptInstances(): Could not instantiate behavior %s", behavior->toString().c_str());
+		warning("Score::createScriptInstance(): Could not instantiate behavior %s", behavior->toString().c_str());
 		return Datum();
 	}
 
@@ -748,7 +748,7 @@ Datum Score::createScriptInstance(BehaviorElement *behavior) {
 	}
 
 	if (g_lingo->_state->stack.size() == 0) {
-		warning("Score::createScriptInstances(): Could not evaluate initializer params '%s' for behavior %s",
+		warning("Score::createScriptInstance(): Could not evaluate initializer params '%s' for behavior %s",
 			behavior->initializerParams.c_str(), behavior->toString().c_str());
 		return inst;
 	}
@@ -756,7 +756,7 @@ Datum Score::createScriptInstance(BehaviorElement *behavior) {
 	Datum proplist = _lingo->pop();
 
 	if (proplist.type != PARRAY) {
-		warning("Score::createScriptInstances(): Could not evaluate initializer params '%s' for behavior %s",
+		warning("Score::createScriptInstance(): Could not evaluate initializer params '%s' for behavior %s",
 			behavior->initializerParams.c_str(), behavior->toString().c_str());
 		return inst;
 	}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 815eda30e53..f702e93fdba 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -536,6 +536,7 @@ public:
 	OpenXLibsHash _openXLibs;
 	OpenXLibsStateHash _openXLibsState;
 	Common::StringArray _openXtras;
+	Common::Array<Datum> _openXtraObjects;
 	OpenXLibsStateHash _openXtrasState;
 
 	Common::String _floatPrecisionFormat;
diff --git a/engines/director/lingo/xlibs/fileio.cpp b/engines/director/lingo/xlibs/fileio.cpp
index 9d74c0341f0..6223a0e0106 100644
--- a/engines/director/lingo/xlibs/fileio.cpp
+++ b/engines/director/lingo/xlibs/fileio.cpp
@@ -195,8 +195,10 @@ void FileIO::open(ObjectType type, const Common::Path &path) {
 		type = kXObj;
 	}
 	FileObject *xobj = new FileObject(type);
-	if (type == kXtraObj)
+	if (type == kXtraObj) {
 		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
 	g_lingo->exposeXObject(xlibName, xobj);
 	g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/directsound.cpp b/engines/director/lingo/xtras/directsound.cpp
index ab4ee81d59e..0d379e5cea4 100644
--- a/engines/director/lingo/xtras/directsound.cpp
+++ b/engines/director/lingo/xtras/directsound.cpp
@@ -176,8 +176,10 @@ Datum DirectsoundXtraObject::getProp(const Common::String &propName) {
 void DirectsoundXtra::open(ObjectType type, const Common::Path &path) {
 	DirectsoundXtraObject::initMethods(xlibMethods);
 	DirectsoundXtraObject *xobj = new DirectsoundXtraObject(type);
-	if (type == kXtraObj)
+	if (type == kXtraObj) {
 		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
 	g_lingo->exposeXObject(xlibName, xobj);
 	g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/filextra.cpp b/engines/director/lingo/xtras/filextra.cpp
index 2850d81d55f..7ce285b208c 100644
--- a/engines/director/lingo/xtras/filextra.cpp
+++ b/engines/director/lingo/xtras/filextra.cpp
@@ -122,8 +122,10 @@ Datum FileXtraObject::getProp(const Common::String &propName) {
 void FileXtra::open(ObjectType type, const Common::Path &path) {
     FileXtraObject::initMethods(xlibMethods);
     FileXtraObject *xobj = new FileXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/keypoll.cpp b/engines/director/lingo/xtras/keypoll.cpp
index b9c21a9ecc8..7158d3e34e9 100644
--- a/engines/director/lingo/xtras/keypoll.cpp
+++ b/engines/director/lingo/xtras/keypoll.cpp
@@ -88,8 +88,10 @@ Datum KeypollXtraObject::getProp(const Common::String &propName) {
 void KeypollXtra::open(ObjectType type, const Common::Path &path) {
     KeypollXtraObject::initMethods(xlibMethods);
     KeypollXtraObject *xobj = new KeypollXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/masterapp.cpp b/engines/director/lingo/xtras/masterapp.cpp
index b915a53cb24..22f1f9e34f8 100644
--- a/engines/director/lingo/xtras/masterapp.cpp
+++ b/engines/director/lingo/xtras/masterapp.cpp
@@ -544,8 +544,10 @@ Datum MasterAppXtraObject::getProp(const Common::String &propName) {
 void MasterAppXtra::open(ObjectType type, const Common::Path &path) {
     MasterAppXtraObject::initMethods(xlibMethods);
     MasterAppXtraObject *xobj = new MasterAppXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/openurl.cpp b/engines/director/lingo/xtras/openurl.cpp
index 16275b2dec6..003e5818d24 100644
--- a/engines/director/lingo/xtras/openurl.cpp
+++ b/engines/director/lingo/xtras/openurl.cpp
@@ -84,8 +84,10 @@ Datum OpenURLXtraObject::getProp(const Common::String &propName) {
 void OpenURLXtra::open(ObjectType type, const Common::Path &path) {
     OpenURLXtraObject::initMethods(xlibMethods);
     OpenURLXtraObject *xobj = new OpenURLXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/oscheck.cpp b/engines/director/lingo/xtras/oscheck.cpp
index 0a95b420cad..918046e9ee7 100644
--- a/engines/director/lingo/xtras/oscheck.cpp
+++ b/engines/director/lingo/xtras/oscheck.cpp
@@ -78,8 +78,10 @@ Datum OSCheckXtraObject::getProp(const Common::String &propName) {
 void OSCheckXtra::open(ObjectType type, const Common::Path &path) {
     OSCheckXtraObject::initMethods(xlibMethods);
     OSCheckXtraObject *xobj = new OSCheckXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/qtvrxtra.cpp b/engines/director/lingo/xtras/qtvrxtra.cpp
index 6ac854d4652..d2281dcfcd8 100644
--- a/engines/director/lingo/xtras/qtvrxtra.cpp
+++ b/engines/director/lingo/xtras/qtvrxtra.cpp
@@ -269,8 +269,10 @@ Datum QtvrxtraXtraObject::getProp(const Common::String &propName) {
 void QtvrxtraXtra::open(ObjectType type, const Common::Path &path) {
     QtvrxtraXtraObject::initMethods(xlibMethods);
     QtvrxtraXtraObject *xobj = new QtvrxtraXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/rtk.cpp b/engines/director/lingo/xtras/rtk.cpp
index bcb1714af88..96e946d1a85 100644
--- a/engines/director/lingo/xtras/rtk.cpp
+++ b/engines/director/lingo/xtras/rtk.cpp
@@ -140,8 +140,10 @@ Datum RolloverToolkitXtraObject::getProp(const Common::String &propName) {
 void RolloverToolkitXtra::open(ObjectType type, const Common::Path &path) {
 	RolloverToolkitXtraObject::initMethods(xlibMethods);
 	RolloverToolkitXtraObject *xobj = new RolloverToolkitXtraObject(type);
-	if (type == kXtraObj)
+	if (type == kXtraObj) {
 		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
 	g_lingo->exposeXObject(xlibName, xobj);
 	g_lingo->initBuiltIns(xlibBuiltins);
 	if (!g_lingo->_openXtrasState.contains("Rollover_Toolkit")) {
diff --git a/engines/director/lingo/xtras/scrnutil.cpp b/engines/director/lingo/xtras/scrnutil.cpp
index eb4cebe43d4..89c8140053f 100644
--- a/engines/director/lingo/xtras/scrnutil.cpp
+++ b/engines/director/lingo/xtras/scrnutil.cpp
@@ -71,6 +71,10 @@ ScrnUtilXtraObject::ScrnUtilXtraObject(ObjectType ObjectType) :Object<ScrnUtilXt
 void ScrnUtilXtra::open(ObjectType type, const Common::Path &path) {
     ScrnUtilXtraObject::initMethods(xlibMethods);
     ScrnUtilXtraObject *xobj = new ScrnUtilXtraObject(type);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/timextra.cpp b/engines/director/lingo/xtras/timextra.cpp
index 9dc84df482c..65681d06952 100644
--- a/engines/director/lingo/xtras/timextra.cpp
+++ b/engines/director/lingo/xtras/timextra.cpp
@@ -89,8 +89,10 @@ Datum TimextraXtraObject::getProp(const Common::String &propName) {
 void TimextraXtra::open(ObjectType type, const Common::Path &path) {
     TimextraXtraObject::initMethods(xlibMethods);
     TimextraXtraObject *xobj = new TimextraXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/lingo/xtras/xsound.cpp b/engines/director/lingo/xtras/xsound.cpp
index ef232f5fd56..8076c8ecdd4 100644
--- a/engines/director/lingo/xtras/xsound.cpp
+++ b/engines/director/lingo/xtras/xsound.cpp
@@ -143,8 +143,10 @@ Datum XsoundXtraObject::getProp(const Common::String &propName) {
 void XsoundXtra::open(ObjectType type, const Common::Path &path) {
     XsoundXtraObject::initMethods(xlibMethods);
     XsoundXtraObject *xobj = new XsoundXtraObject(type);
-    if (type == kXtraObj)
-        g_lingo->_openXtras.push_back(xlibName);
+	if (type == kXtraObj) {
+		g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
     g_lingo->exposeXObject(xlibName, xobj);
     g_lingo->initBuiltIns(xlibBuiltins);
 }
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index e2248eaa1b3..bbab19f11f8 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -2301,7 +2301,7 @@ Common::String Score::formatChannelInfo() {
 		Sprite &sprite = *channel._sprite;
 		Common::Point position = channel.getPosition();
 		if (sprite._castId.member) {
-			result += Common::String::format("CH: %-3d castId: %s, visible: %d, [inkData: 0x%02x [ink: %d, trails: %d, stretch: %d, line: %d], %dx%d@%d,%d type: %d (%s) fg: %d bg: %d], script: %s, colorcode: 0x%x, blendAmount: 0x%x, unk3: 0x%x, constraint: %d, puppet: %d, moveable: %d, movieRate: %f, movieTime: %d (%f), filmLoopFrame: %d\n",
+			result += Common::String::format("CH: %-3d castId: %s, visible: %d, [inkData: 0x%02x [ink: %d, trails: %d, stretch: %d, line: %d], %dx%d@%d,%d type: %d (%s) fg: %08x bg: %08x], script: %s, colorcode: 0x%x, blendAmount: 0x%x, unk3: 0x%x, constraint: %d, puppet: %d, moveable: %d, movieRate: %f, movieTime: %d (%f), filmLoopFrame: %d\n",
 				i + 1, sprite._castId.asString().c_str(), channel._visible, sprite._inkData,
 				sprite._ink, sprite._trails, sprite._stretch, sprite._thickness,
 				channel.getWidth(), channel.getHeight(), position.x, position.y,


Commit: 81307127ba4ca32991688133b5aaefaf2d2c8588
    https://github.com/scummvm/scummvm/commit/81307127ba4ca32991688133b5aaefaf2d2c8588
Author: Scott Percival (code at moral.net.au)
Date: 2025-09-25T21:50:06+02:00

Commit Message:
DIRECTOR: Fix several issues with sprite behaviors

Changed paths:
    engines/director/debugger.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/score.cpp


diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 96ecce2e850..6dca2360080 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -332,10 +332,10 @@ bool Debugger::cmdMovie(int argc, const char **argv) {
 bool Debugger::cmdChannels(int argc, const char **argv) {
 	Score *score = g_director->getCurrentMovie()->getScore();
 
-	int maxSize = MIN<int>(score->_maxChannelsUsed + 3, score->_scoreCache[0]->_sprites.size());
 	int frameId = score->getCurrentFrameNum();
+	int maxFrames = score->getFramesNum();
 	if (argc == 1) {
-		debugPrintf("Channel info for current frame %d of %d\n", frameId, maxSize);
+		debugPrintf("Channel info for current frame %d of %d\n", frameId, maxFrames);
 		debugPrintf("%s\n", score->formatChannelInfo().c_str());
 		return true;
 	}
@@ -343,8 +343,8 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
 	if (argc == 2)
 		frameId = atoi(argv[1]);
 
-	if (frameId >= 1 && frameId <= maxSize) {
-		debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
+	if (frameId >= 1 && frameId <= maxFrames) {
+		debugPrintf("Channel info for frame %d of %d\n", frameId, maxFrames);
 		Frame *frame = score->_scoreCache[frameId - 1];
 		if (frame) {
 			debugPrintf("%s\n", frame->formatChannelInfo().c_str());
@@ -352,7 +352,7 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
 			debugPrintf("  not found\n");
 		}
 	} else {
-		debugPrintf("Must specify a frame number between 1 and %d.\n", maxSize);
+		debugPrintf("Must specify a frame number between 1 and %d.\n", maxFrames);
 	}
 	return true;
 }
@@ -493,8 +493,24 @@ bool Debugger::cmdFuncs(int argc, const char **argv) {
 			}
 		}
 	}
+	if (g_director->getVersion() >= 600) {
+		debugPrintf("Sprite behaviors:\n");
+		for (int i = 0; i < (int)score->_scoreCache.size(); i++) {
+			Frame *frame = score->_scoreCache[i];
+			if (frame) {
+				for (int j = 0; j < (int)frame->_sprites.size(); j++) {
+					Sprite *sprite = frame->_sprites[j];
+					if (!sprite->_behaviors.empty()) {
+						debugPrintf("  %d, sprite %d:\n", i + 1, j);
+						for (auto &it : sprite->_behaviors) {
+							debugPrintf("    %s\n", it.toString().c_str());
+						}
+					}
+				}
+			}
+		}
 
-
+	}
 	return true;
 }
 
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 9c6b471ca11..3b0db000c95 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -657,8 +657,8 @@ bool Lingo::processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int
 
 
 	if (g_director->getVersion() >= 600 && st == kScoreScript && obj) {
-		push(Datum(obj));
 		if (obj->getMethod(_eventHandlerTypes[event]).type != VOIDSYM) {
+			push(Datum(obj));
 			LC::call(_eventHandlerTypes[event], 1, false);
 			return execute();
 		} else {
@@ -712,7 +712,7 @@ void Score::killScriptInstances(int frameNum) {
 
 		if (frameNum < channel->_startFrame || frameNum > channel->_endFrame) {
 			channel->_scriptInstanceList.clear();
-
+			channel->_sprite->_behaviors.clear();
 			debugC(1, kDebugLingoExec, "Score::killScriptInstances(): Killed script instances for channel %d. frame %d [%d-%d]",
 					i + 1, frameNum, channel->_startFrame, channel->_endFrame);
 
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index bbab19f11f8..8b4c3e07400 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1947,10 +1947,10 @@ void Score::loadFrameSpriteDetails(bool skipLog) {
 	Common::MemoryReadStreamEndian *stream = nullptr;
 	for (uint i = 0; i < _currentFrame->_sprites.size(); i++) {
 		Sprite *sprite = _currentFrame->_sprites[i];
+		sprite->_behaviors.clear();
 		if (sprite->_spriteListIdx) {
 			if (!skipLog)
 				debugC(2, kDebugLoading, "Sprite %d", i);
-
 			sprite->_spriteInfo = loadSpriteInfo(sprite->_spriteListIdx, skipLog);
 
 			stream = getSpriteDetailsStream(sprite->_spriteListIdx + 1);
@@ -1966,6 +1966,7 @@ void Score::loadFrameSpriteDetails(bool skipLog) {
 	}
 
 	// Script channel
+	_currentFrame->_mainChannels.behaviors.clear();
 	if (_currentFrame->_mainChannels.scriptSpriteListIdx) {
 		if (!skipLog)
 			debugC(2, kDebugLoading, "Script channel");
@@ -2308,6 +2309,13 @@ Common::String Score::formatChannelInfo() {
 				sprite._spriteType, spriteType2str(sprite._spriteType), sprite._foreColor, sprite._backColor,
 				sprite._scriptId.asString().c_str(), sprite._colorcode, sprite._blendAmount, sprite._unk3,
 				channel._constraint, sprite._puppet, sprite._moveable, channel._movieRate, channel._movieTime, (float)(channel._movieTime/60.0f), channel._filmLoopFrame);
+			if (!sprite._behaviors.empty()) {
+				result += Common::String::format("        behaviours: ");
+				for (auto &it : sprite._behaviors) {
+					result += Common::String::format("(%s), ", it.toString().c_str());
+				}
+				result += Common::String::format("\n");
+			}
 		} else {
 			result += Common::String::format("CH: %-3d castId: 000\n", i + 1);
 		}


Commit: b5a1fad1711143243ed5d863c5f400af8e87555d
    https://github.com/scummvm/scummvm/commit/b5a1fad1711143243ed5d863c5f400af8e87555d
Author: Scott Percival (code at moral.net.au)
Date: 2025-09-25T21:50:06+02:00

Commit Message:
DIRECTOR: Move video palette hack into quirk

Changed paths:
    engines/director/castmember/digitalvideo.cpp
    engines/director/director.cpp
    engines/director/director.h
    engines/director/game-quirks.cpp


diff --git a/engines/director/castmember/digitalvideo.cpp b/engines/director/castmember/digitalvideo.cpp
index 5d99eb48c3b..a725756d760 100644
--- a/engines/director/castmember/digitalvideo.cpp
+++ b/engines/director/castmember/digitalvideo.cpp
@@ -264,6 +264,8 @@ bool DigitalVideoCastMember::loadVideo(Common::String path) {
 		} else {
 			_videoType = kDVVideoForWindows;
 		}
+	} else {
+		warning("DigitalVideoCastMember::loadVideo: Unknown file format for video '%s', skipping", path.c_str());
 	}
 
 	if (result && g_director->_pixelformat.bytesPerPixel == 1) {
@@ -274,7 +276,7 @@ bool DigitalVideoCastMember::loadVideo(Common::String path) {
 		// Generally you don't want these as part of the video, and Video for Windows
 		// seems to deliberately exclude them.
 		// Keep colour 0 and 255 as they are pure white and pure black, respectively.
-		if (g_director->getPlatform() == Common::kPlatformWindows) {
+		if (g_director->_vfwPaletteHack && g_director->getPlatform() == Common::kPlatformWindows) {
 			for (int i = 1; i < 8; i++) {
 				_ditheringPalette[i*3+0] = _ditheringPalette[0];
 				_ditheringPalette[i*3+1] = _ditheringPalette[1];
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 78abf8f4ac2..0d4e2796c5d 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -107,6 +107,7 @@ DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gam
 	_loadSlowdownFactor = 0;
 	_loadSlowdownCooldownTime = 0;
 	_fileIOType = 0;
+	_vfwPaletteHack = false;
 
 	_wm = nullptr;
 
diff --git a/engines/director/director.h b/engines/director/director.h
index 0f640bee7a2..26a6ac5ee04 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -303,6 +303,7 @@ public:
 	uint32 _loadSlowdownFactor;
 	uint32 _loadSlowdownCooldownTime;
 	int _fileIOType;
+	bool _vfwPaletteHack;
 
 private:
 	byte _currentPalette[768];
diff --git a/engines/director/game-quirks.cpp b/engines/director/game-quirks.cpp
index 70fc5d8657d..7d68bc2095f 100644
--- a/engines/director/game-quirks.cpp
+++ b/engines/director/game-quirks.cpp
@@ -22,6 +22,7 @@
 #include "common/compression/vise.h"
 #include "common/macresman.h"
 #include "common/memstream.h"
+#include "common/platform.h"
 #include "common/savefile.h"
 #include "director/director.h"
 
@@ -174,6 +175,10 @@ static void quirkForceFileIOXtra() {
 	g_director->_fileIOType = kXtraObj;
 }
 
+static void quirkVideoForWindowsPalette() {
+	g_director->_vfwPaletteHack = true;
+}
+
 static void quirkHollywoodHigh() {
 	// Hollywood High demo has a killswitch that stops playback
 	// if the year is after 1996.
@@ -301,6 +306,10 @@ const struct Quirk {
 	{ "ingenious", Common::kPlatformWindows, &quirkForceFileIOXObj },
 	{ "ingenious", Common::kPlatformMacintosh, &quirkForceFileIOXObj },
 
+	// McKenzie & Co. uses a greyscale palette in 8-bit mode, along with the standard 16 colour Windows palette.
+	// Remove the 16-colours from the video decoder.
+	{"mckenzie", Common::kPlatformWindows, &quirkVideoForWindowsPalette },
+
 	{ nullptr, Common::kPlatformUnknown, nullptr }
 };
 




More information about the Scummvm-git-logs mailing list