DIRECTOR: LINGO: Track ScriptContext properties in addition order

This commit is contained in:
Scott Percival 2024-05-12 14:59:04 +08:00 committed by Eugene Sandulenko
parent 1c07d3e9aa
commit a1d692963d
10 changed files with 39 additions and 31 deletions

View File

@ -100,7 +100,7 @@ Datum CastMember::getProp(const Common::String &propName) {
return Datum();
}
bool CastMember::setProp(const Common::String &propName, const Datum &value) {
bool CastMember::setProp(const Common::String &propName, const Datum &value, bool force) {
Common::String fieldName = Common::String::format("%d%s", kTheCast, propName.c_str());
if (g_lingo->_theEntityFields.contains(fieldName)) {
return setField(g_lingo->_theEntityFields[fieldName]->field, value);

View File

@ -73,7 +73,7 @@ public:
bool hasProp(const Common::String &propName) override;
Datum getProp(const Common::String &propName) override;
bool setProp(const Common::String &propName, const Datum &value) override;
bool setProp(const Common::String &propName, const Datum &value, bool force = false) override;
bool hasField(int field) override;
Datum getField(int field) override;
bool setField(int field, const Datum &value) override;

View File

@ -679,12 +679,12 @@ static void showVars() {
if (lingo->_state->me.type == OBJECT && lingo->_state->me.u.obj->getObjType() & (kFactoryObj | kScriptObj)) {
ScriptContext *script = static_cast<ScriptContext *>(lingo->_state->me.u.obj);
ImGui::TextColored(head_color, "Instance/property vars:");
for (auto &it : script->_properties) {
keyBuffer.push_back(it._key);
for (uint32 i = 1; i <= script->getPropCount(); i++) {
keyBuffer.push_back(script->getPropAt(i));
}
Common::sort(keyBuffer.begin(), keyBuffer.end());
for (auto &i : keyBuffer) {
Datum &val = script->_properties.getVal(i);
Datum val = script->getProp(i);
displayVariable(i);
ImGui::SameLine();
ImGui::Text(" - [%s] %s", val.type2str(), formatStringForDump(val.asString(true)).c_str());

View File

@ -453,10 +453,10 @@ void LB::b_random(int nargs) {
Datum res;
// Output in D4/D5 seems to be bounded from 1-65535, regardless of input.
if (max <= 0) {
res = g_director->_rnd.getRandom(65535) + 1;
res = Datum(g_director->_rnd.getRandom(65535) + 1);
} else {
max = MIN(max, 65535);
res = g_director->_rnd.getRandom(max) + 1;
res = Datum(g_director->_rnd.getRandom(max) + 1);
}
g_lingo->push(res);
}
@ -962,7 +962,7 @@ void LB::b_getProp(int nargs) {
case OBJECT:
{
if (prop.type != SYMBOL) {
g_lingo->lingoError("b_getProp(): symbol expected");
g_lingo->lingoError("BUILDBOT: b_getProp(): symbol expected, got %s", prop.type2str());
return;
}
Datum d;
@ -1184,7 +1184,7 @@ void LB::b_setProp(int nargs) {
case OBJECT:
{
if (prop.type != SYMBOL) {
g_lingo->lingoError("b_setProp(): symbol expected");
g_lingo->lingoError("BUILDBOT: b_setProp(): symbol expected, got %s", prop.type2str());
return;
}
// unlike the PARRAY case, OBJECT seems to create

View File

@ -1115,7 +1115,7 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
} else if (0 <= index && index < (int16)archive->names.size()) {
const char *name = archive->names[index].c_str();
debugC(5, kDebugLoading, "%d: %s", i, name);
_assemblyContext->_properties[name] = Datum();
_assemblyContext->setProp(name, Datum(), true);
} else {
warning("Property %d has unknown name id %d, skipping define", i, index);
}

View File

@ -389,8 +389,8 @@ void LingoCompiler::registerMethodVar(const Common::String &name, VarType type)
}
(*_methodVars)[name] = type;
if (type == kVarProperty || type == kVarInstance) {
if (!_assemblyContext->_properties.contains(name))
_assemblyContext->_properties[name] = Datum();
if (!_assemblyContext->hasProp(name))
_assemblyContext->setProp(name, Datum(), true);
} else if (type == kVarGlobal) {
if (!g_lingo->_globalvars.contains(name))
g_lingo->_globalvars[name] = Datum();
@ -473,8 +473,8 @@ bool LingoCompiler::visitHandlerNode(HandlerNode *node) {
if (i._value == kVarGlobal)
registerMethodVar(i._key, kVarGlobal);
}
for (auto &i : _assemblyContext->_properties) {
registerMethodVar(i._key, _inFactory ? kVarInstance : kVarProperty);
for (uint32 i = 1; i <= _assemblyContext->getPropCount(); i++) {
registerMethodVar(_assemblyContext->getPropAt(i), _inFactory ? kVarInstance : kVarProperty);
}
COMPILE_LIST(node->stmts);

View File

@ -416,6 +416,7 @@ ScriptContext::ScriptContext(const ScriptContext &sc) : Object<ScriptContext>(sc
}
_constants = sc._constants;
_properties = sc._properties;
_propertyNames = sc._propertyNames;
_id = sc._id;
}
@ -505,15 +506,15 @@ Datum ScriptContext::getProp(const Common::String &propName) {
return _properties["ancestor"].u.obj->getProp(propName);
}
}
_propertyNames.push_back(propName);
return _properties[propName]; // return new property
}
Common::String ScriptContext::getPropAt(uint32 index) {
// FIXME: Refactor the whole thing to have ordered keys
uint32 target = 1;
for (auto &it : _properties) {
for (auto &it : _propertyNames) {
if (target == index) {
return it._key;
return it;
}
target += 1;
}
@ -521,10 +522,10 @@ Common::String ScriptContext::getPropAt(uint32 index) {
}
uint32 ScriptContext::getPropCount() {
return _properties.size();
return _propertyNames.size();
}
bool ScriptContext::setProp(const Common::String &propName, const Datum &value) {
bool ScriptContext::setProp(const Common::String &propName, const Datum &value, bool force) {
if (_disposed) {
error("Property '%s' accessed on disposed object <%s>", propName.c_str(), Datum(this).asString(true).c_str());
}
@ -532,14 +533,20 @@ bool ScriptContext::setProp(const Common::String &propName, const Datum &value)
_properties[propName] = value;
return true;
}
if (_objType == kScriptObj) {
if (force) {
// used by e.g. the script compiler to add properties
_propertyNames.push_back(propName);
_properties[propName] = value;
return true;
} else if (_objType == kScriptObj) {
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
debugC(3, kDebugLingoExec, "Getting prop '%s' from ancestor: <%s>", propName.c_str(), _properties["ancestor"].asString(true).c_str());
return _properties["ancestor"].u.obj->setProp(propName, value);
return _properties["ancestor"].u.obj->setProp(propName, value, force);
}
} else if (_objType == kFactoryObj) {
// D3 style anonymous objects/factories, set whatever properties you like
_propertyNames.push_back(propName);
_properties[propName] = value;
return true;
}
@ -659,7 +666,7 @@ Datum Window::getProp(const Common::String &propName) {
return Datum();
}
bool Window::setProp(const Common::String &propName, const Datum &value) {
bool Window::setProp(const Common::String &propName, const Datum &value, bool force) {
Common::String fieldName = Common::String::format("%d%s", kTheWindow, propName.c_str());
if (g_lingo->_theEntityFields.contains(fieldName)) {
return setField(g_lingo->_theEntityFields[fieldName]->field, value);

View File

@ -56,7 +56,7 @@ public:
virtual Datum getProp(const Common::String &propName) = 0;
virtual Common::String getPropAt(uint32 index) = 0;
virtual uint32 getPropCount() = 0;
virtual bool setProp(const Common::String &propName, const Datum &value) = 0;
virtual bool setProp(const Common::String &propName, const Datum &value, bool force = false) = 0;
virtual bool hasField(int field) = 0;
virtual Datum getField(int field) = 0;
virtual bool setField(int field, const Datum &value) = 0;
@ -181,7 +181,7 @@ public:
uint32 getPropCount() override {
return 0;
};
bool setProp(const Common::String &propName, const Datum &value) override {
bool setProp(const Common::String &propName, const Datum &value, bool force = false) override {
return false;
};
bool hasField(int field) override {
@ -213,11 +213,12 @@ public:
SymbolHash _functionHandlers;
Common::HashMap<uint32, Symbol> _eventHandlers;
Common::Array<Datum> _constants;
DatumHash _properties;
Common::HashMap<uint32, Datum> _objArray;
MethodHash _methodNames;
private:
DatumHash _properties;
Common::Array<Common::String> _propertyNames;
bool _onlyInLctxContexts = false;
public:
@ -237,7 +238,7 @@ public:
Datum getProp(const Common::String &propName) override;
Common::String getPropAt(uint32 index) override;
uint32 getPropCount() override;
bool setProp(const Common::String &propName, const Datum &value) override;
bool setProp(const Common::String &propName, const Datum &value, bool force = false) override;
Symbol define(const Common::String &name, ScriptData *code, Common::Array<Common::String> *argNames, Common::Array<Common::String> *varNames);

View File

@ -108,7 +108,7 @@ Symbol& Symbol::operator=(const Symbol &s) {
}
bool Symbol::operator==(Symbol &s) const {
return ctx == s.ctx && (*name == *s.name);
return ctx == s.ctx && (name->equalsIgnoreCase(*s.name));
}
void Symbol::reset() {
@ -1556,12 +1556,12 @@ Common::String Lingo::formatAllVars() {
if (_state->me.type == OBJECT && _state->me.u.obj->getObjType() & (kFactoryObj | kScriptObj)) {
ScriptContext *script = static_cast<ScriptContext *>(_state->me.u.obj);
result += Common::String(" Instance/property vars: \n");
for (auto &it : script->_properties) {
keyBuffer.push_back(it._key);
for (uint32 i = 1; i <= script->getPropCount(); i++) {
keyBuffer.push_back(script->getPropAt(i));
}
Common::sort(keyBuffer.begin(), keyBuffer.end());
for (auto &i : keyBuffer) {
Datum &val = script->_properties.getVal(i);
Datum val = script->getProp(i);
result += Common::String::format(" %s - [%s] %s\n", i.c_str(), val.type2str(), formatStringForDump(val.asString(true)).c_str());
}
keyBuffer.clear();

View File

@ -185,7 +185,7 @@ public:
Common::String asString() override;
bool hasProp(const Common::String &propName) override;
Datum getProp(const Common::String &propName) override;
bool setProp(const Common::String &propName, const Datum &value) override;
bool setProp(const Common::String &propName, const Datum &value, bool force = false) override;
bool hasField(int field) override;
Datum getField(int field) override;
bool setField(int field, const Datum &value) override;