The odd behavior of "Decide on"

I’m streamlining my movement algorithms; the idea is to use a “decide on” statement to assign each NPC a destination, but something is very wrong.

When the Commander wakes up, he orders everyone to meet him in the cockpit, so everyone’s statement begins like this:

To decide which room is the destination of (character): If Commander Connor is conscious, decide on the cockpit; If (second condition), decide on (second location); (etc, etc.)

But for some reason, everyone’s destination is always coming up as the cockpit, even though the Commander is verifiably unconscious (and yes, unconscious is verifiably the opposite of conscious).

What’s going on here?

Did you mean

To decide which room is the destination of (C - character):

Or are you using literal object names in there?

I’m using literal object names. The actual code reads:

To decide which room is the destination of Jake: if Commander Connor is not unconscious, decide on the Cockpit; if the player is Gail, decide on the location of Gail; decide on the Sickbay.

Etc, etc. But which character it is isn’t important because they all do this.

I don’t see anything immediately wrong with that. You could try it with some debugging commands to see where it goes wrong:

To decide which room is the destination of Jake: say "Deciding the destination for Jake."; if Commander Connor is not unconscious: say "Connor conscious, deciding on Cockpit."; decide on the Cockpit; say "Connor unconscious, continuing."; if the player is Gail: say "The player is Gail, heading towards the player."; decide on the location of Gail; say "The player is not Gail, using the default."; decide on the Sickbay.
This will also tell you if the code is calling this part at all.

Jake and Commander Connor are men.
Gail is a woman.

A person can be unconscious.

Q-Leaping is an action applying to one thing. Understand "leap into [person]" as q-leaping. Carry out Q-leaping: now the player is the noun.

Gift of Lethe is an action applying to nothing. Understand "sleep now" as Gift of Lethe. Carry out Gift of Lethe: now Commander Connor is unconscious.


The Cockpit is a room. The Sickbay is west of the Cockpit. The Arboretum is north of the Cockpit.


To decide which room is the destination of Jake:
	if Commander Connor is not unconscious, decide on the Cockpit;
	if the player is Gail, decide on the location of Gail;
	decide on the Sickbay.

Instead of jumping: say the destination of Jake.

Echoing Juhana here. This seems to compile and run just as advertised.

Turns out that if you want to define a set of “decide” phrases that customize each other, you need to write everything as parameters.

To decide what number is the weight of (T - thing):
	decide on 1.

To decide what number is the weight of (T - the rock):
	decide on 2.

To decide what number is the weight of (T - the stone):
	decide on 3.

You don’t have to define the default (“thing”) case, but if you don’t, invoking the phrase on an undefined object triggers a runtime error.

Juhana: I’ve used debugging commands; that’s how I know that the commander is definitely unconscious, and that the destination is definitely the cockpit.

Here’s my debug code, for anyone who’s interested (the action delay and mobile/stationary bits are other parts of the algorithm, but they aren’t interfering here, as far as I can tell):

Every turn: if Commander Connor is unconscious: say "Connor is unconscious."; repeat with the current character running through another conscious crew members: say "[current character][line break]"; if the action delay of the current character < the max delay of the current character: now the action delay of the current character is the action delay of the current character + 1; now the current character is stationary; otherwise: if the current character is not in the destination of the current character: let the current direction be the best route from the location of the current character to the destination of the current character, using doors; say "Destination is [destination of the current character]."; say "Best direction is [current direction]."; if the current direction is not nothing: try the current character going the current direction; if the location of the current character is the destination of the current character: now the current character is stationary; now the action delay of the current character is 0; otherwise: now the current character is mobile; otherwise: say "In location."; now the current character is stationary.

zarf: I’m not exactly sure what you’re saying there. I was going off of 11.17, which has a couple of examples that don’t use parameters, and I’m not getting a runtime error or any sort of error at all (just incorrect behavior).

Phrasing the first line as “To decide what room is the destination of (J -Jake):” etc. doesn’t have any effect.

Could you post the smallest complete program that exhibits this behaviour? (It’s hard to say anything useful without seeing all the code that has a bearing on this problem.)

OK, here you go:

[code]The cockpit is a room. The hall is west of the cockpit. The sickbay is west of the hall.

A person can be conscious or unconscious. A person is usually conscious.

Jake is a man. Jake is conscious. Jake is in the hall.

Gail is a woman. Gail is conscious. Gail is in the hall. The player is Gail.

Connor is a man. Connor is unconscious. Connor is in the cockpit.

A person has a room called the destination.

Every turn:
if Connor is unconscious:
say “Connor is unconscious.”

To decide which room is the destination of Jake:
if Connor is conscious, decide on the Cockpit;
decide on the Sickbay.

Definition: a person is another if it is not the player.

Every turn:
repeat with the current character running through another conscious people:
say “[current character][line break]”;
if the current character is not in the destination of the current character:
let the current direction be the best route from the location of the current character to the destination of the current character, using doors;
say “Destination is [destination of the current character].”;
say “Best direction is [current direction].”;
if the current direction is not nothing:
try the current character going the current direction;
otherwise:
say “In location.”[/code]

It plays out like this (at least for me):

Is it possible that this is an actual Inform bug? Because I really don’t see what could be wrong with the above code.

After a quick look, there are two problems that contribute to the behavior you’re seeing:

  1. You can’t set a property directly using the “decide on” construction, so you’ve basically defined a phrase that will never fire (stick a debugging print statement into the phrase as Juhana suggested and you’ll see that it is never activated.) Set the property in an every turn rule instead, or do away with the property in favor of a string of decide phrases as suggested by zarf.
  2. The default value for the destination property is the first room created, which happens to be the cockpit, so that room only seems to be actively selected by the decide phrase.

–Erik

OK, but why does it still make the default destination the cockpit in my real game, where the Cockpit is actually the absolute last room created?

And I still don’t know what zarf’s example was supposed to mean or how it is different from mine, or for that matter how mine is different from the examples given in 11.17.

I have no idea–you didn’t post that code. :wink: Define any other room before the Cockpit in this example, though, and you’ll see that that room becomes Jake’s destination.

You have a property called “destination”, but writing the phrase

To decide which room is the destination of Jake:

doesn’t set that destination property. It just creates a form of words: Inform has no idea that “destination” in “destination of Jake” refers to the destination property, nor does it know that “Jake” refers to the person Jake. The compiler will simply look for the exact words “destination of Jake” and substitute the contents of your decision phrase. Since “destination of Jake” doesn’t appear anywhere in your source text, this phrase effectively doesn’t do anything at all.

There are a host of ways you could do this. Here’s one way to do it by using the “description” property:

[code]First every turn:
repeat with subject running through another people:
select goal of the subject.

To select goal of (J - Jake):
if Connor is conscious:
now the destination of J is the Cockpit;
otherwise:
now the destination of J is the Sickbay.

To select goal of (T - thing):
now the destination of T is the Hall.[/code]

Another option would be to remove the line that defines the description property and instead use the “form of words” approach, as outlined by zarf:

[code]To decide which room is the destination of (P - a person):
decide on the Hall.

To decide which room is the destination of (J - Jake):
if Connor is conscious, decide on the Cockpit;
decide on the Sickbay.[/code]

In this case, Inform will substitute a function that returns a room for the pattern “destination of ” throughout your source code. In this way of doing it, there is no property in which the room is stored–Inform runs a function each time it encounters that pattern. Hope that helps.

–Erik

OK, thanks.

If it’s a bug it isn’t a very recent one. At least 5Z71 behaves the same way, i.e. the decide phrase is not called or considered (or whatever it’s called in Inform) at all. Perhaps it doesn’t know to treat “Jake” as a constant rather than a literal?

In 5Z71 you could write:

To decide which room is the destination of (character - Jake): if Connor is conscious, decide on the Cockpit; decide on the Sickbay.
And that would work as expected.
But I think there’s non-fixed bug in later builds that prevents it (see the thread about Sanddancer failing to compile: [url]https://intfiction.org/t/sand-dancer-failing-to-compile-with-6f95/1458/1]).
So perhaps you have to resort to something like this

To decide which room is the destination of (character - person): if the character is Jake: if Connor is conscious, decide on the Cockpit; decide on the Sickbay.