[Scummvm-git-logs] scummvm master -> 9e39b9aaa9f58dedf6205241e36616fde97ccb68

sev- noreply at scummvm.org
Sun Nov 2 00:13:02 UTC 2025


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

Summary:
75388f4177 DIRECTOR: Add detection entry for Charlton Heston's Votage Through the Bible
ce6d3ccf63 DIRECTOR: LINGO: Remove panic warning for a script ending successfully
bd162063b0 DIRECTOR: XTRA: Add xtras for ispyspooky
9323fab977 DIRECTOR: XTRA: Add Audio and Smacker
9e39b9aaa9 DIRECTOR: LINGO: Implement b_symbol


Commit: 75388f417727162cd73998339882d234bd5f4737
    https://github.com/scummvm/scummvm/commit/75388f417727162cd73998339882d234bd5f4737
Author: Scott Percival (code at moral.net.au)
Date: 2025-11-02T01:12:55+01:00

Commit Message:
DIRECTOR: Add detection entry for Charlton Heston's Votage Through the Bible

Changed paths:
    engines/director/detection_tables.h


diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index 66c1c3551f2..f79776b9b0a 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -666,6 +666,7 @@ static const PlainGameDescriptor directorGames[] = {
 	{ "gp2006",				"Grand Prix 2006 & Auto Directory" },
 	{ "guns",				"Multimedia Guns" },
 	{ "haight",				"Haight-Ashbury in the Sixties" },
+	{ "hestonbible",		"Charlton Heston's Voyage Through the Bible" },
 	{ "heuther",			"Understanding Pathophysiology, 3rd Edition" },
 	{ "hikaruhana",			"Shining Flower: Hikaruhana" },					// 光る花
 	{ "hirezaudio",			"Hi Rez Audio" },
@@ -4630,6 +4631,11 @@ static const DirectorGameDescription gameDescriptions[] = {
 
 	MACGAME1t_l("henachocotaizen", "", "LetterShop0.0", "b3fefa664154f160a32a7fdfcc83c047", 292680, Common::JA_JPN, 402),
 
+	WINGAME1f("hestonbible", "Old Testament", "OLDTEST.EXE", "t:56f332fa0190a21d697911887fad0ab5", 1003475, 404, GF_32BPP),
+	MACGAME1f("hestonbible", "Old Testament", "Bible Old Testament 1.0", "rt:49604f6c775663828a91b0999fe4f2aa", 483490, 404, GF_32BPP),
+	WINGAME1f("hestonbible", "New Testament", "ALPHA/NEWTEST.EXE", "t:7e7c9b3fe5aefe59ab930fb7ca47bd4a", 1319489, 404, GF_32BPP),
+	MACGAME1f("hestonbible", "New Testament", "ALPHA/New Testament 1.0", "rt:efeb87cee862bb7ef8ea21f4cbf46aa8", 483490, 404, GF_32BPP),
+
 	// Mac version is D3
 	WINGAME1t("hhouse", "",			"HHOUSE.EXE",  "b0486032820bc6a413dd836650f8b0c3", 3181345, 404),
 	WINDEMO1("hhouse", "1995 Demo", "HAUNTED.EXE", "5b7e970d8b8dec473e31cc6815c03bf6", 1166813, 404),


Commit: ce6d3ccf6351a0f17702a43ae363297061638d42
    https://github.com/scummvm/scummvm/commit/ce6d3ccf6351a0f17702a43ae363297061638d42
Author: Scott Percival (code at moral.net.au)
Date: 2025-11-02T01:12:55+01:00

Commit Message:
DIRECTOR: LINGO: Remove panic warning for a script ending successfully

Changed paths:
    engines/director/lingo/lingo.cpp


diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index f08175b21dd..76e66c49bb6 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -698,7 +698,7 @@ bool Lingo::execute(int targetFrame) {
 		_globalCounter++;
 		localCounter++;
 
-		if (_state->script == nullptr) {
+		if (!_abort && _state->script == nullptr) {
 			debugC(1, kDebugLingoExec, "Lingo::execute(): PANIC: No script to execute (2)");
 			break;
 		}


Commit: bd162063b0ebc167a40d903ce48ff34d72ba9d85
    https://github.com/scummvm/scummvm/commit/bd162063b0ebc167a40d903ce48ff34d72ba9d85
Author: Scott Percival (code at moral.net.au)
Date: 2025-11-02T01:12:55+01:00

Commit Message:
DIRECTOR: XTRA: Add xtras for ispyspooky

Changed paths:
  A engines/director/lingo/xtras/b/budapi.cpp
  A engines/director/lingo/xtras/b/budapi.h
  A engines/director/lingo/xtras/d/displayres.cpp
  A engines/director/lingo/xtras/d/displayres.h
  A engines/director/lingo/xtras/m/mui.cpp
  A engines/director/lingo/xtras/m/mui.h
  A engines/director/lingo/xtras/r/registryreader.cpp
  A engines/director/lingo/xtras/r/registryreader.h
    devtools/director-generate-xobj-stub.py
    engines/director/detection_tables.h
    engines/director/lingo/lingo-object.cpp
    engines/director/module.mk


diff --git a/devtools/director-generate-xobj-stub.py b/devtools/director-generate-xobj-stub.py
index 3c316aee5eb..54ee98335ec 100755
--- a/devtools/director-generate-xobj-stub.py
+++ b/devtools/director-generate-xobj-stub.py
@@ -122,6 +122,7 @@ const XlibFileDesc {xobj_class}::fileNames[] = {{
 
 static MethodProto xlibMethods[] = {{
 {xlib_methods}
+{xlib_toplevels}
 	{{ nullptr, nullptr, 0, 0, 0 }}
 }};
 
@@ -288,24 +289,25 @@ def read_uint32_be(data: bytes) -> int:
 def inject_makefile(slug: str, xcode_type: XCodeType) -> None:
     make_contents = open(MAKEFILE_PATH, "r").readlines()
     slug_alpha = slug[:1]
-    storage_path = f"lingo/xtras/{slug_alpha}" if xcode_type == "Xtra" else f"lingo/xlibs"
+    storage_path = f"lingo/xtras" if xcode_type == "Xtra" else f"lingo/xlibs"
     expr = re.compile(f"^\t{storage_path}/([a-zA-Z0-9\\-]+).o( \\\\|)")
+    obj = f"{slug_alpha}/{slug}"
     for i in range(len(make_contents)):
         m = expr.match(make_contents[i])
         if m:
             if slug == m.group(1):
                 # file already in makefile
-                print(f"{storage_path}/{slug}.o already in {MAKEFILE_PATH}, skipping")
+                print(f"{obj}.o already in {MAKEFILE_PATH}, skipping")
                 return
             elif slug < m.group(1):
-                make_contents.insert(i, f"\t{storage_path}/{slug}.o \\\n")
+                make_contents.insert(i, f"\t{storage_path}/{obj}.o \\\n")
                 with open(MAKEFILE_PATH, "w") as f:
                     f.writelines(make_contents)
                 return
             elif m.group(2) == "":
                 # final entry in the list
                 make_contents[i] += " \\"
-                make_contents.insert(i + 1, f"\t{storage_path}/{slug}.o\n")
+                make_contents.insert(i + 1, f"\t{storage_path}/{obj}.o\n")
                 with open(MAKEFILE_PATH, "w") as f:
                     f.writelines(make_contents)
                 return
@@ -315,9 +317,10 @@ def inject_lingo_object(slug: str, xobj_class: str, director_version: int, xcode
     # write include statement for the object header
     lo_contents = open(LINGO_OBJECT_PATH, "r").readlines()
     slug_alpha = slug[:1]
-    storage_path = f"director/lingo/xtras/{slug_alpha}" if xcode_type == "Xtra" else f"director/lingo/xlibs"
+    storage_path = f"director/lingo/xtras" if xcode_type == "Xtra" else f"director/lingo/xlibs"
     obj_type = "kXtraObj" if xcode_type == "Xtra" else "kXObj"
-    expr = re.compile(f'^#include "{storage_path}/([a-zA-Z0-9\\-]+)\\.h"')
+    header = f"{slug_alpha}/{slug}"
+    expr = re.compile(f'^#include "{storage_path}/([a-zA-Z0-9/\\-]+)\\.h"')
     in_xlibs = False
     for i in range(len(lo_contents)):
         m = expr.match(lo_contents[i])
@@ -325,17 +328,17 @@ def inject_lingo_object(slug: str, xobj_class: str, director_version: int, xcode
             in_xlibs = True
             if slug == m.group(1):
                 print(
-                    f"{storage_path}/{slug}.h import already in {LINGO_OBJECT_PATH}, skipping"
+                    f"{storage_path}/{header}.h import already in {LINGO_OBJECT_PATH}, skipping"
                 )
                 break
             elif slug < m.group(1):
-                lo_contents.insert(i, f'#include "{storage_path}/{slug}.h"\n')
+                lo_contents.insert(i, f'#include "{storage_path}/{header}.h"\n')
                 with open(LINGO_OBJECT_PATH, "w") as f:
                     f.writelines(lo_contents)
                 break
         elif in_xlibs:
             # final entry in the list
-            lo_contents.insert(i, f'#include "{storage_path}/{slug}.h"\n')
+            lo_contents.insert(i, f'#include "{storage_path}/{header}.h"\n')
             with open(LINGO_OBJECT_PATH, "w") as f:
                 f.writelines(lo_contents)
                 break
@@ -634,7 +637,7 @@ def extract_xcode_win32(file: BinaryIO, pe_offset: int) -> XCode:
                 methtable = data[start:end].decode('iso-8859-1').split('\n')
 
     if not methtable_found:
-        raise ValueError("Could not find msgTable!")
+        raise ValueError("Could not find msgTable! You may have to copy the Xtra into real Director, run \"put mMessageList(xtra(\"xtraName\"))\" in the message window, then copy the output to a text file.")
 
     for entry in methtable:
         print(entry)
@@ -764,10 +767,12 @@ def generate_xobject_stubs(
     xobject_class = f"{name}XObject"
     xobj_class = f"{name}XObj"
 
+    slug_alpha = slug[:1]
+
     cpp_text = TEMPLATE.format(
         base="xlibs",
         slug=slug,
-        slug_alpha=slug[:1],
+        slug_alpha=slug_alpha,
         name=name,
         filename=filename,
         xmethtable="\n".join(xmethtable),
@@ -800,7 +805,8 @@ def generate_xobject_stubs(
         print(cpp_text)
         print()
     else:
-        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.cpp"), "w") as cpp:
+        os.makedirs(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}"), exist_ok=True)
+        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}/{slug}.cpp"), "w") as cpp:
             cpp.write(cpp_text)
 
     header_text = TEMPLATE_H.format(
@@ -817,7 +823,8 @@ def generate_xobject_stubs(
         print(header_text)
         print()
     else:
-        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.h"), "w") as header:
+        os.makedirs(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}"), exist_ok=True)
+        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}/{slug}.h"), "w") as header:
             header.write(header_text)
 
     if not dry_run:
@@ -835,9 +842,10 @@ def generate_xcmd_stubs(
 ) -> None:
     xobj_class = f"{name}{type}"
     methtype = "CBLTIN" if type == "XCMD" else "HBLTIN"
+    slug_alpha = slug[:1]
     cpp_text = XCMD_TEMPLATE.format(
         slug=slug,
-        slug_alpha=slug[:1],
+        slug_alpha=slug_alpha,
         name=name,
         filename=filename,
         xobj_class=xobj_class,
@@ -858,7 +866,8 @@ def generate_xcmd_stubs(
         print(cpp_text)
         print()
     else:
-        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.cpp"), "w") as cpp:
+        os.makedirs(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}"), exist_ok=True)
+        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}/{slug}.cpp"), "w") as cpp:
             cpp.write(cpp_text)
 
     header_text = XCMD_TEMPLATE_H.format(
@@ -872,7 +881,8 @@ def generate_xcmd_stubs(
         print(header_text)
         print()
     else:
-        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug}.h"), "w") as header:
+        os.makedirs(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}"), exist_ok=True)
+        with open(os.path.join(LINGO_XLIBS_PATH, f"{slug_alpha}/{slug}.h"), "w") as header:
             header.write(header_text)
 
     if not dry_run:
@@ -910,9 +920,9 @@ def generate_xtra_stubs(
         if argv and argv[-1].strip() == "*":
             min_args = -1
             max_args = 0
-        elif functype == "method":
+        elif functype == "method" or functype == "toplevel":
             min_args -= 1
-            max_args = 0
+            max_args -= 1
 
         meths.append(
             dict(
@@ -952,13 +962,9 @@ def generate_xtra_stubs(
             director_version=director_version,
             methtype="HBLTIN",
         ) for x in meths if x["functype"] == "global"]),
-        xlib_toplevels="\n".join([BUILTIN_TEMPLATE.format(
-            name=x["methname"],
-            xobj_class=xobj_class,
-            min_args=x["min_args"],
-            max_args=x["max_args"],
-            director_version=director_version,
-            methtype="HBLTIN",
+        xlib_toplevels="\n".join([
+            XLIB_METHOD_TEMPLATE.format(
+                    xobj_class=xobj_class, director_version=director_version, **x
         ) for x in meths if x["functype"] == "toplevel"]),
         xtra_props=XTRA_PROPS_TEMPLATE.format(xobj_class=xobj_class,
                                               xobject_class=xobject_class),
@@ -976,6 +982,7 @@ def generate_xtra_stubs(
         print(cpp_text)
         print()
     else:
+        os.makedirs(os.path.join(LINGO_XTRAS_PATH, f"{slug_alpha}"), exist_ok=True)
         with open(os.path.join(LINGO_XTRAS_PATH, f"{slug_alpha}/{slug}.cpp"), "w") as cpp:
             cpp.write(cpp_text)
 
@@ -993,6 +1000,7 @@ def generate_xtra_stubs(
         print(header_text)
         print()
     else:
+        os.makedirs(os.path.join(LINGO_XTRAS_PATH, f"{slug_alpha}"), exist_ok=True)
         with open(os.path.join(LINGO_XTRAS_PATH, f"{slug_alpha}/{slug}.h"), "w") as header:
             header.write(header_text)
 
diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index f79776b9b0a..df9cc86b877 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -8612,6 +8612,9 @@ static const DirectorGameDescription gameDescriptions[] = {
 	WINGAME1_l("ispyschool", "", "Ikzie32.exe",				 "t:2af7f901e9fb93b4323d871067cd7ac5",  1989859, Common::NL_BEL, 600),
 	WINGAME1_l("ispyschool", "", "Ikzie32.exe",				 "t:2af7f901e9fb93b4323d871067cd7ac5",  1989785, Common::NL_NLD, 600),
 
+	MACGAME1("ispyspooky", "", "Play I Spy Spooky Mansion", "rt:66f2146acecb09b969c599d5ec854e5e", 115778, 602),
+	WINGAME1("ispyspooky", "", "_Spooky.exe", "t:b57f9500220d32301f83c6b20b02fb96", 1568954, 602),
+
 	MACGAME1("jmmg", "", "Just Me and My Grandpa", "66f1a7078033867061b05f3789c6e5de", 1032378, 602),
 	WINGAME1("jmmg", "", "JMMG.EXE", "t:9801c1217842b39b25e42584cf5f8548", 1704089, 600),
 
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 5797fcaf1ae..597f9da21cd 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -144,13 +144,18 @@
 #include "director/lingo/xlibs/x/xsoundxfcn.h"
 #include "director/lingo/xlibs/x/xwin.h"
 #include "director/lingo/xlibs/y/yasix.h"
+#include "director/lingo/xtras/b/budapi.h"
 #include "director/lingo/xtras/directsound.h"
+#include "director/lingo/xtras/d/displayres.h"
 #include "director/lingo/xtras/filextra.h"
 #include "director/lingo/xtras/keypoll.h"
 #include "director/lingo/xtras/masterapp.h"
+#include "director/lingo/xtras/m/mui.h"
+#include "director/lingo/xtras/m/mui.h"
 #include "director/lingo/xtras/openurl.h"
 #include "director/lingo/xtras/oscheck.h"
 #include "director/lingo/xtras/qtvrxtra.h"
+#include "director/lingo/xtras/r/registryreader.h"
 #include "director/lingo/xtras/rtk.h"
 #include "director/lingo/xtras/scrnutil.h"
 #include "director/lingo/xtras/timextra.h"
@@ -237,6 +242,7 @@ static const struct XLibProto {
 	XLIBDEF(BatQT,				kXObj,			400),	// D4
 	XLIBDEF(BIMXObj,			kXObj,			400),	// D4
 	XLIBDEF(BlitPictXObj,		kXObj,			400),	// D4
+	XLIBDEF(BudAPIXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(CDROMXObj,			kXObj,			200),	// D2
 	XLIBDEF(CloseBleedWindowXCMD,kXObj,			300),	// D3
 	XLIBDEF(ColorXObj,			kXObj,			400),	// D4
@@ -252,6 +258,7 @@ static const struct XLibProto {
 	XLIBDEF(DialogsXObj,		kXObj,			400),	// D4
 	XLIBDEF(DirUtilXObj,		kXObj,			400),	// D4
 	XLIBDEF(DirectsoundXtra,	kXtraObj,		500),	// D5
+	XLIBDEF(DisplayResXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(DrawXObj,			kXObj,			400),	// D4
 	XLIBDEF(Ednox,				kXObj,			300),	// D3
 	XLIBDEF(EventQXObj,			kXObj,			400),	// D4
@@ -302,6 +309,7 @@ static const struct XLibProto {
 	XLIBDEF(MovieIdxXObj,		kXObj,			400),	// D4
 	XLIBDEF(MovUtilsXObj,		kXObj,			400),	// D4
 	XLIBDEF(MSFile,             kXObj,          400),   // D4
+	XLIBDEF(MuiXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(MystIsleXObj,		kXObj,			400),	// D4
 	XLIBDEF(OSCheckXtra,		kXtraObj,		400),	// D4
 	XLIBDEF(OpenBleedWindowXCMD,kXObj,			300),	// D3
@@ -324,6 +332,7 @@ static const struct XLibProto {
 	XLIBDEF(Quicktime,			kXObj,			300),	// D3
 	XLIBDEF(RearWindowXObj,		kXObj,			400),	// D4
 	XLIBDEF(RegisterComponent,	kXObj,			400),	// D4
+	XLIBDEF(RegistryReaderXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(RemixXCMD,			kXObj,			300),	// D3
 	XLIBDEF(RolloverToolkitXtra,kXtraObj,		500),	// D5
 	XLIBDEF(ScrnUtilXtra,		kXtraObj,		500),	// D5
diff --git a/engines/director/lingo/xtras/b/budapi.cpp b/engines/director/lingo/xtras/b/budapi.cpp
new file mode 100644
index 00000000000..a6246d05d4c
--- /dev/null
+++ b/engines/director/lingo/xtras/b/budapi.cpp
@@ -0,0 +1,503 @@
+/* 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/b/budapi.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * I Spy Spooky Mansion
+ *
+ **************************************************/
+
+/*
+-- xtra BudAPI
+new object me
+
+-- Information Functions
+* baVersion string Type -- returns version information
+* baSysFolder string FolderType -- returns Windows special folders location
+* baCpuInfo string InfoType -- returns information about the processor installed
+* baDiskInfo string Disk, string InfoType -- returns information about Disk
+* baMemoryInfo string InfoType -- returns memory information
+* baFindApp string Extension -- finds application associated with Extension
+* baReadIni string Section, string Keyname, string Default, string IniFile -- reads ini file entry
+* baWriteIni string Section, string Keyname, string Default, string IniFile -- writes ini file entry
+* baFlushIni string IniFile -- flushes ini file to disk
+* baReadRegString string Keyname, string Value, string Default, string Branch -- returns text from the registry
+* baWriteRegString string Keyname, string Value, string NewData, string Branch -- writes a number into the registry
+* baReadRegNumber string Keyname, string Value, integer Default, string Branch -- returns a number from the registry
+* baWriteRegNumber string Keyname, string Value, integer NewData, string Branch  -- writes a number into the registry
+* baDeleteReg string Keyname, string Value, string Branch -- deletes Keyname/Value from registry
+* baRegKeyList string Keyname, string Branch -- returns list of keys in Keyname
+* baRegValueList string Keyname, string Branch -- returns list of values in Keyname
+* baSoundCard -- returns 1 if a sound card is installed
+* baFontInstalled string FontName, string FontStyle -- returns 1 if font is installed
+* baFontList string FontType -- returns list of installed FontType fonts
+* baFontStyleList string FontName -- returns list of available FontName styles
+* baCommandArgs -- returns the arguments the projector was started with
+* baPrevious integer Activate -- returns window handle of a previous instance of application
+* baScreenInfo string InfoType -- returns information about the screen
+
+
+-- System Functions
+* baDisableDiskErrors integer Disable -- disable/enable disk errors
+* baDisableKeys integer Disable, integer WinHandle -- disables key presses in window
+* baDisableMouse integer Disable, integer WinHandle -- disables/enables mouse clicks in window
+* baDisableSwitching integer Disable -- disables/enables task switching
+* baDisableScreenSaver integer Disable -- sets the screen saver on or off
+* baScreenSaverTime integer Time -- sets the screen saver time out
+* baSetScreenSaver string FileName -- sets FileName as the active screen saver
+* baSetWallpaper string FileName, integer Tile -- sets FileName as the desktop wallpaper
+* baSetPattern string Name, string Pattern -- sets Pattern as the desktop pattern
+* baSetDisplay integer Width, integer Height, integer Depth, string Mode, integer Force -- changes the screen display settings
+* baExitWindows string Option -- shuts down Windows
+* baRunProgram string FileName, string State, integer Wait -- runs external program
+* baWinHelp string Command, string FileName, string Data -- shows windows help file
+* baMsgBox string Message, string Caption, string Buttons, string Icon, integer DefaultButton -- shows message box
+* baHideTaskBar integer Hide -- returns whether TaskBar is showing
+* baSetCurrentDir string Dir -- sets the current directory to Dir
+* baCopyText string Text -- copies Text to the clipboard
+* baPasteText -- returns text from clipboard
+* baEncryptText string Text, string Key -- encrypt Text with Key
+* baDecryptText string Text, string Key -- decrypt Text with Key
+* baPlaceCursor integer X, integer Y -- positions the cursor
+* baRestrictCursor integer Left, integer Top, integer Right, integer Bottom -- restirct cursor
+* baFreeCursor -- allows cursor to move freely
+* baSetVolume string Type, integer Volume -- sets current volume for wave, cd, midi
+* baGetVolume string Type -- gets current volume for wave, cd, midi
+* baInstallFont string fontfile, string fontname -- installs the font
+* baKeyIsDown integer Key -- returns 1 if Key is down
+* baKeyBeenPressed integer Key -- returns 1 if Key has been pressed since the last call to baKeyBeenPressed
+* baSleep integer milliSecs -- sleeps for milliSecs
+* baCreatePMGroup string Group -- creates Program Manager / Start Menu group
+* baDeletePMGroup string Group -- deletes Program Manager / Start Menu group
+* baCreatePMIcon string Cmd, string Title, string Icon, integer IconNumber -- creates Program Manager / Start Menu icon
+* baDeletePMIcon string Icon -- deletes Program Manager / Start Menu icon
+* baPMGroupList -- returns list of Program Manager / Start Menu groups
+* baPMIconList string Group -- returns list of icons in Group
+* baPMSubGroupList string Group -- returns list of Start Menu groups in Group
+* baSystemTime string Format -- gets system date/time
+* baSetSystemTime string Format, string Time -- sets system date/time
+* baPrinterInfo string InfoType -- gets information about installed printers
+* baSetPrinter string InfoType, any Data -- sets printer settings
+* baRefreshDesktop integer Wait -- refreshed the desktop icons
+
+-- File Functions
+* baFileAge string FileName -- returns the age of the file
+* baFileExists string FileName -- returns 1 if file exists
+* baFolderExists string DirName -- returns 1 if directory exists
+* baCreateFolder string DirName -- creates directory
+* baDeleteFolder string DirName -- deletes dirname if empty
+* baRenameFile string FileName, string NewName -- renames filename to NewName
+* baDeleteFile string FileName -- deletes filename
+* baDeleteXFiles string DirName, string FileSpec -- deletes files matching FileSpec from DirName
+* baXDelete string DirName, string FileSpec -- deletes files matching FileSpec from DirName, including sub-directories
+* baFileDate string FileName, string dateformat, string timeformat -- returns date of file
+* baFileSize string FileName -- returns size of file in bytes, or -1 if FileName doesn't exist
+* baFileAttributes string FileName -- returns string of set attributes in FileName
+* baSetFileAttributes string FileName, string Attributes -- sets Attributes for FileName
+* baRecycleFile string Filename -- place filename in Recycle Bin
+* baCopyFile string SrcFile, string DestFile, string Overwrite -- copies SrcFile to DestFile
+* baCopyXFiles string SrcDir, string DestDir, string FileSpec, string Overwrite -- copies all FileSpec files in SrcDir to DestDir
+* baXCopy string SrcDir, string DestDir, string FileSpec, string Overwrite, integer MakeDirs -- copies all FileSpec files in SrcDir to DestDir, including sub-directories
+* baFileList string Folder, string Pattern -- returns list of files in Folder
+* baFolderList string Folder -- returns list of folders in Folder
+* baFindFirstFile string Dir, string FileSpec -- finds first file matching FileSpec in Src
+* baFindNextFile -- finds next file
+* baFindClose -- closes a FindFirst/FindNext loop
+* baGetFilename string Operation, string StartDir, string Filename, string Filter, integer Flags, string Instruction, integer NoChangeFolder, integer X, integer Y -- shows Open/save file dialog box
+* baGetFolder string StartDir, string Instruction, integer Flags, string Title, integer X, integer Y -- shows directory selector dialog
+* baFileVersion string FileName -- returns version of FileName
+* baEncryptFile string FileName, string Key -- encrypts FileName with Key
+* baFindDrive string StartDrive, string FileName -- finds drive containing FileName
+* baOpenFile string FileName, string State -- open FileName
+* baOpenURL string FileName, string State -- opens the URL
+* baPrintFile string FileName -- prints a file
+* baShell string Operation, string FileName, string Args, string WorkDir, string State -- executes a file
+* baShortFileName string FileName -- returns the DOS short name of FileName
+* baTempFileName string Prefix -- returns a temporary file name
+* baMakeShortcut string Filename, string Path, string Caption -- creates a Win95/NT shortcut
+* baMakeShortcutEx string File, string Folder, string Title, string Args, string WorkDir, string Icon, integer IconNumber, integer Hotkey, string State -- creates a Win95/NT Shortcut
+* baResolveShortcut string Linkname -- returns file that Linkname points to
+
+-- Window Functions
+* baWindowInfo integer WinHandle, string Info -- gets information about a window
+* baFindWindow string Classname, string caption -- finds a window
+* baActiveWindow -- returns the active window
+* baCloseWindow integer WinHandle -- closes window
+* baCloseApp integer WinHandle -- closes application owning window
+* baSetWindowState integer WinHandle, string State -- sets state of window
+* baActivateWindow integer WinHandle -- activates window
+* baSetWindowTitle integer WinHandle, string Title -- sets title of window
+* baMoveWindow integer WinHandle, integer x, integer y, integer width, integer height, integer activate -- moves/resizes WinHandle
+* baWindowToFront integer WinHandle -- brings window to front
+* baWindowToBack integer WinHandle -- sends window to back
+* baGetWindow integer WinHandle, string relation -- gets window related to WinHandle
+* baWaitTillActive integer WinHandle -- waits till window becomes the active one
+* baWaitForWindow integer WinHandle, string State, integer Ticks -- waits till window is State, for maximuum of Ticks (1 tick = 1/60th sec)
+* baNextActiveWindow integer secs -- returns the next active window apart from the Director/Authorware window, with a timeout of Ticks (1 tick = 1/60th sec)
+* baWindowExists integer WinHandle -- returns 1 if WinHandle is a valid window handle
+* baWindowList string Classname, string Caption, integer Match -- returns list of all matching windows
+* baChildWindowList integer ParentWnd, string Classname, string Caption, integer Match -- returns list of all matching child windows of ParentWnd
+* baWindowDepth integer WinHandle -- returns z-order depth of specified window
+* baSetWindowDepth integer WinHandle, integer Depth -- sets WinHandle to z-order Depth
+* baSendKeys string Keys -- send Keys to the active window
+* baSendMsg integer WinHandle, integer msg, integer wParam, integer lParam, integer wait -- sends msg to window
+* baAddSysItems integer WinHandle, integer SysMenu, integer MinBox, integer MaxBox  -- adds system items
+* baRemoveSysItems integer WinHandle, integer SysMenu, integer MinBox, integer MaxBox -- removes system items
+* baWinHandle -- returns the handle of the Director or Authorware window
+* baStageHandle -- returns the handle of the Director Stage window
+
+-- Buddy Functions
+* baAbout -- shows info about Buddy API
+* baRegister string UserName, integer Number -- enter your registration information
+* baSaveRegistration string UserName, integer UserName -- saves your registration information
+* baGetRegistration -- retrieves your registration information
+* baFunctions -- retrieves the number of functions you are licensed to use
+
+ */
+
+namespace Director {
+
+const char *BudAPIXtra::xlibName = "BudAPI";
+const XlibFileDesc BudAPIXtra::fileNames[] = {
+	{ "budapi",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				BudAPIXtra::m_new,		 0, 0,	500 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "baVersion", BudAPIXtra::m_baVersion, 1, 1, 500, HBLTIN },
+	{ "baSysFolder", BudAPIXtra::m_baSysFolder, 1, 1, 500, HBLTIN },
+	{ "baCpuInfo", BudAPIXtra::m_baCpuInfo, 1, 1, 500, HBLTIN },
+	{ "baDiskInfo", BudAPIXtra::m_baDiskInfo, 2, 2, 500, HBLTIN },
+	{ "baMemoryInfo", BudAPIXtra::m_baMemoryInfo, 1, 1, 500, HBLTIN },
+	{ "baFindApp", BudAPIXtra::m_baFindApp, 1, 1, 500, HBLTIN },
+	{ "baReadIni", BudAPIXtra::m_baReadIni, 4, 4, 500, HBLTIN },
+	{ "baWriteIni", BudAPIXtra::m_baWriteIni, 4, 4, 500, HBLTIN },
+	{ "baFlushIni", BudAPIXtra::m_baFlushIni, 1, 1, 500, HBLTIN },
+	{ "baReadRegString", BudAPIXtra::m_baReadRegString, 4, 4, 500, HBLTIN },
+	{ "baWriteRegString", BudAPIXtra::m_baWriteRegString, 4, 4, 500, HBLTIN },
+	{ "baReadRegNumber", BudAPIXtra::m_baReadRegNumber, 4, 4, 500, HBLTIN },
+	{ "baWriteRegNumber", BudAPIXtra::m_baWriteRegNumber, 4, 4, 500, HBLTIN },
+	{ "baDeleteReg", BudAPIXtra::m_baDeleteReg, 3, 3, 500, HBLTIN },
+	{ "baRegKeyList", BudAPIXtra::m_baRegKeyList, 2, 2, 500, HBLTIN },
+	{ "baRegValueList", BudAPIXtra::m_baRegValueList, 2, 2, 500, HBLTIN },
+	{ "baSoundCard", BudAPIXtra::m_baSoundCard, 0, 0, 500, HBLTIN },
+	{ "baFontInstalled", BudAPIXtra::m_baFontInstalled, 2, 2, 500, HBLTIN },
+	{ "baFontList", BudAPIXtra::m_baFontList, 1, 1, 500, HBLTIN },
+	{ "baFontStyleList", BudAPIXtra::m_baFontStyleList, 1, 1, 500, HBLTIN },
+	{ "baCommandArgs", BudAPIXtra::m_baCommandArgs, 0, 0, 500, HBLTIN },
+	{ "baPrevious", BudAPIXtra::m_baPrevious, 1, 1, 500, HBLTIN },
+	{ "baScreenInfo", BudAPIXtra::m_baScreenInfo, 1, 1, 500, HBLTIN },
+	{ "baDisableDiskErrors", BudAPIXtra::m_baDisableDiskErrors, 1, 1, 500, HBLTIN },
+	{ "baDisableKeys", BudAPIXtra::m_baDisableKeys, 2, 2, 500, HBLTIN },
+	{ "baDisableMouse", BudAPIXtra::m_baDisableMouse, 2, 2, 500, HBLTIN },
+	{ "baDisableSwitching", BudAPIXtra::m_baDisableSwitching, 1, 1, 500, HBLTIN },
+	{ "baDisableScreenSaver", BudAPIXtra::m_baDisableScreenSaver, 1, 1, 500, HBLTIN },
+	{ "baScreenSaverTime", BudAPIXtra::m_baScreenSaverTime, 1, 1, 500, HBLTIN },
+	{ "baSetScreenSaver", BudAPIXtra::m_baSetScreenSaver, 1, 1, 500, HBLTIN },
+	{ "baSetWallpaper", BudAPIXtra::m_baSetWallpaper, 2, 2, 500, HBLTIN },
+	{ "baSetPattern", BudAPIXtra::m_baSetPattern, 2, 2, 500, HBLTIN },
+	{ "baSetDisplay", BudAPIXtra::m_baSetDisplay, 5, 5, 500, HBLTIN },
+	{ "baExitWindows", BudAPIXtra::m_baExitWindows, 1, 1, 500, HBLTIN },
+	{ "baRunProgram", BudAPIXtra::m_baRunProgram, 3, 3, 500, HBLTIN },
+	{ "baWinHelp", BudAPIXtra::m_baWinHelp, 3, 3, 500, HBLTIN },
+	{ "baMsgBox", BudAPIXtra::m_baMsgBox, 5, 5, 500, HBLTIN },
+	{ "baHideTaskBar", BudAPIXtra::m_baHideTaskBar, 1, 1, 500, HBLTIN },
+	{ "baSetCurrentDir", BudAPIXtra::m_baSetCurrentDir, 1, 1, 500, HBLTIN },
+	{ "baCopyText", BudAPIXtra::m_baCopyText, 1, 1, 500, HBLTIN },
+	{ "baPasteText", BudAPIXtra::m_baPasteText, 0, 0, 500, HBLTIN },
+	{ "baEncryptText", BudAPIXtra::m_baEncryptText, 2, 2, 500, HBLTIN },
+	{ "baDecryptText", BudAPIXtra::m_baDecryptText, 2, 2, 500, HBLTIN },
+	{ "baPlaceCursor", BudAPIXtra::m_baPlaceCursor, 2, 2, 500, HBLTIN },
+	{ "baRestrictCursor", BudAPIXtra::m_baRestrictCursor, 4, 4, 500, HBLTIN },
+	{ "baFreeCursor", BudAPIXtra::m_baFreeCursor, 0, 0, 500, HBLTIN },
+	{ "baSetVolume", BudAPIXtra::m_baSetVolume, 2, 2, 500, HBLTIN },
+	{ "baGetVolume", BudAPIXtra::m_baGetVolume, 1, 1, 500, HBLTIN },
+	{ "baInstallFont", BudAPIXtra::m_baInstallFont, 2, 2, 500, HBLTIN },
+	{ "baKeyIsDown", BudAPIXtra::m_baKeyIsDown, 1, 1, 500, HBLTIN },
+	{ "baKeyBeenPressed", BudAPIXtra::m_baKeyBeenPressed, 1, 1, 500, HBLTIN },
+	{ "baSleep", BudAPIXtra::m_baSleep, 1, 1, 500, HBLTIN },
+	{ "baCreatePMGroup", BudAPIXtra::m_baCreatePMGroup, 1, 1, 500, HBLTIN },
+	{ "baDeletePMGroup", BudAPIXtra::m_baDeletePMGroup, 1, 1, 500, HBLTIN },
+	{ "baCreatePMIcon", BudAPIXtra::m_baCreatePMIcon, 4, 4, 500, HBLTIN },
+	{ "baDeletePMIcon", BudAPIXtra::m_baDeletePMIcon, 1, 1, 500, HBLTIN },
+	{ "baPMGroupList", BudAPIXtra::m_baPMGroupList, 0, 0, 500, HBLTIN },
+	{ "baPMIconList", BudAPIXtra::m_baPMIconList, 1, 1, 500, HBLTIN },
+	{ "baPMSubGroupList", BudAPIXtra::m_baPMSubGroupList, 1, 1, 500, HBLTIN },
+	{ "baSystemTime", BudAPIXtra::m_baSystemTime, 1, 1, 500, HBLTIN },
+	{ "baSetSystemTime", BudAPIXtra::m_baSetSystemTime, 2, 2, 500, HBLTIN },
+	{ "baPrinterInfo", BudAPIXtra::m_baPrinterInfo, 1, 1, 500, HBLTIN },
+	{ "baSetPrinter", BudAPIXtra::m_baSetPrinter, 2, 2, 500, HBLTIN },
+	{ "baRefreshDesktop", BudAPIXtra::m_baRefreshDesktop, 1, 1, 500, HBLTIN },
+	{ "baFileAge", BudAPIXtra::m_baFileAge, 1, 1, 500, HBLTIN },
+	{ "baFileExists", BudAPIXtra::m_baFileExists, 1, 1, 500, HBLTIN },
+	{ "baFolderExists", BudAPIXtra::m_baFolderExists, 1, 1, 500, HBLTIN },
+	{ "baCreateFolder", BudAPIXtra::m_baCreateFolder, 1, 1, 500, HBLTIN },
+	{ "baDeleteFolder", BudAPIXtra::m_baDeleteFolder, 1, 1, 500, HBLTIN },
+	{ "baRenameFile", BudAPIXtra::m_baRenameFile, 2, 2, 500, HBLTIN },
+	{ "baDeleteFile", BudAPIXtra::m_baDeleteFile, 1, 1, 500, HBLTIN },
+	{ "baDeleteXFiles", BudAPIXtra::m_baDeleteXFiles, 2, 2, 500, HBLTIN },
+	{ "baXDelete", BudAPIXtra::m_baXDelete, 2, 2, 500, HBLTIN },
+	{ "baFileDate", BudAPIXtra::m_baFileDate, 3, 3, 500, HBLTIN },
+	{ "baFileSize", BudAPIXtra::m_baFileSize, 1, 1, 500, HBLTIN },
+	{ "baFileAttributes", BudAPIXtra::m_baFileAttributes, 1, 1, 500, HBLTIN },
+	{ "baSetFileAttributes", BudAPIXtra::m_baSetFileAttributes, 2, 2, 500, HBLTIN },
+	{ "baRecycleFile", BudAPIXtra::m_baRecycleFile, 1, 1, 500, HBLTIN },
+	{ "baCopyFile", BudAPIXtra::m_baCopyFile, 3, 3, 500, HBLTIN },
+	{ "baCopyXFiles", BudAPIXtra::m_baCopyXFiles, 4, 4, 500, HBLTIN },
+	{ "baXCopy", BudAPIXtra::m_baXCopy, 5, 5, 500, HBLTIN },
+	{ "baFileList", BudAPIXtra::m_baFileList, 2, 2, 500, HBLTIN },
+	{ "baFolderList", BudAPIXtra::m_baFolderList, 1, 1, 500, HBLTIN },
+	{ "baFindFirstFile", BudAPIXtra::m_baFindFirstFile, 2, 2, 500, HBLTIN },
+	{ "baFindNextFile", BudAPIXtra::m_baFindNextFile, 0, 0, 500, HBLTIN },
+	{ "baFindClose", BudAPIXtra::m_baFindClose, 0, 0, 500, HBLTIN },
+	{ "baGetFilename", BudAPIXtra::m_baGetFilename, 9, 9, 500, HBLTIN },
+	{ "baGetFolder", BudAPIXtra::m_baGetFolder, 6, 6, 500, HBLTIN },
+	{ "baFileVersion", BudAPIXtra::m_baFileVersion, 1, 1, 500, HBLTIN },
+	{ "baEncryptFile", BudAPIXtra::m_baEncryptFile, 2, 2, 500, HBLTIN },
+	{ "baFindDrive", BudAPIXtra::m_baFindDrive, 2, 2, 500, HBLTIN },
+	{ "baOpenFile", BudAPIXtra::m_baOpenFile, 2, 2, 500, HBLTIN },
+	{ "baOpenURL", BudAPIXtra::m_baOpenURL, 2, 2, 500, HBLTIN },
+	{ "baPrintFile", BudAPIXtra::m_baPrintFile, 1, 1, 500, HBLTIN },
+	{ "baShell", BudAPIXtra::m_baShell, 5, 5, 500, HBLTIN },
+	{ "baShortFileName", BudAPIXtra::m_baShortFileName, 1, 1, 500, HBLTIN },
+	{ "baTempFileName", BudAPIXtra::m_baTempFileName, 1, 1, 500, HBLTIN },
+	{ "baMakeShortcut", BudAPIXtra::m_baMakeShortcut, 3, 3, 500, HBLTIN },
+	{ "baMakeShortcutEx", BudAPIXtra::m_baMakeShortcutEx, 9, 9, 500, HBLTIN },
+	{ "baResolveShortcut", BudAPIXtra::m_baResolveShortcut, 1, 1, 500, HBLTIN },
+	{ "baWindowInfo", BudAPIXtra::m_baWindowInfo, 2, 2, 500, HBLTIN },
+	{ "baFindWindow", BudAPIXtra::m_baFindWindow, 2, 2, 500, HBLTIN },
+	{ "baActiveWindow", BudAPIXtra::m_baActiveWindow, 0, 0, 500, HBLTIN },
+	{ "baCloseWindow", BudAPIXtra::m_baCloseWindow, 1, 1, 500, HBLTIN },
+	{ "baCloseApp", BudAPIXtra::m_baCloseApp, 1, 1, 500, HBLTIN },
+	{ "baSetWindowState", BudAPIXtra::m_baSetWindowState, 2, 2, 500, HBLTIN },
+	{ "baActivateWindow", BudAPIXtra::m_baActivateWindow, 1, 1, 500, HBLTIN },
+	{ "baSetWindowTitle", BudAPIXtra::m_baSetWindowTitle, 2, 2, 500, HBLTIN },
+	{ "baMoveWindow", BudAPIXtra::m_baMoveWindow, 6, 6, 500, HBLTIN },
+	{ "baWindowToFront", BudAPIXtra::m_baWindowToFront, 1, 1, 500, HBLTIN },
+	{ "baWindowToBack", BudAPIXtra::m_baWindowToBack, 1, 1, 500, HBLTIN },
+	{ "baGetWindow", BudAPIXtra::m_baGetWindow, 2, 2, 500, HBLTIN },
+	{ "baWaitTillActive", BudAPIXtra::m_baWaitTillActive, 1, 1, 500, HBLTIN },
+	{ "baWaitForWindow", BudAPIXtra::m_baWaitForWindow, 3, 3, 500, HBLTIN },
+	{ "baNextActiveWindow", BudAPIXtra::m_baNextActiveWindow, 1, 1, 500, HBLTIN },
+	{ "baWindowExists", BudAPIXtra::m_baWindowExists, 1, 1, 500, HBLTIN },
+	{ "baWindowList", BudAPIXtra::m_baWindowList, 3, 3, 500, HBLTIN },
+	{ "baChildWindowList", BudAPIXtra::m_baChildWindowList, 4, 4, 500, HBLTIN },
+	{ "baWindowDepth", BudAPIXtra::m_baWindowDepth, 1, 1, 500, HBLTIN },
+	{ "baSetWindowDepth", BudAPIXtra::m_baSetWindowDepth, 2, 2, 500, HBLTIN },
+	{ "baSendKeys", BudAPIXtra::m_baSendKeys, 1, 1, 500, HBLTIN },
+	{ "baSendMsg", BudAPIXtra::m_baSendMsg, 5, 5, 500, HBLTIN },
+	{ "baAddSysItems", BudAPIXtra::m_baAddSysItems, 4, 4, 500, HBLTIN },
+	{ "baRemoveSysItems", BudAPIXtra::m_baRemoveSysItems, 4, 4, 500, HBLTIN },
+	{ "baWinHandle", BudAPIXtra::m_baWinHandle, 0, 0, 500, HBLTIN },
+	{ "baStageHandle", BudAPIXtra::m_baStageHandle, 0, 0, 500, HBLTIN },
+	{ "baAbout", BudAPIXtra::m_baAbout, 0, 0, 500, HBLTIN },
+	{ "baRegister", BudAPIXtra::m_baRegister, 2, 2, 500, HBLTIN },
+	{ "baSaveRegistration", BudAPIXtra::m_baSaveRegistration, 2, 2, 500, HBLTIN },
+	{ "baGetRegistration", BudAPIXtra::m_baGetRegistration, 0, 0, 500, HBLTIN },
+	{ "baFunctions", BudAPIXtra::m_baFunctions, 0, 0, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+BudAPIXtraObject::BudAPIXtraObject(ObjectType ObjectType) :Object<BudAPIXtraObject>("BudAPI") {
+	_objType = ObjectType;
+}
+
+bool BudAPIXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum BudAPIXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(BudAPIXtra::xlibName);
+	warning("BudAPIXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void BudAPIXtra::open(ObjectType type, const Common::Path &path) {
+    BudAPIXtraObject::initMethods(xlibMethods);
+    BudAPIXtraObject *xobj = new BudAPIXtraObject(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);
+}
+
+void BudAPIXtra::close(ObjectType type) {
+    BudAPIXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void BudAPIXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("BudAPIXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(BudAPIXtra::m_baVersion, 0)
+XOBJSTUB(BudAPIXtra::m_baSysFolder, 0)
+XOBJSTUB(BudAPIXtra::m_baCpuInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baDiskInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baMemoryInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baFindApp, 0)
+XOBJSTUB(BudAPIXtra::m_baReadIni, 0)
+XOBJSTUB(BudAPIXtra::m_baWriteIni, 0)
+XOBJSTUB(BudAPIXtra::m_baFlushIni, 0)
+XOBJSTUB(BudAPIXtra::m_baReadRegString, 0)
+XOBJSTUB(BudAPIXtra::m_baWriteRegString, 0)
+XOBJSTUB(BudAPIXtra::m_baReadRegNumber, 0)
+XOBJSTUB(BudAPIXtra::m_baWriteRegNumber, 0)
+XOBJSTUB(BudAPIXtra::m_baDeleteReg, 0)
+XOBJSTUB(BudAPIXtra::m_baRegKeyList, 0)
+XOBJSTUB(BudAPIXtra::m_baRegValueList, 0)
+XOBJSTUB(BudAPIXtra::m_baSoundCard, 0)
+XOBJSTUB(BudAPIXtra::m_baFontInstalled, 0)
+XOBJSTUB(BudAPIXtra::m_baFontList, 0)
+XOBJSTUB(BudAPIXtra::m_baFontStyleList, 0)
+XOBJSTUB(BudAPIXtra::m_baCommandArgs, 0)
+XOBJSTUB(BudAPIXtra::m_baPrevious, 0)
+XOBJSTUB(BudAPIXtra::m_baScreenInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baDisableDiskErrors, 0)
+XOBJSTUB(BudAPIXtra::m_baDisableKeys, 0)
+XOBJSTUB(BudAPIXtra::m_baDisableMouse, 0)
+XOBJSTUB(BudAPIXtra::m_baDisableSwitching, 0)
+XOBJSTUB(BudAPIXtra::m_baDisableScreenSaver, 0)
+XOBJSTUB(BudAPIXtra::m_baScreenSaverTime, 0)
+XOBJSTUB(BudAPIXtra::m_baSetScreenSaver, 0)
+XOBJSTUB(BudAPIXtra::m_baSetWallpaper, 0)
+XOBJSTUB(BudAPIXtra::m_baSetPattern, 0)
+XOBJSTUB(BudAPIXtra::m_baSetDisplay, 0)
+XOBJSTUB(BudAPIXtra::m_baExitWindows, 0)
+XOBJSTUB(BudAPIXtra::m_baRunProgram, 0)
+XOBJSTUB(BudAPIXtra::m_baWinHelp, 0)
+XOBJSTUB(BudAPIXtra::m_baMsgBox, 0)
+XOBJSTUB(BudAPIXtra::m_baHideTaskBar, 0)
+XOBJSTUB(BudAPIXtra::m_baSetCurrentDir, 0)
+XOBJSTUB(BudAPIXtra::m_baCopyText, 0)
+XOBJSTUB(BudAPIXtra::m_baPasteText, 0)
+XOBJSTUB(BudAPIXtra::m_baEncryptText, 0)
+XOBJSTUB(BudAPIXtra::m_baDecryptText, 0)
+XOBJSTUB(BudAPIXtra::m_baPlaceCursor, 0)
+XOBJSTUB(BudAPIXtra::m_baRestrictCursor, 0)
+XOBJSTUB(BudAPIXtra::m_baFreeCursor, 0)
+XOBJSTUB(BudAPIXtra::m_baSetVolume, 0)
+XOBJSTUB(BudAPIXtra::m_baGetVolume, 0)
+XOBJSTUB(BudAPIXtra::m_baInstallFont, 0)
+XOBJSTUB(BudAPIXtra::m_baKeyIsDown, 0)
+XOBJSTUB(BudAPIXtra::m_baKeyBeenPressed, 0)
+XOBJSTUB(BudAPIXtra::m_baSleep, 0)
+XOBJSTUB(BudAPIXtra::m_baCreatePMGroup, 0)
+XOBJSTUB(BudAPIXtra::m_baDeletePMGroup, 0)
+XOBJSTUB(BudAPIXtra::m_baCreatePMIcon, 0)
+XOBJSTUB(BudAPIXtra::m_baDeletePMIcon, 0)
+XOBJSTUB(BudAPIXtra::m_baPMGroupList, 0)
+XOBJSTUB(BudAPIXtra::m_baPMIconList, 0)
+XOBJSTUB(BudAPIXtra::m_baPMSubGroupList, 0)
+XOBJSTUB(BudAPIXtra::m_baSystemTime, 0)
+XOBJSTUB(BudAPIXtra::m_baSetSystemTime, 0)
+XOBJSTUB(BudAPIXtra::m_baPrinterInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baSetPrinter, 0)
+XOBJSTUB(BudAPIXtra::m_baRefreshDesktop, 0)
+XOBJSTUB(BudAPIXtra::m_baFileAge, 0)
+XOBJSTUB(BudAPIXtra::m_baFileExists, 0)
+XOBJSTUB(BudAPIXtra::m_baFolderExists, 0)
+XOBJSTUB(BudAPIXtra::m_baCreateFolder, 0)
+XOBJSTUB(BudAPIXtra::m_baDeleteFolder, 0)
+XOBJSTUB(BudAPIXtra::m_baRenameFile, 0)
+XOBJSTUB(BudAPIXtra::m_baDeleteFile, 0)
+XOBJSTUB(BudAPIXtra::m_baDeleteXFiles, 0)
+XOBJSTUB(BudAPIXtra::m_baXDelete, 0)
+XOBJSTUB(BudAPIXtra::m_baFileDate, 0)
+XOBJSTUB(BudAPIXtra::m_baFileSize, 0)
+XOBJSTUB(BudAPIXtra::m_baFileAttributes, 0)
+XOBJSTUB(BudAPIXtra::m_baSetFileAttributes, 0)
+XOBJSTUB(BudAPIXtra::m_baRecycleFile, 0)
+XOBJSTUB(BudAPIXtra::m_baCopyFile, 0)
+XOBJSTUB(BudAPIXtra::m_baCopyXFiles, 0)
+XOBJSTUB(BudAPIXtra::m_baXCopy, 0)
+XOBJSTUB(BudAPIXtra::m_baFileList, 0)
+XOBJSTUB(BudAPIXtra::m_baFolderList, 0)
+XOBJSTUB(BudAPIXtra::m_baFindFirstFile, 0)
+XOBJSTUB(BudAPIXtra::m_baFindNextFile, 0)
+XOBJSTUB(BudAPIXtra::m_baFindClose, 0)
+XOBJSTUB(BudAPIXtra::m_baGetFilename, 0)
+XOBJSTUB(BudAPIXtra::m_baGetFolder, 0)
+XOBJSTUB(BudAPIXtra::m_baFileVersion, 0)
+XOBJSTUB(BudAPIXtra::m_baEncryptFile, 0)
+XOBJSTUB(BudAPIXtra::m_baFindDrive, 0)
+XOBJSTUB(BudAPIXtra::m_baOpenFile, 0)
+XOBJSTUB(BudAPIXtra::m_baOpenURL, 0)
+XOBJSTUB(BudAPIXtra::m_baPrintFile, 0)
+XOBJSTUB(BudAPIXtra::m_baShell, 0)
+XOBJSTUB(BudAPIXtra::m_baShortFileName, 0)
+XOBJSTUB(BudAPIXtra::m_baTempFileName, 0)
+XOBJSTUB(BudAPIXtra::m_baMakeShortcut, 0)
+XOBJSTUB(BudAPIXtra::m_baMakeShortcutEx, 0)
+XOBJSTUB(BudAPIXtra::m_baResolveShortcut, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowInfo, 0)
+XOBJSTUB(BudAPIXtra::m_baFindWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baActiveWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baCloseWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baCloseApp, 0)
+XOBJSTUB(BudAPIXtra::m_baSetWindowState, 0)
+XOBJSTUB(BudAPIXtra::m_baActivateWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baSetWindowTitle, 0)
+XOBJSTUB(BudAPIXtra::m_baMoveWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowToFront, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowToBack, 0)
+XOBJSTUB(BudAPIXtra::m_baGetWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baWaitTillActive, 0)
+XOBJSTUB(BudAPIXtra::m_baWaitForWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baNextActiveWindow, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowExists, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowList, 0)
+XOBJSTUB(BudAPIXtra::m_baChildWindowList, 0)
+XOBJSTUB(BudAPIXtra::m_baWindowDepth, 0)
+XOBJSTUB(BudAPIXtra::m_baSetWindowDepth, 0)
+XOBJSTUB(BudAPIXtra::m_baSendKeys, 0)
+XOBJSTUB(BudAPIXtra::m_baSendMsg, 0)
+XOBJSTUB(BudAPIXtra::m_baAddSysItems, 0)
+XOBJSTUB(BudAPIXtra::m_baRemoveSysItems, 0)
+XOBJSTUB(BudAPIXtra::m_baWinHandle, 0)
+XOBJSTUB(BudAPIXtra::m_baStageHandle, 0)
+XOBJSTUB(BudAPIXtra::m_baAbout, 0)
+XOBJSTUB(BudAPIXtra::m_baRegister, 0)
+XOBJSTUB(BudAPIXtra::m_baSaveRegistration, 0)
+XOBJSTUB(BudAPIXtra::m_baGetRegistration, 0)
+XOBJSTUB(BudAPIXtra::m_baFunctions, 0)
+
+}
diff --git a/engines/director/lingo/xtras/b/budapi.h b/engines/director/lingo/xtras/b/budapi.h
new file mode 100644
index 00000000000..f83525102cd
--- /dev/null
+++ b/engines/director/lingo/xtras/b/budapi.h
@@ -0,0 +1,180 @@
+/* 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_B_BUDAPI_H
+#define DIRECTOR_LINGO_XTRAS_B_BUDAPI_H
+
+namespace Director {
+
+class BudAPIXtraObject : public Object<BudAPIXtraObject> {
+public:
+	BudAPIXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace BudAPIXtra {
+
+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_baVersion(int nargs);
+void m_baSysFolder(int nargs);
+void m_baCpuInfo(int nargs);
+void m_baDiskInfo(int nargs);
+void m_baMemoryInfo(int nargs);
+void m_baFindApp(int nargs);
+void m_baReadIni(int nargs);
+void m_baWriteIni(int nargs);
+void m_baFlushIni(int nargs);
+void m_baReadRegString(int nargs);
+void m_baWriteRegString(int nargs);
+void m_baReadRegNumber(int nargs);
+void m_baWriteRegNumber(int nargs);
+void m_baDeleteReg(int nargs);
+void m_baRegKeyList(int nargs);
+void m_baRegValueList(int nargs);
+void m_baSoundCard(int nargs);
+void m_baFontInstalled(int nargs);
+void m_baFontList(int nargs);
+void m_baFontStyleList(int nargs);
+void m_baCommandArgs(int nargs);
+void m_baPrevious(int nargs);
+void m_baScreenInfo(int nargs);
+void m_baDisableDiskErrors(int nargs);
+void m_baDisableKeys(int nargs);
+void m_baDisableMouse(int nargs);
+void m_baDisableSwitching(int nargs);
+void m_baDisableScreenSaver(int nargs);
+void m_baScreenSaverTime(int nargs);
+void m_baSetScreenSaver(int nargs);
+void m_baSetWallpaper(int nargs);
+void m_baSetPattern(int nargs);
+void m_baSetDisplay(int nargs);
+void m_baExitWindows(int nargs);
+void m_baRunProgram(int nargs);
+void m_baWinHelp(int nargs);
+void m_baMsgBox(int nargs);
+void m_baHideTaskBar(int nargs);
+void m_baSetCurrentDir(int nargs);
+void m_baCopyText(int nargs);
+void m_baPasteText(int nargs);
+void m_baEncryptText(int nargs);
+void m_baDecryptText(int nargs);
+void m_baPlaceCursor(int nargs);
+void m_baRestrictCursor(int nargs);
+void m_baFreeCursor(int nargs);
+void m_baSetVolume(int nargs);
+void m_baGetVolume(int nargs);
+void m_baInstallFont(int nargs);
+void m_baKeyIsDown(int nargs);
+void m_baKeyBeenPressed(int nargs);
+void m_baSleep(int nargs);
+void m_baCreatePMGroup(int nargs);
+void m_baDeletePMGroup(int nargs);
+void m_baCreatePMIcon(int nargs);
+void m_baDeletePMIcon(int nargs);
+void m_baPMGroupList(int nargs);
+void m_baPMIconList(int nargs);
+void m_baPMSubGroupList(int nargs);
+void m_baSystemTime(int nargs);
+void m_baSetSystemTime(int nargs);
+void m_baPrinterInfo(int nargs);
+void m_baSetPrinter(int nargs);
+void m_baRefreshDesktop(int nargs);
+void m_baFileAge(int nargs);
+void m_baFileExists(int nargs);
+void m_baFolderExists(int nargs);
+void m_baCreateFolder(int nargs);
+void m_baDeleteFolder(int nargs);
+void m_baRenameFile(int nargs);
+void m_baDeleteFile(int nargs);
+void m_baDeleteXFiles(int nargs);
+void m_baXDelete(int nargs);
+void m_baFileDate(int nargs);
+void m_baFileSize(int nargs);
+void m_baFileAttributes(int nargs);
+void m_baSetFileAttributes(int nargs);
+void m_baRecycleFile(int nargs);
+void m_baCopyFile(int nargs);
+void m_baCopyXFiles(int nargs);
+void m_baXCopy(int nargs);
+void m_baFileList(int nargs);
+void m_baFolderList(int nargs);
+void m_baFindFirstFile(int nargs);
+void m_baFindNextFile(int nargs);
+void m_baFindClose(int nargs);
+void m_baGetFilename(int nargs);
+void m_baGetFolder(int nargs);
+void m_baFileVersion(int nargs);
+void m_baEncryptFile(int nargs);
+void m_baFindDrive(int nargs);
+void m_baOpenFile(int nargs);
+void m_baOpenURL(int nargs);
+void m_baPrintFile(int nargs);
+void m_baShell(int nargs);
+void m_baShortFileName(int nargs);
+void m_baTempFileName(int nargs);
+void m_baMakeShortcut(int nargs);
+void m_baMakeShortcutEx(int nargs);
+void m_baResolveShortcut(int nargs);
+void m_baWindowInfo(int nargs);
+void m_baFindWindow(int nargs);
+void m_baActiveWindow(int nargs);
+void m_baCloseWindow(int nargs);
+void m_baCloseApp(int nargs);
+void m_baSetWindowState(int nargs);
+void m_baActivateWindow(int nargs);
+void m_baSetWindowTitle(int nargs);
+void m_baMoveWindow(int nargs);
+void m_baWindowToFront(int nargs);
+void m_baWindowToBack(int nargs);
+void m_baGetWindow(int nargs);
+void m_baWaitTillActive(int nargs);
+void m_baWaitForWindow(int nargs);
+void m_baNextActiveWindow(int nargs);
+void m_baWindowExists(int nargs);
+void m_baWindowList(int nargs);
+void m_baChildWindowList(int nargs);
+void m_baWindowDepth(int nargs);
+void m_baSetWindowDepth(int nargs);
+void m_baSendKeys(int nargs);
+void m_baSendMsg(int nargs);
+void m_baAddSysItems(int nargs);
+void m_baRemoveSysItems(int nargs);
+void m_baWinHandle(int nargs);
+void m_baStageHandle(int nargs);
+void m_baAbout(int nargs);
+void m_baRegister(int nargs);
+void m_baSaveRegistration(int nargs);
+void m_baGetRegistration(int nargs);
+void m_baFunctions(int nargs);
+
+} // End of namespace BudAPIXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xtras/d/displayres.cpp b/engines/director/lingo/xtras/d/displayres.cpp
new file mode 100644
index 00000000000..56a8e2b1a65
--- /dev/null
+++ b/engines/director/lingo/xtras/d/displayres.cpp
@@ -0,0 +1,207 @@
+/* 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/d/displayres.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * I Spy Spooky Mansion
+ *
+ **************************************************/
+
+/*
+-- xtra DisplayRes
+-- DisplayRes Xtra, Version 1.0.0.3, 4/27/1997
+-- Copyright 1997 Glenn M. Picher, Dirigo Multimedia
+--
+--Published by g/matter, inc.
+--Sales: sales at gmatter.com, (800)933-6223
+--Tech support: support at gmatter.com, (415)243-0394
+--Web: http://www.gmatter.com
+--
+--Author: Glenn M. Picher, gpicher at maine.com, (207)767-8015
+--Web: http://www.maine.com/shops/gpicher
+--
+-- Registered version-- thank you! See the 'register' handler.
+--
+new object me
+-- Note: this Xtra uses only global handlers, so there's no need to
+-- create any child objects. Just use the handlers listed below.
+--
+-- All methods return a string. Check the result for word 1 'Error:' to
+-- verify proper operation.
+--
+* dresGetDisplaySettings
+-- Provides a string of possible resolutions for the current display,
+-- in the format:
+--   width height colors frequency interlace grayOrColor capability
+-- Reports width in pixels; height in pixels; color depth in bits per pixel: 1 (2
+-- colors), 4 (16 colors),  8 (256 colors), 15 (32K colors), 16 (64K colors),
+-- 24 (16 million colors), 32 (24 million colors plus 8 bits transparency);
+-- vertical refresh rate in cycles per second (a value of 0 or 1 may be returned,
+-- which indicates the default hardware refresh); 'interlaced' or 'noninterlaced';
+-- 'grayscale' or 'color'; and the capabilites (typically 'dynamic' or 'restart,'
+-- but if some error occurs while checking capabilities, could also be 'badFlags',
+-- 'failed', 'badMode', 'notUpdated', or 'unknown'). Note that the quality of
+-- of Windows display drivers varies wildly. Some drivers may report they can
+-- change modes dynamically when they really can't. Some report no error when
+-- actually asked to change modes dynamically and unable to do so (I've observed
+-- this on Windows NT 3.51). Therefore, it's best to verify that the display really
+-- *has* changed with dresGetCurrentDisplay(), after using dresDynamicSetDisplay().
+-- NOTE: This method can return more than one line. Each possible display setting
+-- is on a different line of the returned string. Based on the results, choose
+-- a line number of the new mode you want to set with dresDynamicSetDisplay() (or,
+-- if 'capability' indicates a restart is required, dresRestartSetDisplay).
+--
+* dresDynamicSetDisplay integer lineNumber
+-- Change the monitor to use the display settings on the specified line
+-- of the information returned by dresGetDisplaySettings. Does not affect
+-- registry settings, so the default will be restored on the next restart.
+-- It's best to verify proper operation with dresGetCurrentDisplay().
+--
+* dresRestartSetDisplay integer lineNumber
+-- Change the monitor to use the display settings on the specified line
+-- of the information returned by dresGetDisplaySettings (updating the
+-- default registry settings for the next time the computer restarts).
+-- Note that this method *will* change dynamically if it's possible, as
+-- well as updating the default registry settings. Use dresGetCurrentDisplay()
+-- to verify whether a dynamic change was made.
+* dresRestart
+-- Restart the machine. Lingo's 'restart' doesn't work on Win95/NT.
+* dresShutdown
+-- Shut down the machine. Lingo's 'shutdown' doesn't work on Win95/NT.
+--
+* dresDefaultDisplay
+-- Sets the display to the default values stored in the registry. Useful to
+-- restore the screen after a dynamic change with dresDynamicSetDisplay.
+-- Note that dresRestartSetDisplay() will *change* the defaults, so this method
+-- can't be used to restore an old setting after a restart.
+* dresGetCurrentDisplay
+-- Returns a line of information about the current display settings (in the same
+-- format as dresGetDisplaySettings). This is useful to save the existing settings
+-- when you change the display, so you can know what to restore it to later.
+-- This also returns up-to-date information after a display change, which Lingo's
+-- 'the desktopRectList' and 'the colorDepth' will not (in Director 5 at least).
+-- Note that the values for 'interlace' and 'grayOrColor' are not meaningful; the value
+-- for 'capability' is always 'dynamic' (because by definition the sytem is already
+-- using this display mode); and the value for 'frequency' is only meaningful on
+-- Windows NT. This is due to the nature of the underlying Windows API functions.
+--
++ register object xtraReference, string registrationString
+--
+
+ */
+
+namespace Director {
+
+const char *DisplayResXtra::xlibName = "DisplayRes";
+const XlibFileDesc DisplayResXtra::fileNames[] = {
+	{ "displayres",   nullptr },
+	{ "DispRes",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				DisplayResXtra::m_new,		 0, 0,	500 },
+	{ "register",				DisplayResXtra::m_register,		 1, 1,	500 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "dresGetDisplaySettings", DisplayResXtra::m_dresGetDisplaySettings, 0, 0, 500, HBLTIN },
+	{ "dresDynamicSetDisplay", DisplayResXtra::m_dresDynamicSetDisplay, 1, 1, 500, HBLTIN },
+	{ "dresRestartSetDisplay", DisplayResXtra::m_dresRestartSetDisplay, 1, 1, 500, HBLTIN },
+	{ "dresRestart", DisplayResXtra::m_dresRestart, 0, 0, 500, HBLTIN },
+	{ "dresShutdown", DisplayResXtra::m_dresShutdown, 0, 0, 500, HBLTIN },
+	{ "dresDefaultDisplay", DisplayResXtra::m_dresDefaultDisplay, 0, 0, 500, HBLTIN },
+	{ "dresGetCurrentDisplay", DisplayResXtra::m_dresGetCurrentDisplay, 0, 0, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+DisplayResXtraObject::DisplayResXtraObject(ObjectType ObjectType) :Object<DisplayResXtraObject>("DisplayRes") {
+	_objType = ObjectType;
+}
+
+bool DisplayResXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum DisplayResXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(DisplayResXtra::xlibName);
+	warning("DisplayResXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void DisplayResXtra::open(ObjectType type, const Common::Path &path) {
+    DisplayResXtraObject::initMethods(xlibMethods);
+    DisplayResXtraObject *xobj = new DisplayResXtraObject(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);
+}
+
+void DisplayResXtra::close(ObjectType type) {
+    DisplayResXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void DisplayResXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("DisplayResXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+void DisplayResXtra::m_dresGetDisplaySettings(int nargs) {
+	Common::String result = Common::String::format("%d %d %d %d noninterlaced color dynamic", g_director->_wm->getWidth(), g_director->_wm->getHeight(), g_director->_wm->_pixelformat.bytesPerPixel*8, 0);
+	g_lingo->push(Datum(result));
+}
+
+XOBJSTUB(DisplayResXtra::m_dresDynamicSetDisplay, 0)
+XOBJSTUB(DisplayResXtra::m_dresRestartSetDisplay, 0)
+XOBJSTUB(DisplayResXtra::m_dresRestart, 0)
+XOBJSTUB(DisplayResXtra::m_dresShutdown, 0)
+XOBJSTUB(DisplayResXtra::m_dresDefaultDisplay, 0)
+
+void DisplayResXtra::m_dresGetCurrentDisplay(int nargs) {
+	Common::String result = Common::String::format("%d %d %d %d noninterlaced color dynamic", g_director->_wm->getWidth(), g_director->_wm->getHeight(), g_director->_wm->_pixelformat.bytesPerPixel*8, 0);
+	g_lingo->push(Datum(result));
+}
+
+
+void DisplayResXtra::m_register(int nargs) {
+	Datum key = g_lingo->pop();
+	debugC(5, kDebugXObj, "DisplayResXtra::m_register: %s", key.asString().c_str());
+	g_lingo->push(Datum("OK"));
+}
+
+}
diff --git a/engines/director/lingo/xtras/d/displayres.h b/engines/director/lingo/xtras/d/displayres.h
new file mode 100644
index 00000000000..dd0faa2393a
--- /dev/null
+++ b/engines/director/lingo/xtras/d/displayres.h
@@ -0,0 +1,57 @@
+/* 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_D_DISPLAYRES_H
+#define DIRECTOR_LINGO_XTRAS_D_DISPLAYRES_H
+
+namespace Director {
+
+class DisplayResXtraObject : public Object<DisplayResXtraObject> {
+public:
+	DisplayResXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace DisplayResXtra {
+
+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_dresGetDisplaySettings(int nargs);
+void m_dresDynamicSetDisplay(int nargs);
+void m_dresRestartSetDisplay(int nargs);
+void m_dresRestart(int nargs);
+void m_dresShutdown(int nargs);
+void m_dresDefaultDisplay(int nargs);
+void m_dresGetCurrentDisplay(int nargs);
+void m_register(int nargs);
+
+} // End of namespace DisplayResXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xtras/m/mui.cpp b/engines/director/lingo/xtras/m/mui.cpp
new file mode 100644
index 00000000000..7d256fd44f0
--- /dev/null
+++ b/engines/director/lingo/xtras/m/mui.cpp
@@ -0,0 +1,216 @@
+/* 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/m/mui.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * I Spy Spooky Mansion
+ *
+ **************************************************/
+
+/*
+-- xtra Mui
+-- methods are Initialize, Run, WindowOperation, ItemUpdate --
+----------------------------------------------------------------------
+--  Data types (prop lists required formats)
+--      #widgetTypes	-- call GetWidgetList on object for complete list
+--          #checkBox , #radioButton, #editText, #editTextLarge, #labelNormal, etc
+--      #attributeTypes	-- varies depending on the type of widget, contains 0 or more of the following
+--          #textSize	  : [#large, #tiny, #normal(default)]
+--          #textStyle   : [#bold, #italic, #underline, #plain (default), #inverse (v2)
+--          #textAlign   : [#left, #right, #center (defaults to system language standard)
+--          #popupStyle  : [#tiny, #cramped, #normal (default)
+--          #valueList   : ['one', #two, 3, 4.0] (list of mmvalues, all coerced to strings)
+--          #valueRange  : [#min:0.0, #max:1000.0, #increment:1.0, #jump:10.0, #acceleration:0.5]
+--          #sliderStyle : [#ticks, #value]
+--          #layoutStyle : [#lockPosition, #lockSize, #minimize, #centerH, #right, #left, #centerV, #top, #bottom ]
+--      according to the following breakdown of supported widgets and appropriate attributes
+--      #widgetTypes                         | vs  | UT | Attributes to use, UT	= Uses Title
+--          #none,                           | 1.0 | No | <layoutStyle>
+--          #dividerV,                       | 1.0 | No | <layoutStyle>
+--          #dividerH,                       | 1.0 | No | <layoutStyle>
+--          #bitmap,                         | 1.0 | No | <layoutStyle>
+--          #checkBox,                       | 1.0 | Yes| <textSize><layoutStyle>
+--          #radioButton,                    | 1.0 | Yes| <textSize><layoutStyle>
+--          #popupList,                      | 1.0 | No | <popupStyle><valueList><layoutStyle>
+--          #editText,                       | 1.0 | No | <textSize><justification><textStyle><layoutStyle>
+--          #windowBegin,                    | 1.0 | No |
+--          #windowEnd,                      | 1.0 | No |
+--          #groupHBegin,                    | 1.0 | No |
+--          #groupHEnd,                      | 1.0 | No |
+--          #groupVBegin,                    | 1.0 | No |
+--          #groupVEnd,                      | 1.0 | No |
+--          #label,                          | 1.0 | No | <textSize><justification><textStyle><layoutStyle>
+--          #IntegerSliderH,                 | 1.0 | No | <sliderStyle><valueRange><layoutStyle>
+--          #floatSliderH,                   | 1.0 | No | <sliderStyle><valueRange><layoutStyle>
+--          #defaultPushButton,              | 1.0 | Yes| <textSize><layoutStyle>
+--          #cancelPushButton,               | 1.0 | Yes| <textSize><layoutStyle>
+--          #pushButton,                     | 1.0 | Yes| <textSize><layoutStyle>
+--          #toggleButton,                   | 1.0 | Yes| <textSize><layoutStyle>
+--
+--     alertList    =
+--        [ #buttons    : <#Ok/#OkCancel/#AbortRetryIgnore/#YesNoCancel/#YesNo/#RetryCancel>,
+--          #default    : 1, -- button number to default, 0 for no default
+--          #title      : 'Unsaved File Alert',
+--          #message    : 'Save before quitting?',
+--          #icon       : <#stop/#note/#caution/#question/#error>,
+--          #movable    : <TRUE/FALSE>]
+--     itemPropList    =
+--        [ #value      : <1 or 1.1 or 'string'>,
+--          #type       : <#widgetType>,
+--          #attributes : #attributeTypes,
+--          #title      : <'title'>,          -- title to display for item, '' for no title
+--          #tip        : <'tooltip'>,        -- tip for item, '' for no tip
+--          #locH       : <10>,               -- in pixels from upper left, 0 to accept default
+--          #locV       : <10>                -- in pixels from upper left, 0 to accept default
+--          #width      : <16>,               -- in pixels, 0 if don't care
+--          #height     : <16>,               -- in pixels, 0 if don't care
+--          #enabled    : <TRUE or FALSE>     -- whether or not the item is enabled ]
+--      #windowItemList = [ itemPropList, itemPropList, ...]
+--      #windowPropList =
+--        [ #type       : <#alert/#normal/#palette>,
+--          #name       : 'windowName',       -- name of window, '' for no name
+--          #callback   : 'nothing',          -- callback interface
+--          #mode       : <#data/#dialogUnit/#pixel>,  -- autolayout or your specifications
+--          #XPosition  : <16>,               -- left of window, from left of dialog, -1 = Center
+--          #YPosition  : <16>;               -- top  of window, from top  of dialog, -1 = Center
+--          #width      : <200>;              -- pixel width of window, 0 if don't care/automatic
+--          #height     : <200>,              -- pixel height of window, 0 if don't care/automatic
+--          #modal      : <TRUE or FALSE>,    -- whether or not dialog is modal
+--          #toolTips   : <TRUE or FALSE>,    -- whether or not to INITIALLY use tooltips
+--          #closeBox   : <TRUE or FALSE>,    -- whether or not dialog has close box
+--          #canZoom    : <TRUE or FALSE>;    -- whether or not window zooms
+--      initPropList = [ #windowPropList : [], #windowItemList : [] ]
+--      When an event occurs in dialog, the callback is called with 3 params, 1st a callback event symbol,
+--      callbackEvents = #itemChanged/#itemClicked/#windowOpening/#windowClosed/#windowZoomed/#windowResized
+--                       #itemEnteringFocus/#itemLosingFocus
+--      second, event specific information. (e.g.item events will return item position in #windowItemList), and
+--      third, the new item proplist for the item that was effected.
+----------------------------------------------------------------------
+New                object me -- call this first to access object methods
+Initialize         object me, object initPropList -- call this to setup window items
+Run                object me -- shows window
+Stop               object me, integer stopItem -- stops window, stopitem will be passed to callback if specified
+WindowOperation    object me, symbol operation -- #hide, #show, #center, #zoom, #tipsOn, #tipsOff
+ItemUpdate         object me, integer itemNumber, object itemInputPropList -- update an item
+GetWindowPropList  object me -- returns a property list in the standard format for initing window
+GetItemPropList    object me -- returns a default itemPropList
+GetWidgetList      object me -- returns a linear list of current supported widget symbols
+Alert              object me, object alertList -- display an alert
+GetUrl             object me, string url, boolean movable -- puts up url entry dialog
+FileOpen           object me, string file -- puts up a system standard dialog for opening a file
+FileSave           object me, string file, string prompt -- puts up system dialog for saving a file.
+*MoaErrorToString  integer MoaError -- xtra returns a big neg. int, call and get a string explaining.
+
+ */
+
+namespace Director {
+
+const char *MuiXtra::xlibName = "Mui";
+const XlibFileDesc MuiXtra::fileNames[] = {
+	{ "mui",   nullptr },
+	{ "Mui Dialog",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "New",				MuiXtra::m_New,		 0, 0,	500 },
+	{ "Initialize",				MuiXtra::m_Initialize,		 1, 0,	500 },
+	{ "Run",				MuiXtra::m_Run,		 0, 0,	500 },
+	{ "Stop",				MuiXtra::m_Stop,		 1, 0,	500 },
+	{ "WindowOperation",				MuiXtra::m_WindowOperation,		 1, 0,	500 },
+	{ "ItemUpdate",				MuiXtra::m_ItemUpdate,		 2, 0,	500 },
+	{ "GetWindowPropList",				MuiXtra::m_GetWindowPropList,		 0, 0,	500 },
+	{ "GetItemPropList",				MuiXtra::m_GetItemPropList,		 0, 0,	500 },
+	{ "GetWidgetList",				MuiXtra::m_GetWidgetList,		 0, 0,	500 },
+	{ "Alert",				MuiXtra::m_Alert,		 1, 0,	500 },
+	{ "GetUrl",				MuiXtra::m_GetUrl,		 2, 0,	500 },
+	{ "FileOpen",				MuiXtra::m_FileOpen,		 1, 0,	500 },
+	{ "FileSave",				MuiXtra::m_FileSave,		 2, 0,	500 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "MoaErrorToString", MuiXtra::m_MoaErrorToString, 1, 1, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+MuiXtraObject::MuiXtraObject(ObjectType ObjectType) :Object<MuiXtraObject>("Mui") {
+	_objType = ObjectType;
+}
+
+bool MuiXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum MuiXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(MuiXtra::xlibName);
+	warning("MuiXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void MuiXtra::open(ObjectType type, const Common::Path &path) {
+    MuiXtraObject::initMethods(xlibMethods);
+    MuiXtraObject *xobj = new MuiXtraObject(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);
+}
+
+void MuiXtra::close(ObjectType type) {
+    MuiXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void MuiXtra::m_New(int nargs) {
+	g_lingo->printSTUBWithArglist("MuiXtra::m_New", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(MuiXtra::m_Initialize, 0)
+XOBJSTUB(MuiXtra::m_Run, 0)
+XOBJSTUB(MuiXtra::m_Stop, 0)
+XOBJSTUB(MuiXtra::m_WindowOperation, 0)
+XOBJSTUB(MuiXtra::m_ItemUpdate, 0)
+XOBJSTUB(MuiXtra::m_GetWindowPropList, 0)
+XOBJSTUB(MuiXtra::m_GetItemPropList, 0)
+XOBJSTUB(MuiXtra::m_GetWidgetList, 0)
+XOBJSTUB(MuiXtra::m_Alert, 0)
+XOBJSTUB(MuiXtra::m_GetUrl, 0)
+XOBJSTUB(MuiXtra::m_FileOpen, 0)
+XOBJSTUB(MuiXtra::m_FileSave, 0)
+XOBJSTUB(MuiXtra::m_MoaErrorToString, 0)
+
+}
diff --git a/engines/director/lingo/xtras/m/mui.h b/engines/director/lingo/xtras/m/mui.h
new file mode 100644
index 00000000000..2f99951bc8d
--- /dev/null
+++ b/engines/director/lingo/xtras/m/mui.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_XTRAS_M_MUI_H
+#define DIRECTOR_LINGO_XTRAS_M_MUI_H
+
+namespace Director {
+
+class MuiXtraObject : public Object<MuiXtraObject> {
+public:
+	MuiXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace MuiXtra {
+
+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_Initialize(int nargs);
+void m_Run(int nargs);
+void m_Stop(int nargs);
+void m_WindowOperation(int nargs);
+void m_ItemUpdate(int nargs);
+void m_GetWindowPropList(int nargs);
+void m_GetItemPropList(int nargs);
+void m_GetWidgetList(int nargs);
+void m_Alert(int nargs);
+void m_GetUrl(int nargs);
+void m_FileOpen(int nargs);
+void m_FileSave(int nargs);
+void m_MoaErrorToString(int nargs);
+
+} // End of namespace MuiXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xtras/r/registryreader.cpp b/engines/director/lingo/xtras/r/registryreader.cpp
new file mode 100644
index 00000000000..d5d060e1b9e
--- /dev/null
+++ b/engines/director/lingo/xtras/r/registryreader.cpp
@@ -0,0 +1,118 @@
+/* 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/r/registryreader.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * I Spy Spooky Mansion
+ *
+ **************************************************/
+
+/*
+-- xtra RegistryReader
+-- RegistryReader Xtra in the Magister Goodie series of free Xtras
+-- for Macromedia Director.
+--                         Copyright (C) 1997, Magister Ludi s.r.l.
+--
+-- For other Xtras and multimedia products, check out www.magisterludi.com
+--
+--
+new object me -- do not instantiate this Xtra - it is not needed!
+* GetPrivateProfileString string fileName, sectionName, keyName, defaultStr
+                           -- a wrapper for Windows' GetPrivateProfileString
+* ReadRegistryValue string keyName, valueName
+                           -- reads the key/value in the registry
+                           -- keyName should include "HKEY_CURRENT_USER"
+                           -- or "HKEY_LOCAL_MACHINE"
+
+ */
+
+namespace Director {
+
+const char *RegistryReaderXtra::xlibName = "RegistryReader";
+const XlibFileDesc RegistryReaderXtra::fileNames[] = {
+	{ "registryreader",   nullptr },
+	{ "RegRead",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				RegistryReaderXtra::m_new,		 0, 0,	500 },
+
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "GetPrivateProfileString", RegistryReaderXtra::m_GetPrivateProfileString, 4, 4, 500, HBLTIN },
+	{ "ReadRegistryValue", RegistryReaderXtra::m_ReadRegistryValue, 2, 2, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+RegistryReaderXtraObject::RegistryReaderXtraObject(ObjectType ObjectType) :Object<RegistryReaderXtraObject>("RegistryReader") {
+	_objType = ObjectType;
+}
+
+bool RegistryReaderXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum RegistryReaderXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(RegistryReaderXtra::xlibName);
+	warning("RegistryReaderXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void RegistryReaderXtra::open(ObjectType type, const Common::Path &path) {
+    RegistryReaderXtraObject::initMethods(xlibMethods);
+    RegistryReaderXtraObject *xobj = new RegistryReaderXtraObject(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);
+}
+
+void RegistryReaderXtra::close(ObjectType type) {
+    RegistryReaderXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void RegistryReaderXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("RegistryReaderXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(RegistryReaderXtra::m_GetPrivateProfileString, 0)
+XOBJSTUB(RegistryReaderXtra::m_ReadRegistryValue, 0)
+
+}
diff --git a/engines/director/lingo/xtras/r/registryreader.h b/engines/director/lingo/xtras/r/registryreader.h
new file mode 100644
index 00000000000..c1e8d112b2a
--- /dev/null
+++ b/engines/director/lingo/xtras/r/registryreader.h
@@ -0,0 +1,51 @@
+/* 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_R_REGISTRYREADER_H
+#define DIRECTOR_LINGO_XTRAS_R_REGISTRYREADER_H
+
+namespace Director {
+
+class RegistryReaderXtraObject : public Object<RegistryReaderXtraObject> {
+public:
+	RegistryReaderXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace RegistryReaderXtra {
+
+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_GetPrivateProfileString(int nargs);
+void m_ReadRegistryValue(int nargs);
+
+} // End of namespace RegistryReaderXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 047a956a6fb..ebf3a72b5c6 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -176,13 +176,17 @@ MODULE_OBJS = \
 	lingo/xlibs/x/xsoundxfcn.o \
 	lingo/xlibs/x/xwin.o \
 	lingo/xlibs/y/yasix.o \
+	lingo/xtras/b/budapi.o \
 	lingo/xtras/directsound.o \
+	lingo/xtras/d/displayres.o \
 	lingo/xtras/filextra.o \
 	lingo/xtras/keypoll.o \
 	lingo/xtras/masterapp.o \
+	lingo/xtras/m/mui.o \
 	lingo/xtras/openurl.o \
 	lingo/xtras/oscheck.o \
 	lingo/xtras/qtvrxtra.o \
+	lingo/xtras/r/registryreader.o \
 	lingo/xtras/rtk.o \
 	lingo/xtras/scrnutil.o \
 	lingo/xtras/timextra.o \


Commit: 9323fab977ae73f075a03f5295245dc37086c8d1
    https://github.com/scummvm/scummvm/commit/9323fab977ae73f075a03f5295245dc37086c8d1
Author: Scott Percival (code at moral.net.au)
Date: 2025-11-02T01:12:55+01:00

Commit Message:
DIRECTOR: XTRA: Add Audio and Smacker

Changed paths:
  A engines/director/lingo/xtras/a/audio.cpp
  A engines/director/lingo/xtras/a/audio.h
  A engines/director/lingo/xtras/s/smacker.cpp
  A engines/director/lingo/xtras/s/smacker.h
    devtools/director-generate-xobj-stub.py
    engines/director/lingo/lingo-object.cpp
    engines/director/module.mk


diff --git a/devtools/director-generate-xobj-stub.py b/devtools/director-generate-xobj-stub.py
index 54ee98335ec..f46b5b4a144 100755
--- a/devtools/director-generate-xobj-stub.py
+++ b/devtools/director-generate-xobj-stub.py
@@ -1052,8 +1052,9 @@ def main() -> None:
             args.dry_run,
         )
     elif xcode["type"] == "Xtra":
+        version = args.version if args.version > 500 else 500
         generate_xtra_stubs(
-            xcode["method_table"], slug, name, xcode["filename"], args.version, args.dry_run
+            xcode["method_table"], slug, name, xcode["filename"], version, args.dry_run
         )
     elif xcode["type"] == "XFCN" or xcode["type"] == "XCMD":
         generate_xcmd_stubs(
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 597f9da21cd..4bf4d0c0721 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -144,6 +144,7 @@
 #include "director/lingo/xlibs/x/xsoundxfcn.h"
 #include "director/lingo/xlibs/x/xwin.h"
 #include "director/lingo/xlibs/y/yasix.h"
+#include "director/lingo/xtras/a/audio.h"
 #include "director/lingo/xtras/b/budapi.h"
 #include "director/lingo/xtras/directsound.h"
 #include "director/lingo/xtras/d/displayres.h"
@@ -158,6 +159,7 @@
 #include "director/lingo/xtras/r/registryreader.h"
 #include "director/lingo/xtras/rtk.h"
 #include "director/lingo/xtras/scrnutil.h"
+#include "director/lingo/xtras/s/smacker.h"
 #include "director/lingo/xtras/timextra.h"
 #include "director/lingo/xtras/xsound.h"
 
@@ -237,6 +239,7 @@ static const struct XLibProto {
 	XLIBDEF(AiffXObj,			kXObj,			400),	// D4
 	XLIBDEF(AppleCDXObj,		kXObj,			300),	// D3
 	XLIBDEF(AskUser,			kXObj,			400),	// D4
+	XLIBDEF(AudioXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(BackdropXObj,		kXObj,			400),	// D4
 	XLIBDEF(BarakeObj,			kXObj,			400),	// D4
 	XLIBDEF(BatQT,				kXObj,			400),	// D4
@@ -337,6 +340,7 @@ static const struct XLibProto {
 	XLIBDEF(RolloverToolkitXtra,kXtraObj,		500),	// D5
 	XLIBDEF(ScrnUtilXtra,		kXtraObj,		500),	// D5
 	XLIBDEF(SerialPortXObj,		kXObj,			200),	// D2
+	XLIBDEF(SmackerXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(SmallUtilXObj,		kXObj,			400),	// D4
 	XLIBDEF(SoundJam,			kXObj,			400),	// D4
 	XLIBDEF(SpaceMgr,			kXObj,			400),	// D4
diff --git a/engines/director/lingo/xtras/a/audio.cpp b/engines/director/lingo/xtras/a/audio.cpp
new file mode 100644
index 00000000000..96c0f711f22
--- /dev/null
+++ b/engines/director/lingo/xtras/a/audio.cpp
@@ -0,0 +1,199 @@
+/* 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/a/audio.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * [insert game here]
+ *
+ **************************************************/
+
+/*
+-- xtra audio
+--
+-- Audio Xtra
+-- Published by updateStage
+--
+-- Sales: sales at updatestage.com, (781) 641-6043
+-- Technical support: support at updatestage.com, (781) 641-6043
+-- Web: http://www.updatestage.com
+-- Written by Scott Kildall, Red Eye Software
+--Copyright 1996-1998,  Red Eye Software
+
+new object me,  integer bufferSize
+forget object me
+
++ Register  object xtraRef, string serialNumber -- Registers the Sound Xtra. THIS MUST BE CALLED FOR YOUR RUNTIME (PROJECTOR) FILES
+GetError object me   -- returns the last error number
+GetInfo object me, integer identifier --  returns specific information
+SetInfo object me, integer identifier, integer setting --  sets specific information
+Status object me   -- returns the status of a sound
+ConnectInputDevice object me -- connects to the sound recorder
+DisconnectInputDevice object me -- disconnects from the sound recorder
+SetSoundType object me, string type, string name, string action -- specifies a file for sound recording or playback
+ClearSoundType object me   -- clears information about the sound file
+Play object me   -- plays a sound
+Record object me   -- records a sound
+Stop object me   -- stops a sound
+Pause object me   -- pauses a sound
+Resume object me  -- resumes a paused sound
+GetCurrentTime object me   -- returns the playback time of a sound
+IsASound object me, string type, string name  -- indicates if this sound exists
+DeleteSound object me, string type, string name  -- deletes a sound
+SetPlaySegment object me, int start, int end  -- sets the start and end points of a playback sound
+ClearPlaySegment object me   -- resets the start and end points
+SetSampleRate object me, integer rate    -- sets the sample rate of a sound
+SetSampleDepth object me, integer depth   -- sets the sample depth of a sound
+SetCompression object me, integer compressor   --  sets a compressor for the sound
+GetInputLevel object me   -- returns the input level of the microphone
+FreeRecordingTime object me --  returns the free recording time
+
+-- Wave-plotting functions
+SetForegroundColor object me, integer red, integer green, integer blue -- sets the foreground color for wave-plotting
+SetBackgroundColor object me, integer red, integer green, integer blue -- sets the background color for wave-plotting
+PlotWaveform  object me, member bitmapCastMember, integer width, integer height, integer dotsPerX, integer timebase, integer normalize -- generates a waveform
+--
+
+ */
+
+namespace Director {
+
+const char *AudioXtra::xlibName = "Audio";
+const XlibFileDesc AudioXtra::fileNames[] = {
+	{ "audio",   nullptr },
+	{ "Resaudio",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				AudioXtra::m_new,		 1, 1,	500 },
+	{ "forget",				AudioXtra::m_forget,		 0, 0,	500 },
+	{ "GetError",				AudioXtra::m_GetError,		 0, 0,	500 },
+	{ "GetInfo",				AudioXtra::m_GetInfo,		 1, 1,	500 },
+	{ "SetInfo",				AudioXtra::m_SetInfo,		 2, 2,	500 },
+	{ "Status",				AudioXtra::m_Status,		 0, 0,	500 },
+	{ "ConnectInputDevice",				AudioXtra::m_ConnectInputDevice,		 0, 0,	500 },
+	{ "DisconnectInputDevice",				AudioXtra::m_DisconnectInputDevice,		 0, 0,	500 },
+	{ "SetSoundType",				AudioXtra::m_SetSoundType,		 3, 3,	500 },
+	{ "ClearSoundType",				AudioXtra::m_ClearSoundType,		 0, 0,	500 },
+	{ "Play",				AudioXtra::m_Play,		 0, 0,	500 },
+	{ "Record",				AudioXtra::m_Record,		 0, 0,	500 },
+	{ "Stop",				AudioXtra::m_Stop,		 0, 0,	500 },
+	{ "Pause",				AudioXtra::m_Pause,		 0, 0,	500 },
+	{ "Resume",				AudioXtra::m_Resume,		 0, 0,	500 },
+	{ "GetCurrentTime",				AudioXtra::m_GetCurrentTime,		 0, 0,	500 },
+	{ "IsASound",				AudioXtra::m_IsASound,		 2, 2,	500 },
+	{ "DeleteSound",				AudioXtra::m_DeleteSound,		 2, 2,	500 },
+	{ "SetPlaySegment",				AudioXtra::m_SetPlaySegment,		 2, 2,	500 },
+	{ "ClearPlaySegment",				AudioXtra::m_ClearPlaySegment,		 0, 0,	500 },
+	{ "SetSampleRate",				AudioXtra::m_SetSampleRate,		 1, 1,	500 },
+	{ "SetSampleDepth",				AudioXtra::m_SetSampleDepth,		 1, 1,	500 },
+	{ "SetCompression",				AudioXtra::m_SetCompression,		 1, 1,	500 },
+	{ "GetInputLevel",				AudioXtra::m_GetInputLevel,		 0, 0,	500 },
+	{ "FreeRecordingTime",				AudioXtra::m_FreeRecordingTime,		 0, 0,	500 },
+	{ "SetForegroundColor",				AudioXtra::m_SetForegroundColor,		 3, 3,	500 },
+	{ "SetBackgroundColor",				AudioXtra::m_SetBackgroundColor,		 3, 3,	500 },
+	{ "PlotWaveform",				AudioXtra::m_PlotWaveform,		 6, 6,	500 },
+	{ "Register",				AudioXtra::m_Register,		 1, 1,	500 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+AudioXtraObject::AudioXtraObject(ObjectType ObjectType) :Object<AudioXtraObject>("Audio") {
+	_objType = ObjectType;
+}
+
+bool AudioXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum AudioXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(AudioXtra::xlibName);
+	warning("AudioXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void AudioXtra::open(ObjectType type, const Common::Path &path) {
+    AudioXtraObject::initMethods(xlibMethods);
+    AudioXtraObject *xobj = new AudioXtraObject(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);
+}
+
+void AudioXtra::close(ObjectType type) {
+    AudioXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void AudioXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("AudioXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(AudioXtra::m_forget, 0)
+XOBJSTUB(AudioXtra::m_Register, 0)
+XOBJSTUB(AudioXtra::m_GetError, 0)
+XOBJSTUB(AudioXtra::m_GetInfo, 0)
+XOBJSTUB(AudioXtra::m_SetInfo, 0)
+XOBJSTUB(AudioXtra::m_Status, 0)
+XOBJSTUB(AudioXtra::m_ConnectInputDevice, 0)
+XOBJSTUB(AudioXtra::m_DisconnectInputDevice, 0)
+XOBJSTUB(AudioXtra::m_SetSoundType, 0)
+XOBJSTUB(AudioXtra::m_ClearSoundType, 0)
+XOBJSTUB(AudioXtra::m_Play, 0)
+XOBJSTUB(AudioXtra::m_Record, 0)
+XOBJSTUB(AudioXtra::m_Stop, 0)
+XOBJSTUB(AudioXtra::m_Pause, 0)
+XOBJSTUB(AudioXtra::m_Resume, 0)
+XOBJSTUB(AudioXtra::m_GetCurrentTime, 0)
+XOBJSTUB(AudioXtra::m_IsASound, 0)
+XOBJSTUB(AudioXtra::m_DeleteSound, 0)
+XOBJSTUB(AudioXtra::m_SetPlaySegment, 0)
+XOBJSTUB(AudioXtra::m_ClearPlaySegment, 0)
+XOBJSTUB(AudioXtra::m_SetSampleRate, 0)
+XOBJSTUB(AudioXtra::m_SetSampleDepth, 0)
+XOBJSTUB(AudioXtra::m_SetCompression, 0)
+XOBJSTUB(AudioXtra::m_GetInputLevel, 0)
+XOBJSTUB(AudioXtra::m_FreeRecordingTime, 0)
+XOBJSTUB(AudioXtra::m_SetForegroundColor, 0)
+XOBJSTUB(AudioXtra::m_SetBackgroundColor, 0)
+XOBJSTUB(AudioXtra::m_PlotWaveform, 0)
+
+}
diff --git a/engines/director/lingo/xtras/a/audio.h b/engines/director/lingo/xtras/a/audio.h
new file mode 100644
index 00000000000..36d6cacfc9f
--- /dev/null
+++ b/engines/director/lingo/xtras/a/audio.h
@@ -0,0 +1,77 @@
+/* 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_A_AUDIO_H
+#define DIRECTOR_LINGO_XTRAS_A_AUDIO_H
+
+namespace Director {
+
+class AudioXtraObject : public Object<AudioXtraObject> {
+public:
+	AudioXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace AudioXtra {
+
+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_forget(int nargs);
+void m_Register(int nargs);
+void m_GetError(int nargs);
+void m_GetInfo(int nargs);
+void m_SetInfo(int nargs);
+void m_Status(int nargs);
+void m_ConnectInputDevice(int nargs);
+void m_DisconnectInputDevice(int nargs);
+void m_SetSoundType(int nargs);
+void m_ClearSoundType(int nargs);
+void m_Play(int nargs);
+void m_Record(int nargs);
+void m_Stop(int nargs);
+void m_Pause(int nargs);
+void m_Resume(int nargs);
+void m_GetCurrentTime(int nargs);
+void m_IsASound(int nargs);
+void m_DeleteSound(int nargs);
+void m_SetPlaySegment(int nargs);
+void m_ClearPlaySegment(int nargs);
+void m_SetSampleRate(int nargs);
+void m_SetSampleDepth(int nargs);
+void m_SetCompression(int nargs);
+void m_GetInputLevel(int nargs);
+void m_FreeRecordingTime(int nargs);
+void m_SetForegroundColor(int nargs);
+void m_SetBackgroundColor(int nargs);
+void m_PlotWaveform(int nargs);
+
+} // End of namespace AudioXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/lingo/xtras/s/smacker.cpp b/engines/director/lingo/xtras/s/smacker.cpp
new file mode 100644
index 00000000000..2c2642a941c
--- /dev/null
+++ b/engines/director/lingo/xtras/s/smacker.cpp
@@ -0,0 +1,207 @@
+/* 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/s/smacker.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * I Spy Spooky House
+ *
+ **************************************************/
+
+/*
+-- xtra Smacker
+-- An Xtra for playing Smacker animations.
+--  Version 3.1q
+------------------------------------------
+new object
+*SmackQuickPlay string, integer, integer, string
+*SmackQuickPlayTrans string, integer, integer, integer, integer, integer
+SmackOpen object, string, integer, integer
+SmackOpenTrans object, string, integer, integer, integer, integer, integer
+SmackClose object
+SmackPlay object
+SmackPlayFrames object, integer, integer
+SmackPlayLooped object, integer
+SmackPlayNext object, integer
+SmackRemapToSystemPalette object
+SmackRemapToPalette object, string, string
+SmackRemapToBitmap object, string, string
+SmackSetWindowStyle object, string
+SmackSetWindowTitle object, string
+SmackSetTransBackground object, string, string, integer, integer, integer
+SmackSetInterfaceKeys object, string
+SmackSetBitmap object, string, string
+SmackSetPosition object, integer, integer
+SmackSetAlignment object, integer
+SmackGoto object, integer
+SmackGetFramesPerSecond object
+SmackGetFrameNum object
+SmackGetFrames object
+SmackGetHeight object
+SmackGetWidth object
+SmackGetLastKey object
+SmackGetMouseX object
+SmackGetMouseY object
+SmackGetMouseClickX object
+SmackGetMouseClickY object
+SmackHideVideo object, integer
+SmackSetDisplayMode object, integer
+SmackGetSummary object
+SmackScreenMethod object, integer
+
+ */
+
+namespace Director {
+
+const char *SmackerXtra::xlibName = "Smacker";
+const XlibFileDesc SmackerXtra::fileNames[] = {
+	{ "smacker",   nullptr },
+	{ "Smackx32",   nullptr },
+	{ "SmackerXtra",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				SmackerXtra::m_new,		 0, 0,	500 },
+	{ "SmackOpen",				SmackerXtra::m_SmackOpen,		 3, 3,	500 },
+	{ "SmackOpenTrans",				SmackerXtra::m_SmackOpenTrans,		 6, 6,	500 },
+	{ "SmackClose",				SmackerXtra::m_SmackClose,		 0, 0,	500 },
+	{ "SmackPlay",				SmackerXtra::m_SmackPlay,		 0, 0,	500 },
+	{ "SmackPlayFrames",				SmackerXtra::m_SmackPlayFrames,		 2, 2,	500 },
+	{ "SmackPlayLooped",				SmackerXtra::m_SmackPlayLooped,		 1, 1,	500 },
+	{ "SmackPlayNext",				SmackerXtra::m_SmackPlayNext,		 1, 1,	500 },
+	{ "SmackRemapToSystemPalette",				SmackerXtra::m_SmackRemapToSystemPalette,		 0, 0,	500 },
+	{ "SmackRemapToPalette",				SmackerXtra::m_SmackRemapToPalette,		 2, 2,	500 },
+	{ "SmackRemapToBitmap",				SmackerXtra::m_SmackRemapToBitmap,		 2, 2,	500 },
+	{ "SmackSetWindowStyle",				SmackerXtra::m_SmackSetWindowStyle,		 1, 1,	500 },
+	{ "SmackSetWindowTitle",				SmackerXtra::m_SmackSetWindowTitle,		 1, 1,	500 },
+	{ "SmackSetTransBackground",				SmackerXtra::m_SmackSetTransBackground,		 5, 5,	500 },
+	{ "SmackSetInterfaceKeys",				SmackerXtra::m_SmackSetInterfaceKeys,		 1, 1,	500 },
+	{ "SmackSetBitmap",				SmackerXtra::m_SmackSetBitmap,		 2, 2,	500 },
+	{ "SmackSetPosition",				SmackerXtra::m_SmackSetPosition,		 2, 2,	500 },
+	{ "SmackSetAlignment",				SmackerXtra::m_SmackSetAlignment,		 1, 1,	500 },
+	{ "SmackGoto",				SmackerXtra::m_SmackGoto,		 1, 1,	500 },
+	{ "SmackGetFramesPerSecond",				SmackerXtra::m_SmackGetFramesPerSecond,		 0, 0,	500 },
+	{ "SmackGetFrameNum",				SmackerXtra::m_SmackGetFrameNum,		 0, 0,	500 },
+	{ "SmackGetFrames",				SmackerXtra::m_SmackGetFrames,		 0, 0,	500 },
+	{ "SmackGetHeight",				SmackerXtra::m_SmackGetHeight,		 0, 0,	500 },
+	{ "SmackGetWidth",				SmackerXtra::m_SmackGetWidth,		 0, 0,	500 },
+	{ "SmackGetLastKey",				SmackerXtra::m_SmackGetLastKey,		 0, 0,	500 },
+	{ "SmackGetMouseX",				SmackerXtra::m_SmackGetMouseX,		 0, 0,	500 },
+	{ "SmackGetMouseY",				SmackerXtra::m_SmackGetMouseY,		 0, 0,	500 },
+	{ "SmackGetMouseClickX",				SmackerXtra::m_SmackGetMouseClickX,		 0, 0,	500 },
+	{ "SmackGetMouseClickY",				SmackerXtra::m_SmackGetMouseClickY,		 0, 0,	500 },
+	{ "SmackHideVideo",				SmackerXtra::m_SmackHideVideo,		 1, 1,	500 },
+	{ "SmackSetDisplayMode",				SmackerXtra::m_SmackSetDisplayMode,		 1, 1,	500 },
+	{ "SmackGetSummary",				SmackerXtra::m_SmackGetSummary,		 0, 0,	500 },
+	{ "SmackScreenMethod",				SmackerXtra::m_SmackScreenMethod,		 1, 1,	500 },
+
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "SmackQuickPlay", SmackerXtra::m_SmackQuickPlay, 4, 4, 500, HBLTIN },
+	{ "SmackQuickPlayTrans", SmackerXtra::m_SmackQuickPlayTrans, 6, 6, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+SmackerXtraObject::SmackerXtraObject(ObjectType ObjectType) :Object<SmackerXtraObject>("Smacker") {
+	_objType = ObjectType;
+}
+
+bool SmackerXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum SmackerXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(SmackerXtra::xlibName);
+	warning("SmackerXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void SmackerXtra::open(ObjectType type, const Common::Path &path) {
+    SmackerXtraObject::initMethods(xlibMethods);
+    SmackerXtraObject *xobj = new SmackerXtraObject(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);
+}
+
+void SmackerXtra::close(ObjectType type) {
+    SmackerXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void SmackerXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("SmackerXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(SmackerXtra::m_SmackQuickPlay, 0)
+XOBJSTUB(SmackerXtra::m_SmackQuickPlayTrans, 0)
+XOBJSTUB(SmackerXtra::m_SmackOpen, 0)
+XOBJSTUB(SmackerXtra::m_SmackOpenTrans, 0)
+XOBJSTUB(SmackerXtra::m_SmackClose, 0)
+XOBJSTUB(SmackerXtra::m_SmackPlay, 0)
+XOBJSTUB(SmackerXtra::m_SmackPlayFrames, 0)
+XOBJSTUB(SmackerXtra::m_SmackPlayLooped, 0)
+XOBJSTUB(SmackerXtra::m_SmackPlayNext, 0)
+XOBJSTUB(SmackerXtra::m_SmackRemapToSystemPalette, 0)
+XOBJSTUB(SmackerXtra::m_SmackRemapToPalette, 0)
+XOBJSTUB(SmackerXtra::m_SmackRemapToBitmap, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetWindowStyle, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetWindowTitle, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetTransBackground, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetInterfaceKeys, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetBitmap, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetPosition, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetAlignment, 0)
+XOBJSTUB(SmackerXtra::m_SmackGoto, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetFramesPerSecond, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetFrameNum, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetFrames, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetHeight, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetWidth, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetLastKey, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetMouseX, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetMouseY, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetMouseClickX, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetMouseClickY, 0)
+XOBJSTUB(SmackerXtra::m_SmackHideVideo, 0)
+XOBJSTUB(SmackerXtra::m_SmackSetDisplayMode, 0)
+XOBJSTUB(SmackerXtra::m_SmackGetSummary, 0)
+XOBJSTUB(SmackerXtra::m_SmackScreenMethod, 0)
+
+}
diff --git a/engines/director/lingo/xtras/s/smacker.h b/engines/director/lingo/xtras/s/smacker.h
new file mode 100644
index 00000000000..635c26a2491
--- /dev/null
+++ b/engines/director/lingo/xtras/s/smacker.h
@@ -0,0 +1,83 @@
+/* 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_S_SMACKER_H
+#define DIRECTOR_LINGO_XTRAS_S_SMACKER_H
+
+namespace Director {
+
+class SmackerXtraObject : public Object<SmackerXtraObject> {
+public:
+	SmackerXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace SmackerXtra {
+
+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_SmackQuickPlay(int nargs);
+void m_SmackQuickPlayTrans(int nargs);
+void m_SmackOpen(int nargs);
+void m_SmackOpenTrans(int nargs);
+void m_SmackClose(int nargs);
+void m_SmackPlay(int nargs);
+void m_SmackPlayFrames(int nargs);
+void m_SmackPlayLooped(int nargs);
+void m_SmackPlayNext(int nargs);
+void m_SmackRemapToSystemPalette(int nargs);
+void m_SmackRemapToPalette(int nargs);
+void m_SmackRemapToBitmap(int nargs);
+void m_SmackSetWindowStyle(int nargs);
+void m_SmackSetWindowTitle(int nargs);
+void m_SmackSetTransBackground(int nargs);
+void m_SmackSetInterfaceKeys(int nargs);
+void m_SmackSetBitmap(int nargs);
+void m_SmackSetPosition(int nargs);
+void m_SmackSetAlignment(int nargs);
+void m_SmackGoto(int nargs);
+void m_SmackGetFramesPerSecond(int nargs);
+void m_SmackGetFrameNum(int nargs);
+void m_SmackGetFrames(int nargs);
+void m_SmackGetHeight(int nargs);
+void m_SmackGetWidth(int nargs);
+void m_SmackGetLastKey(int nargs);
+void m_SmackGetMouseX(int nargs);
+void m_SmackGetMouseY(int nargs);
+void m_SmackGetMouseClickX(int nargs);
+void m_SmackGetMouseClickY(int nargs);
+void m_SmackHideVideo(int nargs);
+void m_SmackSetDisplayMode(int nargs);
+void m_SmackGetSummary(int nargs);
+void m_SmackScreenMethod(int nargs);
+
+} // End of namespace SmackerXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index ebf3a72b5c6..8df82063a31 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -177,6 +177,7 @@ MODULE_OBJS = \
 	lingo/xlibs/x/xwin.o \
 	lingo/xlibs/y/yasix.o \
 	lingo/xtras/b/budapi.o \
+	lingo/xtras/a/audio.o \
 	lingo/xtras/directsound.o \
 	lingo/xtras/d/displayres.o \
 	lingo/xtras/filextra.o \
@@ -189,6 +190,7 @@ MODULE_OBJS = \
 	lingo/xtras/r/registryreader.o \
 	lingo/xtras/rtk.o \
 	lingo/xtras/scrnutil.o \
+	lingo/xtras/s/smacker.o \
 	lingo/xtras/timextra.o \
 	lingo/xtras/xsound.o
 


Commit: 9e39b9aaa9f58dedf6205241e36616fde97ccb68
    https://github.com/scummvm/scummvm/commit/9e39b9aaa9f58dedf6205241e36616fde97ccb68
Author: Scott Percival (code at moral.net.au)
Date: 2025-11-02T01:12:55+01:00

Commit Message:
DIRECTOR: LINGO: Implement b_symbol

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-builtins.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 8e8513e5a24..a4bfa867729 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -164,6 +164,7 @@ static const BuiltinProto builtins[] = {
 	{ "pictureP",		LB::b_pictureP,		1, 1, 400, FBLTIN },	//			D4 f
 	{ "stringp",		LB::b_stringp,		1, 1, 200, FBLTIN },	// D2 f
 	{ "symbolp",		LB::b_symbolp,		1, 1, 200, FBLTIN },	// D2 f
+	{ "symbol",		LB::b_symbol,		1, 1, 600, FBLTIN },	//							D6 f
 	{ "voidP",			LB::b_voidP,		1, 1, 400, FBLTIN },	//			D4 f
 	// Misc
 	{ "alert",	 		LB::b_alert,		1, 1, 200, CBLTIN },	// D2 c
@@ -2398,12 +2399,48 @@ void LB::b_stringp(int nargs) {
 	g_lingo->push(res);
 }
 
+void LB::b_symbol(int nargs) {
+	Datum d = g_lingo->pop();
+	switch (d.type) {
+	case SYMBOL:
+		g_lingo->push(d);
+		break;
+	case STRING:
+		{
+			Common::String payload = d.asString();
+			if ((payload.size() == 0) || ((payload.size() == 1) && (payload[0] == ' '))) {
+				payload = "";
+			} else if (payload.size() == 1) {
+				// if the string is one character, allow it
+				// unless it's space, in which case return a zero-length symbol
+			} else {
+				// if the string is more than one character, cut it at the first non [a-zA-Z0-9_] character
+				for (unsigned int i = 0; i < payload.size(); i++) {
+					if (!Common::isAlnum(payload[i]) && (payload[i] != '_')) {
+						payload = payload.substr(0, i);
+						break;
+					}
+				}
+			}
+
+			Datum result(payload);
+			result.type = SYMBOL;
+			g_lingo->push(result);
+		}
+		break;
+	default:
+		g_lingo->pushVoid();
+		break;
+	}
+}
+
 void LB::b_symbolp(int nargs) {
 	Datum d = g_lingo->pop();
 	Datum res((d.type == SYMBOL) ? 1 : 0);
 	g_lingo->push(res);
 }
 
+
 void LB::b_voidP(int nargs) {
 	Datum d = g_lingo->pop();
 	Datum res((d.type == VOID) ? 1 : 0);
diff --git a/engines/director/lingo/lingo-builtins.h b/engines/director/lingo/lingo-builtins.h
index 07d6e40d545..8ed64049131 100644
--- a/engines/director/lingo/lingo-builtins.h
+++ b/engines/director/lingo/lingo-builtins.h
@@ -83,6 +83,7 @@ void b_integerp(int nargs);
 void b_objectp(int nargs);
 void b_pictureP(int nargs);
 void b_stringp(int nargs);
+void b_symbol(int nargs);
 void b_symbolp(int nargs);
 void b_voidP(int nargs);
 




More information about the Scummvm-git-logs mailing list