getContents() is undefined
I'm working on a game and I've found that I need to be able to check for every object of a certain type in a room.
however, the function getContents() is undefined for some reason.
Fortunately, I eventually discovered a workaround:
const get_all_children = function(_room) { var list = scopeBy(item => item.isAtLoc(_room)) var newlist = list list.forEach(function(thingy){ newlist = newlist.concat(get_all_children(thingy)) }) return newlist }
That's great!
To build off of that (using your script), ThePix might be more inclined to add it like this (which builds off of existing code and uses the same "style" as (I think) Pixie would):
//Edited to use ThePix's getContents suggestion
function getContents(obj) {
if (obj.getContents) return obj.getContents()
return []
}
function getDirectChildren(o){
return getContents(o);
}
function getAllChildren(o) {
const directChildren = getDirectChildren(o);
var allChildren = directChildren;
directChildren.forEach(function(c){
allChildren = allChildren.concat(getAllChildren(c));
});
return allChildren;
}
however, the function getContents() is undefined for some reason.
I found it as a prototype function (and I used that code to make the getContents() function above), but the prototype function seems to only work for rooms. w.lounge.getContents() will work, but if you have a foo item (not a room), w.foo.getContents() will throw an error.
Interesting. Secondary issue: COMPONENT() objects are not considered to be isAtLoc of their parents..is this a bug or intended? I haven't found a workaround yet.
UPDATE, I did some testing and I've found what was the problem. getContents() is a method of objects. For instance, here is how its supposed to be used:
msg("OBJECTS HERE: " + formatList(w["lounge"].getContents(world.PARSER), {article:INDEFINITE, lastJoiner:'and'})) + "."
Basicaly, getContents(my_room) isn't defined. However it's somewhat ambiguous in the docs what the syntax is. I blame a lack of consistent formatting.
Basicaly,
getContents(my_room)isn't defined. However it's somewhat ambiguous in the docs what the syntax is. I blame a lack of consistent formatting.
Yeah, it's only set up to do w.my_room.getContents() (or w["my_room"].getContents()), as a method. I used the script from that to make the function last night:
function getContents(o, situation) {
const list = [];
for (let key in w) {
if (w[key].isAtLoc(o.name, situation)) {
list.push(w[key]);
}
}
return list;
}
I would question Pixie's logic, but, every time I've ever questioned Pixie's logic, I've always felt silly and like I should have understood all along once it was explained to me.
Interesting. Secondary issue: COMPONENT() objects are not considered to be isAtLoc of their parents..is this a bug or intended? I haven't found a workaround yet.
Hrmm.... I think Pixie is using isAtLoc for all sorts of things when loading a game, finishing a turn, etc.
So, it might be intentional.
You know... If we did this in the forum, there is a chance that people with much more JS knowledge would help out. They probably won't because most of them only frequent the Quest Forum, but there is a chance that mrangel or someone like that might see all this activity and become interested.
(I know I was the one who advised posting issues here, but that was really only because it was more likely to get Pixie's attention once he's no longer tied up.)
QuestJS needs the counterpart of this Quest 5 function (if it doesn't already have it somewhere):
https://docs.textadventures.co.uk/quest/functions/contains.html
Contains
Contains (object parent, object child)
Returns a boolean -
trueif the child object is contained by the parent. This doesn’t necessarily mean that there is a direct parent-child relationship - for example if objectAhas parentB, andBhas parentC, then
Contains(C, A)
will return
true.
Okay, I think I fixed getAllChildren to work with components too.
function getDirectChildren(o){
const list = [];
for (let key in w) {
if (w[key]["loc"] === o.name) {
list.push(w[key]);
}
}
return list;
}
function getAllChildren(o) {
const directChildren = getDirectChildren(o);
var allChildren = directChildren;
directChildren.forEach(function(c){
allChildren = allChildren.concat(getAllChildren(c));
});
return allChildren;
}
As KVonGit says, you need to do it as room.getContents(), rather than getContents(room). The function is an attribute of the room.
If you want a function like that, I would suggest:
function getContents(obj) {
if (obj.getContents) return obj.getContents()
return []
}
That will work for containers too, but can also handle objects without contents.
To filter, you might want to look at filterByAttribute