adveLite: nested hidden objects on working

In the bedroom is a dresser with a top drawer. In the drawer is a bunch of underwear. When I look in the dresser, I see the drawer. When I look in the drawer, I see the underwear…

In the code, the drawer is hidden in the dresser, and the underwear is hidden in the drawer. I can take the drawer, but not the underwear…

Here’s the code…

[code]#charset “us-ascii”

#include <tads.h>
#include “advlite.h”

versionInfo: GameID
IFID = ‘47ca87f1-2d0e-4b54-a776-2bc128e30927’
name = ‘TADS 3 Lite Test Bed’
byline = ‘by Jerry Ford’
htmlByline = ‘by
Jerry Ford

version = ‘1’
authorEmail = ‘Jerry Ford jerry.o.ford@gmail.com
desc = ‘Test bed for experimenting with TADS 3 Lite.’
htmlDesc = ‘Test bed for experimenting with TADS 3 Lite.’
;

gameMain: GameMainDef
initialPlayerChar = harry
usePastTense = true
;

// harry, main character
harry: Actor ‘Harry;;man self’ @harrysBedroom
“”
contType = Carrier
globalParamName = ‘harry’
isFixed = true
isHim = true
isInitState = true
ownsContents = true
person = 3
proper = true
;

harrysBedroom: Room
‘Bedroom’ ‘bedroom’
“In the bedroom was a plain brown dresser.”
;

  • bedRoomDresser: Fixture, Container ‘dresser’
    “A plain, brown dresser stood against the south wall, opposite the foot of the bed.”

    hiddenIn = [bedRoomDresserTopDrawer]

    dobjFor(Examine) asDobjFor(LookIn)
    ;
    bedRoomDresserTopDrawer: OpenableContainer ‘top drawer; dresser; drawer’
    “Top drawer.”

    bulk = 5001
    hiddenIn = [underwear]

    dobjFor(Open) asDobjFor(Examine)
    dobjFor(LookIn) asDobjFor(Examine)
    dobjFor(Examine)
    {
    action()
    {
    underwear.desc;
    }
    }
    ;
    underwear: Thing ‘underwear;jockey t tee under
    underpants;undershorts teeshirts pants’
    “A jumble of underwear—shorts and tee shirts—filled the drawer.”
    ;
    [/code]

Oh dear!

First off, this really isn’t what hiddenIn is meant to be used for. The drawer isn’t hidden in the dresser; anyone who looks at the dresser can presumably see its drawer in plain sight. Secondly, the dresser isn’t a container, and the drawer isn’t inside the dresser (at least, not as I imagine the layout). The drawer is part of the dresser. Third, we don’t need to use hiddenIn for the underwear since the underwear in any case starts out hidden from view by virtue of being in a close container. Fourth, the description of the underwear is only valid until the underwear is taken. Fifth, your description of the dresser should probably be its specialDesc.

I assume what you want is the player to be told there’s a dresser in the room. Examining the dresser should tell the player that it has a drawer, so we simply mention this in the description of the dresser. To make the drawer part of the dresser we can locate it ‘in’ the dresser with the + syntax, and just make it a Fixture as well as an OpenableContainer. Then we just put the underwear in the drawer. While we’re at it we should set remapIn on the dresser to point to its drawer, so that commands like OPEN DRESSER and LOOK IN DRESSER will be handled by the drawer.

The code to do all this is:

+ bedRoomDresser: Fixture 'dresser'
    "It had a single drawer. "
    
    specialDesc = "A plain, brown dresser stood against the south wall, 
    opposite the foot of the bed. "   
   
    remapIn = bedRoomDresserTopDrawer
;

++ bedRoomDresserTopDrawer: Fixture, OpenableContainer 
    'top drawer; dresser'
    "Top drawer. "   
    
    cannotTakeMsg = 'The drawer was part of the dresser. '
;

+++underwear: Thing 'some underwear;jockey t tee under;
        undershorts teeshirts pants underpants'
    "<<if !moved>>A jumble of underwear-shorts and tee shirts-filled the drawer.
    <<else>>It was just underwear. <<end>> "
;

Or you may prefer to mention the dresser in your room description (rather than in the dresser’s specialDesc, as here); that’s partly a matter of taste and partly a matter of how much attention you want to call to the dresser.

You may also want to make the dresser a Surface, if it’s the sort of thing you can put things on.

You seem to be greatly overcomplicating things for reasons I don’t quite understand! :slight_smile: The much simpler set-up above will provide a dresser and a drawer that should work the way most players would expect them to. (For example, it’s not a good idea to force the player to explicitly look in or examine the dresser before putting the drawer in scope, since this will only annoy players who know perfectly well that it’s there because they’ve played the scene before, and who therefore expect the drawer to be in plain sight).

Incidentally, for an example of a nested hiddenIn that works perfectly well, you can just try this:

  • bedRoomDresser: Surface, Fixture ‘dresser’
    "It had a single drawer. "

    specialDesc = "A plain, brown dresser stood against the south wall,
    opposite the foot of the bed. "

    remapIn = bedRoomDresserTopDrawer
    ;

++ box: Container ‘large red box’
hiddenIn = [smallBox]
;

smallBox: Container ‘small blue box’
hiddenIn = [pin]
;

pin: Thing ‘pin’
;

LOOK IN RED BOX reveals the small blue box; LOOK IN BLUE BOX, then reveals the pin.

Okay, thanks. I will experiment some more with your advice, which is greatly appreciated. I may very well be over-complicating things unnecessarily.

But what got me to where I was is this…

When the game opens, Harry is lying in bed. He can see nothing in the room except the ceiling because he’s lying in bed on his back. In order to see anything in the room, he must a) get out of bed and b) look around in the room. Until he has done both of those things, nothing in the room other than the ceiling (he’s lying on his back) should be visible.

So, I started out just trying to keep things from being listed in the room contents until sufficient conditions are met.

He can’t see his pants or shirt (which are in a pile on the chair) until he’s seen the chair, by a Look command after getting out of bed. He can’t see the pocket in the pants until he sees the pants, and can’t see the wallet until he sees the pocket (not too much of a burden on the player at this point, because he really doesn’t need the wallet, or even to lknow about the wallet, until later, when he finds an ATM machine; by then he will already have put the pants on).

But that got me into the situation where, before Harry looks around the room or sees the pants or the wallet—before he sees anything in the room—the command Look at wallet displayed the wallet’s contents. I didn’t want that. I wanted the response to be “what wallet?” or words that effect (which is part of what got me into custom messaging).

That’s what eventually led me, with your help, to the hiddenIn concept.

Actually, the drawer in the dresser just evolved as part of my attempt to pair the problem down to a manageable number of items for testing and, frankly, for asking for help :slight_smile: The original problem was that wallet, making it truly invisible until it’s time had come.

So, back to the drawing board with your comments at the forefront—both on how to do it and whether I’ve buried too much too deeply.

But I will say this, it’s been a great learning experience, forcing me to try out various things in a medium still new to me :slight_smile:

Another approach you might try experimenting with here is implementing the bedroom as two different rooms (while fooling the player I to thinking they’re the same room). The first room could contain nothing but Harry, the bed and the ceiling. You then make the first GET OUT OF BED action move Harry, bed and ceiling into an alternative version of the bedroom containing all the other objects. (Alternatively, you could have just the one room and move all the other objects into it when Harry gets off the bed). Or you could do this with a Scene that either starts or ends when Harry is not longer in the bed and moves things around accordingly. Either approach should be much easier than trying to hide things that are actually in scope.

As for the other points: if Harry can see the chair he can see anything on the chair, so there’s no point in trying to complicate that.

To deal with the pocket, just make the pocket part of the pants and mention it in the description of the pants, something like:


+pants: Wearable 'pants; navy blue; trousers; them'
   "They're navy blue, with a single pocket. "
;

++ Fixture, Container 'pocket'
       hiddenIn = [wallet]
;

This way the player has to examine the pants to learn of the existence of the pocket, and then has to explicitly LOOK IN or SEARCH the pants to find the wallet. Again this is reasonably realistic and the sort of interaction a typical IF player will expect. A player who’s already played the scene can look in the pocket without examining the pants first, but that’s not a problem; it’s what a second-time player would expect, and in any case Harry must know that his own pants have a pocket, so going out of your way to hide the pocket once the pants are in scope won’t improve the playability of your game.

If you make the wallet an OpenableContainer (which is surely a reasonable thing to do), its contents won’t be visible until the player OPENs or SEARCHes or LOOKs in the wallet, and you can set the contentsListedInLook property on the wallet to nil for good measure, so that the wallet doesn’t in any case list its contents as part of a room description; this again would seem reasonably realistic.

This is one way one might fit all those suggestions together in code (a quick test suggests it seems to work reasonably well):

#charset "us-ascii"

#include <tads.h>
#include "advlite.h"

versionInfo: GameID
    IFID = '47ca87f1-2d0e-4b54-a776-2bc128e30927'
    name = 'TADS 3 Lite Test Bed'
    byline = 'by Jerry Ford'
    htmlByline = 'by <a href="mailto:jerry.o.ford@gmail.com">
                  Jerry Ford</a>'
    version = '1'
    authorEmail = 'Jerry Ford <jerry.o.ford@gmail.com>'
    desc = 'Test bed for experimenting with TADS 3 Lite.'
    htmlDesc = 'Test bed for experimenting with TADS 3 Lite.'
;

gameMain: GameMainDef
    initialPlayerChar = harry
    usePastTense = true
;

// harry, main character
harry: Actor 'Harry;;man self' @bed
    ""
    contType = Carrier
    globalParamName = 'harry'
    isFixed = true   
    isHim = true
    
    ownsContents = true
    person = 3   
    proper = true
;

harrysBedroomStart: Room
    'Bedroom' 'bedroom'
    "Lying on his back all Harry could see was the ceiling..."
    
    north = landing
;

+ bed: Fixture, Platform 'bed'
    dobjFor(GetOutOf) asDobjFor(GetOff)
    
    dobjFor(GetOff)
    {
        action()
        {
            if(harry.isIn(harrysBedroomStart))
            {
                bed.moveInto(harrysBedroom);
                ceiling.moveInto(harrysBedroom);
                harry.moveInto(harrysBedroom);
                if(!gAction.isImplicit)
                    "Harry clambered out of bed. ";
            }
            else
                inherited;
        }
    }
  
;

+ ceiling: Distant 'ceiling'
;

harrysBedroom: Room 'Bedroom' 
    "Harry's bed..."
    
    north = landing
;

+ chair: Platform 'chair'
;

++ pants: Wearable 'pants; blue; trousers; them'
    "They were just blue pants with a single pocket. "
;

+++ pocket: Fixture, Container 'pocket'
    hiddenIn = [wallet]
;


+ bedRoomDresser: Surface, Fixture 'dresser'
    "It had a single drawer. "
    
    specialDesc = "A plain, brown dresser stood against the south wall, 
    opposite the foot of the bed. "   
   
    remapIn = bedRoomDresserTopDrawer
;

++ bedRoomDresserTopDrawer: Fixture, OpenableContainer 
    'top drawer; dresser'
    "Top drawer. "   
    
    cannotTakeMsg = 'The drawer was part of the dresser. '
;

+++underwear: Thing 'some underwear;jockey t tee under;
        undershorts teeshirts pants underpants'
    "<<if !moved>>A jumble of underwear-shorts and tee shirts-filled the drawer.
    <<else>>It was just underwear. <<end>> "
;

wallet: OpenableContainer 'wallet'
    contentsListedInLook = nil
;

+ license: Thing 'driver\'s licence;;license'
;


landing: Room 'Landing'
    south = harrysBedroom
;

Yes, that looks a lot like what I was aiming for, with less of a rat’s nest for code. :slight_smile:

Thanks.