Lighting the location of the player with magic?

Hello, I am completely new and struggling to find answers in documentation or via google.

I want to have a magic spell that will light dark places (ideally for X number of turns) but Inform is really not having it.
The only way I can make it work is by hardcoding it into the spell to work on one specifically named room only. Using “the location” doesn’t work.
All the examples and documentation I find refer to using switches or lighting lamps and torches. I just want to change the property of the room the player is currently in for like 5 turns or something whenever a spell is used.

Problem. You wrote ‘now the location of the player is lit for five turns’, but ‘the location of the player is lit’ isn’t the sort of condition which can be made to be true, in the way that ‘the ball is on the table’ can be made true with a straightforward movement of one object (the ball).

Is there no elegant way to go about this? Do I have to code each room separately to handle the spell?

2 Likes

Welcome to the boards, and congrats on getting into Inform!

I think rooms are typically lighted or dark, whereas lit is a property of light-source objects – not sure if that’s part of the issue? Beyond that, I think the “for five turns” bit might be what’s confusing Inform. I tried a more step-by-step approach that does seem to work, though there might be more elegant solutions others can come up with. Sharing it in case it’s useful (I repurposed the jumping action just to save myself from defining a new action – you can just substitute in whatever your spell action is. I also defined a new kind of room to avoid the situation where the player casts light in a previously-bright room and then the timer plunges it into darkness!)

A darkroom is a kind of room.  A darkroom is dark.  A darkroom has a number called the frotz_timer.

The Lab is a darkroom.  The tunnel is a darkroom.  It is east of the lab.  The hole is a darkroom.  It is down from the tunnel.

After jumping:
	Say "Light blooms all around you -- but for how long?";
	Now the location is lighted;
	Now the frotz_timer of the location is 5.
 
Every turn:
	Repeat with X running through darkrooms:
		If X is lighted:
			Decrement the frotz_timer of X;
			If the frotz_timer of X is 0:
				If X is the location, say "Suddenly you're plunged into darkness!";
				Now X is dark.
1 Like

Thanks for replying! Your code works great! :smiley:
This seems much more complex than I originally thought it might be.

I ran into a runtime error at first, but I think it is just a problem with abstracting myself to the test room. The game seems to think that I am still in the starting room despite it saying otherwise once I abstract. As soon as I casted the spell it threw the error saying the starting room isn’t dark and can’t have such a property changed.
So I just moved the rooms around and now it seems to work just fine! But I don’t understand the first bit of the second part of your code. What does “repeat with X running through darkrooms” mean? Isn’t the X a variable for the given room the player is in?

One other trick: instead of lighting the rooms with your spell, light a hidden object attached to the player for the number of turns the spell lasts.

a third eye is part of the player. the third eye can be lit. 

after casting the see spell: 
    say "You can see! The colors!"; 
    the eye goes out in five turns from now.

At the time when the eye goes out: 
    now the third eye is not lit.

Well, there are probably more elegant ways to solve the problem – @hanon’s code below makes use of the built-in timers Inform gives you access to, and there’s probably a way to make use of them in this case, too! I tend to like to see more of what’s happening since I’m not the strongest Inform programmer, so my example exposes more of the mechanics, for good or ill.

Yeah that sounds like an unrelated issue, from this description.

I dunno whether you’ve programmed in other languages, but “repeat with [variable name] running through [category]” is the main way Inform does loops – what that’s doing is going through each darkroom one by one and advancing the timer, and if it hits zero, darkening the room (the “say” command is the only one that keys off the player’s location – one protip for Inform is that “the location” is always the player’s location – since if they’re not there to see the light go out, I’m presuming they shouldn’t see the message).

Anyway, here are the docs on that!

It’s probably best to stick to that, but lit and lighted are names for the same Inform 6 property, and one can freely use lit/not lit or lighted/not lighted or ask provides the property lit or provides the property lighted interchangeably for either rooms or things. However, the opposite words are restricted. Rooms can’t be unlit, only dark, and things can’t be dark, only unlit.

I’d be even more parsimonious: now the player is lit… at least I think there isn’t someplace where (providing light) in regard to yourself might sneak out. Hanon’s suggestion is safer.

2 Likes

Would making the item that is part of the player concealed and unlisted make sure they never discover it?

I did try directly lighting the player, but that also gave me the same errors as trying to light “the location.” Of course it’s entirely possible I had some kind of syntax problems or some little snag preventing it from working.

Oh that’s interesting. Thanks for the explanation and doc link.

now the player is lit would work. If you did it in combination with for five turns it wouldn’t have.

That shouldn’t be necessary. A part that is lit will really provide light, but I7’s standard rules won’t mention the part, or even that the thing it’s a part of is (providing light) as it would if that thing were directly lit. If you want parts to be mentioned when examining things or looking at rooms, you’ll have to add code to do it.

If you just name it something weird they probably won’t ever find it.

Or make it privately-named- e.g. “the third eye is a privately-named thing” means nothing the player can type will ever refer to it, unless you write further particular code to allow it.

privately-named isn’t a guarantee that the player will never refer to it. (Parser disambiguation and auto-selection can land on privately-named objects.)

This doesn’t mean you should worry about it. I’d stick in a rule like “Instead of doing anything to the third eye: say ‘You can’t do that to the light.’” If the player happens to trip over that response, it won’t hurt the game experience.

3 Likes

So far as I know, the privately-named / undescribed one-two punch makes it impossible both to accidentally refer to it or for the parser to choose it for you. It is still in scope, but its undescribed-ness excludes it from consideration for all the cases I’ve tried. Do you know of any leaks there I may not be thinking of?

Can’t it still get picked up by things like >TAKE (without a noun) when there’s no other object in scope? For most verbs the player will also be in scope and get in the way, but taking will choose anything else before it chooses the player.

I have never in my life been able to remember all of what undescribed (I6 concealed) does without reading through all the library code. So I have no answer here.

(Which I why I recommend writing an Instead rule for it. Just in case.)

2 Likes

Hunh. I thought it couldn’t, 'cause I tried it… with lab is a room. The third eye is an undescribed privately-named part of the player.

lab

> scope
1: yourself (546710)
2: a third eye (546774)

> take all
There are none at all available!

> take
What do you want to take?

> drop
What do you want to drop?

> put
(on yourself)
(first taking yourself)
You are always self-possessed.

…but then…

> take
(the third eye)
That seems to be a part of yourself.

hunh.

Or…

a schplap is part of the player. schplap can be lit.

Or…just call it out.

your eyes is part of the player. Understand "my eyes" as your eyes. your eyes can be lit. The description is "You've never been able to prove their actual existence since you can only see them in a reflection."

1 Like

The issue here is that you need to reset the undescribed status of the eye every turn after it is removed (because the eye is enclosed by the player) by the note object acquisitions rule:

[ NOTE_OBJECT_ACQUISITIONS_R obj;
    objectloop (obj in player) {
        give obj moved;
    }
    objectloop (obj ofclass Object && (obj has concealed)) {
        if (IndirectlyContains(player, obj)) {
            give obj ~concealed;
        }
    }
    rfalse;
];

Without the undescribed property, the eye becomes the single definite best-scoring object in scope when NounDomain() is called and so the parser infers that’s what you meant. With the eye having the undescribed property, all the directions are equally best-scoring, so Inform can’t infer what you meant and defers to the player with ‘What do you want to take?’

So either replace the note object acquisitions rule with an edited one that excludes the eye (requires I6 hacking), or add an I7 rule in the turn sequence between it and reading the next command to restore its undescribed status:

Before reading a command: now the third eye is undescribed.

EDIT this particular ‘Before reading a command’ hack is dodgy, in that it will be bypassed when multiple commands are chained on one line of input, causing multiple turns to pass before another command is read. Better, if slightly more complicated, is to insert a new rule into the turn sequence rules:

A turn sequence rule (this is the keep eye undescribed rule): now the third eye is undescribed.
The keep eye undescribed rule is listed after the note object acquisitions rule in the turn sequence rulebook.
2 Likes

See, this is why I shied away from parser/Inform7. I was working around things with spit and scotch tape instead of knowing how stuff really works! :wink:

1 Like