[Scummvm-git-logs] scummvm master -> 71736bef2d4bdeca88ad3e9e4c113d8ece7e1944

moralrecordings code at moral.net.au
Thu May 14 10:10:57 UTC 2020


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

Summary:
8e0c72291f DIRECTOR: LINGO: Add reference counter to Symbol and Datum
b572116249 DIRECTOR: LINGO: Add copy assignment operator for Datum/Symbol
bdf62e6f26 DIRECTOR: LINGO: Precalculate array size for b_addAt
ee9c723c66 DIRECTOR: LINGO: Improve debug messages for cb_v4theentity*
6bdfc4cfbd DIRECTOR: Replace ad-hoc cast lookups with _vm->getCastMember
127c852077 DIRECTOR: LINGO: Refine cross-type output of compareTo
5ad4e341b9 DIRECTOR: LINGO: Improve debug messages for setTheEntity and getTheEntity
2cb83c4828 DIRECTOR: LINGO: Fix typos in LC::*Data
e41d3e4f6e DIRECTOR: LINGO: Fix setting kTheCastNum
090ca0f68e DIRECTOR: LINGO: Remove last of the loadedCast references
b7cc663aed DIRECTOR: LINGO: Fix switch statement indentation
71736bef2d DIRECTOR: LINGO: Remove Datum(Common::String *val)


Commit: 8e0c72291fbc04c991a86eaee65c321ee0bf6890
    https://github.com/scummvm/scummvm/commit/8e0c72291fbc04c991a86eaee65c321ee0bf6890
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Add reference counter to Symbol and Datum

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-bytecode.cpp
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-code.h
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h
    engines/director/util.cpp
    engines/director/util.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 01d9819e5a..3ad6e07416 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -315,7 +315,7 @@ void Lingo::printSTUBWithArglist(const char *funcname, int nargs, const char *pr
 	for (int i = 0; i < nargs; i++) {
 		Datum d = _stack[_stack.size() - nargs + i];
 
-		s += d.getPrintable();
+		s += d.asString(true);
 
 		if (i != nargs - 1)
 			s += ", ";
@@ -365,125 +365,101 @@ void LB::b_abs(int nargs) {
 
 void LB::b_atan(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = atan(d.u.f);
-	g_lingo->push(d);
+	Datum res(atan(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_cos(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = cos(d.u.f);
-	g_lingo->push(d);
+	Datum res(cos(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_exp(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt(); // Lingo uses int, so we're enforcing it
-	d.makeFloat();
-	d.u.f = exp(d.u.f);
-	g_lingo->push(d);
+	// Lingo uses int, so we're enforcing it
+	Datum res(exp(d.asInt()));
+	g_lingo->push(res);
 }
 
 void LB::b_float(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	g_lingo->push(d);
+	Datum res(d.asFloat());
+	g_lingo->push(res);
 }
 
 void LB::b_integer(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	g_lingo->push(d);
+	Datum res(d.asInt());
+	g_lingo->push(res);
 }
 
 void LB::b_log(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = log(d.u.f);
-	g_lingo->push(d);
+	Datum res(log(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_pi(int nargs) {
-	Datum d;
-	d.makeFloat();
-	d.u.f = M_PI;
-	g_lingo->push(d);
+	Datum res(M_PI);
+	g_lingo->push(res);
 }
 
 void LB::b_power(int nargs) {
 	Datum d1 = g_lingo->pop();
 	Datum d2 = g_lingo->pop();
-	d1.makeFloat();
-	d2.makeFloat();
-	d1.u.f = pow(d2.u.f, d1.u.f);
+	Datum res(pow(d2.asFloat(), d1.asFloat()));
 	g_lingo->push(d1);
 }
 
 void LB::b_random(int nargs) {
 	Datum max = g_lingo->pop();
-	Datum res;
-
-	max.makeInt();
-
-	res.u.i = g_lingo->_vm->_rnd.getRandomNumber(max.u.i - 1) + 1;
-	res.type = INT;
-
+	Datum res((int)(g_lingo->_vm->_rnd.getRandomNumber(max.asInt() - 1) + 1));
 	g_lingo->push(res);
 }
 
 void LB::b_sin(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = sin(d.u.f);
-	g_lingo->push(d);
+	Datum res(sin(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_sqrt(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = sqrt(d.u.f);
-	g_lingo->push(d);
+	Datum res(sqrt(d.asFloat()));
+	g_lingo->push(res);
 }
 
 void LB::b_tan(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeFloat();
-	d.u.f = tan(d.u.f);
-	g_lingo->push(d);
+	Datum res(tan(d.asFloat()));
+	g_lingo->push(res);
 }
 
 ///////////////////
 // String
 ///////////////////
 void LB::b_chars(int nargs) {
-	Datum to = g_lingo->pop();
-	Datum from = g_lingo->pop();
+	int to = g_lingo->pop().asInt();
+	int from = g_lingo->pop().asInt();
 	Datum s = g_lingo->pop();
+	TYPECHECK2(s, STRING, REFERENCE);
 
-	if (s.type == REFERENCE)
-		s.makeString();
-
-	TYPECHECK(s, STRING);
+	Common::String src = s.asString();
 
-	to.makeInt();
-	from.makeInt();
+	int len = strlen(src.c_str());
+	int f = MAX(0, MIN(len, from - 1));
+	int t = MAX(0, MIN(len, to));
 
-	int len = strlen(s.u.s->c_str());
-	int f = MAX(0, MIN(len, from.u.i - 1));
-	int t = MAX(0, MIN(len, to.u.i));
-
-	Common::String *res;
+	Common::String *result;
 	if (f > t) {
-		res = new Common::String("");
+		result = new Common::String("");
 	} else {
-		res = new Common::String(&(s.u.s->c_str()[f]), &(s.u.s->c_str()[t]));
+		result = new Common::String(&(src.c_str()[f]), &(src.c_str()[t]));
 	}
 
-	Datum ret;
-	ret.type = STRING;
-	ret.u.s = res;
-	g_lingo->push(ret);
+	Datum res(result);
+	g_lingo->push(res);
 }
 
 void LB::b_charToNum(int nargs) {
@@ -491,55 +467,50 @@ void LB::b_charToNum(int nargs) {
 
 	TYPECHECK(d, STRING);
 
-	byte chr = d.u.s->c_str()[0];
-	delete d.u.s;
+	int chr = (uint8)d.u.s->c_str()[0];
 
-	d.u.i = chr;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(chr);
+	g_lingo->push(res);
 }
 
 void LB::b_delete(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(d.asInt());
 
 	warning("STUB: b_delete");
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(res);
 }
 
 void LB::b_hilite(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(d.asInt());
 
 	warning("STUB: b_hilite");
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(res);
 }
 
 void LB::b_length(int nargs) {
 	Datum d = g_lingo->pop();
-	if (d.type == REFERENCE)
-		d.makeString();
+	TYPECHECK2(d, STRING, REFERENCE);
 
-	TYPECHECK(d, STRING);
+	int len = strlen(d.asString().c_str());
 
-	int len = strlen(d.u.s->c_str());
-	delete d.u.s;
-
-	d.u.i = len;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(len);
+	g_lingo->push(res);
 }
 
 void LB::b_numToChar(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	char result[2];
+	result[0] = (char)d.asInt();
+	result[1] = 0;
 
-	g_lingo->push(Datum((char)d.u.i));
+	g_lingo->push(Datum(Common::String(result)));
 }
 
 void LB::b_offset(int nargs) {
@@ -547,11 +518,8 @@ void LB::b_offset(int nargs) {
 		b_offsetRect(nargs);
 		return;
 	}
-	Datum target = g_lingo->pop();
-	Datum source = g_lingo->pop();
-
-	target.makeString();
-	source.makeString();
+	Common::String target = g_lingo->pop().asString();
+	Common::String source = g_lingo->pop().asString();
 
 	warning("STUB: b_offset()");
 
@@ -560,15 +528,14 @@ void LB::b_offset(int nargs) {
 
 void LB::b_string(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
-	g_lingo->push(d);
+	Datum res(d.asString());
+	g_lingo->push(res);
 }
 
 void LB::b_value(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
 	warning("STUB: b_value()");
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 ///////////////////
@@ -584,19 +551,18 @@ void LB::b_addAt(int nargs) {
 	ARGNUMCHECK(3);
 
 	Datum value = g_lingo->pop();
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
 
-	TYPECHECK(index, INT);
-	if (index.type == FLOAT)
-		index.makeInt();
+	TYPECHECK2(indexD, INT, FLOAT);
+	int index = indexD.asInt();
 	TYPECHECK(list, ARRAY);
 
-	if (!((uint)index.u.i < list.u.farr->size())) {
-		for (uint i = 0; i < index.u.i-list.u.farr->size()-1; i++)
+	if (!((uint)index < list.u.farr->size())) {
+		for (uint i = 0; i < index - list.u.farr->size() - 1; i++)
 			list.u.farr->push_back(Datum(0));
 	}
-	list.u.farr->insert_at(index.u.i-1, value);
+	list.u.farr->insert_at(index - 1, value);
 }
 
 void LB::b_addProp(int nargs) {
@@ -649,21 +615,21 @@ void LB::b_count(int nargs) {
 void LB::b_deleteAt(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+	TYPECHECK2(indexD, INT, FLOAT);
+	TYPECHECK2(list, ARRAY, PARRAY);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
-		list.u.farr->remove_at(index.u.i-1);
+		list.u.farr->remove_at(index - 1);
 		break;
 	case PARRAY:
-		list.u.parr->remove_at(index.u.i-1);
+		list.u.parr->remove_at(index - 1);
 		break;
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -672,6 +638,7 @@ void LB::b_deleteProp(int nargs) {
 
 	Datum prop = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
@@ -682,12 +649,12 @@ void LB::b_deleteProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			list.u.parr->remove_at(index-1);
+			list.u.parr->remove_at(index - 1);
 		}
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -711,26 +678,25 @@ void LB::b_findPos(int nargs) {
 void LB::b_findPosNear(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum prop = g_lingo->pop();
+	Common::String prop = g_lingo->pop().asString();
 	Datum list = g_lingo->pop();
-	Datum d(0);
+	Datum res(0);
 	TYPECHECK(list, PARRAY);
 
 	// FIXME: Integrate with compareTo framework
-	prop = prop.makeString();
-	prop.u.s->toLowercase();
+	prop.toLowercase();
 
 	for (uint i = 0; i < list.u.parr->size(); i++) {
 		Datum p = *list.u.parr->operator[](i).p;
-		p.makeString();
-		p.u.s->toLowercase();
-		if (p.u.s->find(prop.u.s->c_str()) == 0) {
-			d.u.i = i+1;
+		Common::String tgt = p.asString();
+		tgt.toLowercase();
+		if (tgt.find(prop.c_str()) == 0) {
+			res.u.i = i + 1;
 			break;
 		}
 	}
 
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_getaProp(int nargs) {
@@ -761,20 +727,19 @@ void LB::b_getaProp(int nargs) {
 void LB::b_getAt(int nargs) {
 	ARGNUMCHECK(2);
 
-	Datum index = g_lingo->pop();
+	Datum indexD = g_lingo->pop();
+	TYPECHECK2(indexD, INT, FLOAT);
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		g_lingo->push(list.u.farr->operator[](index.u.i-1));
+		ARRBOUNDSCHECK(index, list);
+		g_lingo->push(list.u.farr->operator[](index - 1));
 		break;
 	case PARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		g_lingo->push(*list.u.parr->operator[](index.u.i-1).v);
+		ARRBOUNDSCHECK(index, list);
+		g_lingo->push(*list.u.parr->operator[](index - 1).v);
 		break;
 	default:
 		TYPECHECK2(list, ARRAY, PARRAY);
@@ -826,12 +791,10 @@ void LB::b_getPos(int nargs) {
 	ARGNUMCHECK(2);
 	Datum val = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY: {
-		if (val.type == FLOAT)
-			val.makeInt();
-		TYPECHECK(val, INT);
 		Datum d(0);
 		int index = LC::compareArrays(LC::eqData, list, val, true).u.i;
 		if (index > 0) {
@@ -850,7 +813,7 @@ void LB::b_getPos(int nargs) {
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -858,6 +821,7 @@ void LB::b_getProp(int nargs) {
 	ARGNUMCHECK(2);
 	Datum prop = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
@@ -870,26 +834,22 @@ void LB::b_getProp(int nargs) {
 		if (index > 0) {
 			g_lingo->push(*list.u.parr->operator[](index-1).v);
 		} else {
-			error("b_getProp: Property %s not found", prop.makeString()->c_str());
+			error("b_getProp: Property %s not found", prop.asString().c_str());
 		}
 		break;
 	}
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
 void LB::b_getPropAt(int nargs) {
 	ARGNUMCHECK(2);
-	Datum index = g_lingo->pop();
+	int index = g_lingo->pop().asInt();
 	Datum list = g_lingo->pop();
 	TYPECHECK(list, PARRAY);
 
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
-
-	g_lingo->push(*list.u.parr->operator[](index.u.i-1).p);
+	g_lingo->push(*list.u.parr->operator[](index-1).p);
 }
 
 void LB::b_list(int nargs) {
@@ -1010,27 +970,26 @@ void LB::b_setaProp(int nargs) {
 void LB::b_setAt(int nargs) {
 	ARGNUMCHECK(3);
 	Datum value = g_lingo->pop();
-	Datum index = g_lingo->pop();
+	int index = g_lingo->pop().asInt();
 	Datum list = g_lingo->pop();
-	if (index.type == FLOAT)
-		index.makeInt();
-	TYPECHECK(index, INT);
+
+	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
 	case ARRAY:
-		if ((uint)index.u.i < list.u.farr->size()) {
-			list.u.farr->operator[](index.u.i-1) = value;
+		if ((uint)index < list.u.farr->size()) {
+			list.u.farr->operator[](index-1) = value;
 		} else {
 			// TODO: Extend the list if we request an index beyond it
-			ARRBOUNDSCHECK(index.u.i, list);
+			ARRBOUNDSCHECK(index, list);
 		}
 		break;
 	case PARRAY:
-		ARRBOUNDSCHECK(index.u.i, list);
-		*list.u.parr->operator[](index.u.i-1).v = value;
+		ARRBOUNDSCHECK(index, list);
+		*list.u.parr->operator[](index-1).v = value;
 		break;
 	default:
-		TYPECHECK2(list, ARRAY, PARRAY);
+		break;
 	}
 }
 
@@ -1067,21 +1026,13 @@ void LB::b_closeDA(int nargs) {
 void LB::b_closeResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_closeResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_closeResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_closeXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_closeXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_closeXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_getNthFileNameInFolder(int nargs) {
@@ -1095,31 +1046,19 @@ void LB::b_getNthFileNameInFolder(int nargs) {
 void LB::b_openDA(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openDA(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openDA(%s)", d.asString().c_str());
 }
 
 void LB::b_openResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_openXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_openXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_openXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_saveMovie(int nargs) {
@@ -1135,31 +1074,19 @@ void LB::b_setCallBack(int nargs) {
 void LB::b_showResFile(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_showResFile(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_showResFile(%s)", d.asString().c_str());
 }
 
 void LB::b_showXlib(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_showXlib(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_showXlib(%s)", d.asString().c_str());
 }
 
 void LB::b_xFactoryList(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_xFactoryList(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_xFactoryList(%s)", d.asString().c_str());
 }
 
 ///////////////////
@@ -1184,15 +1111,13 @@ void LB::b_nothing(int nargs) {
 
 void LB::b_delay(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
 
-	g_director->getCurrentScore()->_nextFrameTime = g_system->getMillis() + (float)d.u.i / 60 * 1000;
+	g_director->getCurrentScore()->_nextFrameTime = g_system->getMillis() + (float)d.asInt() / 60 * 1000;
 }
 
 void LB::b_do(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
-	warning("STUB: b_do(%s)", d.u.s->c_str());
+	warning("STUB: b_do(%s)", d.asString().c_str());
 }
 
 void LB::b_go(int nargs) {
@@ -1350,42 +1275,34 @@ void LB::b_startTimer(int nargs) {
 ///////////////////
 void LB::b_factoryP(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	d.u.i = 1;
-	g_lingo->push(d);
+	Datum res(d.asInt());
+	g_lingo->push(res);
 
 	warning("STUB: b_factoryP");
 }
 
 void LB::b_floatP(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == FLOAT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == FLOAT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_ilk(int nargs) {
 	Datum d = g_lingo->pop();
-	d.u.s = new Common::String(d.type2str(true));
-	d.type = SYMBOL;
-	g_lingo->push(d);
+	Datum res(new Common::String(d.type2str(true)));
+	g_lingo->push(res);
 }
 
 void LB::b_integerp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == INT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == INT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_objectp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == OBJECT) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res ((d.type == OBJECT) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_pictureP(int nargs) {
@@ -1396,26 +1313,20 @@ void LB::b_pictureP(int nargs) {
 
 void LB::b_stringp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == STRING) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == STRING) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_symbolp(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == SYMBOL) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == SYMBOL) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_voidP(int nargs) {
 	Datum d = g_lingo->pop();
-	int res = (d.type == VOID) ? 1 : 0;
-	d.makeInt();
-	d.u.i = res;
-	g_lingo->push(d);
+	Datum res((d.type == VOID) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 
@@ -1425,11 +1336,7 @@ void LB::b_voidP(int nargs) {
 void LB::b_alert(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	warning("STUB: b_alert(%s)", d.u.s->c_str());
-
-	delete d.u.s;
+	warning("STUB: b_alert(%s)", d.asString().c_str());
 }
 
 void LB::b_birth(int nargs) {
@@ -1452,13 +1359,10 @@ void LB::b_cursor(int nargs) {
 	if (d.type == ARRAY) {
 		Datum sprite = d.u.farr->operator[](0);
 		Datum mask = d.u.farr->operator[](1);
-		sprite.makeInt();
-		mask.makeInt();
 
-		g_lingo->func_cursor(sprite.u.i, mask.u.i);
+		g_lingo->func_cursor(sprite.asInt(), mask.asInt());
 	} else {
-		d.makeInt();
-		g_lingo->func_cursor(d.u.i, -1);
+		g_lingo->func_cursor(d.asInt(), -1);
 	}
 }
 
@@ -1477,10 +1381,7 @@ void LB::b_constrainH(int nargs) {
 	Datum num = g_lingo->pop();
 	Datum sprite = g_lingo->pop();
 
-	num.makeInt();
-	sprite.makeInt();
-
-	warning("STUB: b_constrainH(%d, %d)", sprite.u.i, num.u.i);
+	warning("STUB: b_constrainH(%d, %d)", sprite.asInt(), num.asInt());
 
 	g_lingo->push(Datum(0));
 }
@@ -1489,10 +1390,7 @@ void LB::b_constrainV(int nargs) {
 	Datum num = g_lingo->pop();
 	Datum sprite = g_lingo->pop();
 
-	num.makeInt();
-	sprite.makeInt();
-
-	warning("STUB: b_constrainV(%d, %d)", sprite.u.i, num.u.i);
+	warning("STUB: b_constrainV(%d, %d)", sprite.asInt(), num.asInt());
 
 	g_lingo->push(Datum(0));
 }
@@ -1549,15 +1447,15 @@ void LB::b_installMenu(int nargs) {
 	// installMenu castNum
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	int castId = d.asInt();
 
 	if (g_director->getVersion() < 4)
-		d.u.i += g_director->getCurrentScore()->_castIDoffset;
+		castId += g_director->getCurrentScore()->_castIDoffset;
 
-	const Stxt *stxt = g_director->getCurrentScore()->_loadedStxts->getVal(d.u.i, nullptr);
+	const Stxt *stxt = g_director->getCurrentScore()->_loadedStxts->getVal(castId, nullptr);
 
 	if (!stxt) {
-		warning("installMenu: Unknown cast number #%d", d.u.i);
+		warning("installMenu: Unknown cast number #%d", castId);
 		return;
 	}
 
@@ -1682,16 +1580,14 @@ Common::String Lingo::genMenuHandler(int *commandId, Common::String &command) {
 
 void LB::b_label(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	warning("STUB: b_label(%d)", d.u.i);
+	warning("STUB: b_label(%d)", d.asInt());
 
 	g_lingo->push(Datum(0));
 }
 
 void LB::b_marker(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeInt();
-	int marker = g_lingo->func_marker(d.u.i);
+	int marker = g_lingo->func_marker(d.asInt());
 	g_lingo->push(marker);
 }
 
@@ -1779,7 +1675,7 @@ void LB::b_puppetSprite(int nargs) {
 
 void LB::b_puppetTempo(int nargs) {
 	Datum d = g_lingo->pop();
-	warning("STUB: b_puppetTempo(%d)", d.u.i);
+	warning("STUB: b_puppetTempo(%d)", d.asInt());
 }
 
 void LB::b_puppetTransition(int nargs) {
@@ -1797,12 +1693,8 @@ void LB::b_ramNeeded(int nargs) {
 
 void LB::b_rollOver(int nargs) {
 	Datum d = g_lingo->pop();
-
-	d.makeInt();
-
-	int arg = d.u.i;
-
-	d.u.i = 0; // FALSE
+	Datum res(0);
+	int arg = d.asInt();
 
 	if (!g_director->getCurrentScore()) {
 		warning("b_rollOver: Reference to an empty score");
@@ -1812,16 +1704,16 @@ void LB::b_rollOver(int nargs) {
 	Frame *frame = g_director->getCurrentScore()->_frames[g_director->getCurrentScore()->getCurrentFrame()];
 
 	if (arg >= (int32) frame->_sprites.size()) {
-		g_lingo->push(d);
+		g_lingo->push(res);
 		return;
 	}
 
 	Common::Point pos = g_system->getEventManager()->getMousePos();
 
 	if (frame->checkSpriteIntersection(arg, pos))
-		d.u.i = 1; // TRUE
+		res.u.i = 1; // TRUE
 
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_spriteBox(int nargs) {
@@ -1856,37 +1748,32 @@ void LB::b_zoomBox(int nargs) {
 	int delayTicks = 1;
 	if (nargs > 2) {
 		Datum d = g_lingo->pop();
-		d.makeInt();
-
-		delayTicks = d.u.i;
+		delayTicks = d.asInt();
 	}
 
-	Datum endSprite = g_lingo->pop();
-	Datum startSprite = g_lingo->pop();
-
-	startSprite.makeInt();
-	endSprite.makeInt();
+	int endSprite = g_lingo->pop().asInt();
+	int startSprite = g_lingo->pop().asInt();
 
 	Score *score = g_director->getCurrentScore();
 	uint16 curFrame = score->getCurrentFrame();
 	Frame *frame = score->_frames[curFrame];
 
-	Common::Rect *startRect = frame->getSpriteRect(startSprite.u.i);
+	Common::Rect *startRect = frame->getSpriteRect(startSprite);
 	if (!startRect) {
-		warning("b_zoomBox: unknown start sprite #%d", startSprite.u.i);
+		warning("b_zoomBox: unknown start sprite #%d", startSprite);
 		return;
 	}
 
 	// Looks for endSprite in the current frame, otherwise
 	// Looks for endSprite in the next frame
-	Common::Rect *endRect = frame->getSpriteRect(endSprite.u.i);
+	Common::Rect *endRect = frame->getSpriteRect(endSprite);
 	if (!endRect) {
 		if ((uint)curFrame + 1 < score->_frames.size())
-			score->_frames[curFrame + 1]->getSpriteRect(endSprite.u.i);
+			score->_frames[curFrame + 1]->getSpriteRect(endSprite);
 	}
 
 	if (!endRect) {
-		warning("b_zoomBox: unknown end sprite #%d", endSprite.u.i);
+		warning("b_zoomBox: unknown end sprite #%d", endSprite);
 		return;
 	}
 
@@ -1953,13 +1840,10 @@ void LB::b_moveToFront(int nargs) {
 // Point
 ///////////////////
 void LB::b_point(int nargs) {
-	Datum y = g_lingo->pop();
-	Datum x = g_lingo->pop();
+	Datum y(g_lingo->pop().asFloat());
+	Datum x(g_lingo->pop().asFloat());
 	Datum d;
 
-	x.makeFloat();
-	y.makeFloat();
-
 	d.u.farr = new DatumArray;
 
 	d.u.farr->push_back(x);
@@ -2034,17 +1918,13 @@ void LB::b_beep(int nargs) {
 void LB::b_mci(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	g_lingo->func_mci(*d.u.s);
+	g_lingo->func_mci(d.asString());
 }
 
 void LB::b_mciwait(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
-
-	g_lingo->func_mciwait(*d.u.s);
+	g_lingo->func_mciwait(d.asString());
 }
 
 void LB::b_sound(int nargs) {
@@ -2197,10 +2077,9 @@ void Lingo::factoryCall(Common::String &name, int nargs) {
 	debugC(3, kDebugLingoExec, "Stack size after call: %d", _stack.size());
 
 	if (!method.u.s->compareToIgnoreCase("mNew")) {
-		Datum d;
+		Datum d(name);
 
 		d.type = OBJECT;
-		d.u.s = new Common::String(name);
 
 		g_lingo->push(d);
 	}
@@ -2214,20 +2093,17 @@ void LB::b_cast(int nargs) {
 
 	warning("STUB: b_cast");
 
-	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	Datum res(0);
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_field(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.u.i = g_lingo->castIdFetch(d);
-
-	d.type = REFERENCE;
-
-	g_lingo->push(d);
+	Datum res(g_lingo->castIdFetch(d));
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_script(int nargs) {
@@ -2235,10 +2111,9 @@ void LB::b_script(int nargs) {
 
 	warning("STUB: b_script");
 
+	Datum res(0);
 	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 void LB::b_window(int nargs) {
@@ -2246,126 +2121,99 @@ void LB::b_window(int nargs) {
 
 	warning("STUB: b_window");
 
-	d.type = REFERENCE;
-	d.u.i = 0;
-
-	g_lingo->push(d);
+	Datum res(0);
+	res.type = REFERENCE;
+	g_lingo->push(res);
 }
 
 void LB::b_numberofchars(int nargs) {
 	Datum d = g_lingo->pop();
-	d.makeString();
 
-	int len = strlen(d.u.s->c_str());
-	delete d.u.s;
+	int len = strlen(d.asString().c_str());
 
-	d.u.i = len;
-	d.type = INT;
-	g_lingo->push(d);
+	Datum res(len);
+	g_lingo->push(res);
 }
 
 void LB::b_numberofitems(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberofitems = 1;
-	Common::String contents = *d.u.s;
-	for (uint32 i = 0;  i < d.u.s->size(); i++) {
+	Common::String contents = d.asString();
+	for (uint32 i = 0;  i < contents.size(); i++) {
 		if (contents[i] == ',')
 			numberofitems++;
 	}
-	delete d.u.s;
-
-	d.u.i = numberofitems;
-	d.type = INT;
 
-	g_lingo->push(d);
+	Datum res(numberofitems);
+	g_lingo->push(res);
 }
 
 void LB::b_numberoflines(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberoflines = 1;
-	Common::String contents = *d.u.s;
-	for (uint32 i = 0; i < d.u.s->size(); i++) {
+	Common::String contents = d.asString();
+	for (uint32 i = 0; i < contents.size(); i++) {
 		if (contents[i] == '\n')
 			numberoflines++;
 	}
-	delete d.u.s;
 
-	d.u.i = numberoflines;
-	d.type = INT;
-
-	g_lingo->push(d);
+	Datum res(numberoflines);
+	g_lingo->push(res);
 }
 
 void LB::b_numberofwords(int nargs) {
 	Datum d = g_lingo->pop();
 
-	d.makeString();
 	int numberofwords = 0;
-	Common::String contents = *d.u.s;
+	Common::String contents = d.asString();
 	if (contents.empty()) {
-		d.u.i = 0;
-		d.type = INT;
-
-		g_lingo->push(d);
-
+		g_lingo->push(Datum(0));
 		return;
 	}
-	for (uint32 i = 1; i < d.u.s->size(); i++) {
+	for (uint32 i = 1; i < contents.size(); i++) {
 		if (Common::isSpace(contents[i]) && !Common::isSpace(contents[i - 1]))
 			numberofwords++;
 	}
 	// Count the last word
-	if (!Common::isSpace(contents[d.u.s->size() - 1]))
+	if (!Common::isSpace(contents[contents.size() - 1]))
 		numberofwords++;
 
-	d.u.i = numberofwords;
-	d.type = INT;
-
-	g_lingo->push(d);
+	Datum res(numberofwords);
+	g_lingo->push(res);
 }
 
 void LB::b_lastcharof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastcharof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastitemof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastitemof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastlineof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastlineof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 void LB::b_lastwordof(int nargs) {
 	Datum d = g_lingo->pop();
 
 	warning("STUB: b_lastwordof");
-	d.makeInt();
-	d.u.i = 0;
 
-	g_lingo->push(d);
+	g_lingo->push(Datum(0));
 }
 
 } // End of namespace Director
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index b54306830f..868fa4f1d8 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -283,9 +283,8 @@ void LC::cb_localcall() {
 
 void LC::cb_methodcall() {
 	g_lingo->readInt();
-	Datum obj = g_lingo->pop();
-	obj.makeString();
-	warning("STUB: cb_methodcall(%s)", obj.u.s->c_str());
+	Common::String name = g_lingo->pop().asString();
+	warning("STUB: cb_methodcall(%s)", name.c_str());
 
 	Datum nargs = g_lingo->pop();
 	if ((nargs.type == ARGC) || (nargs.type == ARGCNORET)) {
@@ -513,22 +512,21 @@ void LC::cb_varassign() {
 void LC::cb_v4theentitypush() {
 	int bank = g_lingo->readInt();
 
-	Datum firstArg = g_lingo->pop();
-	firstArg.makeInt();
+	int firstArg = g_lingo->pop().asInt();
 	Datum result;
 	result.u.s = NULL;
 	result.type = VOID;
 
-	int key = (bank << 8) + firstArg.u.i;
+	int key = (bank << 8) + firstArg;
 	if (g_lingo->_lingoV4TheEntity.contains(key)) {
-		debugC(3, kDebugLingoExec, "cb_v4theentitypush: mapping 0x%02x, 0x%02x", bank, firstArg.u.i);
+		debugC(3, kDebugLingoExec, "cb_v4theentitypush: mapping 0x%02x, 0x%02x", bank, firstArg);
 		int entity = g_lingo->_lingoV4TheEntity[key]->entity;
 		int field = g_lingo->_lingoV4TheEntity[key]->field;
 		switch (g_lingo->_lingoV4TheEntity[key]->type) {
 		case kTEANOArgs:
 			{
 				Datum id;
-				id.u.s = NULL;
+				id.u.i = 0;
 				id.type = VOID;
 				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(0x%02x, NULL, 0x%02x)", entity, field);
 				result = g_lingo->getTheEntity(entity, id, field);
@@ -559,7 +557,7 @@ void LC::cb_v4theentitypush() {
 			break;
 		}
 	} else {
-		warning("cb_v4theentitypush: unhandled mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentitypush: unhandled mapping 0x%02x 0x%02x", bank, firstArg);
 	}
 
 	g_lingo->push(result);
@@ -599,24 +597,23 @@ void LC::cb_v4theentitynamepush() {
 void LC::cb_v4theentityassign() {
 	int bank = g_lingo->readInt();
 
-	Datum firstArg = g_lingo->pop();
-	firstArg.makeInt();
+	int firstArg = g_lingo->pop().asInt();
 	Datum value = g_lingo->pop();
 	Datum result;
 	result.u.s = NULL;
 	result.type = VOID;
 
-	int key = (bank << 8) + firstArg.u.i;
+	int key = (bank << 8) + firstArg;
 	if (!g_lingo->_lingoV4TheEntity.contains(key)) {
-		warning("cb_v4theentityassign: unhandled mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentityassign: unhandled mapping 0x%02x 0x%02x", bank, firstArg);
 
 		return;
 	}
 
-	debugC(3, kDebugLingoExec, "cb_v4theentityassign: mapping 0x%02x, 0x%02x", bank, firstArg.u.i);
+	debugC(3, kDebugLingoExec, "cb_v4theentityassign: mapping 0x%02x, 0x%02x", bank, firstArg);
 
 	if (!g_lingo->_lingoV4TheEntity[key]->writable) {
-		warning("cb_v4theentityassign: non-writable mapping 0x%02x 0x%02x", bank, firstArg.u.i);
+		warning("cb_v4theentityassign: non-writable mapping 0x%02x 0x%02x", bank, firstArg);
 
 		return;
 	}
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 124f8cdd0c..e629a5342c 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -226,22 +226,22 @@ void LC::c_printtop(void) {
 		}
 		break;
 	case STRING:
-		warning("%s", d.u.s->c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	case POINT:
-		warning("point(%s, %s", (*d.u.farr)[0].getPrintable().c_str(), (*d.u.farr)[1].getPrintable().c_str());
+		warning("point(%s, %s", (*d.u.farr)[0].asString(true).c_str(), (*d.u.farr)[1].asString(true).c_str());
 		break;
 	case SYMBOL:
 		warning("%s", d.type2str(true));
 		break;
 	case OBJECT:
-		warning("#%s", d.u.s->c_str());
+		warning("#%s", d.asString(true).c_str());
 		break;
 	case ARRAY:
-		warning("%s", d.getPrintable().c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	case PARRAY:
-		warning("%s", d.getPrintable().c_str());
+		warning("%s", d.asString(true).c_str());
 		break;
 	default:
 		warning("--unknown--");
@@ -249,10 +249,8 @@ void LC::c_printtop(void) {
 }
 
 void LC::c_intpush() {
-	Datum d;
-	d.u.i = g_lingo->readInt();
-	d.type = INT;
-	g_lingo->push(d);
+	int value = g_lingo->readInt();
+	g_lingo->push(Datum(value));
 }
 
 void LC::c_voidpush() {
@@ -263,15 +261,12 @@ void LC::c_voidpush() {
 }
 
 void LC::c_floatpush() {
-	Datum d;
-	d.u.f = g_lingo->readFloat();
-	d.type = FLOAT;
-	g_lingo->push(d);
+	double value = g_lingo->readFloat();
+	g_lingo->push(Datum(value));
 }
 
 void LC::c_stringpush() {
 	char *s = g_lingo->readString();
-
 	g_lingo->push(Datum(new Common::String(s)));
 }
 
@@ -516,7 +511,7 @@ void LC::c_swap() {
 	g_lingo->push(d1);
 }
 
-Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum, Datum), Datum d1, Datum d2) {
+Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum &, Datum &), Datum &d1, Datum &d2) {
 	// At least one of d1 and d2 must be an array
 	uint arraySize;
 	if (d1.type == ARRAY && d2.type == ARRAY) {
@@ -543,16 +538,22 @@ Datum LC::mapBinaryOp(Datum (*mapFunc)(Datum, Datum), Datum d1, Datum d2) {
 	return res;
 }
 
-Datum LC::addData(Datum d1, Datum d2) {
+Datum LC::addData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::addData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f += d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() + d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() + d2.asInt());
 	} else {
-		d1.u.i += d2.u.i;
+		warning("LC::addData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_add() {
@@ -561,16 +562,22 @@ void LC::c_add() {
 	g_lingo->push(LC::addData(d1, d2));
 }
 
-Datum LC::subData(Datum d1, Datum d2) {
+Datum LC::subData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::subData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f -= d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() - d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() - d2.asInt());
 	} else {
-		d1.u.i -= d2.u.i;
+		warning("LC::subData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_sub() {
@@ -579,16 +586,22 @@ void LC::c_sub() {
 	g_lingo->push(LC::subData(d1, d2));
 }
 
-Datum LC::mulData(Datum d1, Datum d2) {
+Datum LC::mulData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::mulData, d1, d2);
 	}
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f *= d2.u.f;
+
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() * d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() * d2.asInt());
 	} else {
-		d1.u.i *= d2.u.i;
+		warning("LC::mulData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return d1;
+	return result;
 }
 
 void LC::c_mul() {
@@ -597,7 +610,7 @@ void LC::c_mul() {
 	g_lingo->push(LC::mulData(d1, d2));
 }
 
-Datum LC::divData(Datum d1, Datum d2) {
+Datum LC::divData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::divData, d1, d2);
 	}
@@ -606,11 +619,17 @@ Datum LC::divData(Datum d1, Datum d2) {
 			(d2.type == FLOAT && d2.u.f == 0.0))
 		error("division by zero");
 
-	if (g_lingo->alignTypes(d1, d2) == FLOAT) {
-		d1.u.f /= d2.u.f;
+	int alignedType = g_lingo->getAlignedType(d1, d2);
+
+	Datum result;
+	if (alignedType == FLOAT) {
+		result = Datum(d1.asFloat() / d2.asFloat());
+	} else if (alignedType == INT) {
+		result = Datum(d1.asInt() / d2.asInt());
 	} else {
-		d1.u.i /= d2.u.i;
+		warning("LC::divData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
+
 	return d1;
 }
 
@@ -620,18 +639,18 @@ void LC::c_div() {
 	g_lingo->push(divData(d1, d2));
 }
 
-Datum LC::modData(Datum d1, Datum d2) {
+Datum LC::modData(Datum &d1, Datum &d2) {
 	if (d1.type == ARRAY || d2.type == ARRAY) {
 		return LC::mapBinaryOp(LC::modData, d1, d2);
 	}
 
-	d1.makeInt();
-	d2.makeInt();
-	if (d2.u.i == 0)
+	int i1 = d1.asInt();
+	int i2 = d2.asInt();
+	if (i2 == 0)
 		error("division by zero");
 
-	d1.u.i %= d2.u.i;
-	return d1;
+	Datum res(i1 % i2);
+	return res;
 }
 
 void LC::c_mod() {
@@ -640,7 +659,7 @@ void LC::c_mod() {
 	g_lingo->push(LC::modData(d1, d2));
 }
 
-Datum LC::negateData(Datum d) {
+Datum LC::negateData(Datum &d) {
 	if (d.type == ARRAY) {
 		uint arraySize = d.u.farr->size();
 		Datum res;
@@ -652,11 +671,15 @@ Datum LC::negateData(Datum d) {
 		return res;
 	}
 
-	if (d.type == INT) {
-		d.u.i = -d.u.i;
-	} else if (d.type == FLOAT) {
-		d.u.f = -d.u.f;
+	Datum res = d;
+	if (res.type == INT) {
+		res.u.i = -res.u.i;
+	} else if (res.type == FLOAT) {
+		res.u.f = -res.u.f;
+	} else {
+		warning("LC::negateData: not supported for type %s", res.type2str());
 	}
+
 	return d;
 }
 
@@ -669,14 +692,8 @@ void LC::c_ampersand() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s += *d2.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d1.asString() + d2.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_before() {
@@ -687,70 +704,38 @@ void LC::c_after() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s = *d2.u.s + *d1.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d2.asString() + d1.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_concat() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	*d1.u.s += " ";
-	*d1.u.s += *d2.u.s;
-
-	delete d2.u.s;
-
-	g_lingo->push(d1);
+	Datum res(d1.asString() + " " + d2.asString());
+	g_lingo->push(res);
 }
 
 void LC::c_contains() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
+	Common::String s1 = toLowercaseMac(d1.asString());
+	Common::String s2 = toLowercaseMac(d2.asString());
 
-	Common::String *s1 = toLowercaseMac(d1.u.s);
-	Common::String *s2 = toLowercaseMac(d2.u.s);
+	int res = s1.contains(s2) ? 1 : 0;
 
-	int res = s1->contains(*s2) ? 1 : 0;
-
-	delete d1.u.s;
-	delete d2.u.s;
-	delete s1;
-	delete s2;
-
-	d1.type = INT;
-	d1.u.i = res;
-
-	g_lingo->push(d1);
+	g_lingo->push(Datum(res));
 }
 
 void LC::c_starts() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
+	Common::String s1 = toLowercaseMac(d1.asString());
+	Common::String s2 = toLowercaseMac(d2.asString());
 
-	Common::String *s1 = toLowercaseMac(d1.u.s);
-	Common::String *s2 = toLowercaseMac(d2.u.s);
-
-	int res = s1->hasPrefix(*s2) ? 1 : 0;
-
-	delete d1.u.s;
-	delete d2.u.s;
-	delete s1;
-	delete s2;
+	int res = s1.hasPrefix(s2) ? 1 : 0;
 
 	d1.type = INT;
 	d1.u.i = res;
@@ -788,8 +773,7 @@ void LC::c_of() {
 	Datum last_char = g_lingo->pop();
 	Datum first_char = g_lingo->pop();
 
-	target.makeString();
-	Common::String result = *target.u.s;
+	Common::String result = target.asString();
 
 	if (first_line.u.i > 0) {
 		Common::String newline("\r");
@@ -975,34 +959,26 @@ void LC::c_and() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeInt();
-	d2.makeInt();
-
-	d1.u.i = (d1.u.i && d2.u.i) ? 1 : 0;
+	Datum res((d1.asInt() && d2.asInt()) ? 1 : 0);
 
-	g_lingo->push(d1);
+	g_lingo->push(res);
 }
 
 void LC::c_or() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeInt();
-	d2.makeInt();
-
-	d1.u.i = (d1.u.i || d2.u.i) ? 1 : 0;
+	Datum res((d1.asInt() || d2.asInt()) ? 1 : 0);
 
-	g_lingo->push(d1);
+	g_lingo->push(res);
 }
 
 void LC::c_not() {
 	Datum d = g_lingo->pop();
 
-	d.makeInt();
+	Datum res(~d.asInt() ? 1 : 0);
 
-	d.u.i = ~d.u.i ? 1 : 0;
-
-	g_lingo->push(d);
+	g_lingo->push(res);
 }
 
 Datum LC::compareArrays(Datum (*compareFunc)(Datum, Datum), Datum d1, Datum d2, bool location, bool value) {
@@ -1159,9 +1135,8 @@ void LC::c_jump() {
 
 void LC::c_jumpifz() {
 	uint jump = g_lingo->readInt();
-	Datum test = g_lingo->pop();
-	test.makeInt();
-	if (test.u.i == 0) {
+	int test = g_lingo->pop().asInt();
+	if (test == 0) {
 		g_lingo->_pc = jump;
 	}
 }
@@ -1174,10 +1149,9 @@ void LC::c_repeatwhilecode(void) {
 	uint end =  g_lingo->getInt(savepc + 1);
 
 	g_lingo->execute(savepc + 2);	/* condition */
-	d = g_lingo->pop();
-	d.makeInt();
+	int test = g_lingo->pop().asInt();
 
-	while (d.u.i) {
+	while (test) {
 		g_lingo->execute(body + savepc - 1);	/* body */
 		g_lingo->_nextRepeat = false;
 
@@ -1190,8 +1164,7 @@ void LC::c_repeatwhilecode(void) {
 		}
 
 		g_lingo->execute(savepc + 2);	/* condition */
-		d = g_lingo->pop();
-		d.makeInt();
+		test = g_lingo->pop().asInt();
 	}
 
 	if (!g_lingo->_returning)
@@ -1199,7 +1172,6 @@ void LC::c_repeatwhilecode(void) {
 }
 
 void LC::c_repeatwithcode(void) {
-	Datum d;
 	int savepc = g_lingo->_pc;
 
 	uint init = g_lingo->getInt(savepc);
@@ -1239,9 +1211,7 @@ void LC::c_repeatwithcode(void) {
 	}
 
 	g_lingo->execute(init + savepc - 1);	/* condition */
-	d = g_lingo->pop();
-	d.makeInt();
-	counter->u.i = d.u.i;
+	counter->u.i = g_lingo->pop().asInt();
 	counter->type = INT;
 
 	while (true) {
@@ -1258,10 +1228,9 @@ void LC::c_repeatwithcode(void) {
 
 		counter->u.i += inc;
 		g_lingo->execute(finish + savepc - 1);	/* condition */
-		d = g_lingo->pop();
-		d.makeInt();
+		int base = g_lingo->pop().asInt();
 
-		if (counter->u.i == d.u.i + inc)
+		if (counter->u.i == base + inc)
 			break;
 	}
 
@@ -1293,7 +1262,7 @@ void LC::c_ifcode(void) {
 
 	d = g_lingo->pop();
 
-	if (d.makeInt()) {
+	if (d.asInt()) {
 		debugC(8, kDebugLingoExec, "executing then");
 		g_lingo->execute(then + savepc - 1);
 	} else if (elsep) { /* else part? */
@@ -1345,7 +1314,7 @@ void LC::c_tellcode() {
 	uint start = g_lingo->_pc;
 	uint end = g_lingo->readInt() + start - 1;
 
-	warning("STUB: c_tellcode(%s)", d1.getPrintable().c_str());
+	warning("STUB: c_tellcode(%s)", d1.asString(true).c_str());
 
 	g_lingo->_pc = end;
 }
@@ -1622,10 +1591,7 @@ void LC::c_open() {
 	Datum d2 = g_lingo->pop();
 	Datum d1 = g_lingo->pop();
 
-	d1.makeString();
-	d2.makeString();
-
-	warning("STUB: c_open(%s, %s)", d1.u.s->c_str(), d2.u.s->c_str());
+	warning("STUB: c_open(%s, %s)", d1.asString().c_str(), d2.asString().c_str());
 }
 
 void LC::c_hilite() {
diff --git a/engines/director/lingo/lingo-code.h b/engines/director/lingo/lingo-code.h
index 6a5789e51d..82b2be01db 100644
--- a/engines/director/lingo/lingo-code.h
+++ b/engines/director/lingo/lingo-code.h
@@ -29,18 +29,18 @@ namespace LC {
 	void c_xpop();
 	void c_printtop();
 
-	Datum mapBinaryOp(Datum (*func)(Datum, Datum), Datum d1, Datum d2);
-	Datum addData(Datum d1, Datum d2);
+	Datum mapBinaryOp(Datum (*func)(Datum &, Datum &), Datum &d1, Datum &d2);
+	Datum addData(Datum &d1, Datum &d2);
 	void c_add();
-	Datum subData(Datum d1, Datum d2);
+	Datum subData(Datum &d1, Datum &d2);
 	void c_sub();
-	Datum mulData(Datum d1, Datum d2);
+	Datum mulData(Datum &d1, Datum &d2);
 	void c_mul();
-	Datum divData(Datum d1, Datum d2);
+	Datum divData(Datum &d1, Datum &d2);
 	void c_div();
-	Datum modData(Datum d1, Datum d2);
+	Datum modData(Datum &d1, Datum &d2);
 	void c_mod();
-	Datum negateData(Datum d1);
+	Datum negateData(Datum &d1);
 	void c_negate();
 
 	void c_and();
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index d60fa60594..ab0cfaff6c 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -92,7 +92,7 @@ void Lingo::printStack(const char *s, uint pc) {
 
 	for (uint i = 0; i < _stack.size(); i++) {
 		Datum d = _stack[i];
-		stack += Common::String::format("<%s> ", d.getPrintable().c_str());
+		stack += Common::String::format("<%s> ", d.asString(true).c_str());
 	}
 	debugC(5, kDebugLingoExec, "[%3d]: %s", pc, stack.c_str());
 }
@@ -506,11 +506,11 @@ int Lingo::castIdFetch(Datum &var) {
 		else
 			warning("castIdFetch: reference to non-existent cast member: %s", var.u.s->c_str());
 	} else if (var.type == INT || var.type == FLOAT) {
-		var.makeInt();
-		if (!score->_loadedCast->contains(var.u.i))
-			warning("castIdFetch: reference to non-existent cast ID: %d", var.u.i);
+		int castId = var.asInt();
+		if (!score->_loadedCast->contains(castId))
+			warning("castIdFetch: reference to non-existent cast ID: %d", castId);
 		else
-			id = var.u.i;
+			id = castId;
 	} else {
 		error("castIdFetch: was expecting STRING or INT, got %s", var.type2str());
 	}
@@ -587,9 +587,7 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 		if (cast) {
 			switch (cast->_type) {
 			case kCastText:
-				value.makeString();
-				((TextCast *)cast)->setText(value.u.s->c_str());
-				delete value.u.s;
+				((TextCast *)cast)->setText(value.asString().c_str());
 				break;
 			default:
 				warning("varAssign: Unhandled cast type %s", tag2str(cast->_type));
@@ -621,7 +619,7 @@ Datum Lingo::varFetch(Datum &var) {
 		else if (sym->type == FLOAT)
 			result.u.f = sym->u.f;
 		else if (sym->type == STRING)
-			result.u.s = new Common::String(*sym->u.s);
+			result.u.s = sym->u.s;
 		else if (sym->type == POINT)
 			result.u.farr = sym->u.farr;
 		else if (sym->type == SYMBOL)
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 86f03a1757..8cb2d66675 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -72,10 +72,11 @@ struct MCIToken {
 	{ kMCITokenNone, kMCITokenNone,   0, 0 }
 };
 
-void Lingo::func_mci(Common::String &s) {
+void Lingo::func_mci(const Common::String &name) {
 	Common::String params[5];
 	MCITokenType command = kMCITokenNone;
 
+	Common::String s = name;
 	s.trim();
 	s.toLowercase();
 
@@ -170,8 +171,8 @@ void Lingo::func_mci(Common::String &s) {
 	}
 }
 
-void Lingo::func_mciwait(Common::String &s) {
-	warning("STUB: MCI wait file: %s", s.c_str());
+void Lingo::func_mciwait(const Common::String &name) {
+	warning("STUB: MCI wait file: %s", name.c_str());
 }
 
 void Lingo::func_goto(Datum &frame, Datum &movie) {
@@ -181,9 +182,8 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 		return;
 
 	if (movie.type != VOID) {
-		movie.makeString();
-
-		Common::String movieFilename = pathMakeRelative(*movie.u.s);
+		Common::String movieFilenameRaw = movie.asString();
+		Common::String movieFilename = pathMakeRelative(movieFilenameRaw);
 		Common::String cleanedFilename;
 
 		bool fileExists = false;
@@ -213,7 +213,7 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 			}
 		}
 
-		debug(1, "func_goto: '%s' -> '%s' -> '%s' -> '%s'", movie.u.s->c_str(), convertPath(*movie.u.s).c_str(),
+		debug(1, "func_goto: '%s' -> '%s' -> '%s' -> '%s'", movieFilenameRaw.c_str(), convertPath(movieFilenameRaw).c_str(),
 				movieFilename.c_str(), cleanedFilename.c_str());
 
 		if (!fileExists) {
@@ -235,9 +235,7 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 			return;
 		}
 
-		frame.makeInt();
-
-		_vm->_nextMovie.frameI = frame.u.i;
+		_vm->_nextMovie.frameI = frame.asInt();
 
 		return;
 	}
@@ -253,10 +251,8 @@ void Lingo::func_goto(Datum &frame, Datum &movie) {
 		return;
 	}
 
-	frame.makeInt();
-
 	if (_vm->getCurrentScore())
-		_vm->getCurrentScore()->setCurrentFrame(frame.u.i);
+		_vm->getCurrentScore()->setCurrentFrame(frame.asInt());
 }
 
 void Lingo::func_gotoloop() {
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 71c655ef80..77756e8f1c 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -480,7 +480,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 
 void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 	if (debugChannelSet(3, kDebugLingoExec)) {
-		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(\"%s\", %s, \"%s\", %s)", field2str(field), id.getPrintable().c_str(), entity2str(entity), d.getPrintable().c_str());
+		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(\"%s\", %s, \"%s\", %s)", field2str(field), id.asString(true).c_str(), entity2str(entity), d.asString(true).c_str());
 	}
 
 	switch (entity) {
@@ -488,13 +488,13 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 		setTheCast(id, field, d);
 		break;
 	case kTheColorDepth:
-		_vm->_colorDepth = d.makeInt();
+		_vm->_colorDepth = d.asInt();
 
 		// bpp. 1, 2, 4, 8, 32
 		warning("STUB: Lingo::setTheEntity(): Set color depth to %d", _vm->_colorDepth);
 		break;
 	case kTheFloatPrecision:
-		_floatPrecision = d.makeInt();
+		_floatPrecision = d.asInt();
 		_floatPrecision = MAX(0, MIN(_floatPrecision, 19)); // 0 to 19
 		_floatPrecisionFormat = Common::String::format("%%.%df", _floatPrecision);
 		break;
@@ -510,13 +510,13 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 }
 
 void Lingo::setTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId, Datum &d) {
-	warning("STUB: setTheMenuItemEntity(%s, %s, %s, %s, %s)", entity2str(entity), menuId.getPrintable().c_str(), field2str(field),
-				menuItemId.getPrintable().c_str(), d.getPrintable().c_str());
+	warning("STUB: setTheMenuItemEntity(%s, %s, %s, %s, %s)", entity2str(entity), menuId.asString(true).c_str(), field2str(field),
+				menuItemId.asString(true).c_str(), d.asString(true).c_str());
 }
 
 Datum Lingo::getTheMenuItemEntity(int entity, Datum &menuId, int field, Datum &menuItemId) {
-	warning("STUB: getTheMenuItemEntity(%s, %s, %s, %s)", entity2str(entity), menuId.getPrintable().c_str(), field2str(field),
-				menuItemId.getPrintable().c_str());
+	warning("STUB: getTheMenuItemEntity(%s, %s, %s, %s)", entity2str(entity), menuId.asString(true).c_str(), field2str(field),
+				menuItemId.asString(true).c_str());
 
 	return Datum();
 }
@@ -562,8 +562,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_constraint;
 		break;
 	case kTheEditableText:
-		d.makeString();
-		d.u.s = &sprite->_editableText;
+		d = Datum(sprite->_editableText);
 		break;
 	case kTheForeColor:
 		d.u.i = sprite->_foreColor;
@@ -644,8 +643,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 	int id = 0;
 	Score *score = _vm->getCurrentScore();
 
-	d.makeInt(); // Enforce Integer
-
 	if (!score) {
 		warning("Lingo::setTheSprite(): The sprite %d field \"%s\" setting over non-active score", id, field2str(field));
 		return;
@@ -665,94 +662,94 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 
 	switch (field) {
 	case kTheBackColor:
-		sprite->_backColor = d.u.i;
+		sprite->_backColor = d.asInt();
 		break;
 	case kTheBlend:
-		sprite->_blend = d.u.i;
+		sprite->_blend = d.asInt();
 		break;
 	case kTheBottom:
-		sprite->_bottom = d.u.i;
+		sprite->_bottom = d.asInt();
 		break;
 	case kTheCastNum:
-		if (score->_loadedCast->contains(d.u.i)) {
-			score->loadCastInto(sprite, d.u.i);
-			sprite->_castId = d.u.i;
+		if (score->_loadedCast->contains(d.asInt())) {
+			score->loadCastInto(sprite, d.asInt());
+			sprite->_castId = d.asInt();
 		}
 		break;
 	case kTheConstraint:
-		sprite->_constraint = d.u.i;
+		sprite->_constraint = d.asInt();
 		break;
 	case kTheEditableText:
-		sprite->_editableText = *d.makeString();
+		sprite->_editableText = d.asString();
 		break;
 	case kTheForeColor:
-		sprite->_foreColor = d.u.i;
+		sprite->_foreColor = d.asInt();
 		break;
 	case kTheHeight:
-		sprite->_height = d.u.i;
+		sprite->_height = d.asInt();
 		break;
 	case kTheInk:
-		sprite->_ink = static_cast<InkType>(d.u.i);
+		sprite->_ink = static_cast<InkType>(d.asInt());
 		break;
 	case kTheLeft:
-		sprite->_left = d.u.i;
+		sprite->_left = d.asInt();
 		break;
 	case kTheLineSize:
-		sprite->_thickness = d.u.i;
+		sprite->_thickness = d.asInt();
 		break;
 	case kTheLocH:
-		sprite->_currentPoint.x = d.u.i;
+		sprite->_currentPoint.x = d.asInt();
 		break;
 	case kTheLocV:
-		sprite->_currentPoint.y = d.u.i;
+		sprite->_currentPoint.y = d.asInt();
 		break;
 	case kTheMoveableSprite:
-		sprite->_moveable = d.u.i;
+		sprite->_moveable = d.asInt();
 		if (!d.u.i)
 			sprite->_currentPoint = sprite->_startPoint;
 		break;
 	case kTheMovieRate:
-		sprite->_movieRate = d.u.i;
+		sprite->_movieRate = d.asInt();
 		break;
 	case kTheMovieTime:
-		sprite->_movieTime = d.u.i;
+		sprite->_movieTime = d.asInt();
 		break;
 	case kThePattern:
-		sprite->setPattern(d.u.i);
+		sprite->setPattern(d.asInt());
 		break;
 	case kThePuppet:
-		sprite->_puppet = d.u.i;
+		sprite->_puppet = d.asInt();
 		break;
 	case kTheRight:
-		sprite->_right = d.u.i;
+		sprite->_right = d.asInt();
 		break;
 	case kTheStartTime:
-		sprite->_startTime = d.u.i;
+		sprite->_startTime = d.asInt();
 		break;
 	case kTheStopTime:
-		sprite->_stopTime = d.u.i;
+		sprite->_stopTime = d.asInt();
 		break;
 	case kTheStretch:
-		sprite->_stretch = d.u.i;
+		sprite->_stretch = d.asInt();
 		break;
 	case kTheTop:
-		sprite->_top = d.u.i;
+		sprite->_top = d.asInt();
 		break;
 	case kTheTrails:
-		sprite->_trails = d.u.i;
+		sprite->_trails = d.asInt();
 		break;
 	case kTheType:
-		sprite->_spriteType = static_cast<SpriteType>(d.u.i);
+		sprite->_spriteType = static_cast<SpriteType>(d.asInt());
 		break;
 	case kTheVisibility:
 	case kTheVisible:
-		sprite->_visible = (d.u.i == 0 ? false : true);
+		sprite->_visible = (d.asInt() == 0 ? false : true);
 		break;
 	case kTheVolume:
-		sprite->_volume = d.u.i;
+		sprite->_volume = d.asInt();
 		break;
 	case kTheWidth:
-		sprite->_width = d.u.i;
+		sprite->_width = d.asInt();
 		break;
 	default:
 		warning("Lingo::setTheSprite(): Unprocessed setting field \"%s\" of sprite", field2str(field));
@@ -809,8 +806,7 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		d.u.i = castType;
 		break;
 	case kTheFileName:
-		d.makeString();
-		d.u.s = &castInfo->fileName;
+		d = Datum(castInfo->fileName);
 		break;
 	case kTheForeColor:
 		{
@@ -831,24 +827,24 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		d.u.i = 1; //Not loaded handled above
 		break;
 	case kTheName:
-		d.type = STRING;
-		d.u.s = new Common::String(castInfo->name.c_str());
+		d = Datum(castInfo->name);
 		break;
 	case kTheScriptText:
-		d.type = STRING;
-		d.u.s = new Common::String(castInfo->script.c_str());
+		d = Datum(castInfo->script);
 		break;
 	case kTheText:
-		d.makeString();
-		*d.u.s = "";
-		if (castType == kCastText) {
-			if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-				*d.u.s = ((TextCast *)score->_loadedCast->getVal(id))->getText();
+		{
+			Common::String text;
+			if (castType == kCastText) {
+				if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
+					text = ((TextCast *)score->_loadedCast->getVal(id))->getText();
+				} else {
+					warning("Lingo::getTheCast(): Unknown STXT cast id %d", id);
+				}
 			} else {
-				warning("Lingo::getTheCast(): Unknown STXT cast id %d", id);
+				warning("Lingo::getTheCast(): Unprocessed getting text of cast %d type %d", id, castType);
 			}
-		} else {
-			warning("Lingo::getTheCast(): Unprocessed getting text of cast %d type %d", id, castType);
+			d = Datum(text);
 		}
 		break;
 	case kTheWidth:
@@ -893,8 +889,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			}
 			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
 
-			d.makeInt();
-			shape->_bgCol = d.u.i;
+			shape->_bgCol = d.asInt();
 			shape->_modified = 1;
 		}
 		break;
@@ -909,8 +904,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
-		castInfo->fileName = *d.u.s;
+		castInfo->fileName = d.asString();
 		break;
 	case kTheForeColor:
 		{
@@ -924,8 +918,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		}
 		break;
 	case kTheHeight:
-		d.makeInt();
-		score->getCastMemberInitialRect(id).setHeight(d.u.i);
+		score->getCastMemberInitialRect(id).setHeight(d.asInt());
 		score->setCastMemberModified(id);
 		break;
 	case kTheName:
@@ -933,24 +926,21 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
-		castInfo->name = *d.u.s;
+		castInfo->name = d.asString();
 		break;
 	case kTheScriptText:
 		if (!castInfo) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);
 			return;
 		}
-		d.makeString();
 		addCode(d.u.s->c_str(), kSpriteScript, id);
 
-		castInfo->script = *d.u.s;
+		castInfo->script = d.asString();
 		break;
 	case kTheText:
 		if (castType == kCastText) {
 			if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-				d.makeString();
-				((TextCast *)score->_loadedCast->getVal(id))->setText(d.u.s->c_str());
+				((TextCast *)score->_loadedCast->getVal(id))->setText(d.asString().c_str());
 			} else {
 				warning("Lingo::setTheCast(): Unknown STXT cast id %d", id);
 				return;
@@ -960,8 +950,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		}
 		break;
 	case kTheWidth:
-		d.makeInt();
-		score->getCastMemberInitialRect(id).setWidth(d.u.i);
+		score->getCastMemberInitialRect(id).setWidth(d.asInt());
 		score->setCastMemberModified(id);
 		break;
 	default:
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 17d520158c..5b59c05303 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -40,6 +40,8 @@ Lingo *g_lingo;
 Symbol::Symbol() {
 	type = VOID;
 	u.s = nullptr;
+	refCount = new int;
+	*refCount = 1;
 	nargs = 0;
 	maxArgs = 0;
 	parens = true;
@@ -50,6 +52,56 @@ Symbol::Symbol() {
 	archiveIndex = 0;
 }
 
+Symbol::Symbol(const Symbol &s) {
+	type = s.type;
+	u.s = s.u.s;
+	refCount = s.refCount;
+	*refCount += 1;
+	nargs = s.nargs;
+	maxArgs = s.maxArgs;
+	parens = s.parens;
+	global = s.global;
+	argNames = s.argNames;
+	varNames = s.varNames;
+	ctx = s.ctx;
+	archiveIndex = s.archiveIndex;
+}
+
+Symbol::~Symbol() {
+	*refCount -= 1;
+	if (*refCount <= 0) {
+		switch (type) {
+			case HANDLER:
+				delete u.defn;
+				break;
+			case STRING:
+				delete u.s;
+				break;
+			case ARRAY:
+				// fallthrough
+			case POINT:
+				// fallthrough
+			case RECT:
+				delete u.farr;
+				break;
+			case PARRAY:
+				delete u.parr;
+				break;
+			case VAR:
+				// fallthrough
+			case REFERENCE:
+				// fallthrough
+			case INT:
+				// fallthrough
+			case FLOAT:
+				// fallthrough
+			default:
+				break;
+		}
+		delete refCount;
+	}
+}
+
 PCell::PCell() {
 	p = nullptr;
 	v = nullptr;
@@ -347,113 +399,101 @@ void Lingo::restartLingo() {
 	// tuneousScript is not reset
 }
 
-int Lingo::alignTypes(Datum &d1, Datum &d2) {
+int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 	int opType = VOID;
 
-	if (d1.type == REFERENCE || d1.type == SYMBOL)
-		d1.makeString();
+	int d1Type = d1.type;
+	int d2Type = d2.type;
 
-	if (d2.type == REFERENCE || d2.type == SYMBOL)
-		d2.makeString();
-
-	if (d1.type == STRING) {
+	if (d1Type == STRING || d1Type == REFERENCE) {
+		Common::String src = d1.asString();
 		char *endPtr = 0;
-		double d = strtod(d1.u.s->c_str(), &endPtr);
+		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
-			d1.type = FLOAT;
-			d1.u.f = d;
+			d1Type = FLOAT;
 		} else {
-			warning("Unable to parse '%s' as a number", d1.u.s->c_str());
+			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
-	if (d2.type == STRING) {
+	if (d2Type == STRING || d1Type == REFERENCE) {
+		Common::String src = d1.asString();
 		char *endPtr = 0;
-		double d = strtod(d2.u.s->c_str(), &endPtr);
+		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
-			d2.type = FLOAT;
-			d2.u.f = d;
+			d2Type = FLOAT;
 		} else {
-			warning("Unable to parse '%s' as a number", d2.u.s->c_str());
+			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
 
-
-	if (d1.type == FLOAT || d2.type == FLOAT) {
+	if (d1Type == FLOAT || d2Type == FLOAT) {
 		opType = FLOAT;
-		d1.makeFloat();
-		d2.makeFloat();
-	} else if (d1.type == INT && d2.type == INT) {
+	} else if (d1Type == INT && d2Type == INT) {
 		opType = INT;
 	} else {
-		warning("No numeric type alignment available");
+		warning("getAlignedType(): No numeric type alignment available");
 	}
 
 	return opType;
 }
 
-int Datum::makeInt() {
+int Datum::asInt() {
+	int res = 0;
+
 	switch (type) {
 	case REFERENCE:
-		makeString();
 		// fallthrough
 	case STRING:
 		{
+			Common::String src = asString();
 			char *endPtr = 0;
-			int result = strtol(u.s->c_str(), &endPtr, 10);
+			int result = strtol(src.c_str(), &endPtr, 10);
 			if (*endPtr == 0) {
-				u.i = result;
+				res = result;
 			} else {
-				warning("Invalid int '%s'", u.s->c_str());
-				u.i = 0;
+				warning("Invalid int '%s'", src.c_str());
 			}
 		}
 		break;
 	case VOID:
-		u.i = 0;
+		// no-op
 		break;
 	case INT:
-		// no-op
+		res = u.i;
 		break;
 	case FLOAT:
-		{
-			int tmp = (int)u.f;
-			u.i = tmp;
-			break;
-		}
+		res = (int)u.f;
+		break;
 	default:
-		warning("Incorrect operation makeInt() for type: %s", type2str());
+		warning("Incorrect operation asInt() for type: %s", type2str());
 	}
 
-	type = INT;
-
-	return u.i;
+	return res;
 }
 
-double Datum::makeFloat() {
+double Datum::asFloat() {
+	double res = 0.0;
+
 	switch (type) {
 	case REFERENCE:
-		makeString();
 		// fallthrough
 	case STRING:
 		{
+			Common::String src = asString();
 			char *endPtr = 0;
-			double result = strtod(u.s->c_str(), &endPtr);
+			double result = strtod(src.c_str(), &endPtr);
 			if (*endPtr == 0) {
-				u.f = result;
+				res = result;
 			} else {
-				warning("Invalid float '%s'", u.s->c_str());
-				u.f = 0.0;
+				warning("Invalid float '%s'", src.c_str());
 			}
 		}
 		break;
 	case VOID:
-		u.f = 0.0;
+		// no-op
 		break;
 	case INT:
-		{
-			double tmp = (double)u.i;
-			u.f = tmp;
-		}
+		res = (double)u.i;
 		break;
 	case FLOAT:
 		// no-op
@@ -462,54 +502,52 @@ double Datum::makeFloat() {
 		warning("Incorrect operation makeFloat() for type: %s", type2str());
 	}
 
-	type = FLOAT;
-
-	return u.f;
+	return res;
 }
 
-Common::String *Datum::makeString(bool printonly) {
-	Common::String *s = new Common::String();
+Common::String Datum::asString(bool printonly) {
+	Common::String s;
 	switch (type) {
 	case INT:
-		*s = Common::String::format("%d", u.i);
+		s = Common::String::format("%d", u.i);
 		break;
 	case ARGC:
-		*s = Common::String::format("argc: %d", u.i);
+		s = Common::String::format("argc: %d", u.i);
 		break;
 	case ARGCNORET:
-		*s = Common::String::format("argcnoret: %d", u.i);
+		s = Common::String::format("argcnoret: %d", u.i);
 		break;
 	case FLOAT:
-		*s = Common::String::format(g_lingo->_floatPrecisionFormat.c_str(), u.f);
+		s = Common::String::format(g_lingo->_floatPrecisionFormat.c_str(), u.f);
 		if (printonly)
-			*s += "f";		// 0.0f
+			s += "f";		// 0.0f
 		break;
 	case STRING:
 		if (!printonly) {
-			*s = *u.s;
+			s = *u.s;
 		} else {
-			*s = Common::String::format("\"%s\"", u.s->c_str());
+			s = Common::String::format("\"%s\"", u.s->c_str());
 		}
 		break;
 	case SYMBOL:
 		if (!printonly) {
-			*s = Common::String::format("#%s", u.s->c_str());
+			s = Common::String::format("#%s", u.s->c_str());
 		} else {
-			*s = Common::String::format("symbol: #%s", u.s->c_str());
+			s = Common::String::format("symbol: #%s", u.s->c_str());
 		}
 		break;
 	case OBJECT:
 		if (!printonly) {
-			*s = Common::String::format("#%s", u.s->c_str());
+			s = Common::String::format("#%s", u.s->c_str());
 		} else {
-			*s = Common::String::format("object: #%s", u.s->c_str());
+			s = Common::String::format("object: #%s", u.s->c_str());
 		}
 		break;
 	case VOID:
-		*s = "#void";
+		s = "#void";
 		break;
 	case VAR:
-		*s = Common::String::format("var: #%s", u.sym->name.c_str());
+		s = Common::String::format("var: #%s", u.sym->name.c_str());
 		break;
 	case REFERENCE:
 		{
@@ -517,15 +555,15 @@ Common::String *Datum::makeString(bool printonly) {
 			Score *score = g_director->getCurrentScore();
 
 			if (!score) {
-				warning("makeString(): No score");
-				*s = "";
+				warning("asString(): No score");
+				s = "";
 				break;
 			}
 
 			if (!score->_loadedCast->contains(idx)) {
 				if (!score->_loadedCast->contains(idx - score->_castIDoffset)) {
-					warning("makeString(): Unknown REFERENCE %d", idx);
-					*s = "";
+					warning("asString(): Unknown REFERENCE %d", idx);
+					s = "";
 					break;
 				} else {
 					idx -= 1024;
@@ -533,49 +571,43 @@ Common::String *Datum::makeString(bool printonly) {
 			}
 
 			if (!printonly) {
-				*s = ((TextCast *)score->_loadedCast->getVal(idx))->getText();
+				s = ((TextCast *)score->_loadedCast->getVal(idx))->getText();
 			} else {
-				*s = Common::String::format("reference: \"%s\"", ((TextCast *)score->_loadedCast->getVal(idx))->getText().c_str());
+				s = Common::String::format("reference: \"%s\"", ((TextCast *)score->_loadedCast->getVal(idx))->getText().c_str());
 			}
 		}
 		break;
 	case ARRAY:
-		*s = "[";
+		s = "[";
 
 		for (uint i = 0; i < u.farr->size(); i++) {
 			if (i > 0)
-				*s += ", ";
+				s += ", ";
 			Datum d = u.farr->operator[](i);
-			*s += *d.makeString(printonly);
+			s += d.asString(printonly);
 		}
 
-		*s += "]";
+		s += "]";
 		break;
 	case PARRAY:
-		*s = "[";
+		s = "[";
 		if (u.parr->size() == 0)
-			*s += ":";
+			s += ":";
 		for (uint i = 0; i < u.parr->size(); i++) {
 			if (i > 0)
-				*s += ", ";
+				s += ", ";
 			Datum p = *u.parr->operator[](i).p;
 			Datum v = *u.parr->operator[](i).v;
-			*s += Common::String::format("%s:%s", p.makeString(printonly)->c_str(), v.makeString(printonly)->c_str());
+			s += Common::String::format("%s:%s", p.asString(printonly).c_str(), v.asString(printonly).c_str());
 		}
 
-		*s += "]";
+		s += "]";
 		break;
 	default:
-		warning("Incorrect operation makeString() for type: %s", type2str());
+		warning("Incorrect operation asString() for type: %s", type2str());
 	}
 
-	if (printonly)
-		return s;
-
-	u.s = s;
-	type = STRING;
-
-	return u.s;
+	return s;
 }
 
 const char *Datum::type2str(bool isk) {
@@ -608,31 +640,40 @@ const char *Datum::type2str(bool isk) {
 	}
 }
 
-int Datum::compareTo(Datum d, bool ignoreCase) {
+int Datum::compareTo(Datum &d, bool ignoreCase) {
 	if (type == STRING && d.type == STRING) {
 		if (ignoreCase) {
-			return toLowercaseMac(u.s)->compareTo(*toLowercaseMac(d.u.s));
+			return toLowercaseMac(*u.s).compareTo(toLowercaseMac(*d.u.s));
 		} else {
 			return u.s->compareTo(*d.u.s);
 		}
 	} else if (type == SYMBOL && d.type == SYMBOL) {
 		// TODO: Implement union comparisons
 		return ignoreCase ? u.sym->name.compareToIgnoreCase(d.u.sym->name) : u.sym->name.compareTo(d.u.sym->name);
-	} else if (g_lingo->alignTypes(*this, d) == FLOAT) {
-		if (u.f < d.u.f) {
-			return -1;
-		} else if (u.f == d.u.f) {
-			return 0;
-		} else {
-			return 1;
-		}
 	} else {
-		if (u.i < d.u.i) {
-			return -1;
-		} else if (u.i == d.u.i) {
-			return 0;
+		int alignType = g_lingo->getAlignedType(*this, d);
+		if (alignType == FLOAT) {
+			double f1 = asFloat();
+			double f2 = d.asFloat();
+			if (f1 < f2) {
+				return -1;
+			} else if (f1 == f2) {
+				return 0;
+			} else {
+				return 1;
+			}
+		} else if (alignType == INT) {
+			double i1 = asInt();
+			double i2 = asInt();
+			if (i1 < i2) {
+				return -1;
+			} else if (i1 == i2) {
+				return 0;
+			} else {
+				return 1;
+			}
 		} else {
-			return 1;
+			error("Invalid comparison between types %s and %s", type2str(), d.type2str());
 		}
 	}
 }
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index efda8fc023..74b24b1094 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -73,13 +73,16 @@ struct Symbol {	/* symbol table entry */
 	union {
 		int		i;			/* VAR */
 		double	f;			/* FLOAT */
-		ScriptData	*defn;	/* FUNCTION, PROCEDURE */
+		ScriptData	*defn;	/* HANDLER */
 		void (*func)();		/* OPCODE */
 		void (*bltin)(int);	/* BUILTIN */
 		Common::String	*s;	/* STRING */
 		DatumArray *farr;	/* ARRAY, POINT, RECT */
 		PropertyArray *parr;
 	} u;
+
+	int *refCount;
+
 	int nargs;		/* number of arguments */
 	int maxArgs;	/* maximal number of arguments, for builtins */
 	bool parens;	/* whether parens required or not, for builitins */
@@ -91,6 +94,8 @@ struct Symbol {	/* symbol table entry */
 	int archiveIndex; 		/* optional archive to execute with */
 
 	Symbol();
+	Symbol(const Symbol &s);
+	~Symbol();
 };
 
 struct PCell {
@@ -113,19 +118,83 @@ struct Datum {	/* interpreter stack type */
 		PropertyArray *parr; /* PARRAY */
 	} u;
 
-	Datum() { u.sym = NULL; type = VOID; }
-	Datum(int val) { u.i = val; type = INT; }
-	Datum(double val) { u.f = val; type = FLOAT; }
-	Datum(Common::String *val) { u.s = val; type = STRING; }
+	int *refCount;
+
+	Datum() {
+		u.sym = NULL;
+		type = VOID;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(const Datum &d) {
+		type = d.type;
+		u = d.u;
+		refCount = d.refCount;
+		*refCount += 1;
+	}
+	Datum(int val) {
+		u.i = val;
+		type = INT;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(double val) {
+		u.f = val;
+		type = FLOAT;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(const Common::String &val) {
+		u.s = new Common::String(val);
+		type = STRING;
+		refCount = new int;
+		*refCount = 1;
+	}
+	Datum(Common::String *val) {
+		u.s = val;
+		type = STRING;
+		refCount = new int;
+		*refCount = 1;
+	}
+	~Datum() {
+		*refCount -= 1;
+		if (*refCount <= 0) {
+			switch (type) {
+				case STRING:
+					delete u.s;
+					break;
+				case ARRAY:
+					// fallthrough
+				case POINT:
+					// fallthrough
+				case RECT:
+					delete u.farr;
+					break;
+				case PARRAY:
+					delete u.parr;
+					break;
+				case VAR:
+					// fallthrough
+				case REFERENCE:
+					// fallthrough
+				case INT:
+					// fallthrough
+				case FLOAT:
+					// fallthrough
+				default:
+					break;
+			}
+			delete refCount;
+		}
+	}
 
-	double makeFloat();
-	int makeInt();
-	Common::String *makeString(bool printonly = false);
-	Common::String getPrintable() { return *makeString(true); }
+	double asFloat();
+	int asInt();
+	Common::String asString(bool printonly = false);
 
 	const char *type2str(bool isk = false);
 
-	int compareTo(Datum d, bool ignoreCase = false);
+	int compareTo(Datum &d, bool ignoreCase = false);
 };
 
 struct Builtin {
@@ -225,7 +294,7 @@ public:
 	void varAssign(Datum &var, Datum &value);
 	Datum varFetch(Datum &var);
 
-	int alignTypes(Datum &d1, Datum &d2);
+	int getAlignedType(Datum &d1, Datum &d2);
 
 	void printAllVars();
 
@@ -271,8 +340,8 @@ public:
 
 	void factoryCall(Common::String &name, int nargs);
 
-	void func_mci(Common::String &s);
-	void func_mciwait(Common::String &s);
+	void func_mci(const Common::String &name);
+	void func_mciwait(const Common::String &name);
 	void func_beep(int repeats);
 	void func_goto(Datum &frame, Datum &movie);
 	void func_gotoloop();
diff --git a/engines/director/util.cpp b/engines/director/util.cpp
index 599f64abd3..04755940ce 100644
--- a/engines/director/util.cpp
+++ b/engines/director/util.cpp
@@ -84,22 +84,22 @@ static char lowerCaseConvert[] =
 ".. aao.." // c8
 "--.....y";// d0-d8
 
-Common::String *toLowercaseMac(Common::String *s) {
-	Common::String *res = new Common::String;
-	const unsigned char *p = (const unsigned char *)s->c_str();
+Common::String toLowercaseMac(const Common::String &s) {
+	Common::String res;
+	const unsigned char *p = (const unsigned char *)s.c_str();
 
 	while (*p) {
 		if (*p >= 0x80 && *p <= 0xd8) {
 			if (lowerCaseConvert[*p - 0x80] != '.')
-				*res += lowerCaseConvert[*p - 0x80];
+				res += lowerCaseConvert[*p - 0x80];
 			else
-				*res += *p;
+				res += *p;
 		} else if (*p < 0x80) {
-			*res += tolower(*p);
+			res += tolower(*p);
 		} else {
 			warning("Unacceptable symbol in toLowercaseMac: %c", *p);
 
-			*res += *p;
+			res += *p;
 		}
 		p++;
 	}
diff --git a/engines/director/util.h b/engines/director/util.h
index f9401f3f6b..23447da4bf 100644
--- a/engines/director/util.h
+++ b/engines/director/util.h
@@ -32,7 +32,7 @@ namespace Director {
 int castNumToNum(const char *str);
 char *numToCastNum(int num);
 
-Common::String *toLowercaseMac(Common::String *s);
+Common::String toLowercaseMac(const Common::String &s);
 
 Common::String convertPath(Common::String &path);
 


Commit: b572116249979970bcc452c1f6e9dbbdfddabcee
    https://github.com/scummvm/scummvm/commit/b572116249979970bcc452c1f6e9dbbdfddabcee
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Add copy assignment operator for Datum/Symbol

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 3ad6e07416..b024345ed5 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -714,7 +714,7 @@ void LB::b_getaProp(int nargs) {
 		Datum d;
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			d = *list.u.parr->operator[](index-1).v;
+			d = *list.u.parr->operator[](index - 1).v;
 		}
 		g_lingo->push(d);
 		break;
@@ -777,7 +777,7 @@ void LB::b_getOne(int nargs) {
 		Datum d;
 		int index = LC::compareArrays(LC::eqData, list, val, true, true).u.i;
 		if (index > 0) {
-			d = *list.u.parr->operator[](index-1).p;
+			d = *list.u.parr->operator[](index - 1).p;
 		}
 		g_lingo->push(d);
 		break;
@@ -791,6 +791,7 @@ void LB::b_getPos(int nargs) {
 	ARGNUMCHECK(2);
 	Datum val = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(val, INT, FLOAT);
 	TYPECHECK2(list, ARRAY, PARRAY);
 
 	switch (list.type) {
@@ -832,7 +833,7 @@ void LB::b_getProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			g_lingo->push(*list.u.parr->operator[](index-1).v);
+			g_lingo->push(*list.u.parr->operator[](index - 1).v);
 		} else {
 			error("b_getProp: Property %s not found", prop.asString().c_str());
 		}
@@ -845,11 +846,14 @@ void LB::b_getProp(int nargs) {
 
 void LB::b_getPropAt(int nargs) {
 	ARGNUMCHECK(2);
-	int index = g_lingo->pop().asInt();
+
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
+	TYPECHECK2(indexD, INT, FLOAT);
 	TYPECHECK(list, PARRAY);
+	int index = indexD.asInt();
 
-	g_lingo->push(*list.u.parr->operator[](index-1).p);
+	g_lingo->push(*list.u.parr->operator[](index - 1).p);
 }
 
 void LB::b_list(int nargs) {
@@ -955,7 +959,7 @@ void LB::b_setaProp(int nargs) {
 	case PARRAY: {
 		int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 		if (index > 0) {
-			*list.u.parr->operator[](index-1).v = value;
+			*list.u.parr->operator[](index - 1).v = value;
 		} else {
 			PCell cell = PCell(prop, value);
 			list.u.parr->push_back(cell);
@@ -970,15 +974,17 @@ void LB::b_setaProp(int nargs) {
 void LB::b_setAt(int nargs) {
 	ARGNUMCHECK(3);
 	Datum value = g_lingo->pop();
-	int index = g_lingo->pop().asInt();
+	Datum indexD = g_lingo->pop();
 	Datum list = g_lingo->pop();
 
+	TYPECHECK2(indexD, INT, FLOAT);
 	TYPECHECK2(list, ARRAY, PARRAY);
+	int index = indexD.asInt();
 
 	switch (list.type) {
 	case ARRAY:
 		if ((uint)index < list.u.farr->size()) {
-			list.u.farr->operator[](index-1) = value;
+			list.u.farr->operator[](index - 1) = value;
 		} else {
 			// TODO: Extend the list if we request an index beyond it
 			ARRBOUNDSCHECK(index, list);
@@ -986,7 +992,7 @@ void LB::b_setAt(int nargs) {
 		break;
 	case PARRAY:
 		ARRBOUNDSCHECK(index, list);
-		*list.u.parr->operator[](index-1).v = value;
+		*list.u.parr->operator[](index - 1).v = value;
 		break;
 	default:
 		break;
@@ -1004,7 +1010,7 @@ void LB::b_setProp(int nargs) {
 
 	int index = LC::compareArrays(LC::eqData, list, prop, true).u.i;
 	if (index > 0) {
-		*list.u.parr->operator[](index-1).v = value;
+		*list.u.parr->operator[](index - 1).v = value;
 	} else {
 		warning("b_setProp: Property not found");
 	}
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index ab0cfaff6c..417318805b 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -269,10 +269,10 @@ Symbol *Lingo::define(Common::String &name, int nargs, ScriptData *code) {
 		warning("Redefining handler '%s'", name.c_str());
 
 		// Do not attempt to remove code from built-ins
-		if (sym->type == HANDLER)
-			delete sym->u.defn;
-		else
-			sym->type = HANDLER;
+		sym->reset();
+		sym->refCount = new int;
+		*sym->refCount = 1;
+		sym->type = HANDLER;
 	}
 
 	sym->u.defn = code;
@@ -538,27 +538,20 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 			return;
 		}
 
-		if ((sym->type == STRING || sym->type == VOID) && sym->u.s) // Free memory if needed
-			delete var.u.sym->u.s;
-
-		if (sym->type == POINT || sym->type == RECT || sym->type == ARRAY)
-			delete var.u.sym->u.farr;
-		else if (sym->type == PARRAY)
-			delete var.u.sym->u.parr;
-
+		sym->reset();
+		sym->refCount = value.refCount;
+		*sym->refCount += 1;
 		sym->type = value.type;
 		if (value.type == INT) {
 			sym->u.i = value.u.i;
 		} else if (value.type == FLOAT) {
 			sym->u.f = value.u.f;
 		} else if (value.type == STRING) {
-			sym->u.s = new Common::String(*value.u.s);
-			delete value.u.s;
+			sym->u.s = value.u.s;
 		} else if (value.type == POINT || value.type == ARRAY) {
-			sym->u.farr = new DatumArray(*value.u.farr);
-			delete value.u.farr;
+			sym->u.farr = value.u.farr;
 		} else if (value.type == PARRAY) {
-			sym->u.parr = new PropertyArray(*value.u.parr);
+			sym->u.parr = value.u.parr;
 		} else if (value.type == SYMBOL) {
 			sym->u.s = value.u.s;
 		} else if (value.type == OBJECT) {
@@ -575,15 +568,16 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 			warning("varAssign: Assigning to a reference to an empty score");
 			return;
 		}
-		if (!score->_loadedCast->contains(var.u.i)) {
-			if (!score->_loadedCast->contains(var.u.i - score->_castIDoffset)) {
-				warning("varAssign: Unknown REFERENCE %d", var.u.i);
+		int referenceId = var.u.i;
+		if (!score->_loadedCast->contains(referenceId)) {
+			if (!score->_loadedCast->contains(referenceId - score->_castIDoffset)) {
+				warning("varAssign: Unknown REFERENCE %d", referenceId);
 				return;
 			} else {
-				var.u.i -= score->_castIDoffset;
+				referenceId -= score->_castIDoffset;
 			}
 		}
-		Cast *cast = score->_loadedCast->getVal(var.u.i);
+		Cast *cast = score->_loadedCast->getVal(referenceId);
 		if (cast) {
 			switch (cast->_type) {
 			case kCastText:
@@ -613,6 +607,9 @@ Datum Lingo::varFetch(Datum &var) {
 		}
 
 		result.type = sym->type;
+		delete result.refCount;
+		result.refCount = sym->refCount;
+		*result.refCount += 1;
 
 		if (sym->type == INT)
 			result.u.i = sym->u.i;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 5b59c05303..ba6136bec3 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -67,7 +67,26 @@ Symbol::Symbol(const Symbol &s) {
 	archiveIndex = s.archiveIndex;
 }
 
-Symbol::~Symbol() {
+Symbol& Symbol::operator=(const Symbol &s) {
+	if (this != &s) {
+		reset();
+		type = s.type;
+		u.s = s.u.s;
+		refCount = s.refCount;
+		*refCount += 1;
+		nargs = s.nargs;
+		maxArgs = s.maxArgs;
+		parens = s.parens;
+		global = s.global;
+		argNames = s.argNames;
+		varNames = s.varNames;
+		ctx = s.ctx;
+		archiveIndex = s.archiveIndex;
+	}
+	return *this;
+}
+
+void Symbol::reset() {
 	*refCount -= 1;
 	if (*refCount <= 0) {
 		switch (type) {
@@ -102,6 +121,10 @@ Symbol::~Symbol() {
 	}
 }
 
+Symbol::~Symbol() {
+	reset();
+}
+
 PCell::PCell() {
 	p = nullptr;
 	v = nullptr;
@@ -664,7 +687,7 @@ int Datum::compareTo(Datum &d, bool ignoreCase) {
 			}
 		} else if (alignType == INT) {
 			double i1 = asInt();
-			double i2 = asInt();
+			double i2 = d.asInt();
 			if (i1 < i2) {
 				return -1;
 			} else if (i1 == i2) {
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 74b24b1094..dceaa266fa 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -95,6 +95,8 @@ struct Symbol {	/* symbol table entry */
 
 	Symbol();
 	Symbol(const Symbol &s);
+	Symbol& operator=(const Symbol &s);
+	void reset();
 	~Symbol();
 };
 
@@ -132,6 +134,16 @@ struct Datum {	/* interpreter stack type */
 		refCount = d.refCount;
 		*refCount += 1;
 	}
+	Datum& operator=(const Datum &d) {
+		if (this != &d) {
+			reset();
+			type = d.type;
+			u = d.u;
+			refCount = d.refCount;
+			*refCount += 1;
+		}
+		return *this;
+	}
 	Datum(int val) {
 		u.i = val;
 		type = INT;
@@ -156,7 +168,7 @@ struct Datum {	/* interpreter stack type */
 		refCount = new int;
 		*refCount = 1;
 	}
-	~Datum() {
+	void reset() {
 		*refCount -= 1;
 		if (*refCount <= 0) {
 			switch (type) {
@@ -186,6 +198,11 @@ struct Datum {	/* interpreter stack type */
 			}
 			delete refCount;
 		}
+
+	}
+
+	~Datum() {
+		reset();
 	}
 
 	double asFloat();


Commit: bdf62e6f263d27c872a42882a562d597e7a749cc
    https://github.com/scummvm/scummvm/commit/bdf62e6f263d27c872a42882a562d597e7a749cc
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Precalculate array size for b_addAt

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index b024345ed5..f70285ca55 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -558,8 +558,9 @@ void LB::b_addAt(int nargs) {
 	int index = indexD.asInt();
 	TYPECHECK(list, ARRAY);
 
-	if (!((uint)index < list.u.farr->size())) {
-		for (uint i = 0; i < index - list.u.farr->size() - 1; i++)
+	int size = list.u.farr->size();
+	if (index > size) {
+		for (int i = 0; i < index - size - 1; i++)
 			list.u.farr->push_back(Datum(0));
 	}
 	list.u.farr->insert_at(index - 1, value);


Commit: ee9c723c662004bc13b9ad6e67ed7f84ab629e03
    https://github.com/scummvm/scummvm/commit/ee9c723c662004bc13b9ad6e67ed7f84ab629e03
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Improve debug messages for cb_v4theentity*

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 868fa4f1d8..c25edca2f9 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -528,14 +528,14 @@ void LC::cb_v4theentitypush() {
 				Datum id;
 				id.u.i = 0;
 				id.type = VOID;
-				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(0x%02x, NULL, 0x%02x)", entity, field);
+				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(%s, VOID, %s)", g_lingo->entity2str(entity), g_lingo->field2str(field));
 				result = g_lingo->getTheEntity(entity, id, field);
 			}
 			break;
 		case kTEAItemId:
 			{
 				Datum id = g_lingo->pop();
-				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(0x%02x, id, 0x%02x)", entity, field);
+				debugC(3, kDebugLingoExec, "cb_v4theentitypush: calling getTheEntity(%s, %s, %s)", g_lingo->entity2str(entity), id.asString(true).c_str(), g_lingo->field2str(field));
 				result = g_lingo->getTheEntity(entity, id, field);
 			}
 			break;
@@ -587,7 +587,7 @@ void LC::cb_v4theentitynamepush() {
 	TheEntity *entity = g_lingo->_theEntities[name];
 
 	debugC(3, kDebugLingoExec, "cb_v4theentitynamepush: %s", name.c_str());
-	debugC(3, kDebugLingoExec, "cb_v4theentitynamepush: calling getTheEntity(0x%02x, id, kTheNOField)", entity->entity);
+	debugC(3, kDebugLingoExec, "cb_v4theentitynamepush: calling getTheEntity(%s, VOID, kTheNOField)", g_lingo->entity2str(entity->entity));
 	Datum result = g_lingo->getTheEntity(entity->entity, id, kTheNOField);
 
 	g_lingo->push(result);
@@ -626,14 +626,14 @@ void LC::cb_v4theentityassign() {
 			Datum id;
 			id.u.s = NULL;
 			id.type = VOID;
-			debugC(3, kDebugLingoExec, "cb_v4theentityassign: calling setTheEntity(0x%02x, NULL, 0x%02x, value)", entity, field);
+			debugC(3, kDebugLingoExec, "cb_v4theentityassign: calling setTheEntity(%s, VOID, %s, %s)", g_lingo->entity2str(entity), g_lingo->field2str(field), value.asString(true).c_str());
 			g_lingo->setTheEntity(entity, id, field, value);
 		}
 		break;
 	case kTEAItemId:
 		{
 			Datum id = g_lingo->pop();
-			debugC(3, kDebugLingoExec, "cb_v4theentityassign: calling setTheEntity(0x%02x, id, 0x%02x, value)", entity, field);
+			debugC(3, kDebugLingoExec, "cb_v4theentityassign: calling setTheEntity(%s, %s, %s, %s)", g_lingo->entity2str(entity), id.asString(true).c_str(), g_lingo->field2str(field), value.asString(true).c_str());
 			g_lingo->setTheEntity(entity, id, field, value);
 		}
 		break;


Commit: 6bdfc4cfbd085905ef7a3a4040695a24ab47e8b6
    https://github.com/scummvm/scummvm/commit/6bdfc4cfbd085905ef7a3a4040695a24ab47e8b6
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: Replace ad-hoc cast lookups with _vm->getCastMember

Changed paths:
    engines/director/director.h
    engines/director/frame.cpp
    engines/director/lingo/lingo-codegen.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/lingo/lingo.h
    engines/director/resource.cpp
    engines/director/score.cpp
    engines/director/score.h


diff --git a/engines/director/director.h b/engines/director/director.h
index 7a768782c7..cdd47cedac 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -116,6 +116,7 @@ public:
 	uint16 getPaletteColorCount() const { return _currentPaletteLength; }
 	void loadSharedCastsFrom(Common::String filename);
 	void clearSharedCast();
+	Cast *getCastMember(int castId);
 	void loadPatterns();
 	uint32 transformColor(uint32 color);
 	Graphics::MacPatterns &getPatterns();
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 9982ae5279..fe5e032efa 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -603,16 +603,11 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
 				break;
 			}
 		} else {
-			if (!_vm->getCurrentScore()->_loadedCast->contains(_sprites[i]->_castId)) {
-				if (!_vm->getSharedScore() || !_vm->getSharedScore()->_loadedCast->contains(_sprites[i]->_castId)) {
-					debugC(1, kDebugImages, "Frame::renderSprites(): Cast id %d not found", _sprites[i]->_castId);
-					continue;
-				} else {
-					debugC(1, kDebugImages, "Frame::renderSprites(): Getting cast id %d from shared cast", _sprites[i]->_castId);
-					castType = _vm->getSharedScore()->_loadedCast->getVal(_sprites[i]->_castId)->_type;
-				}
+			Cast *member = _vm->getCastMember(_sprites[i]->_castId);
+			if (!member) {
+				debugC(1, kDebugImages, "Frame::renderSprites(): Cast id %d not found", _sprites[i]->_castId);
 			} else {
-				castType = _vm->getCurrentScore()->_loadedCast->getVal(_sprites[i]->_castId)->_type;
+				castType = member->_type;
 			}
 		}
 
@@ -774,7 +769,14 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
 
 	// This may not be a button cast. It could be a textcast with the channel forcing it
 	// to be a checkbox or radio button!
-	ButtonCast *button = (ButtonCast *)_vm->getCurrentScore()->_loadedCast->getVal(castId);
+	Cast *member = _vm->getCastMember(castId);
+	if (!member) {
+		warning("renderButton: unknown cast id %d", castId);
+	} else if (member->_type != kCastButton) {
+		warning("renderButton: cast id %d not of type kCastButton", castId);
+		return;
+	}
+	ButtonCast *button = (ButtonCast *)member;
 
 	// Sometimes, at least in the D3 Workshop Examples, these buttons are just TextCast.
 	// If they are, then we just want to use the spriteType as the button type.
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 417318805b..8c6b4bc188 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -507,7 +507,7 @@ int Lingo::castIdFetch(Datum &var) {
 			warning("castIdFetch: reference to non-existent cast member: %s", var.u.s->c_str());
 	} else if (var.type == INT || var.type == FLOAT) {
 		int castId = var.asInt();
-		if (!score->_loadedCast->contains(castId))
+		if (!_vm->getCastMember(castId))
 			warning("castIdFetch: reference to non-existent cast ID: %d", castId);
 		else
 			id = castId;
@@ -569,24 +569,18 @@ void Lingo::varAssign(Datum &var, Datum &value) {
 			return;
 		}
 		int referenceId = var.u.i;
-		if (!score->_loadedCast->contains(referenceId)) {
-			if (!score->_loadedCast->contains(referenceId - score->_castIDoffset)) {
-				warning("varAssign: Unknown REFERENCE %d", referenceId);
-				return;
-			} else {
-				referenceId -= score->_castIDoffset;
-			}
+		Cast *member = g_director->getCastMember(referenceId);
+		if (!member) {
+			warning("varAssign: Unknown cast id %d", referenceId);
+			return;
 		}
-		Cast *cast = score->_loadedCast->getVal(referenceId);
-		if (cast) {
-			switch (cast->_type) {
-			case kCastText:
-				((TextCast *)cast)->setText(value.asString().c_str());
-				break;
-			default:
-				warning("varAssign: Unhandled cast type %s", tag2str(cast->_type));
-				break;
-			}
+		switch (member->_type) {
+		case kCastText:
+			((TextCast *)member)->setText(value.asString().c_str());
+			break;
+		default:
+			warning("varAssign: Unhandled cast type %s", tag2str(member->_type));
+			break;
 		}
 	}
 }
@@ -633,16 +627,7 @@ Datum Lingo::varFetch(Datum &var) {
 		}
 
 	} else if (var.type == REFERENCE) {
-		Score *score = g_director->getCurrentScore();
-		if (!score->_loadedCast->contains(var.u.i)) {
-			if (!score->_loadedCast->contains(var.u.i - score->_castIDoffset)) {
-				warning("varFetch: Unknown REFERENCE %d", var.u.i);
-				return result;
-			} else {
-				var.u.i -= score->_castIDoffset;
-			}
-		}
-		Cast *cast = score->_loadedCast->getVal(var.u.i);
+		Cast *cast = _vm->getCastMember(var.u.i);
 		if (cast) {
 			switch (cast->_type) {
 			case kCastText:
@@ -653,6 +638,8 @@ Datum Lingo::varFetch(Datum &var) {
 				warning("varFetch: Unhandled cast type %s", tag2str(cast->_type));
 				break;
 			}
+		} else {
+			warning("varFetch: Unknown cast id %d", var.u.i);
 		}
 
 	}
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 8cb2d66675..e9f2e8f232 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -333,30 +333,31 @@ void Lingo::func_play(Datum &frame, Datum &movie) {
 	func_goto(frame, movie);
 }
 
-void Lingo::func_cursor(int c, int m) {
+void Lingo::func_cursor(int cursorId, int maskId) {
 	if (_cursorOnStack) {
 		// pop cursor
 		_vm->getMacWindowManager()->popCursor();
 	}
 
-	if (m != -1) {
-		Score *score = _vm->getCurrentScore();
-		if (!score->_loadedCast->contains(c) || !score->_loadedCast->contains(m)) {
-			warning("cursor: non-existent cast reference");
+	if (maskId != -1) {
+		Cast *cursorCast = _vm->getCastMember(cursorId);
+		Cast *maskCast = _vm->getCastMember(maskId);
+		if (!cursorCast || !maskCast) {
+			warning("func_cursor(): non-existent cast reference");
 			return;
 		}
 
-		if (score->_loadedCast->getVal(c)->_type != kCastBitmap || score->_loadedCast->getVal(m)->_type != kCastBitmap) {
-			warning("cursor: wrong cast reference type");
+		if (cursorCast->_type != kCastBitmap || maskCast->_type != kCastBitmap) {
+			warning("func_cursor(): wrong cast reference type");
 			return;
 		}
 
-		if (score->_loadedCast->getVal(c)->_surface == nullptr) {
-			warning("cursor: empty sprite %d surface", c);
+		if (cursorCast->_surface == nullptr) {
+			warning("func_cursor(): empty surface for bitmap cast %d", cursorId);
 			return;
 		}
-		if (score->_loadedCast->getVal(m)->_surface == nullptr) {
-			warning("cursor: empty sprite %d surface", m);
+		if (maskCast->_surface == nullptr) {
+			warning("func_cursor(): empty surface for bitmap cast %d", maskId);
 			return;
 		}
 
@@ -366,15 +367,15 @@ void Lingo::func_cursor(int c, int m) {
 		for (int y = 0; y < 16; y++) {
 			const byte *cursor = nullptr, *mask = nullptr;
 
-			if (y < score->_loadedCast->getVal(c)->_surface->h &&
-					y < score->_loadedCast->getVal(m)->_surface->h) {
-				cursor = (const byte *)score->_loadedCast->getVal(c)->_surface->getBasePtr(0, y);
-				mask = (const byte *)score->_loadedCast->getVal(m)->_surface->getBasePtr(0, y);
+			if (y < cursorCast->_surface->h &&
+					y < maskCast->_surface->h) {
+				cursor = (const byte *)cursorCast->_surface->getBasePtr(0, y);
+				mask = (const byte *)maskCast->_surface->getBasePtr(0, y);
 			}
 
 			for (int x = 0; x < 16; x++) {
-				if (x >= score->_loadedCast->getVal(c)->_surface->w ||
-						x >= score->_loadedCast->getVal(m)->_surface->w) {
+				if (x >= cursorCast->_surface->w ||
+						x >= maskCast->_surface->w) {
 					cursor = mask = nullptr;
 				}
 
@@ -398,7 +399,7 @@ void Lingo::func_cursor(int c, int m) {
 	}
 
 	// and then push cursor.
-	switch (c) {
+	switch (cursorId) {
 	case 0:
 	case -1:
 	default:
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 77756e8f1c..f71117ada3 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -671,7 +671,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		sprite->_bottom = d.asInt();
 		break;
 	case kTheCastNum:
-		if (score->_loadedCast->contains(d.asInt())) {
+		if (_vm->getCastMember(d.asInt())) {
 			score->loadCastInto(sprite, d.asInt());
 			sprite->_castId = d.asInt();
 		}
@@ -836,8 +836,9 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		{
 			Common::String text;
 			if (castType == kCastText) {
-				if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-					text = ((TextCast *)score->_loadedCast->getVal(id))->getText();
+				Cast *member = _vm->getCastMember(id);
+				if (member && member->_type == kCastText) {
+					text = ((TextCast *)member)->getText();
 				} else {
 					warning("Lingo::getTheCast(): Unknown STXT cast id %d", id);
 				}
@@ -878,7 +879,12 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		return;
 	}
 
-	CastType castType = score->_loadedCast->getVal(id)->_type;
+	Cast *member = _vm->getCastMember(id);
+	if (!member) {
+		error("Lingo::setTheCast(): Cast id %d doesn't exist", id);
+		return;
+	}
+	CastType castType = member->_type;
 	CastInfo *castInfo = score->_castsInfo[id + score->_castIDoffset];
 
 	switch (field) {
@@ -887,7 +893,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 			if (castType != kCastShape) {
 				warning("Lingo::setTheCast(): Field \"%s\" of cast %d not found", field2str(field), id);
 			}
-			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
+			ShapeCast *shape = (ShapeCast *)member;
 
 			shape->_bgCol = d.asInt();
 			shape->_modified = 1;
@@ -912,7 +918,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 				warning("Lingo::setTheCast(): Field \"%s\" of cast %d not found", field2str(field), id);
 				return;
 			}
-			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
+			ShapeCast *shape = (ShapeCast *)member;
 			shape->_fgCol = d.u.i;
 			shape->_modified = 1;
 		}
@@ -939,8 +945,8 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		break;
 	case kTheText:
 		if (castType == kCastText) {
-			if (score->_loadedCast->contains(id) && score->_loadedCast->getVal(id)->_type == kCastText) {
-				((TextCast *)score->_loadedCast->getVal(id))->setText(d.asString().c_str());
+			if (member->_type == kCastText) {
+				((TextCast *)member)->setText(d.asString().c_str());
 			} else {
 				warning("Lingo::setTheCast(): Unknown STXT cast id %d", id);
 				return;
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index dceaa266fa..b93899c571 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -366,7 +366,7 @@ public:
 	void func_gotoprevious();
 	void func_play(Datum &frame, Datum &movie);
 	void func_playdone();
-	void func_cursor(int c, int mask);
+	void func_cursor(int cursorId, int maskId);
 	int func_marker(int m);
 
 	// lingo-the.cpp
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index c2f9c50df3..e0921e89c4 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -376,4 +376,15 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
 	_lingo->_archiveIndex = 0;
 }
 
+Cast *DirectorEngine::getCastMember(int castId) {
+	Cast *result = nullptr;
+	if (_currentScore) {
+		result = _currentScore->getCastMember(castId);
+	}
+	if (result == nullptr && _sharedScore) {
+		result = _sharedScore->getCastMember(castId);
+	}
+	return result;
+}
+
 } // End of namespace Director
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 45aba04df2..0be5558a01 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -764,10 +764,9 @@ void Score::setSpriteCasts() {
 			if (castId == 0)
 				continue;
 
-			if (_loadedCast->contains(castId)) {
-				_frames[i]->_sprites[j]->_cast = _loadedCast->getVal(castId);
-			} else if (_vm->getSharedScore() && _vm->getSharedScore()->_loadedCast && _vm->getSharedScore()->_loadedCast->contains(castId)) {
-				_frames[i]->_sprites[j]->_cast = _vm->getSharedScore()->_loadedCast->getVal(castId);
+			Cast *member = _vm->getCastMember(castId);
+			if (member) {
+				_frames[i]->_sprites[j]->_cast = member;
 			}
 		}
 	}
@@ -948,28 +947,29 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id,
 			break;
 		}
 
-		// FIXME. Disabled by default, requires --debugflags=bytecode for now
+		Cast *member = _loadedCast->getVal(id);
+		// FIXME. Bytecode disabled by default, requires --debugflags=bytecode for now
 		if (_vm->getVersion() >= 4 && castType == kCastLingoScript && debugChannelSet(-1, kDebugBytecode)) {
 			// Try and load the compiled Lingo script associated with this cast
-			uint scriptId = ((ScriptCast *)(*_loadedCast)[id])->_id - 1;
+			uint scriptId = ((ScriptCast *)member)->_id - 1;
 			if (scriptId < _castScriptIds.size()) {
 				int resourceId = _castScriptIds[scriptId];
 				Common::SeekableSubReadStreamEndian *r;
-				_lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), ((ScriptCast *)_loadedCast->getVal(id))->_scriptType, id);
+				_lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), ((ScriptCast *)member)->_scriptType, id);
 				delete r;
 			} else {
 				warning("Score::loadCastData(): Lingo context missing a resource entry for script %d referenced in cast %d", scriptId, id);
 			}
 		} else {
 			if (!ci->script.empty()) {
-				if (_loadedCast->getVal(id)->_type == kCastLingoScript) {
+				if (member->_type == kCastLingoScript) {
 					// the script type here could be wrong!
 					if (ConfMan.getBool("dump_scripts"))
-						dumpScript(ci->script.c_str(), ((ScriptCast *)_loadedCast->getVal(id))->_scriptType, id);
+						dumpScript(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id);
 
-					_lingo->addCode(ci->script.c_str(), ((ScriptCast *)_loadedCast->getVal(id))->_scriptType, id);
+					_lingo->addCode(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id);
 				} else {
-					warning("Score::loadCastData(): Wrong cast type: %d", _loadedCast->getVal(id)->_type);
+					warning("Score::loadCastData(): Wrong cast type: %d", member->_type);
 				}
 			}
 		}
@@ -1781,4 +1781,13 @@ void Score::renderZoomBox(bool redraw) {
 	}
 }
 
+Cast *Score::getCastMember(int castId) {
+	Cast *result = nullptr;
+
+	if (_loadedCast->contains(castId)) {
+		result = _loadedCast->getVal(castId);
+	}
+	return result;
+}
+
 } // End of namespace Director
diff --git a/engines/director/score.h b/engines/director/score.h
index 9b31b9ed92..cda63f850f 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -108,6 +108,8 @@ public:
 
 	int32 getStageColor() { return _stageColor; }
 
+	Cast *getCastMember(int castId);
+
 private:
 	void update();
 	void readVersion(uint32 rid);


Commit: 127c8520777b52807bbd5c51de3098c3415a8edd
    https://github.com/scummvm/scummvm/commit/127c8520777b52807bbd5c51de3098c3415a8edd
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Refine cross-type output of compareTo

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


diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index ba6136bec3..f0d49f48b2 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -434,8 +434,6 @@ int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
 			d1Type = FLOAT;
-		} else {
-			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
 	if (d2Type == STRING || d1Type == REFERENCE) {
@@ -444,8 +442,6 @@ int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 		strtod(src.c_str(), &endPtr);
 		if (*endPtr == 0) {
 			d2Type = FLOAT;
-		} else {
-			warning("getAlignedType(): Unable to parse '%s' as a number", src.c_str());
 		}
 	}
 
@@ -453,8 +449,6 @@ int Lingo::getAlignedType(Datum &d1, Datum &d2) {
 		opType = FLOAT;
 	} else if (d1Type == INT && d2Type == INT) {
 		opType = INT;
-	} else {
-		warning("getAlignedType(): No numeric type alignment available");
 	}
 
 	return opType;
@@ -664,18 +658,19 @@ const char *Datum::type2str(bool isk) {
 }
 
 int Datum::compareTo(Datum &d, bool ignoreCase) {
-	if (type == STRING && d.type == STRING) {
-		if (ignoreCase) {
-			return toLowercaseMac(*u.s).compareTo(toLowercaseMac(*d.u.s));
-		} else {
-			return u.s->compareTo(*d.u.s);
-		}
-	} else if (type == SYMBOL && d.type == SYMBOL) {
+	if (type == SYMBOL && d.type == SYMBOL) {
 		// TODO: Implement union comparisons
 		return ignoreCase ? u.sym->name.compareToIgnoreCase(d.u.sym->name) : u.sym->name.compareTo(d.u.sym->name);
 	} else {
 		int alignType = g_lingo->getAlignedType(*this, d);
-		if (alignType == FLOAT) {
+
+		if ((alignType == VOID && (type == STRING || d.type == STRING)) || (type == STRING && d.type == STRING)) {
+			if (ignoreCase) {
+				return toLowercaseMac(asString()).compareTo(toLowercaseMac(d.asString()));
+			} else {
+				return asString().compareTo(d.asString());
+			}
+		} else if (alignType == FLOAT) {
 			double f1 = asFloat();
 			double f2 = d.asFloat();
 			if (f1 < f2) {


Commit: 5ad4e341b97e12f70d74d2cdbe2afb9f92b13e19
    https://github.com/scummvm/scummvm/commit/5ad4e341b97e12f70d74d2cdbe2afb9f92b13e19
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Improve debug messages for setTheEntity and getTheEntity

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


diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index f71117ada3..46008e0386 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -325,6 +325,10 @@ const char *Lingo::field2str(int id) {
 }
 
 Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
+	if (debugChannelSet(3, kDebugLingoExec)) {
+		debugC(3, kDebugLingoExec, "Lingo::getTheEntity(%s, %s, %s)", entity2str(entity), id.asString(true).c_str(), field2str(field));
+	}
+
 	Datum d;
 
 	switch (entity) {
@@ -480,7 +484,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 
 void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 	if (debugChannelSet(3, kDebugLingoExec)) {
-		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(\"%s\", %s, \"%s\", %s)", field2str(field), id.asString(true).c_str(), entity2str(entity), d.asString(true).c_str());
+		debugC(3, kDebugLingoExec, "Lingo::setTheEntity(%s, %s, %s, %s)", entity2str(entity), id.asString(true).c_str(), field2str(field), d.asString(true).c_str());
 	}
 
 	switch (entity) {


Commit: 2cb83c482866b47a6ae37dffd6af9f0f55c1d75e
    https://github.com/scummvm/scummvm/commit/2cb83c482866b47a6ae37dffd6af9f0f55c1d75e
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Fix typos in LC::*Data

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


diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index e629a5342c..15ef71ba1a 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -545,15 +545,15 @@ Datum LC::addData(Datum &d1, Datum &d2) {
 
 	int alignedType = g_lingo->getAlignedType(d1, d2);
 
-	Datum result;
+	Datum res;
 	if (alignedType == FLOAT) {
-		result = Datum(d1.asFloat() + d2.asFloat());
+		res = Datum(d1.asFloat() + d2.asFloat());
 	} else if (alignedType == INT) {
-		result = Datum(d1.asInt() + d2.asInt());
+		res = Datum(d1.asInt() + d2.asInt());
 	} else {
 		warning("LC::addData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return result;
+	return res;
 }
 
 void LC::c_add() {
@@ -569,15 +569,15 @@ Datum LC::subData(Datum &d1, Datum &d2) {
 
 	int alignedType = g_lingo->getAlignedType(d1, d2);
 
-	Datum result;
+	Datum res;
 	if (alignedType == FLOAT) {
-		result = Datum(d1.asFloat() - d2.asFloat());
+		res = Datum(d1.asFloat() - d2.asFloat());
 	} else if (alignedType == INT) {
-		result = Datum(d1.asInt() - d2.asInt());
+		res = Datum(d1.asInt() - d2.asInt());
 	} else {
 		warning("LC::subData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return result;
+	return res;
 }
 
 void LC::c_sub() {
@@ -593,15 +593,15 @@ Datum LC::mulData(Datum &d1, Datum &d2) {
 
 	int alignedType = g_lingo->getAlignedType(d1, d2);
 
-	Datum result;
+	Datum res;
 	if (alignedType == FLOAT) {
-		result = Datum(d1.asFloat() * d2.asFloat());
+		res = Datum(d1.asFloat() * d2.asFloat());
 	} else if (alignedType == INT) {
-		result = Datum(d1.asInt() * d2.asInt());
+		res = Datum(d1.asInt() * d2.asInt());
 	} else {
 		warning("LC::mulData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
-	return result;
+	return res;
 }
 
 void LC::c_mul() {
@@ -621,16 +621,16 @@ Datum LC::divData(Datum &d1, Datum &d2) {
 
 	int alignedType = g_lingo->getAlignedType(d1, d2);
 
-	Datum result;
+	Datum res;
 	if (alignedType == FLOAT) {
-		result = Datum(d1.asFloat() / d2.asFloat());
+		res = Datum(d1.asFloat() / d2.asFloat());
 	} else if (alignedType == INT) {
-		result = Datum(d1.asInt() / d2.asInt());
+		res = Datum(d1.asInt() / d2.asInt());
 	} else {
 		warning("LC::divData: not supported between types %s and %s", d1.type2str(), d2.type2str());
 	}
 
-	return d1;
+	return res;
 }
 
 void LC::c_div() {
@@ -680,7 +680,7 @@ Datum LC::negateData(Datum &d) {
 		warning("LC::negateData: not supported for type %s", res.type2str());
 	}
 
-	return d;
+	return res;
 }
 
 void LC::c_negate() {


Commit: e41d3e4f6e267e78c1be014dee1cd14dd4d43347
    https://github.com/scummvm/scummvm/commit/e41d3e4f6e267e78c1be014dee1cd14dd4d43347
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Fix setting kTheCastNum

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


diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 46008e0386..eef6cab7d1 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -676,7 +676,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		break;
 	case kTheCastNum:
 		if (_vm->getCastMember(d.asInt())) {
-			score->loadCastInto(sprite, d.asInt());
+			sprite->_cast = _vm->getCastMember(d.asInt());
 			sprite->_castId = d.asInt();
 		}
 		break;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 0be5558a01..587bc6400b 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -981,10 +981,6 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id,
 		warning("Score::loadCastData(): size3: %x", size3);
 }
 
-void Score::loadCastInto(Sprite *sprite, int castId) {
-	sprite->_cast = _loadedCast->getVal(castId);
-}
-
 Common::Rect Score::getCastMemberInitialRect(int castId) {
 	Cast *cast = _loadedCast->getVal(castId);
 
diff --git a/engines/director/score.h b/engines/director/score.h
index cda63f850f..5b6044d674 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -94,7 +94,6 @@ public:
 	void copyCastStxts();
 	Graphics::ManagedSurface *getSurface() { return _surface; }
 
-	void loadCastInto(Sprite *sprite, int castId);
 	Common::Rect getCastMemberInitialRect(int castId);
 	void setCastMemberModified(int castId);
 


Commit: 090ca0f68e3d48f7dc60e21588ab86d23a2ef777
    https://github.com/scummvm/scummvm/commit/090ca0f68e3d48f7dc60e21588ab86d23a2ef777
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Remove last of the loadedCast references

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index f70285ca55..da39337f1d 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1652,7 +1652,7 @@ void LB::b_puppetSound(int nargs) {
 	if (castId == 0) {
 		sound->stopSound(1);
 	} else {
-		Cast *cast = score->_loadedCast->getVal(castId);
+		Cast *cast = g_director->getCastMember(castId);
 		if (!cast) {
 			warning("b_puppetSound: attempted to play a NULL cast member");
 			return;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index eef6cab7d1..78fb2fdded 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -769,29 +769,33 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 	d.type = INT;
 
 	if (!score) {
-		warning("Lingo::getTheCast(): No cast loaded");
+		warning("Lingo::getTheCast(): No score loaded");
 		return d;
 	}
 
-	CastType castType;
-	CastInfo *castInfo;
-	if (id > score->_castIDoffset) {
-		id -= score->_castIDoffset;
-	}
-
-	if (!score->_loadedCast->contains(id)) {
-		if (field == kTheLoaded)
+	Cast *member = _vm->getCastMember(id);
+	if (!member) {
+		if (field == kTheLoaded) {
 			d.u.i = 0;
-
+		} else {
+			warning("Lingo::getTheCast(): Cast %d not found", id);
+		}
 		return d;
 	}
 
-	castType = score->_loadedCast->getVal(id)->_type;
-	castInfo = score->_castsInfo[id];
-
-	//TODO: castInfo uses full offsets, so check the higher value.
-	if (castInfo == nullptr)
-		castInfo = score->_castsInfo[id + score->_castIDoffset];
+	CastType castType = member->_type;
+	CastInfo *castInfo = nullptr;
+	if (score->_castsInfo.contains(id)) {
+		castInfo = score->_castsInfo.getVal(id);
+	} else {
+		Score *shared = _vm->getSharedScore();
+		if (shared && shared->_castsInfo.contains(id)) {
+			castInfo = shared->_castsInfo.getVal(id);
+		} else {
+			warning("Lingo::getTheCast(): Cast info for %d not found", id);
+			return d;
+		}
+	}
 
 	switch (field) {
 	case kTheBackColor:
@@ -802,7 +806,7 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 				return d;
 			}
 
-			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
+			ShapeCast *shape = (ShapeCast *)member;
 			d.u.i = shape->_bgCol;
 		}
 		break;
@@ -820,7 +824,7 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 				return d;
 			}
 
-			ShapeCast *shape = (ShapeCast *)score->_loadedCast->getVal(id);
+			ShapeCast *shape = (ShapeCast *)member;
 			d.u.i = shape->_fgCol;
 		}
 		break;
@@ -840,7 +844,6 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		{
 			Common::String text;
 			if (castType == kCastText) {
-				Cast *member = _vm->getCastMember(id);
 				if (member && member->_type == kCastText) {
 					text = ((TextCast *)member)->getText();
 				} else {
@@ -889,7 +892,7 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		return;
 	}
 	CastType castType = member->_type;
-	CastInfo *castInfo = score->_castsInfo[id + score->_castIDoffset];
+	CastInfo *castInfo = score->_castsInfo[id];
 
 	switch (field) {
 	case kTheBackColor:
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index f0d49f48b2..fb59b8bdcf 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -569,28 +569,17 @@ Common::String Datum::asString(bool printonly) {
 	case REFERENCE:
 		{
 			int idx = u.i;
-			Score *score = g_director->getCurrentScore();
-
-			if (!score) {
-				warning("asString(): No score");
+			Cast *member = g_director->getCastMember(idx);
+			if (!member) {
+				warning("asString(): Unknown cast id %d", idx);
 				s = "";
 				break;
 			}
 
-			if (!score->_loadedCast->contains(idx)) {
-				if (!score->_loadedCast->contains(idx - score->_castIDoffset)) {
-					warning("asString(): Unknown REFERENCE %d", idx);
-					s = "";
-					break;
-				} else {
-					idx -= 1024;
-				}
-			}
-
 			if (!printonly) {
-				s = ((TextCast *)score->_loadedCast->getVal(idx))->getText();
+				s = ((TextCast *)member)->getText();
 			} else {
-				s = Common::String::format("reference: \"%s\"", ((TextCast *)score->_loadedCast->getVal(idx))->getText().c_str());
+				s = Common::String::format("reference: \"%s\"", ((TextCast *)member)->getText().c_str());
 			}
 		}
 		break;


Commit: b7cc663aedc7c3bef71fe3724f7cbe4a0559e4af
    https://github.com/scummvm/scummvm/commit/b7cc663aedc7c3bef71fe3724f7cbe4a0559e4af
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Fix switch statement indentation

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


diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index fb59b8bdcf..c3c7279d42 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -90,32 +90,32 @@ void Symbol::reset() {
 	*refCount -= 1;
 	if (*refCount <= 0) {
 		switch (type) {
-			case HANDLER:
-				delete u.defn;
-				break;
-			case STRING:
-				delete u.s;
-				break;
-			case ARRAY:
-				// fallthrough
-			case POINT:
-				// fallthrough
-			case RECT:
-				delete u.farr;
-				break;
-			case PARRAY:
-				delete u.parr;
-				break;
-			case VAR:
-				// fallthrough
-			case REFERENCE:
-				// fallthrough
-			case INT:
-				// fallthrough
-			case FLOAT:
-				// fallthrough
-			default:
-				break;
+		case HANDLER:
+			delete u.defn;
+			break;
+		case STRING:
+			delete u.s;
+			break;
+		case ARRAY:
+			// fallthrough
+		case POINT:
+			// fallthrough
+		case RECT:
+			delete u.farr;
+			break;
+		case PARRAY:
+			delete u.parr;
+			break;
+		case VAR:
+			// fallthrough
+		case REFERENCE:
+			// fallthrough
+		case INT:
+			// fallthrough
+		case FLOAT:
+			// fallthrough
+		default:
+			break;
 		}
 		delete refCount;
 	}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index b93899c571..4665036d7f 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -172,29 +172,29 @@ struct Datum {	/* interpreter stack type */
 		*refCount -= 1;
 		if (*refCount <= 0) {
 			switch (type) {
-				case STRING:
-					delete u.s;
-					break;
-				case ARRAY:
-					// fallthrough
-				case POINT:
-					// fallthrough
-				case RECT:
-					delete u.farr;
-					break;
-				case PARRAY:
-					delete u.parr;
-					break;
-				case VAR:
-					// fallthrough
-				case REFERENCE:
-					// fallthrough
-				case INT:
-					// fallthrough
-				case FLOAT:
-					// fallthrough
-				default:
-					break;
+			case STRING:
+				delete u.s;
+				break;
+			case ARRAY:
+				// fallthrough
+			case POINT:
+				// fallthrough
+			case RECT:
+				delete u.farr;
+				break;
+			case PARRAY:
+				delete u.parr;
+				break;
+			case VAR:
+				// fallthrough
+			case REFERENCE:
+				// fallthrough
+			case INT:
+				// fallthrough
+			case FLOAT:
+				// fallthrough
+			default:
+				break;
 			}
 			delete refCount;
 		}


Commit: 71736bef2d4bdeca88ad3e9e4c113d8ece7e1944
    https://github.com/scummvm/scummvm/commit/71736bef2d4bdeca88ad3e9e4c113d8ece7e1944
Author: Scott Percival (code at moral.net.au)
Date: 2020-05-14T18:09:32+08:00

Commit Message:
DIRECTOR: LINGO: Remove Datum(Common::String *val)

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


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index da39337f1d..b4a39c0993 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -451,11 +451,11 @@ void LB::b_chars(int nargs) {
 	int f = MAX(0, MIN(len, from - 1));
 	int t = MAX(0, MIN(len, to));
 
-	Common::String *result;
+	Common::String result;
 	if (f > t) {
-		result = new Common::String("");
+		result = Common::String("");
 	} else {
-		result = new Common::String(&(src.c_str()[f]), &(src.c_str()[t]));
+		result = Common::String(&(src.c_str()[f]), &(src.c_str()[t]));
 	}
 
 	Datum res(result);
@@ -1296,7 +1296,7 @@ void LB::b_floatP(int nargs) {
 
 void LB::b_ilk(int nargs) {
 	Datum d = g_lingo->pop();
-	Datum res(new Common::String(d.type2str(true)));
+	Datum res(Common::String(d.type2str(true)));
 	g_lingo->push(res);
 }
 
@@ -2012,15 +2012,15 @@ void LB::b_soundBusy(int nargs) {
 // Constants
 ///////////////////
 void LB::b_backspace(int nargs) {
-	g_lingo->push(Datum(new Common::String("\b")));
+	g_lingo->push(Datum(Common::String("\b")));
 }
 
 void LB::b_empty(int nargs) {
-	g_lingo->push(Datum(new Common::String("")));
+	g_lingo->push(Datum(Common::String("")));
 }
 
 void LB::b_enter(int nargs) {
-	g_lingo->push(Datum(new Common::String("\n")));
+	g_lingo->push(Datum(Common::String("\n")));
 }
 
 void LB::b_false(int nargs) {
@@ -2028,15 +2028,15 @@ void LB::b_false(int nargs) {
 }
 
 void LB::b_quote(int nargs) {
-	g_lingo->push(Datum(new Common::String("\"")));
+	g_lingo->push(Datum(Common::String("\"")));
 }
 
 void LB::b_returnconst(int nargs) {
-	g_lingo->push(Datum(new Common::String("\n")));
+	g_lingo->push(Datum(Common::String("\n")));
 }
 
 void LB::b_tab(int nargs) {
-	g_lingo->push(Datum(new Common::String("\t")));
+	g_lingo->push(Datum(Common::String("\t")));
 }
 
 void LB::b_true(int nargs) {
@@ -2046,10 +2046,10 @@ void LB::b_true(int nargs) {
 void LB::b_version(int nargs) {
 	switch (g_director->getVersion()) {
 	case 3:
-		g_lingo->push(Datum(new Common::String("3.1.1"))); // Mac
+		g_lingo->push(Datum(Common::String("3.1.1"))); // Mac
 		break;
 	case 4:
-		g_lingo->push(Datum(new Common::String("4.0"))); // Mac
+		g_lingo->push(Datum(Common::String("4.0"))); // Mac
 		break;
 	default:
 		error("Unsupported Director for 'version'");
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 15ef71ba1a..073d4be005 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -267,7 +267,7 @@ void LC::c_floatpush() {
 
 void LC::c_stringpush() {
 	char *s = g_lingo->readString();
-	g_lingo->push(Datum(new Common::String(s)));
+	g_lingo->push(Datum(Common::String(s)));
 }
 
 void LC::c_symbolpush() {
@@ -276,7 +276,7 @@ void LC::c_symbolpush() {
 	// TODO: FIXME: Currently we push string
 	// If you change it, you must also fix func_play for "play done"
 	// command
-	Datum d(new Common::String(s));
+	Datum d = Datum(Common::String(s));
 	d.type = SYMBOL;
 
 	g_lingo->push(d);
@@ -285,7 +285,7 @@ void LC::c_symbolpush() {
 void LC::c_namepush() {
 	Datum d;
 	int i = g_lingo->readInt();
-	g_lingo->push(Datum(new Common::String(g_lingo->getName(i))));
+	g_lingo->push(Datum(Common::String(g_lingo->getName(i))));
 }
 
 void LC::c_argcpush() {
@@ -344,7 +344,7 @@ void LC::c_varpush() {
 	// In immediate mode we will push variables as strings
 	// This is used for playAccel
 	if (g_lingo->_immediateMode) {
-		g_lingo->push(Datum(new Common::String(name)));
+		g_lingo->push(Datum(Common::String(name)));
 
 		return;
 	}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 4665036d7f..bc109f984c 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -162,12 +162,6 @@ struct Datum {	/* interpreter stack type */
 		refCount = new int;
 		*refCount = 1;
 	}
-	Datum(Common::String *val) {
-		u.s = val;
-		type = STRING;
-		refCount = new int;
-		*refCount = 1;
-	}
 	void reset() {
 		*refCount -= 1;
 		if (*refCount <= 0) {




More information about the Scummvm-git-logs mailing list