Intercept raw user input

In Inform 7 I’m able to take a look at all or part of user input with ‘the topic understood’, but Inform 6 seems to be much more rigid with the action, noun, second table detailed in the DM under conversation – is there a way, ideally within a life rule, to intercept all of a user’s input? I’m specifically wondering about a situation like:

Object Priest...
life [; 
                     Answer: ... ! todo: parse entire input between 'say' command and 'to' qualifier to find keywords/phrases like 'sacred text' and 'learning'
     ];
...and then user inputs:
>say I am interested in learning about the sacred text to priest                   

where more than just the noun ‘I’ and second ‘priest’ is needed to formulate a coherent response.

It sounds like you want to look at consult_from and consult_words, described on that DM page. They describe a subset of the user’s input as measured in words (start and count). This is the same information encoded in I7’s topic understood, except that I7 has facilities to auto-convert that information into a text, whereas in I6 you have to use NextWord() to dig through the word list.

See https://www.inform-fiction.org/manual/html/s16.html for more info.

1 Like

I discovered that the internal ‘buffer’ variable of the library will hold the raw user input see Roger Firth deep dive here, but it’s a pain to step through manually. consult_from/to and NextWord() are much more (relatively) elegant!

I’m having some trouble with NextWord() – I keep seeing something like

Ask: 
 for(index = 0: index < consult_words: index++) {
        currentWord = NextWord();
        print "^the ", index, "th word in the any clause is [", currentWord,"].";
        if(currentWord == 'test') {
             print "^Found the test token!";
        }
   }

with input string “ask MyCharacter about something test stuff” gives output:

the 0th word in the any clause is [0]
the 1th word in the any clause is [0]
the 2th word in the any clause is [0]

and currentWord never matches ‘test’. Do I need to convert the return value from NextWord() in some way?

Try something like this.

[ PrintWord wordn   at len;
	at = parse->(wordn * 4 + 1);
	len = parse->(wordn * 4) + at;
	for ( : at < len: at++)
		print (char) buffer->at;
];

Object Bob "Bob" room
with
	name 'bob',
	Life [ w cw flag;
		Ask:
			wn = consult_from;
			cw = consult_words;
			while (cw) {
				w = NextWord();
				switch (w) {
					'worda', 'wordb', 'wordc':
						flag = 1;
						print "~I know everything about ", (PrintWord) (wn-1), ".~^";
					'wordd', 'worde':
						flag = 1;
						print "~I know everything about ", (PrintWord) (wn-1), ".~^";
				}
				cw--;
			}
			if (~~flag) "~I don't know anything about ", (PrintWord) (wn-1), ".~";
			rtrue;
	],
has animate proper;

Nextword()'s starting word is in wn. So you have to load wn with the right value: here, it is consult_from (the position of the first word in the topic tag).
consult_words contains the number of words that the player has entered in topic tag.

*** updated ***
*** updated ***

1 Like

It’s better style to copy consult_words to a local and decrement that. Just in case some other rule wants to look at consult_from/consult_words in the same turn.

1 Like

That’s the whole difference between professionals and amateurs; I updated the example.

additional query: I noticed that with the following code

wn = consult_from; 
consultWords = consult_words; 
while(consultWords) {
   consultToken = NextWord();
   consultWords--;
   print "Examining consult token [", consultToken,"]";
}

that I get output like

examining consult token [9877]

I’m guessing that’s the address of the string or something similar; how do I dereference it to get the actual string value for printing/storage?

Something like that?

[ PrintWord wordn   at len;
	at = parse->(wordn * 4 + 1);
	len = parse->(wordn * 4) + at;
	for ( : at < len : at++)
		print (char) buffer->at;
];

[ AdditionalQuery   w cw;
	wn = consult_from; 
	cw = consult_words; 
	while(cw) {
		w = NextWord();
		print "Examining consult token [", (PrintWord) (wn-1), "]^";
		cw--;
	}
];

I updated my first example.

Somewhat unintuitively, the I6 command to print a dictionary word is

print (address) wd;

…the difference between what I posted and aureas’s sample code is that (address) prints the canonical form of the dict word, which will be lowercase and perhaps truncated to nine characters. The PrintWord function quoted above will print the subset of the player’s input which matched that dict word.

I also did it this way for “~I don’t know anything about … ~”; the word may not be in the dictionary. It’s a topic tag, the input is free.
But in this case, it might be better to display the whole topic than just one word.