[I6] Room description prints contents of scenery supporters but not scenery containers

Under normal circumstances, if you have an immoveable object, you would either:
(a) describe it in the room description and give it an attribute of scenery; or
(b) not describe it in the room description and give it an attribute of static.

If you choose option (a) and the scenery object is a supporter and there are objects on the supporter, then the library lists those objects after the room description, but before the other objects are listed. For example, “On the table are some food scraps.”

Unfortunately, the library does not do the same thing for containers and there are no hooks to provide for this. I want to say something like, “In the sink are some dirty dishes.”

The library also uses one paragraph per supporter. I would prefer to compress this into one paragraph for all supporters and containers with one sentence each.

As far as I can see, the only way to overcome the flawed logic in the library is to replace Locale with a custom routine. Unfortunately, like everything in the library, it is very hard to work out what’s going on.

Has anyone ever done this before?

@DavidG, as you’re working on the library at the moment, could this be added to the list of things to do?

Incidentally, it is easy to do the listing of objects on scenery containers (and scenery supporters) AFTER the other objects are described using a custom LookRoutine, but it would be better to include them after the room description and BEFORE the other objects.

This was the big drawback of Inform 6 that I7 was intended to address…

I’ll note that people usually ask how to change the supporter behavior, since it’s easier add custom text for container contents than to remove the default text for supporter contents!

The standard answer is “add an initial property which calls WriteListFrom().” If you want to do this for every static container, that’s not much more work. Typically (in my I6 days) I wanted to write custom text for each room and static object anyhow.

To add that functionality to Locale, you’d look for calls to SayWhatsOn() and create a parallel function called SayWhatsIn().

I don’t have an easy way to do that. (In either I6 or I7, I’ll admit.)

1 Like

I seem to recall doing something like this in my reimplementation of “Uninvited”. If you can write up something detailing exactly what you want at https://gitlab.com/DavidGriffith/inform6lib, I’ll get on it.

Thanks guys. Doing an initial is no problem, but then it’s one paragraph per object interspersed amongst any other initials that you may have. Reordering the object definitions can help there. If doing an initial routine, you can also use <<Search self>>; rather than WriteListFrom();. I use this in conjunction with the object descriptions.

I also tried the SayWhatsIn() approach, but wasn’t happy with the one paragraph per object. This would probably be required with a library update.

I’ve written a routine to put the contents of scenery supporters and containers in the one paragraph, so it’s just a case of working out how to put that in the Locale routine without breaking the rest of the functionality in that routine. I’ll do a Replace. I won’t change the library.

I’ll add an issue at gitlab in the next day or two. I presume I’ll need to register for that.

I’ve used Replace Locale; and replaced the top part of Locale with the following:

[ Locale descin text_without_ALSO text_with_ALSO o p num_objs must_print_ALSO x flag;
  num_objs = 0;
  objectloop (o in descin)
  {
    if (o has scenery && (o has supporter || (o has container && o has open or transparent)) && children(o) > 0)
    {
      flag = 0;
      objectloop (x in o)
        if (x hasnt scenery && x hasnt concealed)
          flag = 1;
      if (flag > 0)
      {
        if (num_objs == 0)
          print "^";
        else
          print " ";
        if (o has supporter)
          print "On ", (the)o;
        else
          print "In ", (the)o;
        WriteListFrom(child(o), ENGLISH_BIT+TERSE_BIT+CONCEAL_BIT+ISARE_BIT);
        print ".";
        num_objs = 1;
      }
    }
  }
  if (num_objs > 0)
    print "^";
  objectloop (o in descin)
    give o ~workflag;
  objectloop (o in descin)
    if (o hasnt concealed && NotSupportingThePlayer(o))
    {
      #Ifndef MANUAL_PRONOUNS;
      PronounNotice(o);
      #Endif;
      if (o hasnt scenery)
      {

then everything else as per what was in the else clause onwards. It no longer uses SayWhatsOn(). It seems to work nicely. I’m just about to test it in a real game. Can you guys see any problem with this?

1 Like

I have used this routine in a large game with a lot of scenic containers and supporters. It works a treat. There was just one glitch. I was trying to re-use all the existing variables as best as possible. I thought num_objs was counting the number of paragraphs. I was wrong. It is counting the number of objects, hence you have to reset it to 0 just before the third objectloop (o in descin). In fact, I see no reason why the second and third objectloop (o in descin) can’t be merged.

I was also wrong when I said it no longer uses SayWhatsOn(). I see that it’s still used further down in the Locale routine in the part that’s not shown in my code fragment.

I’ve raised an issue on the GitLab page. I hope this is clear enough.

In the meantime, I’ve used my stop-gap solution in a real game that’s currently being beta tested. I like the the way it works now. I’ll see if the beta testers have anything to say about it.

FWIW, the difference in behaviour between scenery containers and supporters is explicitly documented, so it is intentional.

The description of the contents of scenery supporters is briefly mentioned in Appendix A1 of DM4. The description of the contents of scenery containers is not mentioned at all, as it is not provided in the library. This is the issue. It’s probably an oversight in the library that no one’s noticed before, as scenery containers probably aren’t all that common.

Scenery containers are common – more common than scenery supporters, in my games.

As I said, the assumption is that you’re going to put in your own WriteListFrom call, either in an initial property or in the room description.

(Not to say this shouldn’t be a library feature if people want it. Just that it wasn’t overlooked.)

It’s been forever since I’ve read the DM, since I’m mostly doing I7 now. But FWIW in I7’s WI3.8 it does explicitly state:

If a supporter is scenery, it may still be mentioned in the room description after all, but only as part of a paragraph about other items … [removing all items will hide the supporter description as well] … (Scenery containers do not behave in this way: their contents are assumed to be less immediately visible, and will be mentioned only if the player looks inside them.)

And over in WI18.28 there’s:

The “describe what’s on scenery supporters in room descriptions rule” is somewhat controversial. It prints text such as “On the mantelpiece is a piece of chalk.” for items which, like the mantelpiece, are scenery mentioned - we assume - in the main room description. (It is assumed that scenery supporters make their contents more prominently visible than scenery containers, which we do not announce the contents of.)

I assume similar logic applied to I6’s library, since they had a common basis.

Thus the assumption is that for scenery items you are mentioning the existence of both kinds of thing somewhere in the room description – then items on supporters are explicitly called out (as items on a shelf or table are in plain view) while items in containers are not (as a box or chest must normally be actually inspected to see contents, even if open).

Something like that could help?

Include "parser";
Include "verblib";

Object room "Room"
   with description "You are in a room."
has light;

object box "box" room
	with  
		name 'box',
		when_open [;
         print "In ", (the) self;
         if (WriteListFrom(child(self), ENGLISH_BIT+TERSE_BIT+CONCEAL_BIT+ISARE_BIT) == 0)
            print " is nothing";
         ".";
      ],
!		when_closed [; ],
	has container openable open static;

object apple "apple" box
	with name 'apple';

[ Initialise; location = room; ];

Include "grammar";

Room
You are in a room.

In the box is an apple.

>