[I6] Inform 6.33.1-b3 issues

I’ve been playing around with this release and, working through some of the examples in the DM4, I’ve noticed a couple of issues:

1. An issue with examining objects in closed transparent containers

Constant Story "CLOSED TRANSPARENT CONTAINERS";
Constant Headline "^An Interactive Bug Reproduction^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere",
  with description "You're not sure where you are.",
  has light;

Object -> glass_cube "glass cube"
  with name 'glass' 'cube',
  has container transparent;

Object -> -> rock "rock"
  with name 'rock';
 
[ Initialise;
  location = Start_Room;
];

Include "Grammar";

Expected behavior: The rock can be seen inside the transparent container, but not interacted with since it’s not open.
Actual behavior:

2. An issue with the after rule for Insert not being called.

(Noticed this when experimenting with Ruins and wondering why putting a treasure into the packing case didn’t increase my score.)

Constant Story "INSERTION RULES";
Constant Headline "^An Interactive Bug Reproduction^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere",
  with description "You're not sure where you are.",
  has light;

Object -> packing_case "packing case"
  with name 'packing' 'case',
       before [;
           Receive: print "[packing_case: before: Receive]^";
       ],
       after [;
           Receive: print "[packing_case: after: Receive]^";
       ],
  has static container openable open;

Object -> rock "rock"
  with name 'rock',
       before [;
           Insert: print "[rock: before: Insert]^";
       ],
       after [;
           Insert: print "[rock: after: Insert]^";
       ];
 
[ Initialise;
  location = Start_Room;
];

Include "Grammar";

Expected behavior: The rock’s after rule for Insert is called since none of the other 3 rules returns true and since Insert is a substantive action that changes the game state.
Actual behavior:

It’s been years since I’ve really messed around with Inform 6, so I’d like to get a sanity check on these in case I’m doing something wrong.

Thanks.

They both look valid. I’ve created issues for them in Github at inform7.com/mantis/view.php?id=1806.

I’ll look at them tomorrow.

Thanks.

I’ve run into a couple more issues. Would you prefer that I post them here for you to verify, file them on Mantis, file them on Github, or some combo of these?

Please post them here. Perhaps this will benefit from having several people go over the issues.

I’ve fixed the two bugs described. Waiting for your reports on new ones.

The latest git of Inform6unix has the fixes. If you don’t want to do that, just grab the latest verlibm.h.

Thanks for the fixes. I’ll pull the latest and greatest from git.

Ok, here we go.

1. Implicit action notification happens late.

Constant Story "IMPLICIT ACTION NOTIFICATION ORDERING";
Constant Headline "^An Interactive Bug Reproduction^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere",
  with description "You're not sure where you are.",
  has light;

Object -> cage "cage"
  with name 'cage',
       after [;
           Open: "You hesitantly swing open the cage door.";
       ],
  has enterable container openable transparent static; 

[ Initialise;
  location = Start_Room;
];

Include "Grammar";

Expected: When the player takes an action (such as entering the cage in the example program) that triggers an implicit action (opening the cage), a notification that the implicit action is being attempted (i.e. “(first opening the cage)”) is reported to the player first, followed by a report about the results of the attempted action.

Actual: The results of the implicit action are reported first, followed by the report that the action is being attempted.

2. Orders fully parsed by an animate/talkable object’s grammar routine are not being delivered to its orders routine.

This is a simplified version of exercise 30 in the DM4. See page 140 for an explanation of what the return values from grammar are supposed to indicate and a description of the exercise, and pages 449-450 for the official solution.

Constant Story "GRAMMAR AND ORDERS";
Constant Headline "^An Interactive Bug Reproduction^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere"
  with description "You're not sure where you are.",
  has light;

Object -> girl "girl"
  with name 'girl',
       orders [;
           WaveHands: "The girl waves energetically.";
       ],
       grammar [;
           if (verb_word == 'xyzzy') {
               action = ##WaveHands;
               noun = 0;
               second = 0;
               rtrue;
           }
       ],
  has animate female;

[ Initialise;
  location = Start_Room;
];

Include "Grammar";

Expected: “girl, xyzzy” produces the “The girl waves energetically.” message.

Actual: “girl, xyzzy” produces “Nothing to do!” from the parser. I took a look at the library code and see that both L__M(##Miscellany, 2) and L__M(##Miscellany, 43) are defined with this text.

3. Infix ;give command output missing a newline before new prompt

This is just a trivial cosmetic issue.

Same example program as 2. above. Compile it with the -X Infix debugging flag and we have:

Thank you, Vince, for reporting those bugs ! It’s really helpful, and thanks for the minimal source codes too!

Comment on git stuff.

Did a

and got your top level repo and the lib submodule with no problem, but it gave me a permissions error on the src submodule:

However, I can do a direct http clone of the Inform6 repo with no problems:

I notice in the clone output that the submodules are specified differently: “git://github.com/DavidGriffith/inform6lib.git” vs. “git@github.com:DavidKinder/Inform6.git”. Looks like one is using the git protocol and the other is trying to log on as user git@github. Is this as it should be?

Please give it a try again.

Problem solved. Thanks.

For “Implicit action notification happens late”, I reordered things for ImplicitOpen() to get the messages in the right order. It was a bit convoluted to do so. Can you any other After() rules that would be similarly affected. I went over the other ImplicitX() actions, but I’m not sure.

I haven’t discovered other cases of misordering, but, while poking around looking for them, I did notice something that’s less of a bug and more me second-guessing the library design 20 years too late.

Constant Story "IMPLICIT TAKE BEFORE EATING";
Constant Headline "^An Interactive Investigation^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere",
  with description "You're not sure where you are.",
  has light;

Object -> apple "apple"
  with name 'apple',
       article "an",
       after [; Take: "You pick up the apple eagerly."; ],
  has edible;  

[ Initialise;
  location = Start_Room;
];

Include "Grammar";

My questions are:

  1. Why isn’t the eat action attempted after the take action succeeds? Should returning true from an implicit action’s after() routine completely halt the library’s processing of the action that motivated that implicit action, or merely prevent the library from reporting the results of the implicit action? Presumably, once the implicit action has made it through both before() and FooSub(), it can be said to have already succeeded, clearing the way for the original action that was dependent on it to be attempted. It seems like the library is conflating “no need to do any reporting of the implicit action’s success” with “no need to continue processing pending actions” because both are wrapped up in the single return value from after().

  2. Why are the results of the successful implicit take action reported rather than suppressed? This is mostly rhetorical. It’s clear that, as things stand now, the silencing of implicit action reports can only occur without author intervention for actions reported within the library itself, since game-level after() routines report customized action results via print (a core Inform keyword) rather than calling a facility provided by the library that could suppress these reports.

What if after() routines called a new report_action_if_needed() library routine rather than calling print directly, or queried the library state to determine if an implicit action was in progress prior to reporting on an action? The latter idea puts more burden on authors, but I decided to test it out, thinking that it could be done w/o library changes. I tried wrapping action reports with an “if (~~keep_silent)” check, but it turns out that keep_silent is 0 during the call to the after() routine for the implicit take in the example above. I looked at the library code a bit and saw that there are a couple of other variables associated with implicit actions, notheld_mode and anotheld_mode, but that neither is exported like keep_silent.

Interested in thoughts on these things, or pointers to past discussions where they were hashed out.

Edit: Having thought about this some more, I can see why, if the library isn’t going to allow an author to specify whether or not to report an action separately from whether or not to continue action processing, it makes sense to be conservative and print all non-default messages and halt action processing as soon as one is printed. E.g., if taking the apple causes a vengeful apple tree to materialize and demand the apple back or else, it would be unfair for the game to suppress this new info or to proceed with eating the fruit w/o giving the player a chance to react to it.

This is similar to “go to ” halting if anything significant happens on the way, the difference being that “go to” tends to be handled solely at the game/extension level where knowledge of what’s significant is available, while action reporting and processing is split between the game and library with the library not having knowledge of what’s significant and what’s merely flavor text. One could argue that the insignificant stuff should just be put in LibraryMessages and that everything reported by an after() or react_after() routine should be viewed as significant, but filling LibraryMessages full of object-specific messages would be fairly gross and defeat the principle of encapsulating an object’s behavior within the object itself.

(I’m starting to feel like Jon Favreau’s character in Swingers in the scene where he digs a hole for himself by leaving a sequence of answering machine messages, so I’ll stop here for now.)

I’ve continued working through DM4, and I’ve encountered an issue related to the exercises in §27 (Listing and grouping objects).

I have a group of Scrabble letters with a list_together routine (DM exercise 67) and a group of identical featureless cubes. The library’s item listing code produces a number of errors when these two groups of items coexist either in the same room or in the player’s inventory. If they are separated (one group in the room and the other group in the player’s inventory) or if only one group is implemented (comment out either of the chunks of code between dashed lines in the test program below), item listing behaves as expected.

Adding a regular item (e.g., Object → rock “rock” with name ‘rock’:wink: doesn’t appear to have an impact either way. When the letters and cubes are together, the issue manifests.

Constant Story "MULTIPLE GROUPS IN ITEM LISTINGS";
Constant Headline "^An Interactive Bug Reproduction^";

Include "Parser";
Include "VerbLib";

Object Start_Room "Somewhere"
  with description "You're not sure where you are.",
  has light;

! DM4 Exercise 67
Class Letter
  with name 'letter' 'scrabble' 'piece' 'letters//p' 'pieces//p',
!----------------------
       list_together [;
           if (inventory_stage == 1) {
               print "the letters ";
               c_style = c_style | (ENGLISH_BIT + NOARTICLE_BIT);
               c_style = c_style & ~(NEWLINE_BIT + INDENT_BIT);
           } else {
               print " from a Scrabble set";
           }
       ],
!----------------------
       short_name [;
           if (listing_together ofclass Letter) rfalse;
           print "letter ", (object) self, " from a Scrabble set";
           rtrue;
       ],
       article "the";

Letter -> "X" with name 'x//';
Letter -> "Y" with name 'y//';
Letter -> "Z" with name 'z//';

! Created to test Exercise 66.
Class Cube
  with name 'cube' 'cubes//p' 'featureless' 'white',
       short_name "featureless white cube",
       plural "featureless white cubes"; 

!----------------------
Cube ->;
Cube ->;
Cube ->;
Cube ->;
!----------------------

[ Initialise;
  location = Start_Room;
];

Include "Grammar";

Edit: When the test program is compiled without strict mode (-~S), we get the following more readable summary of errors:

Another trivial issue:

The output of the PLACES command has an extra newline after it. Using advent.z5 in the demos directory as an example:

I see that in the beta library (and in lib 6/12 in the archive), in LanguageLM() in english.h, we have:

  Places: switch (n) {
        1:  print "You have visited: ";
        2:  ".^";
    }

while in lib 6/11 in the archive, we have:

  Places: switch (n) {
        1:  print "You have visited: ";
        2:  print ".^";
    }

I see minor differences in the 6/12 version of Places1Sub() in verblibm.h:

return L__M(##Places, 2)

when we reach the end of the list vs. the 6/11 version:

{ L__M(##Places, 2); return; }

but nothing that would obviously produce different numbers of newlines beyond what’s in the L__M. So, I’m not sure what happened there between 6/11 and 6/12.

Whether or not you get the default response of “You eat the apple. Not bad.” depends upon the value returned from the After rule that catches “Take”. Indeed it allows for your vengeful tree example.

I think this is the result of some cleanups I did regarding excess newlines here and there and made things worse in a few places.

This one is definitely a bug. I’ve filed it at inform7.com/mantis/view.php?id=1854

(>TAKE SHOVEL)

I wasn’t confused about what happens so much as conflicted about what should happen. The after() stage of the library’s action processing model interacts with the implicit action aspect of the library in unfortunate ways, I think.

Without implicit actions, after() returning true is pretty straightforward. As with any other stage of action processing, a return value of true is telling the library “no need to continue processing this action. It’s handled.” This could be merely because the after() routine has printed a custom msg reporting the action and thus doesn’t need the library to also report the action, or it could be because something substantive has happened in the game world as a consequence of the action having been completed (such as in the vengeful tree example) and action processing should be stopped so that the player has a chance to respond to it. During the after() stage, “reporting an action” and “continuing action processing” are synonymous, since the library will have done its manipulation of the model world during an earlier stage. So, these two possible interpretations of after()'s return value collapse into one and we don’t care about the distinction.

However, add implicit actions to the mix, and now they are no longer synonymous. In the “eat apple” example, the command generates both an implicit ##Take action and an ##Eat action. If we’re in the apple’s after() routine handling the implicit ##Take, returning true won’t just cause the library not to report the current action (which it presumably wouldn’t have reported anyway since the action is implicit), it will also stop action processing for the subsequent ##Eat action that’s queued up. The library, though, is just stopping action processing because after() returned true. It doesn’t recognize the distinction between the two interpretations of “return true” that now exists because multiple actions are in progress.

We could resolve some of these issues by allowing for better communication between after() routines and the library. In the game->library direction, we could add an extra possible return value from after() so that we have: 0 - continue everything, 1 - stop everything, 2 - stop the current action, but continue with any subsequent actions. In the library->game direction, the library could set an action_is_implicit flag that an after() routine could consult to conditionally print or suppress action reports as needed. This would allow something like:

Another option that doesn’t require library changes is for an author to let LibraryMessages handle custom action reports while after() only handles events that follow on from completed actions. For example, LibraryMessages could test for (noun == apple) and replace the “Taken” msg with “You pick up the apple eagerly”, but following this approach would crud up a game’s LibraryMessages with a bunch of object-specific conditionals.

I think I’ve fixed this. The problem stemmed from improper usage of return value from ZRegion(). In the old inform-2006 repository, there was an effort to get rid of calls to ZRegion(), replacing them with metaclass(). Two calls were left in. One was used properly, but the other treated the return value as it if was from metaclass(). I have changed both calls to ZRegion() to their modern equivalents.

Awesome.

While you’re paying attention to the thread, I noticed another small issue in DropSub in verblibm.h:

    if (noun notin actor && ~~ImplicitTake(noun)) return L__M(##Drop, 2, noun);

Looking at ImplicitTake, it returns true on failure and false on success, so the test above ought to be ImplictTake(noun) rather than ~~ImplicitTake(noun), as it is in all of the other calls in verblibm.h.

I think that this issue has gone undetected in the past because the grammar for Drop uses the multiheld and multiexcept tokens which cause the parser to generate its own ImplicitTake prior to DropSub ever being called. I discovered the issue after having extended the grammar for Drop and having adapted DropSub in one of my own programs to handle a special case (of liquid in a container).