A phone, Alice's phone, her phone: dealing with owned/personal objects

TADS3/adv3 automagically accepts the use of possessives to disambiguate between objects based on location. So >X ALICE'S PHONE will work even if Alice’s phone is declared just as “phone”.

Unfortunately it doesn’t automagically use possessives to prompt for disambiguation, even if an explicit owner is declared. That’s easy enough to fix: just define disambigName as theNameWithOwner (and so on for the other similar disambiguation name properties, like theDisambigName).

Handling switching between “the phone” and “her phone” to catch all the stock library messages that report using the {the dobj/him} message parameter substitution and so on seems to be a little more tricky, unless I’m missing something. And I’m not convinced that I’m catching all the special cases (in fact, I’m pretty sure I’m not catching all of them).

So is there a simpler way to handle this?

Simple demo to illustrate: Alice and Bob and their phones. They’ll let you order them to drop and pick up their phones:

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

class PersonalItem: Thing
        theName() {
                if(owner != nil)
                        return(owner.itPossAdj + ' ' + name);
                return(inherited);
        }
        disambigName() {
                if(owner != nil)
                        return(theNameWithOwner);
                return(inherited);
        }
        theDisambigName() {
                if(owner != nil)
                        return(theNameWithOwner);
                return(inherited);
        }
        aDisambigName() {
                if(owner != nil)
                        return(aNameOwnerLoc(true));
                return(inherited);
        }
;

class Phone: PersonalItem 'phone' 'phone'
        "It\'s <<theNameWithOwner>>. "
;
class PhonePerson: Person
        obeyCommand(fromActor, action) {
                if(action.ofKind(DropAction))
                        return(true);
                if(action.ofKind(TakeAction))
                        return(true);
                return(inherited(fromActor, action));
        }
;

startRoom:      Room 'Void'
        "This is a featureless void. "
;
+me:    Person;
+alice: PhonePerson 'Alice' 'Alice'
        "She looks like the first person you'd turn to in a problem. "
        isProperName = true
        isHer = true
;
++alicePhone: Phone
        owner = alice
;
+bob: PhonePerson 'Bob' 'Bob'
        "He looks like a Robert, only shorter. "
        isProperName = true
        isHim = true
;
++bobPhone: Phone
        owner = bob
;

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
;

This produces more or less what I want insofar as my test cases so far go:

Void
This is a featureless void.

Alice and Bob are standing here.

>x alice's phone
It's Alice's phone.

>alice, drop phone
Alice puts down her phone.

>alice, take phone
Alice takes her phone.

>x phone
Which phone do you mean, Alice's phone, or Bob's phone?

>alice, drop phone
Alice puts down her phone.

>take phone
(Alice's phone)
Taken.

What I care about is just that the parser prefers to prompt for a possessive to disambiguate (without having to explicitly define a possessive on each object), and in general when the actors are fiddling with their “personal” items they’re “her phone” or “his phone” (instead of “Alice’s phone” or “Bob’s phone”, so you don’t get "Bob puts down Bob’s phone. " and so on), and when the player is fiddling around with them they’re (unless otherwise modified) “Alice’s phone” instead of “her phone”. If that all makes sense.

2 Likes

I’m out on this one…

Bumping this with an additional complication. The “fix” I describe above works(-ish) for an item-as-item (a phone represented by a phone object) but it gets very messy when the base Thing gets some Components.

For example, let’s add a PhoneScreen to every phone:

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

class PersonalItem: Thing
        theName() {
                if(owner != nil) return(owner.itPossAdj + ' ' + name);
                return(inherited);
        }
        disambigName() {
                if(owner != nil) return(theNameWithOwner);
                return(inherited);
        }
        theDisambigName() {
                if(owner != nil) return(theNameWithOwner);
                return(inherited);
        }
        aDisambigName() {
                if(owner != nil) return(aNameOwnerLoc(true));
                return(inherited);
        }
;

class Phone: PersonalItem 'phone' 'phone'
        "It\'s <<theNameWithOwner>>. "
        initializeThing() {
                inherited();
                _addScreen();
        }
        _addScreen() {
                local obj;

                obj = PhoneScreen.createInstance();
                //obj.targetObj = self;
                obj.owner = self.owner;
                obj.moveInto(self);
        }
;
class PhoneScreen: PersonalItem, Component '(phone) screen' 'phone screen'
        "It\'s the screen on <<location.theNameWithOwner>>. "
;

startRoom:      Room 'Void'
        "This is a featureless void.  A television is mounted on one wall. "
;
+me:    Person;
++Phone owner = me;
+alice: Person 'Alice' 'Alice'
        "She looks like the first person you'd turn to in a problem. "
        isProperName = true
        isHer = true
;
++Phone owner = alice;
+Fixture 'television' 'television'
        "It's a television.  It has a screen.  "
;
++Component, NameAsOther '(television) screen' 'television screen'
        "It's a television screen. "
        targetObj = location
;

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
;

This gets us:

Void
This is a featureless void.  A television is mounted on one wall.

Alice is standing here.

>x screen
Which screen do you mean, your phone screen, Alice's phone screen, or the
television screen?

>x phone screen
Which phone screen do you mean, Alice's phone screen, or your phone screen?

>x alice's phone screen
It's the screen on Alice's phone.

>x the screen on alice's phone
It's the screen on Alice's phone.

…but also leaves us with…

>x the screen of alice's phone
You see no phone here.

Is there a better/“solved” way of handling this sort of thing, or is it just down to hacking away with special grammar rules? And if it’s grammar rules, is there a cheatsheet for handling them as abstract cases instead of explicit literals? All examples in Handling Odd Noun Phrases in TADS 3 assume that the rules will either be literals or regexen. Not for something like any valid possessive followed by ‘phone’ followed by ‘screen’ or things like that.

Finally, when you’re declaring an object’s vocabulary, you can put adjectives in parentheses to indicate to only use them if they occur alongside a valid noun in the vocabulary. What’s the equivalent to this for nouns? E.g. if I wanted >X SCREEN to not include the phone screens as long as there’s some other kind of screen in scope, but do include them if there are no other screens in scope, and always include them if the player uses X PHONE SCREEN?

One of the approaches I had attempted to handle this is by adjusting PhoneScreen.vocabLikelihood but that hadn’t worked because it turns out you have to spell “vocabLikelihood” correctly.

Anyway, doing something like:

class PhoneScreen: PersonalItem, Component '(phone) screen' 'phone screen'
        "It\'s the screen on <<location.theNameWithOwner>>. "
        vocabLikelihood = -30
;

…produces the desired behavior (excluding the phone screens from >X SCREEN if there are other screens, but including them if there are no other screens or if the player uses >X PHONE SCREEN.

1 Like

this is the hidden virtue of the library reference manual: you can cut&paste the correct spelling, whatever is its length and strangeCamelCase (a3Lite has a more consistent CamelCasing, one must recognise…)

Best regards from Italy,
dott. Piergiorgio.