[I6] Is it possible to list conditional exits?

I have written an EXITS command to list available exits as follows:

[ ExitsSub count direction;
  if (location == thedark)
    "You can't see any exits in the dark.";
  count = 0;
  objectloop(direction in Compass)
    if (metaclass(location.(direction.door_dir)) == Object)
      count++;
  if (count == 0)
    "There are no obvious exits from here.";
  if (count == 1)
    print "The only obvious exit is ";
  else
    print "Obvious exits are ";
  objectloop(direction in Compass)
    if (metaclass(location.(direction.door_dir)) == Object)
    {
      LanguageDirection(direction.door_dir);
      count--;
      if (count > 1)
        print ", ";
      if (count == 1)
        print " and ";
      if (count == 0)
        ".";
    }
];

This works fine if all the exits are unconditional, but there are very few games where this is the case. Is it possible to modify this routine so that it also lists any exits that are defined in a routine and the routine returns a room number in the current situation? I suspect that I should be able to somehow change the two if (metaclass(location.(direction.door_dir)) == Object) tests.

Try to call the property, if it answers 0 it means that there is no way out.

Include "parser";
Include "verblib";

Object room1 "Room1"
   with description "You are in a room1.",
   e_to room2,
   w_to [;
      return random (0, room2);
   ],
has light;

Object room2 "Room2"
   with description "You are in a room2.",
   w_to room1,
has light;

[ Initialise   o n;
   location = room1;
   objectloop(o in Compass) {
      if ( (location.(o.door_dir))() ) n++;
   }
   print "Number of exits: ", n, "^";
];
Include "grammar";

Okay. I’ll give that a try. I quite often return a string, though, so that probably won’t work. Perhaps if I try returning as many things as I can think of in a test case and see what they all return.

Are you sure these properties can return a string? No.

update
I said “NO”, but, as always, it seems a little more complicated than that!

Forget about my proposal. If you call the function, it will run, which is not the purpose!

The n_to, etc property can return a room ID, door ID, 0, or 1. The tricky case (for this problem) is when the routine prints a string and returns 1. There’s no easy way to determine the result without the string being printed.

You could set up all your direction property methods to accept an optional “try this silently” flag. This is kind of a lot of work. Or you could define a separate “can I go this way” property in each room which returns true or false according to the same logic. This is also kind of a lot of work.

Would @output_stream 3 dummy be overkill here? Redirect printing to an array in memory, call the routine, then turn off redirection?

In other words, something like:

Array scratchspace -> 128;

[ CallWithoutPrinting routine tmp ;
    @output_stream 3 scratchspace;
    tmp = routine();
    @output_stream -3;
    return tmp;
];

Then:

if(CallWithoutPrinting(location.(o.door_dir))) n++;

(Untested)

Thanks guys. Lots of good suggestions there, but, like zarf said, it’s kind of a lot of work for very little benefit. I think I might skip the idea for now, as the exits are mentioned in room descriptions anyway.

I was also thinking ahead to possibly doing some ports of old-school text adventures where they used to have a brief room description followed by a list of exits and a list of objects. I could probably still use it there. I used to like the old way of doing it. It’s a lot more concise than the bloated textual descriptions that we all use nowadays.

In this case, check out Scott Adams’ Adventureland, ported to Inform 6 by Graham Nelson; that’s exactly what he’s doing. The Adventureland.inf file is on the Interactive Fiction Archive.

Summary
Class ScottRoom
 with initial
      [;  give self ~visited;
      ],
      describe
      [ i c d;  print (string) self.description;
          print "^^Obvious exits: ";
          for (i=n_to: i<=d_to: i++)
              if (self.i ~= 0) c++;
          if (c==0) print "none!";
          else
          {   for (i=n_to: i<=d_to: i++)
                  if (self.i ~= 0)
                  {   if (d++>0) print ", ";
                      if (i==n_to) print "North";
                      if (i==s_to) print "South";
                      if (i==e_to) print "East";
                      if (i==w_to) print "West";
                      if (i==u_to) print "Up";
                      if (i==d_to) print "Down";
                  }
              print ".";
          }
          new_line;
          c=0; d=0;
          objectloop (i in self)
              if (i ~= player) { c++; give i concealed; }
          if (c==0) rtrue;
          print "^You can also see: ";
          objectloop (i in self)
              if (i ~= player)
              {   if (d++>0) print " - "; PrintShortName(i);
              }
          new_line; rtrue;
      ];

All the other Scott Adams games have also been converted to Inform and use a similar display, probably using a similar technique.

There are some interesting ideas in here, like the way Graham has used a class for the room with all the display formatting done in a describe routine that calls the description to print the room description, then the exits and visible objects. Neat. The way he loops through the exits is interesting too. I didn’t know you could do that.