DTPM disambiguations don't run on scenery [Does The Player Mean]

Some peculiar disambiguation behaviour I’ve noticed. In this scenario, the player is permanently carrying around an object that is understood as map, but will occasionally run across some other maps out in the world. The rule I want is that x map always refers to a map other than the one you’re carrying, if there’s an ambiguity, which is easy enough. The weirdness ensues when I tried to print a message when preventing taking another map:

Limbo is a room.  "An ethereal space, empty save for a paper map mysteriously floating in midair."

The player carries Grandpa's Map.  The description is "Your grandfather's old map."
Instead of dropping Grandpa's Map, say "No, no, you'll get utterly lost without a map."

A paper map is scenery in Limbo.  The description is "An ancient tattered paper map."
Instead of taking the paper map, say "The map is too old, it would fall to pieces if you tried that."

Does the player mean examining or taking Grandpa's Map: it is unlikely.
Does the player mean examining or taking the paper map: it is likely.

Test me with "rules all / x map / take map".

In the rules output for x map the DTPM rules are run and it does examine the paper map instead of Grandpa’s map, as intended.

For take map, on the other hand, it doesn’t even look at them; it just decides to go with the carried map regardless.

The main trigger for this appears to be that the paper map is tagged as scenery (and undescribed does the same thing). Somehow both these things appear to make Inform decide that the player couldn’t possibly want to take it, to the point that it doesn’t even check the disambiguation rules. Oddly, whatever causes this, it doesn’t appear to affect examining, just taking.

Removing those tags makes it run the DTPM rules and then it correctly selects the paper map in both cases.

Is there any way to teach it the error of its ways without removing the scenery tag? (I do know a workaround, but that still requires removing the scenery tag and using another method to hide it from the contents list. But I’d prefer something tidier.)

I’m afraid not. The parser uses a cumulative internal scoring system. The DTPM rules are worth up to 4; the scenery flag is worth 10. So they can’t beat it.

(The undescribed flag is worth 100, in case you were wondering.)

But then why do examine and take behave differently?

(It’s especially silly because take should prefer items not held anyway.)

Oh actually, another piece of the puzzle. The problem (of not even trying to run the DTPM rules) appears to be related to the [things] token.

If I add the following, then this causes x map to break in the same manner as take map:

Understand nothing as examining.
Understand "x [things]" as examining.

Right, the library definitions are

Understand "examine [something]" as examining.
Understand "take [things]" as taking.

I have to set up NarraScope stuff so I can’t dig down into the exact differences right now…

Take does prefer items not held, but that occurs at a different level of the I6 parser code.

According to the standard rules:

Rule for deciding whether all includes scenery while taking or taking off or
	removing (this is the exclude scenery from take all rule): it does not.

And then there’s this:

Check an actor taking (this is the can't take scenery rule):
	if the noun is scenery:
		if the actor is the player:
			say "[regarding the noun][They're] hardly portable." (A);
		stop the action.

I think I’ve figured out why this is happening. The parser.i6t code contains this:

  if (context==MULTI_TOKEN && ultimate==ScopeCeiling(actor)
            && n~=actor && n hasnt concealed && n hasnt scenery) 
        {   good_ones++; last=n; }

which has the effect of adding one to the variable good_ones when there’s a multiple token like “[things]” for the taking action.

Then there’s this:

if (good_ones == 1) {
		if (indef_mode == 1 && indef_type & PLURAL_BIT ~= 0 &&
	        BeginActivity(DECIDING_WHETHER_ALL_INC_ACT, last);
            if ((ForActivity(DECIDING_WHETHER_ALL_INC_ACT, last)) &&
            	(RulebookFailed())) good_ones = 0;
	        EndActivity(DECIDING_WHETHER_ALL_INC_ACT, last);
			if (good_ones == 1) return last;
		} else {
			return last;

which–if good_ones has been set to 1–runs the “deciding whether all includes” activity. As AJ pointed out, this excludes the scenery map.

Now, I can’t work out the logic of what goes on in that second call, but I would guess that when all but one thing gets excluded from “all” the parser automatically chooses the only remaining thing, even if the noun entered was singular.

To confirm this, if you add The player carries a dummy map. then “take map” goes to the paper map, presumably because two things survive the “deciding whether all includes” activity, which means that Inform has to run the DTPM rules anyway, and then the paper map wins the DTPM rules.

tl;dr: When you have an action that takes a plural token, the parser runs the Deciding Whether All Includes rules no matter whether you typed a plural, and if only one thing is left it picks that regardless of DTPM. If more than one thing is left and you didn’t run a plural, it runs DTPM on everything that might qualify.

zarf–it doesn’t seem to me as though the DTPM rules are only worth up to 4. It’s a bit hard to track it through the parser, but it seemed like the DTPM rules wind up returning a value from 0 to 4 through ChooseObjects, and then ScoreMatchL has this line

its_score = its_score + SCORE__CHOOSEOBJ * ChooseObjects(obj, 2);

which multiplies the result of ChooseObjects by SCORE__CHOOSEOBJ which is 1000. So this would swamp SCORE__NOTSCENERY which is 10, if it applies. Looking at various traces, the DTPM rules do seem to be moving things by increments of 1000.

Interesting. I wonder why that didn’t show up in the rules all trace. (I do have a deciding whether all includes rule, although it’s for a different object, but I would have expected it to print a rejection if they were consulted at all.)

The “rules” testing command skips over some rules; I’m not sure whether it’s that it skips rules for activities or what, but you’ll never see it tell you about rules for deciding the scope of or DTPM rules or like that. “Rules all” doesn’t get those rules–I think the difference between “rules all” and “rules” is that, of the rules in question (action rules and every turn rules and some others), “rules all” gives you even the ones that don’t run because they fail the rule header check. Not sure though, I almost never use “rules all.”

About your “deciding whether all includes” rule, that’s probably not what’s messing things up–what’s messing things up is the one AJ Mako pointed out from the standard rules, that excludes scenery from all when taking. I wouldn’t expect it to print a rejection–the point of excluding something from a “take all” is to make sure that it’s not included in the multiple actions so it doesn’t print rejections. So if there are three non-scenery things and two scenery things in the location, and you “take all,” the rule whittles the multiple object list down to the three non-scenery things and has you take them one by one, but you don’t get a “That’s fixed in place” message for the scenery things.

Ooh, good catch. I was 100% wrong.

I wonder what bit of I6 parser weighting I was trying to remember? There was something in there that I never managed to override.

Oh I know that it wasn’t my other “all includes” rule at fault – the problem was still happening in a test story where it wasn’t even present, or I would have mentioned it – I was just surprised that it didn’t show up in the output if the rulebook was being consulted at all. Amusingly enough, that particular rule is intended to mitigate a related issue:

Rule for deciding whether all includes undescribed portable things while taking: it does.

(Where I wanted take all in a location with some undescribed things to still take them, which doesn’t happen by default.)

Interestingly I don’t see any I7 standard rules affecting undescribed objects for this – I think it’s something in the I6 layer (concealed) doing it. But this I7 rule does solve that issue for me (not directly related to the original issue in this thread though.)

Actually I have seen DTPM (and I think also “deciding whether all includes”, though I’m less certain about that) in the output of rules all, so at least in principle it’s possible for them to print something sometimes.

I don’t often use rules all, because it can be quite spammy, but it’s frequently handy to determine that Inform did at least consider running a rule that you’re expecting it to (rather than bombing out before it’s reached), meaning that your condition is probably wrong. (Usually the culprit there is where I’m using a generic name like “stone” to refer to an ambiguous object and it’s decided to check the wrong one.)

Although the stated reason for failure (wrong action) is a little misleading, as it also can mean that anything else in the when/while clause failed. That had me confused for a while.

1 Like