Inform best practices mud wrestling: ‘undescribed’

I think the correct way to deal with something that shouldn’t be described and that the player shouldn’t be able to reference, is to keep it out of play altogether until needed. :dizzy:

I would, in all seriousness, like to split off the “undescribed” discussion into a separate thread titled “Inform best practices mud wrestling: ‘undescribed’”.

6 Likes

@HanonO could you assist us, please?

images

2 Likes

I just wrote a short extension that makes it easy to selectively keep out of scope things that otherwise would be… it’s written for the current development version and would take tweaking for previous versions.

With it in place, this example:

Include Don't Scope by Zed Lopez.

Lab is a room.

mattress is in the lab.
The mattress is undescribed.
bed is in the lab.

Don't scope an undescribed thing: rule succeeds.

when play begins:
  repeat with t running through things in the location begin;
    say "[t][line break]";
  end repeat;

test me with "x mattress"

would result in:

yourself
mattress
bed

scope
An Interactive Fiction
Release 1 / Serial number 240505 / Inform 7 v10.2.0 / D

Lab
You can see bed here.

>test me
(Testing.)

>[1] x mattress
You can't see any such thing.

>
Don't Scope by Zed Lopez

Don't Scope by Zed Lopez begins here.

Don't scope is an object based rulebook.
The don't scope rulebook is accessible to Inter as "DONT_SCOPE_RB".

Don't scope the player (this is the don't unscope player rule): rule fails.

The don't unscope player rule is listed first in the Don't scope rules.

Include (-
[ DoScopeAction item;

    FollowRulebook(DONT_SCOPE_RB, item);
    if (latest_rule_result-->0 == RS_SUCCEEDS) return;

    #Ifdef DEBUG;
    if (parser_trace >= 6)
        print "[DSA on ", (the) item, " with reason = ", scope_reason,
            " p1 = ", parser_one, " p2 = ", parser_two, "]^";
    #Endif; ! DEBUG

    @push parser_one; @push scope_reason;

        switch(scope_reason) {
                TESTSCOPE_REASON: if (item == parser_one) parser_two = 1;
                LOOPOVERSCOPE_REASON: if (parser_one ofclass Routine) parser_one(item);
                PARSING_REASON, TALKING_REASON: MatchTextAgainstObject(item);
    }

    @pull scope_reason; @pull parser_one;
];

-) replacing "DoScopeAction"

Don't Scope ends here.

[Edited to modify the extension to ensure the player isn’t taken out of scope.]

2 Likes

It’s not surprising that people confuse these. The library confuses them too!

Okay, here is my undescribed rant. (If you look back in forum history you can probably find me giving in more than once.)

In the original Inform 6 (library 6/11), the concealed attribute could be (and was) used for three different concepts:

  1. An object which the player doesn’t know about; it is not visible to the player; but it can be interacted with if the player knows about it or if some game message tips them off. (E.g. something “hidden” in a messy room. You can SEARCH for it, but if you know it’s there you can just take it without searching.)
  2. An object which the player doesn’t know about; it is not visible and can’t be interacted with until game logic removes concealed. (E.g. a secret door which is closed.)
  3. An object which the player does know about and can refer to normally; it’s taken for granted and thus doesn’t have to be mentioned in the room description. (E.g. the player object itself.)

There are little hacks all over the library to support these different uses:

  • For (1): If you pick up a portable concealed object, the concealed flag is removed and the object behaves normally thereafter.
  • For (2): You can’t move through a concealed door.
  • For (1) and (3): Concealed objects are downrated, but not forbidden, in disambiguation.
  • For (3): When you switch player objects, the concealed attribute is removed from the old player object and added to the new one.

The only behavior that makes sense for all three cases is that concealed objects are omitted from listing.

The problem, of course, is that these three uses are obviously different and can’t be made consistent with each other! You can EXAMINE a concealed door but not walk through it. Etc.

On top of that, all three cases get tangled up with other library features that don’t use concealed. (1) and (3) are a whole lot like scenery, but not exactly. (You can’t pick up scenery.) There are other ways to keep people from moving through a door (2) – keeping it closed, for a start. Simply moving an object off-stage works great for (2), except for doors, which are messy to move around. (Not as messy as they are in I7, but still a pain.)

Anyhow, I7 inherited all of these cases and inconsistent behaviors. It just renamed the property to undescribed and stuck it behind a documentation note saying “This is a last resort.”

(I think all of the above still applies to the latest I7, although I haven’t tested every detail.)

This is all basically unfixable. Anything you do to make one of these cases work better will screw up the others.

Example: I see Zed just proposed an I7 rules change to make undescribed/concealed objects unscopable, i.e. the player can’t refer to them at all. That makes sense for (2) but not for (1) or (3). (Zed’s change had to explicitly skip the player object to avoid breaking EXAMINE ME.) Would this be better? Well, it would cut down on the mud wrestling. But it’s hard to say that this is what everybody wants, because undescribed/concealed is such a mess that there’s no single behavior everybody wants out of it!

On the up side, it’s easier than ever in I7 to get what you want without using undescribed/concealed.

7 Likes

Having not been there for the history of disagreements on the subject, I have a simpler, perhaps a veritably simplistic viewpoint, centered on being really sanguine about throwing Case 1 under the bus.

Keeping undescribed things other than the player out of scope serves cases 2 and 3 just fine.

For (1): If you pick up a portable concealed object, the concealed flag is removed and the object behaves normally thereafter.

Undescribed things being kept out of scope wouldn’t break the Note Object Acquisitions rule, but it would make it even less relevant.

For (2): You can’t move through a concealed door.

Support for this case would be improved inasmuch as we remove an avenue for leaking the door’s existence.

For (1) and (3): Concealed objects are downrated, but not forbidden, in disambiguation.

Clearly, this one changes (in a way I’m claiming is a feature).

For (3): When you switch player objects, the concealed attribute is removed from the old player object and added to the new one.

Behavior of this case would be unchanged.


Perhaps even better (and less contentious) would be to do something to the effect of incorporating Scopability by Brady Garvin, where objects can be scopable or unscopable and are usually scopable. Then we could just say:

  1. use undescribed/scopable for case 1
  2. use undescribed/unscopable for case 2 (authors can switch something to described/scopable when revealed)
  3. the player is always undescribed/scopable; ChangePlayer is modified to give scopable as well as concealed.

Undescribed would become fit to serve for both Case 1 and Case 2 without drawbacks that break its utility for the other case and maybe it wouldn’t have to be considered such a last resort.

With the Don’t Scope rulebook above, this (save for the tweak to ChangePlayer) could be achieved with:

An object can be scopable or unscopable. An object is usually scopable.
Don't scope an unscopable object: rule succeeds.

(Technically, we wouldn’t even need to tweak ChangePlayer since Don’t Scope’s first rule is to never render the player unscoped.)

1 Like

It’s fixable if the semantics of the different use cases are separated from one another.

I would say that in I7 Case 2 is definitely intended to be superseded by the concealment relation and the associated concealed adjective. However, in the current template code rooms cannot conceal things, which I think is the main reason why people keep reaching for undescribed.

Case 3 is important for the player object, but I’m not sure how often any author would want to make use of that meaning (i.e. taken for granted) for a different object.

Case 1 is the problem. As far as I know, it’s a remnant of legacy design from the Adventure/Infocom era, and I’m not sure that it needs to exist any more as a feature.

Modifying TestConcealment() and ConcealedFromLists() to allow rooms to conceal things goes a long way toward addressing the confusion.

I agree that (1) is an awkward historical relic. People have been complaining about it since the 1990s. (If you want the player to search for an object, make them search for it. Allowing them to remember it from a previous play-through or a walkthrough is a mimesis failure.)

Nonetheless, that is how the property works. Changing it now is going to surprise many of the people using it. You say it’s how undescribed should “intuitively” work but I’m afraid this is just not universally true.

I am more or less on board with this. Extending “concealment”, mentioning Scopabilities, and then removing undescribed entirely seems doable, although it will lead to several years of “how the heck do I do this now” questions.

It’s also worth noting that case (1) can be implemented straightforwardly without undescribed:

Rule for writing a paragraph about the not handled rock:
	now the rock is mentioned.

Now the rock is portable and omitted from room descriptions until it is picked up.

(I admit this doesn’t cover things hidden in containers. So I don’t have a complete argument yet.)

Maybe a deeper solution is to have scenery objects be takeable!

The Standard Rules already say:

Scenery is usually fixed in place. [An implication.]

You can refuse this implication and declare an object portable scenery. It just doesn’t work; the scenery property alone is enough to prevent TAKE. If we genuinely separated these concepts, then portable scenery would cover all the cases of omitting objects from room listings. (Without breaking the existing default that “Foo is scenery” means fixed-in-place by default.)

(There would be some secondary effects on disambiguation: the downscoring for scenery is weaker than the downscoring for undescribed. But I think this would be tolerable.)

3 Likes

Undescribed is currently a feature that works sufficiently badly for two different cases that its use is discouraged for both of them. I think throwing either of them under the bus and making the feature something that could be recommended for the other would be an improvement over what we have now. (I’m ignoring Case 3, because it actually works just fine for that one.)

But you’ve convinced me that simply keeping undescribed non-player objects out of scope in the absence of a more comprehensive plan isn’t an appropriate measure and I’ve withdrawn that PR.

Proof of concept of rooms concealing things (for current dev version):

Lab is a room.

The elephant is a thing in the lab.

For deciding the concealed possessions of the lab: if the particular possession is the elephant, yes; no.

Before choosing notable locale objects of a room (called loc):
  let x be the first thing held by loc;
  while x is not nothing begin;
    if loc conceals x, now x is mentioned;
    now x is the next thing held after x;
  end while;

Include (- +replacing
[ ConcealedFromLists obj c;
        if ((obj has concealed) || (obj has scenery)) rtrue;
        c = parent(obj);
        if ((c) && (c ofclass K5_container or K6_supporter or K1_room) && (TestConcealment(c, obj))) rtrue;
        rfalse;
];
-)

Include (- +replacing
[ TestConcealment A B;
        if ((A ofclass K2_thing or K1_room) && B ofclass K2_thing) {
                if (IndirectlyContains(A, B)) {
                        particular_possession = B;
                        if (CarryOutActivity(DECIDING_CONCEALED_POSSESS_ACT, A)) rtrue;
                }
        }
        rfalse;
];
-)

reveals no elephants:

Welcome
An Interactive Fiction
Release 1 / Serial number 240506 / Inform 7 v10.2.0 / D

Lab

>

[ edited to remove replacement of ObviouslyOccupied; it wouldn’t be consulted for the room case and so didn’t need to change ]

Since this use case comes up a lot on the forum, it might be desirable to make some small additions to the Standard Rules:

A thing can be hidden.

Rule for deciding the concealed possessions of a room:
	if the particular possession is hidden, yes;
	no.

Then the elephant can just be declared as a hidden thing.

1 Like

I use undescribed, too, exclusively for things I don’t want mentioned in a LOOK but which I do want in scope. It has behaviour and doubles as a flag, which is handy.

Most often I have something start undescribed but then I can do a NOW BLAH IS NOT UNDESCRIBED and it appears, and gets rid of the undescribed behaviour, too.

Looks like I’ve used it about 40 times in my WIP out of 1200 things so far.

It created problems a couple of times and solved an unexpected problem a different time (from notes)

An undescribed thing doesn’t automatically set any pronouns. That may be a problem depending on the situation.

It messed up disambiguation when an undescribed thing shared a word with a direction name.

The time it helped me was when I had set someone’s hands to be scenery, and that made Inform super prejudiced against some actions involving the hands, like inserting into them. So I changed the hands to not be scenery, and to be undescribed instead, and the problem went away.

-Wade

2 Likes

A particular-possession-centered approach is especially handy for the door case given that the rooms on either side pass it back and forth like a hot potato.,

This is the recommended work-around, right? If you want a hidden object that can be found by searching another object, then simply put the hidden object somewhere else and only bring it to the room when the key object is searched. I don’t see any problem with doing it that way, therefore no problem!

Honestly I see no reason to have the player be kept undescribed at all. Just check the value of the player variable instead of checking for the undescribed flag, and now you don’t have to worry about the variable and the flag being in sync.

2 Likes

Hunh. That looks like a surprisingly tractable change.

I think we’re ready for a proof of concept of literally eliminating described/undescribed/the i6 concealed attribute altogether.

  • eliminate the can’t take scenery rule: if someone goes out of their way to declare something portable scenery, it can be taken
  • have the note object acquisition rule look for scenery in inventory and remove the scenery flag
  • let rooms conceal, like my code above (and replace can’t go through undescribed doors with can’t go through concealed doors)
  • have relevant room description code check “is this the player”
2 Likes

My proposal at this point would be:

  • Remove the can’t take scenery rule, as zarf proposed. Scenery is implied to be fixed in place, so this won’t break any existing works (unless they specifically override that rule for some reason), but now you can use portable scenery for things that aren’t supposed to be described.
  • Remove the special rules about the player being undescribed. The code that checks for undescribed in the list-writer and the parser can instead check for the player object. Now there’s no concern about the flag and the variable getting desynced.
  • Remove the can’t go through undescribed doors rule. This one may break some things, but if someone is currently relying on this behavior, it’s very easy to reinstate it: create a new property and write a “check going through a whatever door” rule.
  • Remove the link between undescribed and I6 concealed. This will make the library no longer care about it in any way, letting it be a standard I7 property. Then say that an undescribed thing is usually portable scenery.

The only changes most users will see is that undescribed things are slightly less dispreferred when guessing what object you mean (scenery has less of a penalty than undescribed), and they no longer become described when you pick them up. And these will only happen if people are ignoring the documentation’s guidance to avoid that property in the first place.

EDIT in response to the edit above: Or make it so that things become no longer scenery when picked up. That seems reasonable enough; either way, we just pick one and stick to it.

1 Like

We’ve been forgetting about the compass and thedark. I’m not sure it matters whether they lose their concealed flag.

I don’t think you want to remove the can't take scenery rule so much as make it apply only to fixed in place scenery. It’s the rule that produces the very familiar “That's hardly portable.” message.

It shouldn’t matter about compass. That object is not normally placed in scope, anyway, only its children (the directions) via ScopeWithin().

The point of the can't go through undescribed doors rule is to mimic the message for an invalid direction. If it’s going to be dropped, then I think the standard set going variables rule and/or the determine map connection rule need to be adjusted to check for concealment.

1 Like