spurious text in examine item output (adv3Lite)

I have a dresser that contains three drawers. When I examine the drawers as a set (x drawers), I see some unexpected text (You can’t see the drawer) for the middle drawer:

The spurious text is the cannot see obj BMsg text, which is the library response for a not visible precondition. But nowhere in the game code is the drawer’s visibility unset.

So, in an attempt to track down what’s happening, I set a breakpoint in dobjFor(Examine) { check() }, and I when I step through and let the code continue, I get some more spurious text—the description of another object in the game—a driver’s license—which is irrelevant to the dresser drawers…

In fact, this driver’s license text shows up for any of the three drawers when a breakpoint is set in that drawer’s dobjFor(Examine { check() }.

If I examine just the middle drawer with the breakpoint in place, I get the driver’s license text, but I don’t get the can’t see it BMsg text…

And if I remove the breakpoint and examine just the one drawer, everything works fine…

Compounding my mystification is the fact that when I isolate the dresser in a test-bed environment where nothing exists other than the dresser and its drawers, everything works find, with no BMsg text.

Any suggestions on how I can further track this down?

Jerry

This sounds very weird. The fact that you’re getting different results with and without breakpoints set suggests to me that the problem (or at least part of the problem) has more to do with the TADS 3 compiler or debugger than the adv3Lite library; I recall a similar phenomenon a couple of years back when I was getting different behaviour with and without breakpoints, which made it pretty impossible to track down a bug I was trying to fix. In email correspondence with Mike Roberts it turns out it was something to do with the spelling corrector, and in particular the fact that it was subject to a real-time limit that was affected by the time taken in the debugger when a breakpoint was hit.

I don’t know if what you’re seeing could be at all related, but just in case it is you could try setting Parser.autoSpell to nil to see if that makes a difference.

Another point that occurs to me is that the BMsg text you refer to should print the theName of the object it’s talking about. So when it says “You can’t see the drawer” it appears to be talking about an object called just “drawer”, as opposed to the objects called “top drawer”, “middle drawer” and “bottom drawer”. Is there another object in your game that’s just called “drawer”? If so this might explain why you’re not seeing the problem in your testbed case, where only the chest and the three specifically-named drawers exist, but not this other drawer object.

Another question I have is what code you have in dobjFor(Examine) { check() } to set a breakpoint in, since I don’t think the library defines anything there. A more useful place to set a breakpoint might be in Action.verify() or, to narrow it down further, objVisible.verifyPreCondition(obj), since this is where the “You can’t see the drawer” message seems likely to come from, and you could at least inspect the value of obj to determine precisely what object it is that can’t be seen.

Aha! That’s it!

The dresser with the top, middle and bottom drawers is in a SenseRegion that includes the adjacent living room, in which there is a desk with a drawer—a Decoration with the vocab of ‘drawer;desk’. Changing that to ‘desk drawer’ changes the can’t see text to You can’t see the desk drawer.

Looks like I need to do some experimenting to find a way to exclude the desk drawer from the Examine command while keeping the rooms bound in the region.

As for the breakpoint, it’s my own dobjFor(Examine) code. The dresser drawers are closed and locked. If the Examine command comes before they’ve been unlocked and opened, I don’t want the contents revealed, so I put some alternate text in the check()…

    dobjFor(Examine)
    {
        check()
        {
            if(!isOpen)
            {
                "The face of the drawer is plain, unadorned except for a single
                brushed metal pull in the center. <.p>";
            }
        }
    }

I put the breakpoint on the if() statement.

Jerry

The quick and dirty way is to give it a plural that won’t be matched by “drawers”, e,g,

Decoration 'drawer{-zz}; desk'
;

That said, I’m still a bit puzzled by the message saying you can’t see it.

EDIT: A quick test shows how this is likely to come about: would I be right in thinking that you’ve defined canSeeAcross = nil on the SenseRegion that connects with the adjacent room? That would explain why the desk drawer is in scope but can’t be seen. I also need to think about whether this is the best behaviour here; if you can’t see it, then maybe EXAMINE shouldn’t report on it at all (even though in principle the desk drawer should be in scope for other actions that don’t require line of sight, such as SMELL and LISTEN].

And we still haven’t tracked down where the stuff about the driver’s license was coming from!

This hardly seems an advisable use of check, and I can’t even see why it’s necessary: if a container is closed when you examine it, it won’t report on its contents. Moreover, outputting text in check() is a way of signalling that an action has failed, but the EXAMINE action doesn’t fail in this case. A better way to handle it, if you want a different description of the drawer when it’s closed, would be to write its desc property accordingly:

++ Component, OpenableContainer 'top drawer'
    "<<unless isOpen>>The face of the drawer is plain, unadorned except for a
    single brushed metal pull in the center. <<end>>"
;

I’ve taken a further look at the DRAWERS issue and made a few tweaks to the library that should help alleviate it in future. These have now been uploaded to GitHub. These are all changes to the way the parser selects objects in remote locations. First, objects in remote locations are only put into scope if the player character knows about them (if there’s line of sight from the player to the remote location, everything visible in the remote location should immediately become known, so this is really only relevant to SenseRegions that don’t pass sight). Second, in the case of a plural match like DRAWERS that can refer to both local and remote objects, the remote objects are exluded if the action requires touching them and there are local objects available, or if the action requires seeing them and they aren’t visible and there are local ones available. This should prevent commands like EXAMINE DRAWERS or OPEN DRAWERS from trying to act on objects the player probably didn’t intend.

Can’t do that; the desk drawer object is a one-stop-shopping item. The desk is described as having a center drawer and drawers down both sides. The drawer object is a Decoration that reacts to any attempt to do anything with any or all of these desk drawers, so “examine drawers” while in the living room is a valid command that should display the drawer object’s notImportantMsg.

Yes, you are correct.

And not likely to under current circumstances.

For whatever unknown reason—whim of the IF gods? something I tried (if so, now forgotten) while fiddling around looking for a fix to the real problem at hand? don’t know—that text no longer appears when I set a break point.

I thought somewhat similar thoughts when I wrote it. I was expecting “The drawer is closed” but I got the drawer’s desc text instead. I understand, that’s working correctly, but it isn’t what I want or need so I started looking for a way to get the results I need, which is what led me to putting the text in check(). (I get that you don’t see the need for putting it in check()—and the fact that you wrote the library adds considerable weight to your opinion—but why is it not advisable? Other than not being proper form, what’s the downside?)

But now, well, hmmm, your example is different than mine. You’ve defined it as Component, OpenableContainer.

I defined each drawer as type DresserDrawer, which I subclassed from Container, for which I set isOpenable = true and isOpen = nil. Does using OpenableContainer do anything more for me than make the container openable? Aren’t the two approaches functionally equivalent?

As for the description of contents, I need the it to be part of the desc text for each drawer, such as…

bottomDrawer: DresserDrawer 'bottom drawer' "The drawer contains more socks than you've ever seen in one place outside of a department store. <.p>"

You can take as many socks out of the drawer as you want, but there is in fact only one pair of socks.

The socks object gets regenerated in code each time you take a pair out of the drawer (you can only have one pair at a time, but you can go through the process of take-dispose-take-dispose-take-dispose indefinitely).

Maybe you’re right, a conditional description for each of the drawers is the way to go, but I have to tell you, the solution I currently have in place—a Doer :slight_smile:—is working pretty well…

[code]Doer ‘examine Thing’
where = nextRoom
execAction(curCmd)
{
if(!gDobj.isOpen && gDobj.ofKind(DresserDrawer))
{
switch(gDobj.name)
{
case ‘top drawer’:
“The face of the <<gDobj.name>> is plain, unadorned except for a
single brushed metal pull in the center. <.p>”;
break;
case ‘middle drawer’:
“A simple pull protrudes from the center of the otherwise plain
middle drawer face.<.p>”;
break;
case ‘bottom drawer’:
“As with the top and middle drawers, the bottom drawer is a
simple smooth face unbroken by adornment other than a simple
brushed-metal pull. <.p>”;
break;
}
}
else if(gDobj != livingRoomDeskDrawers)
inherited(curCmd);

}

;[/code]

One thing I like about this approach is the grouping of drawer descriptions in one easy-to-edit place, rather than having to scroll through each drawer object in the code.

Jerry

The “quick and dirty” way has been overtaken by events. In my subsequent post I said I’d uploaded another fix to GitHub, so if and when you get that it should hopefully solve your problem.

Well, it’s your game, and I guess you can always take the attitude that what works, works. But if you use check() effectively to display an alternative description, you’re signalling to the library that the EXAMINE action failed when it in fact succeeded. None of the afterAction notifications will be sent, and various bits of housekeeping, such as noting that the drawer has been examined, won’t be carried out. Perhaps none of that matters in your game. OTOH if you come along a month later and write a bit of code that relies on the EXAMINE action working normally, for example a hint system that relies on being able to check whether the drawer has been examined - you could be left scratching your head trying to figure out why things don’t work as you expect, since you’ll probably have forgotten that the EXAMINE action that appears to be working successfully is in fact counted as a failure by the library. Even if this particular case doesn’t bite you, another one down the road probably will, so it’s a habit that’s best to avoid.

Okay, got the new library from GitHub and yes, it does solve the problem. Thanks.

Jerry