Handling Object as Singular and Plural

Alright. I’m losing sleep over this.

I don’t know how to best explain this problem.

Let’s say we have a bunch of desks, but all represented with a plural object called “desks”.

What do you do if you want “PUT APPLE ON DESK” to have the same functionality as “PUT APPLE ON DESKS”?

And then the listing says “you see an apple on one of the desks”.

Then you try “FEEL DESK” and you get “The desks are not important” instead of “one of the desks are not important” or “one of the desks is not important” or "the desks is not important$.

I have many such “objects” in my game, which should be treated as “one example from of a collection” vs “the collection as a whole” on a per-action basis. You can imagine this is a vocab matching nightmare, and the action reports keep mismatching between “is” and “are”.

Is there a way people usually handle this?

EDIT: To clarify, I am not meaning to implement a bunch of individual desks. There, ideally, would be a “this specific desk if the player needs just one” and “the whole collection of desks, if it doesn’t matter”, but ideally it would actually be the same object in the code, and would vary it’s plurality and printed name, based on the action taken.

1 Like

I hacked my way through this in a couple situations but would also love a more comprehensive approach (which I have not put in the time for yet)

1 Like

for the whole collection of desks, I have just dealt with wardrobes and drawers, (you, and other cogniscenti, already known…) and I’ll quote the relevant code (minus the actual text, for avoiding spoilers…):

Mward: OpenableContainer, Fixture 'northern (NICK\'s) wardrobe*wardrobes' 
'northern wardrobe' @dressing
"<<one of>> [adprose about opening the wardrobe first]<<or>>[adprose of wardrobe already opened<<stopping>> SPOILER OMISSIS
lookInDesc = "SPOILER OMITTED "
openStatusReportable = nil

dobjFor(Examine)
   {
     action()
     {
       inherited;
/* Thanks to the common plural in their VocabWords, makeOpen, when applied to 
all wardrobes, opens ALL three wardrobes.. so, on paper, only one makeopen 
suffice, but for safety, let's cutpaste makeOpen on all three relevant 
dobjFors.. */
	   makeOpen(true);
       changeName();
     }
   }

dobjFor(LookIn)
   {
     action()
     {
       inherited;
       changeName();
     }
   }

changeName()
  {
    name = 'HER NAME\'s wardrobe';
    initializeVocabWith('NAME\'s NICK\'s wardrobe*wardrobes');
  } 
;

As you can see, the common plural in this and the other two wardrobe allows X WARDROBES act like a X ALL WARDROBE (and only the wardrobe in scope and with the same plural; as evidenced in the comment above, this allows nifty tricks); I think this cover enough of your “the whole collection, if it doesn’t matter” question.

I’m not sure if this cover the other question "this specific, if needs just one, and I must be very strict in cutting out, because is a component of an early major puzzle of my WIP, but is a variant of the wardrobe handling.

here the item are again three, all being parchments hanging on a wall:

// this is for suggesting to X invidually the parchments
Decoration 'framed three trio*parchments' 'three parchments' @office
"the three parchments hanging on the wall have an formal and official aura; 
you should examine, or attempt to read, them individually, left, central (or 
middle) and right, the order perhaps doesn't matter, but SPOILER BEYOND THIS POINT."
;
Lparch: Fixture, Readable 'framed left parchment' 'left parchment' @office
readDesc { THIS METHOD IS ALL A SPOILER }
;

If you notice, here the parchment’s VocabWords don’t have a plural, and the plural point to a decoration, whose role is pointing toward X individually the parchment, plus an hint for the puzzle involving said parchment. I’m not sure if this can help in answering your other question about “this specific, if needed just one”, though.

HTH and
Best regards from Italy,
dott. Piergiorgio.

PS. of course, the above is for adv3: I haven’t tested if the plural trick works also in adv3lite (the vocabWord format is the major incompatibility between adv3 and adv3lite…)

1 Like

Yeah, the problem specifically is a room that might have 20 desks in it. It’s absolutely unreasonable to ask the player to manage 20 individual desks, so we instead have the player have access to one specific desk, if a desk is needed at all, otherwise the plural object (which represents the 20 desks) is used instead.

hmmmm… let’s say that the specific desk is the tenth, you can exploit VocabVords so:

(adv3 of course)
specific_desk: Surface ‘specific tenth desk’ ‘the specific tenth desk’ “this desk is the unique and one tenth desk”
;

dummy_desk: Decoration ‘first second… ninth eleven… twelfth desk*desks’ ‘one or all of the other 19 generic desks’ “this is a generic desk, or bunch of desks, unrelated to the specific desk, the tenth”
;

Dunno this works in adv3, less so in a3lite…

Best regards from Italy,
dott. Piergiorgio.

1 Like

In some cases you can kinda cheese this sort of thing by making the singular form have a high vocabLikelihood and the plural form a lower one, and/or giving the plural verify() { dangerous; } or something like that.

But what do you need the user experience to look like? Like are you expecting to be able to handle something like >SEARCH THE DESK WITH THE APPLE ON IT and that kind of thing?

I hammered this out for the playing cards, where something like >X CARD and >X CARDS and X ACE OF SPADES and so on all can mean slightly different things depending on whether the player is currently in a game, or just watching a game, or a game is not even in progress (or a game is in progress and the player is examining their own cards versus a different player’s cards versus other cards (i.e. un-dealt cards). I ended up wrapping this in a Vaporous, MultiLoc with a custom report manager to handle almost all of the actions, and then separate game objects (that don’t have most of the vocabulary they seem like they might) more or less as props. So when playing, the player gets an inventory item that identifies itself as “your playing cards” (as defined by their name), but they don’t have “playing cards” in their vocabWords. The MultiLoc object does have all those vocabulary words, but never shows up in any room/whatever descriptions (because it’s Vapourous).

I don’t know if you need to handle as many disambiguation cases as I did, but it works pretty well for things that are mostly scenery-ish (and so you want interactions to work according to some number of special rules, instead of mostly being handled via normal T3 object handling rules). If that all makes sense.

2 Likes

Nothing quite this intense. Mostly I just want the game to respond with the plural version if the player referred to the plural version, and then respond with the singular version of the player referred to the singular version, but the plural and singular are both the same code object, so actions done to either are actually done to the same object.

>PUT APPLE ON DESK, >PUT APPLE ON ONE OF THE DESKS, and PUT APPLE ON DESKS should put the apple on the same object, and the parser should respond with

Okay, you put the apple on one of the desks.

for the PutOn action. Then, for the >FEEL DESK, >FEEL ONE OF THE DESKS, and >FEEL DESKS the parser would say

You feel nothing unexpected from the desk.

You feel nothing unexpected from the desk.

and

You feel nothing special from the desks.

respectively.

Again, ideally this is for situations where there could be 2 to 20 desks, but the exact number isn’t stated. It’s just implied that there’s too many to use all of them, so a specific one will always be volunteered if necessary.

The problem, specifically, is remapping an action to another object also changes which object gets reported. So I’m mostly trying to figure out how to remap actions from objectA to objectB but still report {the dobj} as objectA.

At least, that’s one solution I have in progress. The other solution I have would be…a lot weirder.

I’m no stranger to weird solutions, but I’ve learned it’s better to ask around if anyone knows something simpler first, before I go completely wild on the code.

multiple apples… desks… cards…

together generates an interesting puzzle: there’s, say, a number of desks, each with their Apple ][, and each apple ][ has his slots filled with cards; every Apple is broken, but… taking working cards from broken ][s, one can put together a working apple ][…

… i think this can be an interesting, albeit hard, coding challenge…

Best regards from Italy,
dott. Piergiorgio.

1 Like

Exactly, and even if all the individual instances aren’t really there, and it’s just background detail, then at least the detail gets reported as the player expects.

Okay, I solved it.

Here’s the code for fakePlural.t, which creates the FakePlural interface.

class FakePlural: object {
    ambiguouslyPlural = true
    plural = true

    // The string that refers to a single unit of the plural
    // For example: 'desk'
    fakeSingularPhrase = (name)
    // Make use of the "one of the ____" phrase
    useOneOfThe = true

    // Was the preposition recently polled?
    polledWithPrep = nil

    objInPrep() {
        polledWithPrep = true;
        return inherited();
    }

    objOutOfPrep() {
        polledWithPrep = true;
        return inherited();
    }

    objOutIntoPrep() {
        polledWithPrep = true;
        return inherited();
    }

    setSingularStatus() {
        // Prepositional phrases usually make more sense with singular
        if (polledWithPrep) {
            plural = nil;
        }
        else if (gCommand == nil) {
            plural = true;
        }
        else if (gAction == nil) {
            plural = true;
        }
        else if (gActionIs(Look) || gAction.actionFailed) {
            plural = true;
        }
        else if (gIobj == self || gActionIs(Board) || gActionIs(Enter) || gActionIs(LieOn) || gActionIs(SitOn) || gActionIs(StandOn)) {
            plural = nil;
            polledWithPrep = true;
        }
        else {
            plural = gCommand.verbProd.dobjMatch.grammarTag != 'normal';
        }
        polledWithPrep = nil;
    }

    aNameFrom(str) {
        plural = true;
        polledWithPrep = nil;
        return inherited(str);
    }

    pronoun() {
        setSingularStatus();
        return inherited();
    }

    theNameFrom(str) {
        setSingularStatus();

        local preferredNoun = str;
        if (!plural) preferredNoun = fakeSingularPhrase;

        if (ownerNamed && nominalOwner != nil) {
            return nominalOwner.possAdj + ' ' + preferredNoun;
        }
        
        if (qualified) {
            return preferredNoun;
        }

        if (!plural && useOneOfThe) {
            return 'one of the <<str>>';
        }

        return 'the <<preferredNoun>>';
    }
}

To create a Thing which is also a FakePlural, just add the latter to the inheritance list:

class FakePluralThing: FakePlural, Thing;

Example room of this in action:

classroom: Room { 'The Classroom'
    "Scattered desks litter the otherwise-empty classroom. "
}
+pedestal: Platform {
    'pedestal'
    "A simple pedestal, made from welded bars of metal. "
}
++apple: Thing {
    'apple;red plastic fake'
    "A red apple. It looks like it's made of plastic. "
}
+pluralDesk: FakePlural, Platform {
    'desks;desk[weak] one[weak] of[prep];desk top[weak] tops[weak] desktop desktops'
    "A collection of desks with a fake, wood-grain surfaces.
    All are made to factory standard. "
    fakeSingularPhrase = 'desk'
    isFixed = true
}
1 Like