Okay, I called it a “bug”, but I’ll let you make your own judgment.
Let’s say you have a noodle that is straight up illogical as iobj for AttackWith. You have a gargoyle that is nonObvious as dobj for AttackWith. Yet, if you >kill gargoyle with limp noodle
the gargoyle will indeed be slain even if you’ve never laid eyes on the proper gargoyle-killing weapon. I’m pretty sure that’s not what Mike Roberts intended?
I was stumped about this for quite awhile, debug printing in various places of iobjFor/verify, doActionOnce, callVerifyProp, verifyAction, withVerifyResults etc. I finally determined through reflection of the VerifyResultLists in play that the illogical result was never at any point showing up in the result list if there was already a nonObvious one in there. The solution to the mystery is that VerifyResultList.addResult first uses the method identicalTo to determine whether it’s about to add a redundant result. But identicalTo only looks at the numerical ranking, and a nonObvious is purposely ranked the same as an illogical numerically! They only differ in the allowAction property, but this is not looked at, so once a nonObvious is in the list, all succeeding illogicals are discarded!
I propose the following changes, after enforcing which you will be told that your limp noodle isn’t suitable for attacking anything. It’s hard for me to foresee how these changes could cause undesirable behavior, but if anyone has input, by all means speak out.
I’ve never used TADS, but my feeling is the keywords “nonObvious” and “illogical” are meant to filter out possibilities when an explicit object is not given by the player (e.g. for disambiguation prompts).
But in your case, explicit objects were given in the command.
I think T3 semantics are a little confusing here, because illogical is “supposed” to be used to block actions in addition to adjusting their priority in noun resolution, while nonObvious appears to be “purely” for excluding objects from noun resolution except when explicitly used.
I use scare quotes because the stated design intent isn’t identical to the actual mechanics used by the parser. There’s also dangerous, which is a slightly more strident form of nonObvious, with the difference ostensibly being that nonObvious is for objects being used in actions where their capacity for such use is supposed to be hidden, while dangerous is for cases where the ability of the object to handle the action is apparent but theoretically manifestly undesirable. And therefore, again, something that the parser won’t consider unless the command explicitly says to do so.
In this case dangerous “works”—a dangerous direct object being acted on by an illogical indirect object will be rejected with the iobj’s illogical failure message.
I’m not going to wade into the talmudic deliberations over whether attacking a gargoyle should be considered prima facie more dangerous than non-obvious, but I suspect it’s a) an easier fix, and b) probably indicative of a bug (or at least very sneaky misfeature) in T3 action verification.
there’s a minor issue, but is really for master and grandmaster adventurers, the example in the TADS documentation present as example attempting to drink a poison, but let turn it into a matter of taste, literally.
That is, let’s posit that tasting the poison reveal a meaty taste, perfect for a carnivore guard-type block, optionally at the price of fusing a little daemon which keep the PC dizzy for few turns, so tasting for the first time should pass the verify stage, but next time is an illogical thing to do. This seems to me one of the rationale of the illogical/dangerous etc. differentiations in the verify stage.
dangerous is only downgraded to a logicalRank of 90, which is well above the illogical (and nonObvious) 30, thus there’s no confusion to the parser about which is worse.
The verify routine (of which the nonObvious results and illogical results are a part) serves a twofold purpose: it picks the most “logical” game object as a target when the player’s input can match the vocabulary of more than one thing, but it also acts as a screening routine to see if the action (supposing an object can be determined) should pass on to the actual “action” phase, or fail outright. Only if the parser cannot find any criteria to consider one object more logical than others (amongst those whose vocabulary match) will it go into a disambiguation routine.
Because the parser’s job in verify is to relieve, if possible, the player from having to do any more typing or specifying, one of its primary purposes is to pick “default” objects that can reasonably be supposed to be the target of the command (if that information was ambiguous or left out).
The entire purpose of using a nonObvious verify result is simply to notify the parser: “Don’t choose this object by default or logical preference (for this verb), because it’s the solution to a puzzle! Make the player explicitly mention that they’re using this object, with no ambiguity. Thus, rather than pick this object, give them a disambiguation prompt.”
There is no rationale (that I can see) for which the use of nonObvious should disable the rest of the normal verify mechanics if an iobj is involved in the verb. The use of illogical (whether in iobj or dobj) is intended to fail the action, no questions asked, it only becomes a question of which involved object is the most illogical so that the parser can use the smartest-sounding answer.
So if the dobj is nonObvious, all it’s saying is “Don’t pick me as a direct object if there’s ambiguity in the direct object”, but we can (and should, I think) imply that it is also saying “But still make sure the player is using a proper iobj when they verb me or else fail the action on those grounds.”