[I6] Weird bugs when using no_implicit_actions

I don’t understand why this works, but it does. I found the piece of code in parser.h that is doing the tests for before_implicit and no_implicit_actions prior to doing the implicit take. I changed my water and rocks objects in the sample code so that they can’t be taken under normal circumstances, expecting the implicit take to fail, but it didn’t fail. Go figure.

Unfortunately, this stuff is not documented anywhere (as far as I know), apart from in the release notes. I think the lesson to take away from this is that if you are using the global no_implicit_actions = true and you want to bypass this in specific situations, you can’t just divert one action to another, but must use before_implicit to allow the implicit action then do the diversion.

Damn. Just when I thought I had a hacky solution that worked, I tried applying it to a real game and it no longer works. I’m back where I started.

There must surely be a library maintainer out there who knows the rationale behind all this implicit stuff and how to get it working properly.

All I want to do is divert PUT WATER IN BUCKET to FILL BUCKET WITH WATER because the water cannot be held. Is that too much to ask?

Include "parser";
Include "verblib";

[ Initialise;
  no_implicit_actions = true;
  location = stream;
];

Object stream "Stream"
with
  description "You are standing by a steam.",
has light;

Object water "water" stream
with
  name 'water',
  article "some",
  before_implicit [;
    Take: if (action_to_be == ##Insert) return 1;
    return 3;
  ],
has;

Object bucket "bucket" stream
with
  name 'bucket',
  description "It's a metal bucket.",
has container open;

Include "grammar";

Extend 'fill' first
  * noun 'with' noun -> Insert reverse;
>fill bucket with water
You put the water into the bucket.

>fill bucket with water
The water is already here.

>put water in bucket   
You put the water into the bucket.

>put water in bucket
You put the water into the bucket.

There’s still a few things to worry about!

Thanks for trying to help, but the problem is a little deeper than I implied in my simple example. It’s actually the age old problem of global water vs local water. Let’s say I have a stream. The stream contains global water which is scenery. I can’t take the global water, as it trickles through my fingers. I need to put it in a bucket. The water in the bucket is the local water. I can FILL BUCKET WITH WATER, GET WATER WITH BUCKET and so on, no problem. (They basically make sure that the bucket is empty and move the local water to the bucket.) The only problem is that I think players are extremely likely to try PUT WATER IN BUCKET. This is an Insert action, but the library won’t let me divert an Insert action to a Fill action. The before_implicit doesn’t help, because that will implicitly get the global water, not the local water. As I write this, I’m wondering whether I should allow the implicit take of the global water, then swap the global water for the local water in the Fill routine. I don’t know whether that will work, because the global water is scenery, the local water isn’t.

All this stuff used to work in the old days prior to the introduction of implicit actions in version 6.12.

And no one has answered question 1 regarding the different error responses for the rocks and the water. None of this makes sense.

I have reverted to the grammar changes for ‘put’, ‘insert’ and related verbs. Now everything works as intended. I still can’t explain why the ‘noun’ token works, but the ‘multiexcept’ token doesn’t.

Multiexcept is a tricky beast. Does the Library still need my attention on this?

I think so. I’ve identified three issues related to no_implicit_actions:

  1. The noun token works where the multiexcept token doesn’t work. Multiexcept should effectively build a list of nouns and treat each one in turn. It should not abort prematurely in situations where the noun token does not abort.
  2. If an object provides a before handler for Insert, it should be run. The library should not abort prematurely before the before handler has a chance to run.
  3. If the library ignores the requirements of 1 and 2 above, it should not provide two different error responses for different objects for no apparent reason.

I’ve tried to make sense of the library myself (specifically parser.h), but the really long functions, spaghetti-like code (use of jumps), untidy formatting and extensive use of obscure global variables makes it extremely difficult to work out what’s going on. As you’re more familiar with the source code than I am, I’m sure you’ll at least have a fighting chance of identifying (and fixing?) the problems. Thanks if you can.

I filed a new issue for this at https://gitlab.com/DavidGriffith/inform6lib/-/issues/92

I’m not sure what the problem is with this. If you add

        before [;
        Fill:
                move second to self;
                "You fill the bucket with ", (the)second, ".";
        ],

to the bucket, then things seem to work okay. Can you give me some examples of what’s expected and what actually happens when the above before property is used?

You’re right. I haven’t used Inform 6 in a while and I’m a little rusty.
What confused me with “>put water in the bucket” action the second time, was the lack of the message: “(first get the water out of the bucket)”. But this is the normal before_implicit operation with 1 as return parameter (1 to try the TAKE without sending the message first).
But this wasn’t, I think, Garry’s original problem; check with him.

I may have been a little hasty in agreeing with you.
The addition of this code does not seem necessary:

        before [;
        Fill:
                move second to self;
                "You fill the bucket with ", (the)second, ".";
        ],

What’s a bit weird is that Fill and Put, which are both directed to Insert, don’t behave the same way.

It’s probably best to read the original query. There’s nothing wrong with Fill. This behaves as it should. The problem is when you try to put an object in a container when you are not holding the object. This should run the Insert action, but it never gets there. Instead, you get one of two really weird (and inappropriate) responses.

Copy, paste and compile the original code and follow the instructions I gave. It’s a standalone program and clearly illustrates the problems raised.

From grammar.h:

Verb 'put'
    * multiexcept 'in'/'inside'/'into' noun     -> Insert
    * multiexcept 'on'/'onto' noun              -> PutOn
    * 'on' held                                 -> Wear
    * 'down' multiheld                          -> Drop
    * multiheld 'down'                          -> Drop;

Rather than noun 'with' noun, If I extend the FILL with noun 'with' multiexcept, then FILL BUCKET WITH WATER appears to behave the same as `PUT WATER IN BUCKET.

Extend 'fill' first
  * noun 'with' multiexcept -> Insert reverse

Given this, I’ll mark it as complete.

But FILL wasn’t broken. It was PUT that was broken. If you change FILL to behave the same as PUT, then they’ll both be broken.

The PUT stuff in grammar.h is wrong?

No, it’s not the grammar, it’s the multiexcept token. If you use this token, the examples given in the original question never get to the before routine, so you can’t handle exceptions to the general case. The responses don’t make sense and are somewhat random for reasons I can’t fathom. Run the standalone program in the original question and you’ll see what I mean. The only workaround I could find was to replace the multiexcept token with noun and everything works fine.

My I6 is way too rusty, but I suspect that your issue with multiexcept and scenery objects is related to some trouble I had recently in I7 with the [things] grammar token completely ignoring scenery objects if it could find any matching non-scenery objects.

Does it work as expected if your water is not scenery or backdrop?

The workaround I ended up doing (again, I7, sorry, but you should be able to adapt it) was to make the object fixed in place instead of scenery and then use another rule to hide it from the location description instead. (This was the thread discussing it, if you’re curious.)

This is a bit off-topic, but the issue arose when the token could find exactly one matching non-scenery object; if it could find two then it didn’t arise. See this post.

(I also kind of doubt that this is the same issue, because the I7 issue seemed to have to do with some things in the I7 parser like the “deciding whether all includes” activity that I don’t think are in the I6 parser, but I really don’t know anything about I6 and can’t be definitive there.)

Thanks for the suggestion, but I’m pretty sure these are different issues. For me, reading Inform 7 is like reading a foreign language. I just don’t get it.

I don’t think my issue is related to scenery, as it occurs with scenery objects and non-scenery objects as shown in the example. It occurs because I’m using no_implicit_actions. I think everything works fine when not using that. I can’t use implicit actions because it causes various issues elsewhere and if I do use it, it tries to get the water first, the water trickles through your fingers (not shown in the example), so you can’t put it in the bucket. What I want is a transfer action. If I say PUT WATER IN BUCKET (a very natural thing to try), I should be able to run a before routine that allows me to do the transfer, but it never gets to the before routine. The library thinks it knows better and spits the dummy with nonsensical error messages.

It is in the I6 parser; it’s the ChooseObjects entry point (phase 2). But Warrigal looks correct in saying that that’s unrelated.