Removing an object from scope

I’d like to know what’s the best way to remove an object from scope. My usecase is removing an object from scope when in darkness, but it can apply to other situations.

In this post, the proposed code to prevent sequence-breaking in darkness is:

(prevent [open/search #secretcompartment])
    ~(player can see)
    You can't see well enough to do that in the dark.

But even though opening the compartment will fail, typing “open compartment” will still reveal its presence. (An unrecognised object would produce the response “I only understood you as far as…”). And it’ll still be proposed in disambiguation questions. So I thought about several solutions.

First solution, simply moving the object off-stage. It works quite well for scenery and ($ attracts $). Maybe something like that:

(inherently dark #room)
(#room attracts #secretcompartment)
    (player can see) %% Only if not in darkness.

Second solution, refuse the action and fake an unrecognised response. But I’m not sur the response will always match the one produced by the parser, and it won’t work with disambiguations questions. Something like:

(refuse $Action)
    ~(player can see)
    (#secretcompartment is one of $Action)
    %% We replace the compartment in the action with an empty list.
    (collect $Element)
        *($Original is one of $Action)
        (if)($Original = #secretcompartment)(then)
            ($Element = [])
        (else)
            ($Element = $Original)
        (endif)
    (into $ProcessedAction)
    %% "open compartment" will produce "I only understood you as far as wanting to open something".
    \(I only understood as far as wanting to (describe action $ProcessedAction).\)

Third solution, directly modify the ($ is in scope) rule to omit certain objects. It may seem obvious, so maybe the standard library should provide something by default? (Maybe with a trait like (out of scope in darkness $). Or even just (out of scope $) with whatever condition in the rule body.) Or is there some performance issue I overlooked?

I’ve got the feeling I’m overthinking it, so any pointers are welcome.

1 Like

I think the third option is probably the best in general. I haven’t tested it but I think you could do:

~($Object is in scope)
    ~(player can see)
    (current room $Room)
    ($Object is in room $Room)
    (current player $Player)
    ~($Object = $Player)
    ($Relationship is one of [#partof #wornby #heldby])
    ~($Object is recursively $Relationship $Player)

This should make it so when you’re in the dark (or otherwise blinded) you may only interact with yourself and what you are holding or wearing. Performance-wise, I don’t think it will be terrible because you’re only considering objects in the current room. I’d be curious to hear if this actually works or not.

In your code, shouldn’t

($Relationship is one of [#partof #wornby #heldby])

be a multi-query? (So that we test each of the listed relation.)

In any case, I don’t think it will work. It’s all good when only testing if a particular object is in scope, but it will cause problems if we are backtracking over all objects in scope. If the negated rule succeeds, it will shortcircuit the backtracking, omitting any remaining objects that would otherwise be in scope.

At least that’s how I understand it, and this post seems to confirm it (funnily enough, it’s was an answer to one of your posts :slightly_smiling_face:).

The only solution would be to edit the original ($ is in scope) to make it fail for specific objects. But I haven’t tried it yet. That’s why I was proposing to add an (out of scope $) trait to the library.