Having trouble understanding PlaceInScope()

Hi, I’m currently working on designing a light switch class in Inform 6 to give or take away light from the room the lightswitch is in whenever it is switched. However I have been having difficulty understanding how to properly use PlaceInScope() so that the light switch can be switched on again once the light in the room is gone.

Here’s the snippet of code dealing with the light switch specifically, that I’ve tried to implement.

Class Light_Switch
  with short_name "light switch",
       name 'light' 'switch',
       after [;
         SwitchOn: give parent(self) light;
         SwitchOff: give parent(self) ~light;
                   PlaceInScope(self);
       ],
  has switchable on static;

And here’s the entirety of the code (in case the problem somehow lies elsewhere).

Constant Story "Testing Grounds";
Constant Headline "Testing";

Include "Parser";
Include "Verblib";

Attribute inside;

Class Light_Switch
  with short_name "light switch",
       name 'light' 'switch',
       after [;
         SwitchOn: give parent(self) light;
         SwitchOff: give parent(self) ~light;
                    PlaceInScope(self);
       ],
  has switchable on static;

Object testing_room "Testing Grounds"
  has inside light, 
  with description "This is the testing room.",
  with name 'testing room';

Light_Switch ->;

[ Initialise;
  location = testing_room;
];


Include "Grammar";

I have tried looking through the DM4 and it’s examples a bit, especially Example 101 where I found PlaceInScope() to try using. However I think even with this example I’ve failed to understand exactly how PlaceInScope() should be used and how it works. Any further explanation would be very appreciated.

It would be easier to give it scenery, rather than static and include it in the room description. In this way, it is always in scope, it doesn’t appear in the object list and you don’t have to muck about with PlaceInScope().

Thank you for the response. Unfortunately it appears that replacing has static with has scenery and removing PlaceInScope(self); does not allow for the light switch to remain in scope in darkness however.

Here is the Class with these changes. The rest of the program remains unchanged.

Class Light_Switch
  with short_name "light switch",
       name 'light' 'switch',
       after [;
         SwitchOn: give parent(self) light;
         SwitchOff: give parent(self) ~light;
       ],
  has switchable on scenery;

“Switch on light switch” after “Switch off light switch” behaves the same as the code before the changes, with the parser printing “You can’t see any such thing”.

The direct answer to your question is that PlaceInScope() should only be called when a scope search is going on. It doesn’t make a permanent change to the world. The parser is going through the list of objects-in-scope; calling PlaceInScope() means “while you’re at it, also check here.”

What this means is, you should only call this from the InScope() routine or a scope token routine. Not in an action before/after routine.

3 Likes

Ah, good point. I wasn’t thinking of that. According to The Inform Designer’s Manual, 4th edn (DM4), PlaceInScope() is only meant to be used in “scope routines”, although I’m not sure what Graham Nelson means by a “scope routine”. I think exercise 101 in the DM4 may be close to what you need.

Edit: Ah, good old Zarf has clarified what is meant by a “scope routine” while I was penning my response.

Since the add_to_scope() property of rooms is usually ignored, you can create a version of InScope() that makes the property active during scope determination:

Include "Parser";

[ InScope act ;
    act = act; ! suppress compilation warning
    if (real_location provides add_to_scope)
        real_location.add_to_scope();
    rfalse; ! signal "continue normal scope processing"
];

Include "VerbLib";

Note the use of real_location because you want it to apply while the player is in darkness.

With that in place, any room or class of rooms can include:

with    add_to_scope [ i ;
            objectloop(i in self && i ofclass LightSwitch)
                PlaceInScope(i);
        ]

Full working example:

Light Switch Problem
Constant Story "Light Switch Problem";
Constant Headline "^from https://intfiction.org/t/having-trouble-understanding-placeinscope/53617^";

Include "Parser";

[ InScope act ;
    act = act; ! suppress compilation warning
    if (real_location provides add_to_scope)
        real_location.add_to_scope();
    rfalse; ! signal "continue normal scope processing"
];

Include "VerbLib";
Include "Grammar";

Class Room
    with    add_to_scope [ i ;
                objectloop(i in self && i ofclass LightSwitch)
                    PlaceInScope(i);
            ]
    has light;

Class LightSwitch
  with short_name "light switch",
       name 'light' 'switch',
       after [;
         SwitchOn: give parent(self) light;
         SwitchOff: give parent(self) ~light;
       ],
  has switchable on static;


Room Start "Starting Point"
    with    description
                "An uninteresting room.";

Lightswitch ->;

[ Initialise ;

    location = Start;

];

which yields:

Starting Point
An uninteresting room.

You can see a light switch here.

>X SWITCH
The light switch is currently switched on.

>TURN IT OFF
You switch the light switch off.

It is now pitch dark in here!

>X IT
Darkness, noun.  An absence of light to see by.

>TURN IT ON
You switch the light switch on.

Starting Point
An uninteresting room.

You can see a light switch here.

For safety’s sake, you might also want a routine to be called by Initialise() to ensure that the status of the light property for all rooms is synchronized to the on property of the applicable switch.

3 Likes

Thank you. This has helped me understand PlaceInScope() a bit more and I think this is the best direct answer in regard to PlaceInScope(). I’ll have to look into scope searches use a bit more in the DM4 to really understand them.

Thank you, this seems like the perfect solution to what I was trying to achieve. I will have to work on implementing this, along with the synchronization routine you mention, when I have the time.