TADS3/adv3 convenience methods for getting stuff in scope?

I’m frequently finding myself devising concoctions like:

visibleStuff(actor) {
        if(!actor) return([]);
                { x, info: !x.ofKind(Fixture) && x != actor
                        && !x.getCarryingActor}));

To enumerate lists of stuff in various scopes (here, non-fixture objects not currently in an actor’s inventory). This works, but it’s a bit of a mouthful.

Does adv3/TADS provide a more straightforward way to do this sort of thing? Like a way to leverage the logical already built into various existing actions? Like for instance if I wanted to anticipate what a >TAKE ALL would include. At first glance it looks like one might be able to do something like call TakeAction.getAllDob() directly, but this appears not to work. We could also do something like wrapping a command inside a try() or something, but that seems inelegant.

(Been occupied recently, am catching up.)

I don’t know if adv3 offers what you’re asking for, but adv3Lite has its “Q” query object which holds a similar purpose.

I doubt it could be ported as-is to adv3, but I could see using it as a springboard for an adv3-specific class.

1 Like

Does Actor.scopeList() help?

Build a list of all of the objects of which an actor is aware.

An actor is aware of an object if the object is within reach of the actor’s senses, and has some sort of presence in that sense. Note that both of these conditions must be true for at least one sense possessed by the actor; an object that is within earshot, but not within reach of any other sense, is in scope only if the object is making some kind of noise.

In addition, objects that the actor is holding (i.e., those contained by the actor directly) are always in scope, regardless of their reachability through any sense.

1 Like

Kinda? It’s a very specific sort of the kind of thing I’m thinking of, but it doesn’t “solve” the general case.

Basically I find myself frequently wanting to enumerate two kinds of lists: all the stuff that would be affected by some Action in some situation; and more or less the equivalent of an in-game grep–go through a list of objects in scope and apply a filter.

And coding this sort of thing from scratch isn’t a huge challenge…it’s just that these sorts of things seem so foundational that I wonder if they might already be implemented somewhere that I’m just missing. So I’m asking to avoid re-inventing the wheel.

Just to give a better feel for what I’m talking about, here is a simple example:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

startRoom:      Room 'Void'
        "This is a featureless void with a built-in bookshelf. "
+ Thing 'small round pebble' 'pebble'
        "It's a small, round pebble. "
+ Thing 'red brick' 'brick'
        "It's a red brick. "
+ Thing 'black book*books' 'black book'
        "It's a black book. "
+ Fixture, Surface 'shelf/bookshelf' 'bookshelf'
        "It's a generic bookshelf. "
++ Thing 'red book*books' 'red book'
        "It's a red book. "
++ Thing 'green book*books' 'green book'
        "It's a green book. "
++ Thing 'blue book*books' 'blue book'
        "It's a blue book. "
me:     Person
        location = startRoom
versionInfo:    GameID
        name = 'sample'
        byline = 'nobody'
        authorEmail = 'nobody <foo@bar.com>'
        desc = '[This space intentionally left blank]'
        version = '1.0'
        IFID = '12345'
gameMain:       GameMainDef
        initialPlayerChar = me

In the game we can do something like:

This is a featureless void with a built-in bookshelf.

You see a pebble, a brick, and a black book here.  On the bookshelf are a red
book, a green book, and a blue book.

>get all books from shelf except red book
green book: Taken.
blue book: Taken.

But as near as I can tell there isn’t anything remotely as concise to accomplish the same thing in the source code. Which seems…unsatisfying.

Like I mean yeah I can totally manage the coding required to produce that list, it’s just nowhere near as convenient as it is to do in-game. And the fact that it happens in-game means that all the necessary logic is already there (in, for example, TakeAction). So it would be nice to just directly leverage it instead of implementing some separate logic that (hopefully) works the same way.

A protype-ish thing to illustrate:

senseGrep(sense, fn, actor?) {
        if(actor == nil) actor = gActor;
        if(!sense || !actor || !actor.ofKind(Actor)) return([]);
        return(senseInfoTableSubset(getPOVDefault(actor ? actor : gActor)
                .senseInfoTable(sense), fn));
sightGrep(fn, actor?) { return(senseGrep(sight, fn, actor)); }
soundGrep(fn, actor?) { return(senseGrep(sound, fn, actor)); }
smellGrep(fn, actor?) { return(senseGrep(smell, fn, actor)); }
touchGrep(fn, actor?) { return(senseGrep(touch, fn, actor)); }
filterNoun(txt) {
        return({ x, info: !txt || (x.noun && x.noun.indexOf(txt) != nil) }); }
        { return({ x, info: !txt
                || (x.adjective && x.adjective.indexOf(txt) != nil) }); }

…which lets you do something like:

sightGrep(filterNoun('book')).forEach(function(o) {
        // stuff goes here

…to iterate over all the visible books or:

sightGrep(filterAdjective('red')).forEach(function(o) {
        // stuff goes here

…to iterate over all visible red objects.

But this is way less general/powerful than the logic that is already baked into adv3 in various places but which aren’t easily accessible (as far as I can tell) to the game implementor.