[I7] Some problem with conversation

This is a problem I’ve seen before, but I’ve never isolated it before now. And it’s become a problem.

DNA is a kind of thing. Some skin is a kind of thing. Some DNA and some skin is part of every person.

Felix is a man.
Dr Wilbur is a man.
The Lab is a room. Wilbur is here. The player is Felix.

After asking Wilbur about "[DNA]", say "'Your genetic code has somehow been altered.'"
After asking Wilbur about "[skin]", say "'Yes, that was where I scraped off some DNA for my sample.'"

Test me with "ask wilbur about wilbur's DNA/ask wilbur about wilbur's skin".

For some reason, whenever I ask about something created as part of an assembly, only the first After rule (or Instead rule) that applies to said parts is matched. Am I doing something terrifying and/or wrong, is this a bug, or have I just utterly lost my marbles? Anyone know?

The After and Instead rulebooks have default outcomes “rule succeeds” and “rule fails,” respectively. Most other common rulebooks use the default “make no decision.” The difference is exactly as you describe: when a rule in After or Instead applies, and it doesn’t specifically make no decision, processing of the rulebook stops at that point (there is no meaningful difference between “rule fails” and “rule succeeds” in these situations).

I don’t think you’re doing anything wrong.

It seems that even after the parser has identified Wilbur’s skin as the relevant object, it still tries to apply the first ‘After asking Wilbur about [TOPIC]’ rule to that object.

There’s apparently an I6 routine called ConsultNounFilterToken that tests if the rule (or possibly some other routine) is applicable on the skin and decides it isn’t. That’s why the block asking rule is applied instead. And if you force a positive answer from ConsultNounFilterToken, asking wilbur about Wilbur’s skin will trigger the ‘after asking Wilbur about “[DNA]”’ rule! (Because it’s the first ‘After asking wilbur about [TOPIC]’ rule defined in your source, I bet.)

I have no idea why this is so, however, or what to do about it. Perhaps the Original Parser extension is just hackable enough to help …

I think it might be a bug.

If you crank up the debug output using “trace 6” and enter “ask wilbur about wilbur’s skin”, it looks like the parser is rejecting the match it makes on “wilbur’s skin” even though it initially seems to identify it as a higher-quality match:

If you look at the generated I6 file, you can see that it is creating separate Consult_Grammar_N functions using separate Noun_Filter_N functions for each of the after rules created. Following are some excerpts from auto.inf when I compiled your sample code:

[code]! ----------------------------------------------------------------------------------------------------
! Rules in rulebook: After (B24_after)
! ----------------------------------------------------------------------------------------------------
! Rule 1/2 ! After asking Wilbur about ~[DNA]~:
! === which is equally specific with ===
! Rule 2/2 ! After asking Wilbur about ~[skin]~:
! ----------------------------------------------------------------------------------------------------
! No specific request
! After asking Wilbur about ~[DNA]~:
[ R_740 ;
if ((action ==##Ask) && (actor==player) && ((noun == I95_dr_wilbur) && (true)) && (Consult_Grammar_100(consult_from, consult_words)~=GPR_FAIL)) { ! Runs only when pattern matches
self = noun;
if (debug_rules) DB_Rule(R_740, 740);
! phrase 1
! [1: say ~‘Your genetic code has somehow been altered.’~]
say__p=1;ParaContent(); print (PrintText) SC_12; new_line; .L_Say3; .L_SayX3;
RulebookSucceeds(); rtrue;
} ! Runs only when pattern matches
else if (debug_rules > 1) DB_Rule(R_740, 740, true);
rfalse;
];
! No specific request
! After asking Wilbur about ~[skin]~:
[ R_741 ;
if ((action ==##Ask) && (actor==player) && ((noun == I95_dr_wilbur) && (true)) && (Consult_Grammar_101(consult_from, consult_words)~=GPR_FAIL)) { ! Runs only when pattern matches
self = noun;
if (debug_rules) DB_Rule(R_741, 741);
! phrase 1
! [1: say ~‘Yes, that was where I scraped off some DNA for my sample.’~]
say__p=1;ParaContent(); print (PrintText) SC_13; new_line; .L_Say4; .L_SayX4;
RulebookSucceeds(); rtrue;
} ! Runs only when pattern matches
else if (debug_rules > 1) DB_Rule(R_741, 741, true);
rfalse;
];
! ----------------------------------------------------------------------------------------------------

[ Consult_Grammar_100
range_from ! call parameter: word number of snippet start
range_words ! call parameter: snippet length
original_wn ! first word of text parsed
group_wn ! first word matched against A/B/C/… disjunction
w ! for use by individual grammar lines
rv ! for use by individual grammar lines
;
wn = range_from; original_wn = wn; rv = GPR_PREPOSITION;
w = ParseTokenStopped(ROUTINE_FILTER_TT, Noun_Filter_4);
if (w == GPR_FAIL) jump Fail_1; rv = w;
if ((range_words==0) || (wn-range_from==range_words)) return rv;
.Fail_1; rv = GPR_PREPOSITION; wn = original_wn;
return GPR_FAIL;
];

[ Consult_Grammar_101
range_from ! call parameter: word number of snippet start
range_words ! call parameter: snippet length
original_wn ! first word of text parsed
group_wn ! first word matched against A/B/C/… disjunction
w ! for use by individual grammar lines
rv ! for use by individual grammar lines
;
wn = range_from; original_wn = wn; rv = GPR_PREPOSITION;
w = ParseTokenStopped(ROUTINE_FILTER_TT, Noun_Filter_5);
if (w == GPR_FAIL) jump Fail_1; rv = w;
if ((range_words==0) || (wn-range_from==range_words)) return rv;
.Fail_1; rv = GPR_PREPOSITION; wn = original_wn;
return GPR_FAIL;
];
[ Noun_Filter_4 x;
x=noun;
return ((noun ofclass K16_dna));
];
[ Noun_Filter_5 x;
x=noun;
return ((noun ofclass K17_skin));
];
[/code]

So it looks like it wants to do what you’re asking it to, but when it’s evaluating rules, it seems to skip over whichever after rule is defined second. I’m not really sure why.

One thing you might not have intended: You’ll get the same response whether you ask about “felix’s dna” or “wilbur’s dna”.

Thanks. And yeah, I did intend to get the same results, because I want to match the topic of DNA in general. In this kind of conflict we get entire subjects that are no longer recognized as topics, and that’s annoying (not to mention fatal to my project).

EDIT: Reported it as a bug.

I added a bug comment. The problem is that matching the “[DNA]” topic corrupts the noun global variable, which screws up the rest of the action rulebook. It’s definitely a bug.

Lest we go too far down the wrong path, let me note that there’s no problem doing it the simple way:

After asking Wilbur about “DNA”: …
After asking Wilbur about “skin”: …

I’ve never liked the way topics are handled - which is why I prefer to use a conversation extension that deals with objects instead. But my Objects Matching Snippets extension is intended to serve as a middle ground, for cases like this:

where the comma prevents the command from being interpreted as a keyword.

I’m currently working on an acceleration for it, as it is quite slow.

Here’s a fix (and I added a note about it to the bug report):

Include (-

[ MakeMatch obj quality i;
#Ifdef DEBUG;
if (parser_trace >= 6) print "
Match with quality ",quality,"^";
#Endif; ! DEBUG
if (token_filter ~= 0 && ConsultNounFilterToken(obj) == 0) {
!print token_filter; print "^"; print (name)obj; print": "; print ConsultNounFilterToken(obj); print "^";
#Ifdef DEBUG;
if (parser_trace >= 6) print "
Match filtered out: token filter ", token_filter, "^";
#Endif; ! DEBUG
rtrue;
}
if (quality < match_length) rtrue;
if (quality > match_length) { match_length = quality; number_matched = 0; }
else {
if (number_matched >= MATCH_LIST_WORDS) rtrue;
for (i=0 : i<number_matched : i++)
if (match_list-->i == obj) rtrue;
}
match_list-->number_matched++ = obj;
#Ifdef DEBUG;
if (parser_trace >= 6) print "
Match added to list^";
#Endif; ! DEBUG
];

[ ConsultNounFilterToken obj n tf;
if (token_filter ofclass Routine) { 
n = noun;
noun = obj;
tf = indirect(token_filter);
noun = n;
return tf;
}
if (obj has (token_filter-1)) rtrue;
rfalse;
];

-) instead of "Match List" in "Parser.i6t".

Changes are made above to the ConsultNounFilterToken routine which in its original form looks like this:

[ ConsultNounFilterToken obj; if (token_filter ofclass Routine) { noun = obj; return indirect(token_filter); } if (obj has (token_filter-1)) rtrue; rfalse; ];