Inform: Blocking Take From a Container

If you have an object lying on the floor, and you don't want the player to take it -- under some conditions -- you override the Take action, of course.

  
Object brick "brick" TheRoom
  with
    name 'brick',
    before [;
      Take:
        if (self has hot)
          "It's too hot!";
    ],
  has hot;

   A Room
Not much here.

You can see a brick here.

>get brick
It's too hot!

But what if the object is inside a container, or a supporter?

Mistake

  
! Wrong !

Object box "metal box" TheRoom
  with
    name 'metal' 'box',
  has container open charged;

Object key "key" box
  with
    name 'key',
    before [;
      Take:
        if (self in box && box has charged)
          "The box zaps you!";
    ];

   A Room
Not much here.

You can see a metal box (in which is a key) here.

>get key
The box zaps you!

And you'd think that'd solve it. But...

   >remove key from box
Removed.

>undo
A Room
[Previous turn undone.]

>get box
Taken.

>empty box
key: Dropped.

>get key
Taken.

The "remove X from Y", "empty X", and "empty X to Y" commands are not well-known. But they can all be used to get an object out of a container without triggering a Take action.

So it seems that you have to override not only Take, but Remove, Empty, and EmptyT as well.

Solution

Actually, the Right Way (tm) is to override the LetGo action on the container.

  
Object box "metal box" TheRoom
  with
    name 'metal' 'box',
    before [;
      LetGo:
        if (self has charged)
          "The box zaps you!";
    ],
  has container open charged;

Object key "key" box
  with
    name 'key';

   A Room
Not much here.

You can see a metal box (in which is a key) here.

>get key
The box zaps you!

>remove key from box
The box zaps you!

>empty box
key: The box zaps you!

This also makes for slightly more elegant code. The test is on the container, where it belongs, instead of having to be written separately for each object that might be inside.

Special Case

Joe Mason notes: "Receive and LetGo aren't called if the player is actually standing in/on the container/supporter. So if you have a platform that you can both stand on and put things on, the player can get around your LetGo rule by standing on the platform and typing 'drop'."

There are several ways to resolve this, depending on exactly what you want to forbid. But this is a rare case. Work it out yourself.

Prevention

When you want to prevent the player from taking something from a container or support, test all these commands: "take object", "remove object from container", "empty container", "empty container to container2".


More Inform Tricks