Okay... if anyone is bored:
This concerns the game.scopebackdrop
script, ScopeReachableNotHeldForRoom()
, and do
.
do
creates a new dictionary, then adds "items" as a key which points to an object list. It then calls the game.scopebackdrop
script with that dictionary as a parameter, hence creating the items
variable in the game.scopebackdrop
script.
<function name="ScopeReachableNotHeldForRoom" type="objectlist" parameters="room">
<![CDATA[
result = NewObjectList()
foreach (obj, GetAllChildObjects(room)) {
if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
list add(result, obj)
}
}
if (HasScript(game, "scopebackdrop")) {
dict = NewDictionary()
dictionary add (dict, "items", result)
do (game, "scopebackdrop", dict)
}
return (result)
]]>
</function>
The game.scopebackdrop
script:
<scopebackdrop type="script">
if (HasAttribute(game.pov.parent, "stock")) {
foreach (o, GetDirectChildren(game.pov.parent.stock)) {
list add (items, o)
}
}
</scopebackdrop>
This works correctly.
...until I use a never-released, abandoned piece of software that Alex created to convert a Quest game to HTML.
I have updated the code quite a few times over the years, with a lot of help from some of you, and someone recently asked for help with it. So, here we are. I've fixed quite a few things that I couldn't figure out last time, and it successfully converts a game with a shop now, but I have to alter ScopeReachableNotHeldForRoom()
and add a little code to the game.scopebackdrop
script to make things work in the HTML version which is created.
Note that I have things working right now; I'm just trying to wrap my mind around one thing:
Here is the skinny on do
:
do (object, string attribute name, dictionary parameters)
Runs an object’s script attribute, passing in parameters via dictionary. The key/value pairs in the dictionary will be turned into local variables for the script. The special variable “this” can be used in the script to reference the object.
Now, here is the JS function which replaces do
(which was written by Alex, not me):
function runscriptattribute3(object, attribute, parameters) {
var fn = GetAttribute(object, attribute);
fn.call(object, parameters);
}
And here is the JS version of ScopeReachableNotHeldForRoom()
(which was created by the game-converting software):
function ScopeReachableNotHeldForRoom(room)
{
var result = NewObjectList();
var list_obj = GetAllChildObjects(room);
var list_obj_isarray = (Object.prototype.toString.call(list_obj) === '[object Array]');
for (var iterator_obj in list_obj) {
var obj = list_obj_isarray ? list_obj[iterator_obj] : iterator_obj;
if (list_obj_isarray || iterator_obj!="__dummyKey") { if (ContainsReachable(room, obj) && obj != _obj323.pov && !(Contains(_obj323.pov, obj))) {
listadd (result, obj);
} }
}
if (HasScript(_obj323, "scopebackdrop")) {
var dict = NewDictionary();
dictionaryadd (dict, "items", result);
runscriptattribute3 (_obj323, "scopebackdrop", dict);
}
return (result);
}
And finally, here is the JS version of game.scopebackdrop
(created by the software):
"scopebackdrop": function() { if (HasAttribute(_obj323.pov.parent, "stock")) {
var list_o = GetDirectChildren(_obj323.pov.parent.stock);
var list_o_isarray = (Object.prototype.toString.call(list_o) === '[object Array]');
for (var iterator_o in list_o) {
var o = list_o_isarray ? list_o[iterator_o] : iterator_o;
if (list_o_isarray || iterator_o!="__dummyKey") { listadd (items, o); }
}
} },
This throws an error, because items
does not exist.
So, I decided to be smart and add some code to game.scopebackdrop
to declare items
if it did not exist. I used IsDefined()
in Quest to do this, and it works in Quest just fine.
if (not IsDefined("items")) {
result = NewObjectList()
foreach (obj, GetAllChildObjects(room)) {
if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
list add(result, obj)
}
}
items = result
}
if (HasAttribute(game.pov.parent, "stock")) {
foreach (o, GetDirectChildren(game.pov.parent.stock)) {
list add (items, o)
}
}
I ran into issues once the game was converted to HTML, though.
First, the IsDefined()
function in the converting software was obviously added while testing something and Alex most probably intended to go back and fix it.
function IsDefined(variable) {
return true;
}
So that (obviously) didn't help, and I still got the same error in the browser because items
did not exist.
So, I decided to fix that function.
function IsDefined(variable) {
return (typeof variable != undefined;
}
Well, that (come to find out) will always return true
, because the variable is a string.
In Quest, I need it to be IsDefined("items")
, but in JS it should be IsDefined(items)
for that to work.
I also tried using TypeOf()
, but it throws an error in Quest if the variable does not exist.
In the end, I just created attributes to check if the game was being played in Quest or if it was the HTML version as a workaround, but I still think there is a way to check if something is defined in Quest without using IsDefined()
and without throwing any errors if the variable does not exist.
So... finally, to questions.
ScopeReachableNotHeldForRoom()
, and do
Okay, so result
is an object list of everything that should normally be in scope.
Then, if game.scopebackdrop
exists, the do
script runs. Anything the do
script adds to the variable items
is retained while ScopeReachableNotHeldForRoom()
is still running, and then ScopeReachableNotHeldForRoom()
returns that modified result
object list at the end.
Do I have that right?
If so, I'm assuming Javascript does not handle a "dictionary" (which is just an object in JS, if I'm not mistaken) as a parameter at all in the same way the do
script in Quest handles a Quest dictionary.
IsDefined()
in JSQuest needs it written this way: IsDefined("items")
.
Javascript needs it written this way: IsDefined(items)
.
Does JS have a way to convert the string "items"
to a variable name items
?