Change variables with a snippet of code

Probably spent more time trying to write a sensible title than writing this out…

I’ve got a table of NPC barks that fires off every turn until it runs out. When it runs out I want to change a bunch of variables and take some actions like moving the player.

From my limited I7 skillset my instinct was to use a “to say”, but I understand that to be wrong since a “to say” fires off everything, even if you have “if/otherwise” statements in there.

Table of HoldingArea
Talkorder	Event
1	"Final line of the NPC talking.[OpenTrapDoor]"

To say OpenTrapDoor:
    if the player is Kevin:
         say "The trapdoor opens!";
         move the player to Dungeon;
         now TrapMarker is 1;
    otherwise if the player is Susie:
         say "The trapdoor opens!";
         move the player to Cavern;
         now TrapMarker is 2.

So, even if the player is Susie, TrapMarker is set as “1” and they’re moved to the Dungeon.

Is there a way to fire off a chunk of code like that (wrong) “to say” that would be independent from a player action?

I think there must be something else going on, because the “to say” phrase should work and, in general, respect the current state at the time it is called.

You haven’t given a complete example to try it out, but this minimal more-or-less similar example works for me:

The Lab is a room.

Kevin is a man in the Lab. 
Susie is a woman in the Lab.

When play begins:
	now the player is Kevin;

After waiting:
	if the player is Kevin:
		say "You are now Susie.";
		now the player is Susie;
	otherwise:
		say "You are now Kevin.";
		now the player is Kevin.

After jumping:
	say "Uh-oh. [OpenTrapDoor]".

To say OpenTrapDoor:
	if the player is Kevin:
		 say "The trapdoor opens for Kevin!";
		 move the player to Dungeon;
	otherwise if the player is Susie:
		 say "The trapdoor opens for Susie!";
		 move the player to Cavern;

The Dungeon is a room.

The Cavern is a room.

Test me with "jump / z / jump / z / jump".

Result as expected:

>[1] jump
Uh-oh. The trapdoor opens for Kevin!

Dungeon

>[2] z
You are now Susie.

>[3] jump
Uh-oh. The trapdoor opens for Susie!

Cavern

>[4] z
You are now Kevin.

>[5] jump
Uh-oh. The trapdoor opens for Kevin!

Dungeon

>
1 Like

I think this approach should work, per @StJohnLimbo, but it feels a bit hacky to me. The natural way to do this in Inform would be via a scene, I think - it’s hard to tell exactly how you’re tracking the NPC bark progression from this snippet, but it should be simple to trigger a new scene beginning based on that, and then put this code in a “when SCENE begins” rule.

(Scenes are in Chapter 10 of WWI)

1 Like

Huh. Was told in a older, separate thread that I shouldn’t do such a thing in descriptions, so I assumed that would be the same here.

I have an “every turn” firing off the barks. I’ve had a hard time wrapping my head around scenes, specifically how to turn them on and off again, but sounds like this might be time to try and figure it out.

Thank you, both!

Ah, okay, thanks for the link. Juhana has a good point there, so this might then indeed be one of the cases where, in the complete context of your code, it produces unforeseen consequences, unlike in my minimal example. I don’t know.

Then it’s probably best to let a scene begin on the appropriate condition, as Mike says. It can be tricky to get the exact desired results with scenes, depending on what you want to happen at what point, and you can’t let them begin explicitly, you’ll have to set a condition like: “Trapdoor Scene begins when …”. But they’re a nice tool, and useful to know!

Well, doing it in a description is especially fraught, 'cause the code might be getting run when you’re not expecting it. But sneaking code into say statements can be a viable strategy.

That said, this might be an easy way to organize this:

npcbark-count is initially 0.
To npcbark:
	increment npcbark-count;
	if npcbark-count is:
	-- 1: say "A";
	-- 2: say "B";
	-- 3: say "C";
		opentrapdoor;
1 Like

What does this mean? I see people say it all the time. Does it mean you’re forcing code to achieve a goal that it’s not intended for?

Yeah, I also put off figuring out how they worked for a while when I was learning Inform since they seem complicated - and there are some idiosyncrasies, as others have noted, but I think they’re a pretty powerful tool.

(With that said, you could also probably just put your code somewhere in that every turn rule, too…)

Yeah, that’s my understanding - it’s a hacked-together solution (this is I think where the term “hacker” originally came from?) I should say my code is like 90% hacked-together nonsense so I don’t have much of a left to stand on here!

2 Likes

This may or may not apply in this case, but remember if you have multiple “Every Turn” rules you can run into problems. If one Every Turn rule succeeds or stops the action or redirects with an Instead, it won’t run the other rule - and it may not process the rest of that rule that occurs after it succeeds or fails.

If you have lots of stuff to make happen every turn, you can make one Every Turn rule and split processes out:

Every turn:
     foo the bar;
     bar the foo;

To foo the bar:
     say "This is an odd thing to have happen every turn."

To bar the foo:
     say "[one of]I agree, and this is another case of that.[or]I concur.[or]This seems like a dangerous situation...[OpenTrapDoor][stopping]"

To say OpenTrapDoor:
	if the player is Kevin: [...]
2 Likes

I don’t recommend this sort of thing. Having several every-turn rules is a normal (and documented) thing to do. The whole point of the rule system is that you can have one rule for each bit of behavior.

You just have to remember that “stop the action” isn’t valid in an every-turn rule. Or anywhere else outside of an action.