[Scummvm-git-logs] scummvm master -> 1f8de850f030a72141fea74c0047edbd08fdcf2b

sev- noreply at scummvm.org
Sat Feb 8 13:46:01 UTC 2025


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

Summary:
b0742e6e6d DIRECTOR: LINGO: Add sprite reference datum type
3c3794fc0f DIRECTOR: LINGO: Make Movie::getHandler accept a castLib hint
8b207537b8 DIRECTOR: LINGO: Add the searchPaths property
a71ec6fc78 DIRECTOR: XTRA: Add alias for PrintOMatic
fa8e65de44 DIRECTOR: Attempt to auto-load Xtras from path
5b0a0b1497 DIRECTOR: LINGO: Allow referencing "me" from cb_thepush
44d18e7392 DIRECTOR: Fix palette bounds check when converting BitmapCastMember from 8 to 32 bit
7b0934135f DIRECTOR: Add FilmLoopCastMember loader for D5
1f8de850f0 DIRECTOR: Quieten benign warnings


Commit: b0742e6e6d126efa156a5cc01291bbbf1638b966
    https://github.com/scummvm/scummvm/commit/b0742e6e6d126efa156a5cc01291bbbf1638b966
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: LINGO: Add sprite reference datum type

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index d09244c8dd4..7705397463b 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -233,8 +233,9 @@ static const BuiltinProto builtins[] = {
 	// References
 	{ "cast",			LB::b_cast,			1, 1, 400, FBLTIN },	//			D4 f
 	{ "castLib",		LB::b_castLib,		1, 1, 500, FBLTIN },	//				D5 f
-	{ "member",			LB::b_member,		1, 2, 500, FBLTIN },	//				D5 f
+	{ "member",			LB::b_member,		1, 1, 500, FBLTIN },	//				D5 f
 	{ "script",			LB::b_script,		1, 1, 400, FBLTIN },	//			D4 f
+	{ "sprite",			LB::b_sprite,		1, 1, 500, FBLTIN },	//				D5 f
 	{ "window",			LB::b_window,		1, 1, 400, FBLTIN },	//			D4 f
 	{ "windowPresent",	LB::b_windowPresent,1, 1, 500, FBLTIN },	//				D5 f
 	// Field operations
@@ -3168,6 +3169,8 @@ void LB::b_intersect(int nargs) {
 	Datum d;
 	Datum r2 = g_lingo->pop();
 	Datum r1 = g_lingo->pop();
+	TYPECHECK(r1, RECT);
+	TYPECHECK(r2, RECT);
 	Common::Rect rect1(r1.u.farr->arr[0].asInt(), r1.u.farr->arr[1].asInt(), r1.u.farr->arr[2].asInt(), r1.u.farr->arr[3].asInt());
 	Common::Rect rect2(r2.u.farr->arr[0].asInt(), r2.u.farr->arr[1].asInt(), r2.u.farr->arr[2].asInt(), r2.u.farr->arr[3].asInt());
 
@@ -3180,6 +3183,9 @@ void LB::b_inside(int nargs) {
 	Datum d;
 	Datum r2 = g_lingo->pop();
 	Datum p1 = g_lingo->pop();
+	TYPECHECK(r2, RECT);
+	TYPECHECK(p1, POINT);
+
 	Common::Rect rect2(r2.u.farr->arr[0].asInt(), r2.u.farr->arr[1].asInt(), r2.u.farr->arr[2].asInt(), r2.u.farr->arr[3].asInt());
 	Common::Point point1(p1.u.farr->arr[0].asInt(), p1.u.farr->arr[1].asInt());
 
@@ -3476,15 +3482,8 @@ void LB::b_castLib(int nargs) {
 
 void LB::b_member(int nargs) {
 	Movie *movie = g_director->getCurrentMovie();
-	Datum library;
-	Datum member;
-	if (nargs == 1) {
-		member = g_lingo->pop();
-	} else if (nargs == 2) {
-		library = g_lingo->pop();
-		member = g_lingo->pop();
-	}
-	CastMemberID res = g_lingo->toCastMemberID(member, library);
+	Datum member = g_lingo->pop();
+	CastMemberID res = member.asMemberID();
 	if (!movie->getCastMember(res)) {
 		g_lingo->lingoError("No match found for cast member");
 		return;
@@ -3525,6 +3524,13 @@ void LB::b_script(int nargs) {
 	g_lingo->push(Datum());
 }
 
+void LB::b_sprite(int nargs) {
+	Datum d = g_lingo->pop();
+	Datum res(d.asInt());
+	res.type = SPRITEREF;
+	g_lingo->push(res);
+}
+
 void LB::b_window(int nargs) {
 	Datum d = g_lingo->pop();
 	FArray *windowList = g_lingo->_windowList.u.farr;
diff --git a/engines/director/lingo/lingo-builtins.h b/engines/director/lingo/lingo-builtins.h
index 5da53477bbe..b2941b5882c 100644
--- a/engines/director/lingo/lingo-builtins.h
+++ b/engines/director/lingo/lingo-builtins.h
@@ -180,10 +180,6 @@ void b_offsetRect(int nargs);
 void b_rect(int nargs);
 void b_union(int nargs);
 
-void b_member(int nargs);
-void b_window(int nargs);
-void b_windowPresent(int nargs);
-
 void b_beep(int nargs);
 void b_mci(int nargs);
 void b_mciwait(int nargs);
@@ -202,7 +198,11 @@ void b_version(int nargs);
 
 void b_cast(int nargs);
 void b_castLib(int nargs);
+void b_member(int nargs);
 void b_script(int nargs);
+void b_sprite(int nargs);
+void b_window(int nargs);
+void b_windowPresent(int nargs);
 
 void b_charPosToLoc(int nargs);
 void b_linePosToLocV(int nargs);
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index f61cdc54732..035b3bc2eb1 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -972,8 +972,18 @@ void LC::c_intersects() {
 	Datum d1 = g_lingo->pop();
 
 	Score *score = g_director->getCurrentMovie()->getScore();
-	Channel *sprite1 = score->getChannelById(d1.asInt());
-	Channel *sprite2 = score->getChannelById(d2.asInt());
+	Channel *sprite1 = nullptr;
+	Channel *sprite2 = nullptr;
+	if (d1.type == SPRITEREF) {
+		sprite1 = score->getChannelById(d1.u.i);
+	} else {
+		sprite1 = score->getChannelById(d1.asInt());
+	}
+	if (d2.type == SPRITEREF) {
+		sprite2 = score->getChannelById(d2.u.i);
+	} else {
+		sprite2 = score->getChannelById(d2.asInt());
+	}
 
 	if (!sprite1 || !sprite2) {
 		g_lingo->push(Datum(0));
@@ -993,8 +1003,18 @@ void LC::c_within() {
 	Datum d1 = g_lingo->pop();
 
 	Score *score = g_director->getCurrentMovie()->getScore();
-	Channel *sprite1 = score->getChannelById(d1.asInt());
-	Channel *sprite2 = score->getChannelById(d2.asInt());
+	Channel *sprite1 = nullptr;
+	Channel *sprite2 = nullptr;
+	if (d1.type == SPRITEREF) {
+		sprite1 = score->getChannelById(d1.u.i);
+	} else {
+		sprite1 = score->getChannelById(d1.asInt());
+	}
+	if (d2.type == SPRITEREF) {
+		sprite2 = score->getChannelById(d2.u.i);
+	} else {
+		sprite2 = score->getChannelById(d2.asInt());
+	}
 
 	if (!sprite1 || !sprite2) {
 		g_lingo->push(Datum(0));
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 0d91fe3d15d..ffe6cb51787 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -1450,7 +1450,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		return d;
 	}
 
-	if (id1.type == INT) {
+	if ((id1.type == SPRITEREF) || (id1.type == INT)) {
 		id = id1.u.i;
 	} else {
 		warning("Lingo::getTheSprite(): Unknown the sprite id type: %s", id1.type2str());
@@ -1614,15 +1614,22 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 }
 
 void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
-	int id = id1.asInt();
 	Movie *movie = _vm->getCurrentMovie();
 	Score *score = movie->getScore();
+	int id = 0;
 
 	if (!score) {
 		warning("Lingo::setTheSprite(): The sprite %d field \"%s\" setting over non-active score", id, field2str(field));
 		return;
 	}
 
+	if ((id1.type == SPRITEREF) || (id1.type == INT)) {
+		id = id1.u.i;
+	} else {
+		warning("Lingo::setTheSprite(): Unknown the sprite id type: %s", id1.type2str());
+		return;
+	}
+
 	Channel *channel = score->getChannelById(id);
 	if (!channel)
 		return;
@@ -1666,8 +1673,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 
 			if (targetMember != sprite->_castId) {
 				movie->getWindow()->addDirtyRect(channel->getBbox());
-				movie->duplicateCastMember(targetMember, sprite->_castId);
-				channel->_sprite->setCast(sprite->_castId);
+				channel->setCast(targetMember);
 				// Ensure the new sprite, whether larger or smaller, appears correctly on the screen
 				movie->getWindow()->addDirtyRect(channel->getBbox());
 				channel->_dirty = true;
@@ -1681,7 +1687,8 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 			CastMemberID castId = d.asMemberID();
 			if (field == kTheMemberNum) {
 				// Setting the cast ID as a number will preserve whatever is in castLib
-				castId = CastMemberID(d.asInt(), sprite->_castId.castLib);
+				// The member part will be demultiplexed if required, and the castLib portion ignored.
+				castId = CastMemberID(castId.member, sprite->_castId.castLib);
 			} else if (field == kTheCastLibNum) {
 				castId = CastMemberID(sprite->_castId.member, d.asInt());
 			}
@@ -2360,6 +2367,13 @@ void Lingo::getObjectProp(Datum &obj, Common::String &propName) {
 		}
 		g_lingo->push(d);
 		return;
+	} else if (obj.type == SPRITEREF) {
+		Common::String key = Common::String::format("%d%s", kTheSprite, propName.c_str());
+		if (_theEntityFields.contains(key)) {
+			d = getTheSprite(obj, _theEntityFields[key]->field);
+		}
+		g_lingo->push(d);
+		return;
 	}
 
 	if (_builtinFuncs.contains(propName) && _builtinFuncs[propName].nargs == 1) {
@@ -2436,6 +2450,11 @@ void Lingo::setObjectProp(Datum &obj, Common::String &propName, Datum &val) {
 		if (_theEntityFields.contains(key)) {
 			setTheCastLib(obj, _theEntityFields[key]->field, val);
 		}
+	} else if (obj.type == SPRITEREF) {
+		Common::String key = Common::String::format("%d%s", kTheSprite, propName.c_str());
+		if (_theEntityFields.contains(key)) {
+			setTheSprite(obj, _theEntityFields[key]->field, val);
+		}
 	} else {
 		g_lingo->lingoError("Lingo::setObjectProp: Invalid object: %s", obj.asString(true).c_str());
 	}
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index f8205245593..4c4d786c8c3 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -1177,6 +1177,9 @@ Common::String Datum::asString(bool printonly) const {
 	case FIELDREF:
 		s = Common::String::format("field %d of castLib %d", u.cast->member, u.cast->castLib);
 		break;
+	case SPRITEREF:
+		s = Common::String::format("sprite %d", u.i);
+		break;
 	case CHUNKREF:
 		{
 			Common::String chunkType;
diff --git a/engines/director/types.h b/engines/director/types.h
index 72fd4772e20..effb41a6f8a 100644
--- a/engines/director/types.h
+++ b/engines/director/types.h
@@ -382,6 +382,7 @@ enum DatumType {
 	POINT,
 	PROPREF,
 	RECT,
+	SPRITEREF,
 	STRING,
 	SYMBOL,
 	VARREF,


Commit: 3c3794fc0f245b5c3d6439796157003987f3924f
    https://github.com/scummvm/scummvm/commit/3c3794fc0f245b5c3d6439796157003987f3924f
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: LINGO: Make Movie::getHandler accept a castLib hint

When resolving a global function, the castLib of the currently executing
script should be preferenced first. This is important when there are
different global functions with the same name across multiple casts.

Fixes animating the falling leaf-like stick insect in The Gigglebone
Gang World Tour (P2.DXR).

Changed paths:
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-object.cpp
    engines/director/lingo/lingo-object.h
    engines/director/lingo/lingo.cpp
    engines/director/movie.cpp
    engines/director/movie.h


diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index 4f26b7f4b2b..03ef7fc29fb 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -1113,7 +1113,7 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
 	} else {
 		debugC(1, kDebugCompile, "Add V4 script %d: %s %d", scriptId, scriptType2str(scriptType), _assemblyId);
 
-		sc = _assemblyContext = new ScriptContext(!castName.empty() ? castName : Common::String::format("%d", _assemblyId), scriptType, _assemblyId);
+		sc = _assemblyContext = new ScriptContext(!castName.empty() ? castName : Common::String::format("%d", _assemblyId), scriptType, _assemblyId, archive->cast->_castLibID);
 	}
 
 	// initialise each property
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 142c1330762..601defdc412 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -132,7 +132,7 @@ ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoA
 	_assemblyArchive = archive;
 	_assemblyAST = nullptr;
 	_assemblyId = id.member;
-	ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, type, _assemblyId);
+	ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, type, _assemblyId, id.castLib);
 	_currentAssembly = new ScriptData;
 
 	_methodVars = new VarTypeHash;
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index f09aa27c8d0..bedc847577f 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -440,8 +440,8 @@ void LM::m_dispose(int nargs) {
 
 /* ScriptContext */
 
-ScriptContext::ScriptContext(Common::String name, ScriptType type, int id)
-	: Object<ScriptContext>(name), _scriptType(type), _id(id) {
+ScriptContext::ScriptContext(Common::String name, ScriptType type, int id, uint16 castLibHint)
+	: Object<ScriptContext>(name), _scriptType(type), _id(id), _castLibHint(castLibHint) {
 	_objType = kScriptObj;
 }
 
@@ -461,6 +461,7 @@ ScriptContext::ScriptContext(const ScriptContext &sc) : Object<ScriptContext>(sc
 	_propertyNames = sc._propertyNames;
 
 	_id = sc._id;
+	_castLibHint = sc._castLibHint;
 }
 
 ScriptContext::~ScriptContext() {
diff --git a/engines/director/lingo/lingo-object.h b/engines/director/lingo/lingo-object.h
index 1350b41fe29..9bcfd95bfb9 100644
--- a/engines/director/lingo/lingo-object.h
+++ b/engines/director/lingo/lingo-object.h
@@ -214,6 +214,7 @@ class ScriptContext : public Object<ScriptContext> {
 public:
 	ScriptType _scriptType;
 	int _id;
+	uint16 _castLibHint;
 	Common::Array<Common::String> _functionNames; // used by cb_localcall
 	Common::HashMap<Common::String, Common::Array<uint32>> _functionByteOffsets;
 	SymbolHash _functionHandlers;
@@ -229,7 +230,7 @@ private:
 	bool _onlyInLctxContexts = false;
 
 public:
-	ScriptContext(Common::String name, ScriptType type = kNoneScript, int id = 0);
+	ScriptContext(Common::String name, ScriptType type = kNoneScript, int id = 0, uint16 castLibHint = 0);
 	ScriptContext(const ScriptContext &sc);
 	~ScriptContext() override;
 
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 4c4d786c8c3..705a4a978fe 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -338,7 +338,7 @@ Symbol Lingo::getHandler(const Common::String &name) {
 	if (_state->context && _state->context->_functionHandlers.contains(name))
 		return _state->context->_functionHandlers[name];
 
-	sym = g_director->getCurrentMovie()->getHandler(name);
+	sym = g_director->getCurrentMovie()->getHandler(name, _state->context->_castLibHint);
 	if (sym.type != VOIDSYM)
 		return sym;
 
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index afac709ed4a..193b95259a5 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -625,7 +625,13 @@ ScriptContext *Movie::getScriptContext(ScriptType type, CastMemberID id) {
 	return result;
 }
 
-Symbol Movie::getHandler(const Common::String &name) {
+Symbol Movie::getHandler(const Common::String &name, uint16 castLibHint) {
+	// Always check the current cast library for a match first
+	if (castLibHint && _casts.contains(castLibHint)) {
+		Cast *cast = _casts.getVal(castLibHint);
+		if (cast->_lingoArchive->functionHandlers.contains(name))
+			return cast->_lingoArchive->functionHandlers[name];
+	}
 	for (auto &it : _casts) {
 		if (it._value->_lingoArchive->functionHandlers.contains(name))
 			return it._value->_lingoArchive->functionHandlers[name];
diff --git a/engines/director/movie.h b/engines/director/movie.h
index b78a431b4bd..b61162a5051 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -123,7 +123,7 @@ public:
 	LingoArchive *getMainLingoArch();
 	LingoArchive *getSharedLingoArch();
 	ScriptContext *getScriptContext(ScriptType type, CastMemberID id);
-	Symbol getHandler(const Common::String &name);
+	Symbol getHandler(const Common::String &name, uint16 castLibHint = 0);
 
 	// events.cpp
 	bool processEvent(Common::Event &event);


Commit: 8b207537b83002b6a276742a6286aa633c9b8bfc
    https://github.com/scummvm/scummvm/commit/8b207537b83002b6a276742a6286aa633c9b8bfc
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: LINGO: Add the searchPaths property

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


diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index ffe6cb51787..e4bf96203cc 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -146,6 +146,7 @@ TheEntity entities[] = {					//	hasId  ver.	isFunction
 	{ kTheScummvmVersion,	"scummvmVersion",	false, 200, true }, // 					ScummVM only
 	{ kTheSearchCurrentFolder,"searchCurrentFolder",false,400, true },//			D4 f
 	{ kTheSearchPath,		"searchPath",		false, 400, true },	//			D4 f
+	{ kTheSearchPaths,		"searchPaths",		false, 500, false },	//				D5 p
 	{ kTheSelection,		"selection",		false, 200, true },	// D2 f
 	{ kTheSelEnd,			"selEnd",			false, 200, false },	// D2 p
 	{ kTheSelStart,			"selStart",			false, 200, false },	// D2 p
@@ -930,6 +931,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		d = 1;
 		break;
 	case kTheSearchPath:
+	case kTheSearchPaths:
 		d = g_lingo->_searchPath;
 		break;
 	case kTheSelection:
@@ -1265,6 +1267,7 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 		warning("BUILDBOT: Trying to set SearchCurrentFolder lingo property");
 		break;
 	case kTheSearchPath:
+	case kTheSearchPaths:
 		g_lingo->_searchPath = d;
 		break;
 	case kTheSelEnd:
diff --git a/engines/director/lingo/lingo-the.h b/engines/director/lingo/lingo-the.h
index 82a2dccb339..14691f8450f 100644
--- a/engines/director/lingo/lingo-the.h
+++ b/engines/director/lingo/lingo-the.h
@@ -130,6 +130,7 @@ enum TheEntityType {
 	kTheScummvmVersion,			// set the Director version via lingo in tests
 	kTheSearchCurrentFolder,
 	kTheSearchPath,
+	kTheSearchPaths,
 	kTheSelection,
 	kTheSelEnd,
 	kTheSelStart,


Commit: a71ec6fc7826c60be29354df136a8c9d782ed5ce
    https://github.com/scummvm/scummvm/commit/a71ec6fc7826c60be29354df136a8c9d782ed5ce
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: XTRA: Add alias for PrintOMatic

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


diff --git a/engines/director/lingo/xlibs/printomatic.cpp b/engines/director/lingo/xlibs/printomatic.cpp
index fa9492a533c..99259e19c1a 100644
--- a/engines/director/lingo/xlibs/printomatic.cpp
+++ b/engines/director/lingo/xlibs/printomatic.cpp
@@ -195,6 +195,7 @@ namespace Director {
 const char *PrintOMaticXObj::xlibName = "PrintOMatic";
 const XlibFileDesc PrintOMaticXObj::fileNames[] = {
 	{ "PrintOMatic",   nullptr },
+	{ "PMATIC",   nullptr },
 	{ nullptr,        nullptr },
 };
 


Commit: fa8e65de4459024b7d41822bdff4eda56743f8bf
    https://github.com/scummvm/scummvm/commit/fa8e65de4459024b7d41822bdff4eda56743f8bf
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: Attempt to auto-load Xtras from path

In D5 and up, you don't have to do "openXlib" for Xtras. Having
them somewhere in the top-level Xtras folder is apparently enough.
Also the files can be in there up to five levels deep.

Fixes initial loading in Ingenious.

Changed paths:
    engines/director/resource.cpp
    engines/director/window.h


diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index c8da60f975b..65f1d9d6eb5 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "common/archive.h"
 #include "common/config-manager.h"
 #include "common/error.h"
 #include "common/file.h"
@@ -61,6 +62,9 @@ Common::Error Window::loadInitialMovie() {
 		return Common::kPathNotFile;
 
 	loadINIStream();
+	if (g_director->getVersion() >= 500) {
+		loadXtrasFromPath();
+	}
 	Common::Path path = findPath(movie);
 	_mainArchive = g_director->openArchive(path);
 
@@ -209,34 +213,6 @@ void Window::probeResources(Archive *archive) {
 		}
 		delete resFork;
 	}
-
-	// Xtras
-	if (g_director->getVersion() >= 500) {
-		Common::Path basePath(g_director->getEXEName(), g_director->_dirSeparator);
-		basePath = basePath.getParent().appendComponent("Xtras");
-		basePath = findPath(basePath, false, false, true);
-		if (!basePath.empty()) {
-			Common::StringArray directory_list = basePath.splitComponents();
-			Common::FSNode d = Common::FSNode(*g_director->getGameDataDir());
-			bool escape = false;
-			for (auto &it : directory_list) {
-				d = d.getChild(it);
-				if (!d.exists()) {
-					escape = true;
-					break;
-				}
-			}
-			if (!escape) {
-				debug(0, "Detected Xtras folder");
-				Common::FSList xtras;
-				d.getChildren(xtras, Common::FSNode::kListFilesOnly);
-				for (auto &it : xtras) {
-					debug(0, "Detected Xtra '%s'", it.getName().c_str());
-					g_lingo->openXLib(it.getName(), kXtraObj, basePath.appendComponent(it.getName()));
-				}
-			}
-		}
-	}
 }
 
 void DirectorEngine::addArchiveToOpenList(const Common::Path &path) {
@@ -591,6 +567,24 @@ Archive *DirectorEngine::loadMac(const Common::Path &movie) {
 	return result;
 }
 
+void Window::loadXtrasFromPath() {
+	// For D5 and above, Xtras are considered plug and play.
+	// According to Director Demystified: it considers an
+	// Xtra installed if it's located in the folder named "Xtras"
+	// that's on the same level (i.e., in the same folder)
+	// as the application itself. Xtras can be buried up to
+	// five layers deep in nested folders within this folder,
+	// and they'll still be recognized.
+	Common::ArchiveMemberList targets;
+	SearchMan.listMatchingMembers(targets, Common::Path("xtras/*"), true);
+	for (auto &it : targets) {
+		if (it->isDirectory())
+			continue;
+		debugC(5, kDebugLingoExec, "Window::loadXtrasFromPath(): attempting to open Xtra %s", it->getPathInArchive().toString(g_director->_dirSeparator).c_str());
+		g_lingo->openXLib(it->getFileName(), kXtraObj, it->getPathInArchive());
+	}
+}
+
 void Window::loadStartMovieXLibs() {
 	if (strcmp(g_director->getGameId(), "warlock") == 0 && g_director->getPlatform() != Common::kPlatformWindows) {
 		g_lingo->openXLib("FPlayXObj", kXObj, Common::Path());
diff --git a/engines/director/window.h b/engines/director/window.h
index fce9be0a3b0..32d9509d0f1 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -185,6 +185,7 @@ public:
 	Common::Error loadInitialMovie();
 	void probeResources(Archive *archive);
 	void loadINIStream();
+	void loadXtrasFromPath();
 	void loadStartMovieXLibs();
 
 	// lingo/lingo-object.cpp


Commit: 5b0a0b1497d383905f6d4a925118d20a193e495c
    https://github.com/scummvm/scummvm/commit/5b0a0b1497d383905f6d4a925118d20a193e495c
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: LINGO: Allow referencing "me" from cb_thepush

Fixes the guitar battle interface in Total Distortion.

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


diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index 03ef7fc29fb..c9856b58142 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -645,6 +645,12 @@ void LC::cb_thepush() {
 			return;
 		}
 
+		if (name.equals("me")) {
+			g_lingo->push(g_lingo->_state->me);
+			g_debugger->propReadHook(name);
+			return;
+		}
+
 		warning("cb_thepush: me object has no property '%s', type: %d", name.c_str(), g_lingo->_state->me.type);
 	} else {
 		debugC(1, kDebugLingoExec, "cb_thepush: attempted to access property '%s' with no me object, returning VOID", name.c_str());


Commit: 44d18e73921c49ae7615c9ce39c4d4aa68a4f564
    https://github.com/scummvm/scummvm/commit/44d18e73921c49ae7615c9ce39c4d4aa68a4f564
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: Fix palette bounds check when converting BitmapCastMember from 8 to 32 bit

Changed paths:
    engines/director/castmember/bitmap.cpp
    engines/director/picture.cpp
    engines/director/picture.h


diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index 2e0092d3de2..2e0907750fe 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -377,8 +377,8 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
 			// For BMP images especially, they'll often have the right colors
 			// but in the wrong palette order.
 			const byte *palPtr = _external ? _picture->_palette : srcPal.palette;
-			int palLength = _external ? _picture->getPaletteSize() : srcPal.length;
-			dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, palPtr, palLength, dstPalette, dstPaletteCount, Graphics::kDitherNaive);
+			int palCount = _external ? _picture->getPaletteCount() : srcPal.length;
+			dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, palPtr, palCount, dstPalette, dstPaletteCount, Graphics::kDitherNaive);
 		}
 		break;
 	default:
diff --git a/engines/director/picture.cpp b/engines/director/picture.cpp
index 2a25a8d79ab..d8afe4d06bf 100644
--- a/engines/director/picture.cpp
+++ b/engines/director/picture.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "common/textconsole.h"
 #include "image/image_decoder.h"
 #include "director/picture.h"
 
@@ -36,14 +37,16 @@ Picture::Picture(Picture &picture) {
 
 Picture::~Picture() {
 	_surface.free();
-	delete[] _palette;
 }
 
 void Picture::copyPalette(const byte *src, int numColors) {
-	delete[] _palette;
 	if (src) {
+		if (numColors > 256) {
+			warning("Picture::copyPalette: tried to load a palette with %d colors, capping to 256", numColors);
+			numColors = 256;
+		}
 		_paletteColors = numColors;
-		_palette = new byte[3 * 256]();
+		memset(_palette, 0, sizeof(_palette));
 		memcpy(_palette, src, getPaletteSize());
 	} else {
 		_paletteColors = 0;
diff --git a/engines/director/picture.h b/engines/director/picture.h
index c88ae4aa1d3..db4c1a05a23 100644
--- a/engines/director/picture.h
+++ b/engines/director/picture.h
@@ -32,13 +32,17 @@ namespace Director {
 
 struct Picture {
 	Graphics::Surface _surface;
-	byte *_palette = nullptr;
+	byte _palette[256*3];
 	int _paletteColors = 0;
 
 	int getPaletteSize() const {
 		return _paletteColors * 3;
 	}
 
+	int getPaletteCount() const {
+		return _paletteColors;
+	}
+
 	Picture() {}
 	Picture(Image::ImageDecoder &img);
 	Picture(Picture &picture);


Commit: 7b0934135f06630f391156cb15c98116e4b81718
    https://github.com/scummvm/scummvm/commit/7b0934135f06630f391156cb15c98116e4b81718
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: Add FilmLoopCastMember loader for D5

Changed paths:
    engines/director/cast.cpp
    engines/director/castmember/filmloop.cpp
    engines/director/frame.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 305d35fb952..f27605d78ef 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -1436,16 +1436,6 @@ void Cast::loadCastInfo(Common::SeekableReadStreamEndian &stream, uint16 id) {
 		warning("STUB: Cast::loadCastInfo(): Sound cast member info not yet supported for version %d", _version);
 	}
 
-	// For FilmLoopCastMember, read the flags in the CastInfo
-	if (_version >= kFileVer400 && _version < kFileVer500 && member->_type == kCastFilmLoop) {
-		((FilmLoopCastMember *)member)->_looping = castInfo.flags & 64 ? 0 : 1;
-		((FilmLoopCastMember *)member)->_enableSound = castInfo.flags & 8 ? 1 : 0;
-		((FilmLoopCastMember *)member)->_crop = castInfo.flags & 2 ? 0 : 1;
-		((FilmLoopCastMember *)member)->_center = castInfo.flags & 1 ? 1 : 0;
-	} else if (_version >= kFileVer500 && member->_type == kCastFilmLoop) {
-		warning("STUB: Cast::loadCastInfo(): Film loop cast member info not yet supported for version %d", _version);
-	}
-
 	// For PaletteCastMember, run load() as we need it right now
 	if (member->_type == kCastPalette)
 		member->load();
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index 251d3f51d1f..f9e58af2c82 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -45,6 +45,23 @@ FilmLoopCastMember::FilmLoopCastMember(Cast *cast, uint16 castId, Common::Seekab
 	_enableSound = true;
 	_crop = false;
 	_center = false;
+
+	if (cast->_version >= kFileVer400) {
+		_initialRect = Movie::readRect(stream);
+		uint8 unk1 = stream.readByte();
+		uint8 unk2 = stream.readByte();
+		uint8 unk3 = stream.readByte();
+		uint8 flags = stream.readByte();
+		uint8 unk4 = stream.readByte();
+		uint8 unk5 = stream.readByte();
+		debugC(5, kDebugLoading, "FilmLoopCastMember::FilmLoopCastMember(): unk1: %d, unk2: %d, unk3: %d, flags: %d, unk4: %d, unk5: %d",
+			unk1, unk2, unk3, flags, unk4, unk5
+		);
+		_looping = flags & 64 ? 0 : 1;
+		_enableSound = flags & 8 ? 1 : 0;
+		_crop = flags & 2 ? 0 : 1;
+		_center = flags & 1 ? 1 : 0;
+	}
 }
 
 FilmLoopCastMember::FilmLoopCastMember(Cast *cast, uint16 castId, FilmLoopCastMember &source)
@@ -304,12 +321,7 @@ void FilmLoopCastMember::loadFilmLoopDataD4(Common::SeekableReadStreamEndian &st
 				Sprite sprite(nullptr);
 				sprite._movie = g_director->getCurrentMovie();
 				if (newFrame.sprites.contains(channel)) {
-					// In some cases, particularly in Total Distortion, there could be sprites of type kInactiveSprite.
-					// We need to skip processing them to avoid issues.
-
-					if (newFrame.sprites.getVal(channel)._spriteType == kBitmapSprite) {
-						sprite = newFrame.sprites.getVal(channel);
-					}
+					sprite = newFrame.sprites.getVal(channel);
 				}
 
 				sprite._stretch = true;
@@ -373,6 +385,256 @@ void FilmLoopCastMember::loadFilmLoopDataD4(Common::SeekableReadStreamEndian &st
 
 }
 
+void FilmLoopCastMember::loadFilmLoopDataD5(Common::SeekableReadStreamEndian &stream) {
+	_initialRect = Common::Rect();
+	_frames.clear();
+
+	uint32 size = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "loadFilmLoopDataD5: SCVW body:");
+		uint32 pos = stream.pos();
+		stream.seek(0);
+		stream.hexdump(size);
+		stream.seek(pos);
+	}
+	uint32 framesOffset = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "loadFilmLoopDataD5: SCVW header:");
+		stream.hexdump(framesOffset - 8);
+	}
+	stream.skip(6);
+	uint16 channelSize = kSprChannelSizeD5;
+	stream.readUint16BE(); // should be kSprChannelSizeD5 = 24!
+	stream.skip(framesOffset - 16);
+
+	FilmLoopFrame newFrame;
+
+	while (stream.pos() < size) {
+		uint16 frameSize = stream.readUint16BE();
+		if (frameSize == 0) {
+			continue;
+		}
+		frameSize -= 2;
+		if (debugChannelSet(5, kDebugLoading)) {
+			debugC(5, kDebugLoading, "loadFilmLoopDataD5: Frame entry:");
+			stream.hexdump(frameSize);
+		}
+
+		while (frameSize > 0) {
+			uint16 msgWidth = stream.readUint16BE();
+			uint16 order = stream.readUint16BE();
+			frameSize -= 4;
+
+			int channel = order / channelSize;
+			int channelOffset = order % channelSize;
+			int offset = order;
+
+			debugC(8, kDebugLoading, "loadFilmLoopDataD5: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
+			if (debugChannelSet(8, kDebugLoading)) {
+				stream.hexdump(msgWidth);
+			}
+
+			uint16 segSize = msgWidth;
+			uint16 nextStart = (channel + 1) * kSprChannelSizeD5;
+
+			while (segSize > 0) {
+				Sprite sprite(nullptr);
+				sprite._movie = g_director->getCurrentMovie();
+				if (newFrame.sprites.contains(channel)) {
+					sprite = newFrame.sprites.getVal(channel);
+				}
+
+				sprite._stretch = true;
+
+				uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
+				int startPosition = stream.pos() - channelOffset;
+				int finishPosition = stream.pos() + needSize;
+				readSpriteDataD5(stream, sprite, startPosition, finishPosition);
+				// Swap castLib ID value of -1 for the film loop's castLib ID
+				if (sprite._castId.castLib == -1)
+					sprite._castId.castLib = _cast->_castLibID;
+				if (sprite._scriptId.castLib == -1)
+					sprite._scriptId.castLib = _cast->_castLibID;
+				newFrame.sprites.setVal(channel, sprite);
+				segSize -= needSize;
+				offset += needSize;
+				channel += 1;
+				channelOffset = 0;
+				nextStart += kSprChannelSizeD5;
+			}
+
+			frameSize -= msgWidth;
+		}
+
+		for (auto &s : newFrame.sprites) {
+			debugC(5, kDebugLoading, "loadFilmLoopDataD5: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
+					s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
+					s._value._width, s._value._height);
+
+			if (s._key == -1) {
+				debugC(5, kDebugLoading, "loadFilmLoopDataD5: Skipping channel -1");
+				if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
+						 (s._value._height != -256 && s._value._height != 0))
+					warning("BUILDBOT: loadFilmLoopDataD5: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
+						s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
+						s._value._width, s._value._height);
+				continue;
+			}
+
+			s._value.setCast(s._value._castId);
+			Common::Point topLeft = s._value._startPoint;
+			if (s._value._cast) {
+				topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
+			}
+			Common::Rect spriteBbox(
+				topLeft.x,
+				topLeft.y,
+				topLeft.x + s._value._width,
+				topLeft.y + s._value._height
+			);
+			if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
+				if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
+					_initialRect = spriteBbox;
+				} else {
+					_initialRect.extend(spriteBbox);
+				}
+			}
+			debugC(8, kDebugLoading, "loadFilmLoopDataD5: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
+
+		}
+
+		_frames.push_back(newFrame);
+
+	}
+	debugC(5, kDebugLoading, "loadFilmLoopDataD5: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
+}
+
+void FilmLoopCastMember::loadFilmLoopDataD6(Common::SeekableReadStreamEndian &stream) {
+	_initialRect = Common::Rect();
+	_frames.clear();
+
+	uint32 size = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "loadFilmLoopDataD6: SCVW body:");
+		uint32 pos = stream.pos();
+		stream.seek(0);
+		stream.hexdump(size);
+		stream.seek(pos);
+	}
+	uint32 framesOffset = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "loadFilmLoopDataD6: SCVW header:");
+		stream.hexdump(framesOffset - 8);
+	}
+	stream.skip(6);
+	uint16 channelSize = kSprChannelSizeD6;
+	stream.readUint16BE(); // should be kSprChannelSizeD6 = 24!
+	stream.skip(framesOffset - 16);
+
+	FilmLoopFrame newFrame;
+
+	while (stream.pos() < size) {
+		uint16 frameSize = stream.readUint16BE();
+		if (frameSize == 0) {
+			continue;
+		}
+		frameSize -= 2;
+		if (debugChannelSet(5, kDebugLoading)) {
+			debugC(5, kDebugLoading, "loadFilmLoopDataD6: Frame entry:");
+			stream.hexdump(frameSize);
+		}
+
+		while (frameSize > 0) {
+			uint16 msgWidth = stream.readUint16BE();
+			uint16 order = stream.readUint16BE();
+			frameSize -= 4;
+
+			int channel = order / channelSize;
+			int channelOffset = order % channelSize;
+			int offset = order;
+
+			debugC(8, kDebugLoading, "loadFilmLoopDataD6: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
+			if (debugChannelSet(8, kDebugLoading)) {
+				stream.hexdump(msgWidth);
+			}
+
+			uint16 segSize = msgWidth;
+			uint16 nextStart = (channel + 1) * kSprChannelSizeD4;
+
+			while (segSize > 0) {
+				Sprite sprite(nullptr);
+				sprite._movie = g_director->getCurrentMovie();
+				if (newFrame.sprites.contains(channel)) {
+					sprite = newFrame.sprites.getVal(channel);
+				}
+
+				sprite._stretch = true;
+
+				uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
+				int startPosition = stream.pos() - channelOffset;
+				int finishPosition = stream.pos() + needSize;
+				readSpriteDataD6(stream, sprite, startPosition, finishPosition);
+				// Swap castLib ID value of -1 for the film loop's castLib ID
+				if (sprite._castId.castLib == -1)
+					sprite._castId.castLib = _cast->_castLibID;
+				if (sprite._scriptId.castLib == -1)
+					sprite._scriptId.castLib = _cast->_castLibID;
+				newFrame.sprites.setVal(channel, sprite);
+				segSize -= needSize;
+				offset += needSize;
+				channel += 1;
+				channelOffset = 0;
+				nextStart += kSprChannelSizeD6;
+			}
+
+			frameSize -= msgWidth;
+		}
+
+		for (auto &s : newFrame.sprites) {
+			debugC(5, kDebugLoading, "loadFilmLoopDataD6: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
+					s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
+					s._value._width, s._value._height);
+
+			if (s._key == -1) {
+				debugC(5, kDebugLoading, "loadFilmLoopDataD6: Skipping channel -1");
+				if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
+						 (s._value._height != -256 && s._value._height != 0))
+					warning("BUILDBOT: loadFilmLoopDataD6: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
+						s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
+						s._value._width, s._value._height);
+				continue;
+			}
+
+			s._value.setCast(s._value._castId);
+			Common::Point topLeft = s._value._startPoint;
+			if (s._value._cast) {
+				topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
+			}
+			Common::Rect spriteBbox(
+				topLeft.x,
+				topLeft.y,
+				topLeft.x + s._value._width,
+				topLeft.y + s._value._height
+			);
+			if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
+				if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
+					_initialRect = spriteBbox;
+				} else {
+					_initialRect.extend(spriteBbox);
+				}
+			}
+			debugC(8, kDebugLoading, "loadFilmLoopDataD6: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
+
+		}
+
+		_frames.push_back(newFrame);
+
+	}
+	debugC(5, kDebugLoading, "loadFilmLoopDataD6: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
+}
+
+
+
 Common::String FilmLoopCastMember::formatInfo() {
 	return Common::String::format(
 		"initialRect: %dx%d@%d,%d, boundingRect: %dx%d@%d,%d, frameCount: %d, subchannelCount: %d, enableSound: %d, looping: %d, crop: %d, center: %d",
@@ -401,7 +663,7 @@ void FilmLoopCastMember::load() {
 		} else {
 			warning("FilmLoopCastMember::load(): Film loop not found");
 		}
-	} else if (_cast->_version >= kFileVer400 && _cast->_version < kFileVer500) {
+	} else if (_cast->_version >= kFileVer400 && _cast->_version < kFileVer700) {
 		Common::SeekableReadStreamEndian *loop = nullptr;
 		uint16 filmLoopId = 0;
 		uint32 tag = 0;
@@ -416,7 +678,13 @@ void FilmLoopCastMember::load() {
 
 		if (loop) {
 			debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
-			loadFilmLoopDataD4(*loop);
+			if (_cast->_version < kFileVer500) {
+				loadFilmLoopDataD4(*loop);
+			} else if (_cast->_version < kFileVer600) {
+				loadFilmLoopDataD5(*loop);
+			} else if (_cast->_version < kFileVer700) {
+				loadFilmLoopDataD6(*loop);
+			}
 			delete loop;
 		} else {
 			warning("FilmLoopCastMember::load(): No SCVW resource found in %d children", _children.size());
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 75c6171fbc0..8277114cc7a 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -923,11 +923,10 @@ void readSpriteDataD5(Common::SeekableReadStreamEndian &stream, Sprite &sprite,
 			break;
 		case 2:
 			if (sprite._puppet) {
-				stream.skip(4);
+				stream.readSint16();
 			} else {
-				uint16 castLib = stream.readUint16();
-				uint16 memberID = stream.readUint16();
-				sprite._castId = CastMemberID(memberID, castLib);
+				int castLib = stream.readSint16();
+				sprite._castId = CastMemberID(sprite._castId.member, castLib);
 			}
 			break;
 		case 4:
@@ -939,9 +938,8 @@ void readSpriteDataD5(Common::SeekableReadStreamEndian &stream, Sprite &sprite,
 			}
 			break;
 		case 6: {
-				uint16 scriptCastLib = stream.readUint16();
-				uint16 scriptMemberID = stream.readUint16();
-				sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
+				int scriptCastLib = stream.readSint16();
+				sprite._scriptId = CastMemberID(sprite._scriptId.member, scriptCastLib);
 			}
 			break;
 		case 8: {
@@ -1139,20 +1137,30 @@ void readSpriteDataD6(Common::SeekableReadStreamEndian &stream, Sprite &sprite,
 			sprite._backColor = g_director->transformColor(backColor);
 			}
 			break;
-		case 4: {
-				uint16 castLib = stream.readUint16();
+		case 4:
+			if (sprite._puppet || sprite.getAutoPuppet(kAPCast)) {
+				stream.readSint16();
+			} else {
+				int castLib = stream.readSint16();
+				sprite._castId = CastMemberID(sprite._castId.member, castLib);
+			}
+			break;
+		case 6:
+			if (sprite._puppet || sprite.getAutoPuppet(kAPCast)) {
+				stream.readUint16();
+			} else {
 				uint16 memberID = stream.readUint16();
-
-				if (sprite._puppet || sprite.getAutoPuppet(kAPCast))
-					continue;
-
-				sprite._castId = CastMemberID(memberID, castLib);
+				sprite._castId = CastMemberID(memberID, sprite._castId.castLib);  // Inherit castLib from previous frame
 			}
 			break;
 		case 8: {
-				uint16 scriptCastLib = stream.readUint16();
+				int scriptCastLib = stream.readSint16();
+				sprite._scriptId = CastMemberID(sprite._scriptId.member, scriptCastLib);
+			}
+			break;
+		case 10: {
 				uint16 scriptMemberID = stream.readUint16();
-				sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
+				sprite._scriptId = CastMemberID(scriptMemberID, sprite._scriptId.castLib);  // Inherit castLib from previous frame
 			}
 			break;
 		case 12: {


Commit: 1f8de850f030a72141fea74c0047edbd08fdcf2b
    https://github.com/scummvm/scummvm/commit/1f8de850f030a72141fea74c0047edbd08fdcf2b
Author: Scott Percival (code at moral.net.au)
Date: 2025-02-08T14:45:53+01:00

Commit Message:
DIRECTOR: Quieten benign warnings

Changed paths:
    engines/director/archive.cpp
    engines/director/director.cpp
    engines/director/lingo/lingo.cpp
    engines/director/resource.cpp
    engines/director/score.cpp


diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index fa374b1b5c9..455f02ae5c2 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -606,7 +606,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 		stream->seek(startOffset);
 
 		if (Common::MacResManager::isMacBinary(*stream)) {
-			warning("RIFXArchive::openStream(): MacBinary detected, overriding");
+			warning("RIFXArchive::openStream: MacBinary detected, overriding");
 
 			// We need to look at the resource fork to detect XCOD resources
 			Common::SeekableSubReadStream *macStream = new Common::SeekableSubReadStream(stream, 0, stream->size());
@@ -663,7 +663,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 	}
 
 	_rifxType = endianStream.readUint32();
-	warning("RIFX: type: %s", tag2str(_rifxType));
+	debugC(1, kDebugLoading, "RIFX: type: %s", tag2str(_rifxType));
 
 	// Now read the memory map.
 	// At the same time, we will patch the offsets in the dump data.
@@ -729,12 +729,12 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 			}
 		}
 
-		warning("No 'File' resource present in APPL archive");
+		warning("RIFXArchive::openStream: No 'File' resource present in APPL archive");
 		return false;
 	}
 
 	if (ConfMan.getBool("dump_scripts")) {
-		debug("RIFXArchive::openStream(): Dumping %d resources", _resources.size());
+		debug("RIFXArchive::openStream: Dumping %d resources", _resources.size());
 
 		Common::DumpFile out;
 
@@ -749,7 +749,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 
 	// A KEY* must be present
 	if (!hasResource(MKTAG('K', 'E', 'Y', '*'), -1)) {
-		warning("No 'KEY*' resource present");
+		warning("RIFXArchive::openStream: No 'KEY*' resource present");
 	} else {
 		// Parse the KEY*
 		Common::SeekableReadStreamEndian *keyStream = getFirstResource(MKTAG('K', 'E', 'Y', '*'), true);
@@ -793,12 +793,12 @@ bool RIFXArchive::readMemoryMap(Common::SeekableReadStreamEndian &stream, uint32
 			dumpStream->writeUint32LE(mmapOffset - movieStartOffset);
 	}
 	uint32 version = stream.readUint32(); // 0 for 4.0, 0x4c1 for 5.0, 0x4c7 for 6.0, 0x708 for 8.5, 0x742 for 10.0
-	warning("mmap: mapversion: %d version: %x offset: 0x%x (%d)", mapversion, version, mmapOffset, mmapOffset);
+	debugC(2, kDebugLoading, "RIFXArchive::readMemoryMap: mapversion: %d version: %x offset: 0x%x (%d)", mapversion, version, mmapOffset, mmapOffset);
 
 	stream.seek(mmapOffset);
 
 	if (stream.readUint32() != MKTAG('m', 'm', 'a', 'p')) {
-		warning("RIFXArchive::readMemoryMap(): mmap expected but not found");
+		warning("RIFXArchive::readMemoryMap: mmap expected but not found");
 		return false;
 	}
 
@@ -843,7 +843,7 @@ bool RIFXArchive::readMemoryMap(Common::SeekableReadStreamEndian &stream, uint32
 	}
 
 	if (debugChannelSet(5, kDebugLoading)) {
-		debugC(5, kDebugLoading, "RIFXArchive::readMemoryMap(): Resources found:");
+		debugC(5, kDebugLoading, "RIFXArchive::readMemoryMap: Resources found:");
 		for (const auto &it : _types) {
 			debugC(5, kDebugLoading, "%s: %d", tag2str(it._key), it._value.size());
 		}
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 463521dfb6c..3579f1932f5 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -271,7 +271,7 @@ Common::Error DirectorEngine::run() {
 
 	_pixelformat = _wm->_pixelformat;
 
-	debug("Director pixelformat is: %s", _pixelformat.toString().c_str());
+	debugC(1, kDebugImages, "Director pixelformat is: %s", _pixelformat.toString().c_str());
 
 	_stage = new Window(_wm->getNextId(), false, false, false, _wm, this, true);
 	*_stage->_refCount += 1;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 705a4a978fe..fea157e9316 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -220,7 +220,7 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
 	initMethods();
 	initXLibs();
 
-	warning("Lingo Inited");
+	debugC(1, kDebugLingoExec, "Lingo inited");
 }
 
 Lingo::~Lingo() {
@@ -234,7 +234,7 @@ Lingo::~Lingo() {
 }
 
 void Lingo::reloadBuiltIns() {
-	debug("Reloading builtins");
+	debugC(1, kDebugLingoExec, "Reloading builtins");
 	cleanupBuiltIns();
 	cleanUpTheEntities();
 	cleanupMethods();
@@ -289,7 +289,7 @@ ScriptContext *LingoArchive::findScriptContext(uint16 id) {
 Common::String LingoArchive::getName(uint16 id) {
 	Common::String result;
 	if (id >= names.size()) {
-		warning("Name id %d not in list", id);
+		warning("LingoArchive::getName: Name id %d not in list", id);
 		return result;
 	}
 	result = names[id];
@@ -349,7 +349,7 @@ Symbol Lingo::getHandler(const Common::String &name) {
 
 
 void LingoArchive::patchCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName, uint32 preprocFlags) {
-	debugC(1, kDebugCompile, "Patching code for type %s(%d) with id %d in '%s%s'\n"
+	debugC(1, kDebugCompile, "LingoArchive::patchCode: Patching code for type %s(%d) with id %d in '%s%s'\n"
 			"***********\n%s\n\n***********", scriptType2str(type), type, id, utf8ToPrintable(g_director->getCurrentPath()).c_str(), utf8ToPrintable(cast->getMacName()).c_str(), formatStringForDump(code.encode()).c_str());
 	if (!getScriptContext(type, id)) {
 		// If there's no existing script context, don't try and patch it.
@@ -375,7 +375,7 @@ void LingoArchive::patchCode(const Common::U32String &code, ScriptType type, uin
 
 
 void LingoArchive::addCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName, uint32 preprocFlags) {
-	debugC(1, kDebugCompile, "Add code for type %s(%d) with id %d in '%s%s'\n"
+	debugC(1, kDebugCompile, "LingoArchive::addCode: Add code for type %s(%d) with id %d in '%s%s'\n"
 			"***********\n%s\n\n***********", scriptType2str(type), type, id, utf8ToPrintable(g_director->getCurrentPath()).c_str(), utf8ToPrintable(cast->getMacName()).c_str(), formatStringForDump(code.encode()).c_str());
 
 	if (getScriptContext(type, id)) {
@@ -713,19 +713,19 @@ bool Lingo::execute() {
 void Lingo::executeScript(ScriptType type, CastMemberID id) {
 	Movie *movie = _vm->getCurrentMovie();
 	if (!movie) {
-		warning("Request to execute script with no movie");
+		warning("Lingo::executeScript: Request to execute script with no movie");
 		return;
 	}
 
 	ScriptContext *sc = movie->getScriptContext(type, id);
 
 	if (!sc) {
-		debugC(3, kDebugLingoExec, "Request to execute non-existent script type %d id %d of castLib %d", type, id.member, id.castLib);
+		debugC(3, kDebugLingoExec, "Lingo::executeScript: Request to execute non-existent script type %d id %d of castLib %d", type, id.member, id.castLib);
 		return;
 	}
 
 	if (!sc->_eventHandlers.contains(kEventGeneric)) {
-		debugC(3, kDebugLingoExec, "Request to execute script type %d id %d of castLib %d with no scopeless lingo", type, id.member, id.castLib);
+		debugC(3, kDebugLingoExec, "Lingo::executeScript: Request to execute script type %d id %d of castLib %d with no scopeless lingo", type, id.member, id.castLib);
 		return;
 	}
 
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 65f1d9d6eb5..6376c474ce3 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -69,7 +69,7 @@ Common::Error Window::loadInitialMovie() {
 	_mainArchive = g_director->openArchive(path);
 
 	if (!_mainArchive) {
-		warning("Cannot open main movie");
+		warning("Window::loadInitialMovie: Cannot open main movie");
 		return Common::kNoGameDataFoundError;
 	}
 	probeResources(_mainArchive);
@@ -128,7 +128,7 @@ Common::Error Window::loadInitialMovie() {
 
 void Window::probeResources(Archive *archive) {
 	if (archive->hasResource(MKTAG('B', 'N', 'D', 'L'), "Projector")) {
-		warning("Detected Projector file");
+		debugC(2, kDebugLoading, "Window::probeResources: Detected Projector file");
 
 		if (archive->hasResource(MKTAG('v', 'e', 'r', 's'), -1)) {
 			Common::Array<uint16> vers = archive->getResourceIDList(MKTAG('v', 'e', 'r', 's'));
@@ -136,7 +136,7 @@ void Window::probeResources(Archive *archive) {
 				Common::SeekableReadStreamEndian *vvers = archive->getResource(MKTAG('v', 'e', 'r', 's'), iterator);
 				Common::MacResManager::MacVers *v = Common::MacResManager::parseVers(vvers);
 
-				debug(0, "Detected vers %d.%d %s.%d region %d '%s' '%s'", v->majorVer, v->minorVer, v->devStr.c_str(),
+				debugC(2, kDebugLoading, "Window::probeResources: Detected vers %d.%d %s.%d region %d '%s' '%s'", v->majorVer, v->minorVer, v->devStr.c_str(),
 					v->preReleaseVer, v->region, v->str.c_str(), v->msg.c_str());
 
 				delete v;
@@ -151,17 +151,17 @@ void Window::probeResources(Archive *archive) {
 			Common::SeekableReadStreamEndian *name = archive->getResource(MKTAG('S', 'T', 'R', '#'), 0);
 			int num = name->readUint16();
 			if (num != 1) {
-				warning("Incorrect number of strings in Projector file");
+				warning("Window::probeResources: Incorrect number of strings in Projector file");
 			}
 
 			if (num == 0)
-				error("No strings in Projector file");
+				error("Window::probeResources: No strings in Projector file");
 
 			Common::String sname = decodePlatformEncoding(name->readPascalString());
 			Common::Path moviePath = findMoviePath(sname);
 			if (!moviePath.empty()) {
 				_nextMovie.movie = moviePath.toString(g_director->_dirSeparator);
-				warning("Replaced score name with: %s (from %s)", _nextMovie.movie.c_str(), sname.c_str());
+				warning("Window::probeResources: Replaced score name with: %s (from %s)", _nextMovie.movie.c_str(), sname.c_str());
 
 				if (_currentMovie) {
 					delete _currentMovie;
@@ -173,7 +173,7 @@ void Window::probeResources(Archive *archive) {
 					probeResources(subMovie);
 				}
 			} else {
-				warning("Couldn't find score with name: %s", sname.c_str());
+				warning("Window::probeResources: Couldn't find score with name: %s", sname.c_str());
 			}
 			delete name;
 		}
@@ -190,7 +190,7 @@ void Window::probeResources(Archive *archive) {
 				Common::Array<uint16> xcod = resFork->getResourceIDList(MKTAG('X', 'C', 'O', 'D'));
 				for (auto &iterator : xcod) {
 					Resource res = resFork->getResourceDetail(MKTAG('X', 'C', 'O', 'D'), iterator);
-					debug(0, "Detected XObject '%s'", res.name.c_str());
+					debug(0, "Window::probeResources: Detected XObject '%s'", res.name.c_str());
 					g_lingo->openXLib(res.name, kXObj, resForkPathName);
 				}
 			}
@@ -198,7 +198,7 @@ void Window::probeResources(Archive *archive) {
 				Common::Array<uint16> xcmd = resFork->getResourceIDList(MKTAG('X', 'C', 'M', 'D'));
 				for (auto &iterator : xcmd) {
 					Resource res = resFork->getResourceDetail(MKTAG('X', 'C', 'M', 'D'), iterator);
-					debug(0, "Detected XCMD '%s'", res.name.c_str());
+					debug(0, "Window::probeResources: Detected XCMD '%s'", res.name.c_str());
 					g_lingo->openXLib(res.name, kXObj, resForkPathName);
 				}
 			}
@@ -206,7 +206,7 @@ void Window::probeResources(Archive *archive) {
 				Common::Array<uint16> xfcn = resFork->getResourceIDList(MKTAG('X', 'F', 'C', 'N'));
 				for (auto &iterator : xfcn) {
 					Resource res = resFork->getResourceDetail(MKTAG('X', 'F', 'C', 'N'), iterator);
-					debug(0, "Detected XFCN '%s'", res.name.c_str());
+					debug(0, "Window::probeResources: Detected XFCN '%s'", res.name.c_str());
 					g_lingo->openXLib(res.name, kXObj, resForkPathName);
 				}
 			}
@@ -270,7 +270,7 @@ void Window::loadINIStream() {
 		free(script);
 		delete iniStream;
 	} else {
-		warning("No LINGO.INI");
+		debugC(1, kDebugLoading, "Window::loadINIStream: No LINGO.INI");
 	}
 }
 
@@ -464,7 +464,7 @@ Archive *DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
 	/* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
 	uint32 flags = stream->readUint32LE();
 
-	warning("DirectorEngine::loadEXEv4(): PJ93 projector flags: %08x", flags);
+	debugC(1, kDebugLoading, "DirectorEngine::loadEXEv4(): PJ93 projector flags: %08x", flags);
 
 	return loadEXERIFX(stream, rifxOffset);
 }
@@ -489,7 +489,7 @@ Archive *DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
 	stream->readUint32LE(); // number of driver files
 	stream->readUint32LE(); // fontMapOffset
 
-	warning("DirectorEngine::loadEXEv5(): PJ95 projector pflags: %08x  flags: %08x", pflags, flags);
+	debugC(1, kDebugLoading, "DirectorEngine::loadEXEv5(): PJ95 projector pflags: %08x  flags: %08x", pflags, flags);
 
 	return loadEXERIFX(stream, rifxOffset);
 }
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index a50e298e692..4dbaddd2c3b 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1631,7 +1631,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
 			_framesStream->readUint16(); // Skip
 		}
 
-		warning("STUB: Score::loadFrames(): frame1Offset: 0x%x, version: %d, spriteRecordSize: 0x%x, numChannels: %d, numChannelsDisplayed: %d",
+		debugC(1, kDebugLoading, "Score::loadFrames(): frame1Offset: 0x%x, version: %d, spriteRecordSize: 0x%x, numChannels: %d, numChannelsDisplayed: %d",
 			frame1Offset, _framesVersion, spriteRecordSize, _numChannels, _numChannelsDisplayed);
 		// Unknown, some bytes - constant (refer to contuinity).
 	} else {




More information about the Scummvm-git-logs mailing list