Using tables as a variable

Hello!

I couldn’t find this in the documentation somehow although I know that there must be some example somewhere, so sorry for asking here. Nevertheless you guys are extremely helpful and I’m thankful for all the great answers I get here extremely fast! :smiley:

Here’s what I want to do: I want to add a random idle message out of several tables. The table used varies, depending on conditions.

[code]A person can be known or unknown. A person is usually unknown.

The bookshop is a room. The wing chair is in the bookshop. It is an enterable supporter. The shopkeeper is a man. The shopkeeper is unknown.
Carry out examining the wing chair:
now the shopkeeper is on the wing chair.

Carry out examining the shopkeeper:
now the shopkeeper is known.

Table of Idle Events shopkeeper nowhere
event
“idle 1_nowhere”
“idle 2_nowhere”
“idle 3_nowhere”

Table of Idle Events shopkeeper unknown
event
“idle 1_unknown”
“idle 2_unknown”
“idle 3_unknown”

Table of Idle Events shopkeeper known
event
“idle 1_known”
“idle 2_known”
“idle 3_known”
[/code]
Now I need something like “Every turn when the player is in the bookshop: pick a random row from a table depending on the given conditions and print the line.”
For this I guess I need another table that refers to the three tables, so I need the table as a variable. If it is possible I don’t want to pre-define the row in the table of tables but let Inform automatically search for the right row depending on the first column. With this I mean pre-defining conditions like “the shopkeeper is nowhere”, “the shopkeeper is unknown” and “the shopkeeper is known” and having these conditions in the first column and letting Inform search for the appropriate row.
I will need the same procedure in conversation when I have different replies to different topics depending on the time asked the same topic (the person asked will only repeat one time and then say a standard message the tells the player that he should already know that).

Thanks for all your answers and sorry for my n00byness. :wink:

A straightforward but redundant solution is to add this to your program:

Every turn when the location is the bookshop and the shopkeeper is nowhere:
	Choose a random row from Table of Idle Events shopkeeper nowhere;
	say "[event entry][line break]".
	
Every turn when the location is the bookshop and the unknown shopkeeper is not nowhere:
	Choose a random row from Table of Idle Events shopkeeper unknown;
	say "[event entry][line break]".
	
Every turn when the location is the bookshop and the known shopkeeper is not nowhere:
	Choose a random row from Table of Idle Events shopkeeper known;
	say "[event entry][line break]".

Here’s one way to remove the redundancy:

A person can be known or unknown. A person is usually unknown.

The bookshop is a room. The wing chair is in the bookshop. It is an enterable supporter. The shopkeeper is a man. The shopkeeper is unknown.

The shopkeeper has a table name called the idle events table. The idle events table of the shopkeeper is Table of Idle Events shopkeeper nowhere.

Carry out examining the wing chair:
	now the shopkeeper is on the wing chair;
	now the idle events table of the shopkeeper is Table of Idle Events shopkeeper unknown.

Carry out examining the shopkeeper:
	now the shopkeeper is known;
	now the idle events table of the shopkeeper is Table of Idle Events shopkeeper known.

Table of Idle Events shopkeeper nowhere
event
"idle 1_nowhere"
"idle 2_nowhere"
"idle 3_nowhere"

Table of Idle Events shopkeeper unknown
event
"idle 1_unknown"
"idle 2_unknown"
"idle 3_unknown"

Table of Idle Events shopkeeper known
event
"idle 1_known"
"idle 2_known"
"idle 3_known"

Every turn when the location is the bookshop:
	Choose a random row from idle events table of the shopkeeper;
	say "[event entry][line break]".

Here’s another way, which is less error prone if you’re going to be changing the shopkeeper’s state back and forth from multiple places:

A person can be known or unknown. A person is usually unknown.

The bookshop is a room. The wing chair is in the bookshop. It is an enterable supporter. The shopkeeper is a man. The shopkeeper is unknown.

Carry out examining the wing chair:
	now the shopkeeper is on the wing chair.

Carry out examining the shopkeeper:
	now the shopkeeper is known.

To decide which table name is the idle events table of the shopkeeper:
	if the shopkeeper is nowhere, decide on Table of Idle Events shopkeeper nowhere;
	if the shopkeeper is unknown, decide on Table of Idle Events shopkeeper unknown;
	decide on Table of Idle Events shopkeeper known.
	
Table of Idle Events shopkeeper nowhere
event
"idle 1_nowhere"
"idle 2_nowhere"
"idle 3_nowhere"

Table of Idle Events shopkeeper unknown
event
"idle 1_unknown"
"idle 2_unknown"
"idle 3_unknown"

Table of Idle Events shopkeeper known
event
"idle 1_known"
"idle 2_known"
"idle 3_known"

Every turn when the location is the bookshop:
	Choose a random row from the idle events table of the shopkeeper;
	say "[event entry][line break]".

Yes, that solution is understandable and working. However, what I’m after is something like

Table of Idle Events of the Shopkeeper condition table "shopkeeper_nowhere" Table of Idle Events shopkeeper nowhere "shopkeeper_unknown" Table of Idle Events shopkeeper unknown "shopkeeper_known" able of Idle Events shopkeeper known So I can automatically search the needed “[condition]” in the super table. Is this even possible? For this I’d need to set a variable as “shopkeeper condition” attached to the shopkeeper and decide on the condition with if clauses. Then I should be able to search for the condition in the super table. That’s also what I want to do when constructing a conversation model.

You could do what you suggest, but I don’t understand what benefits you think that this solution will provide over the others.

The shopkeeper condition variable is a bit of a red flag to me, because it duplicates the state that’s already represented by the shopkeeper’s existing properties (such as known/unknown). This violates the DRY (don’t repeat yourself) principle and opens the door to a new class of bugs where information is duplicated and the duplicates don’t agree with one another.

You can “automatically search the needed condition” in the table, but only if you first execute some conditional logic that sets shopkeeper condition so that it can later be used to index into the table. Why not instead just use that conditional logic to set a table name variable in the shopkeeper directly (as in my second example) or to determine a table at the time that a random idle event must be printed (as in my third example)?

Hey— I don’t know you guys, but I’ve been following this thread with interest. Alpha, I think I can see where you’re going with this (as far as expanding it to a conversation system), but I have to go with Vince — you seem to be over-complicating it. Using three different tables for a single NPC seems unnecessary. I’ve taken the liberty of using yours and Vince’s code to show how I would do it with one table:

[code]
A person can be known or unknown. A person is usually unknown.

The Bookshop is a room. The wing chair is in the bookshop. It is an enterable supporter. The shopkeeper is a man. The shopkeeper is unknown.

Carry out examining the wing chair:
now the shopkeeper is on the wing chair.

Carry out examining the shopkeeper:
now the shopkeeper is known.

To decide which number is the current-status of (P - a person):
if P is nowhere:
decide on 1;
if P is unknown:
decide on 2;
otherwise:
decide on 3.

Every turn when the location is the bookshop:
sort the Table of Idle Events Shopkeeper in random order;
let S be the current-status of the shopkeeper;
say “status [S] if S is 1.else if S is 2.else if S is 3.”;
choose a row with status of S in the Table of Idle Events Shopkeeper;
say “[event entry][line break]”.

Table of Idle Events Shopkeeper
event status
“idle 1_nowhere” 1
“idle 2_nowhere” 1
“idle 3_nowhere” 1
“idle 1_unknown” 2
“idle 2_unknown” 2
“idle 3_unknown” 2
“idle 1_known” 3
“idle 2_known” 3
“idle 3_known” 3

test me with “l/z/x chair/z/x shopkeeper/g/g”.[/code]
Note that since there are only three options per status, there will be plays that seem to be non-random. Additional replays will verify that the table has indeed been randomized. I’m also concerned with this whole “nowhere” thing, but since I don’t know your ultimate vision, there’s no reason for me to speculate. Keep going — you may be on to something.

Hi Mike!

“Nowhere” is Informese for “out of play”; it’s not something weird that Alpha’s doing. It means that an object has no parent and consequently has no location is the game world (unless it’s been defined as “part of” another object that does). So Alpha’s three shopkeeper states are: out of play, in play but unknown, and in play and known. An unstated assumption of mine here has been that in play -> in the bookshop.

When an author wants an object to be discovered in a location as a result of an action or event, the typical implementation strategy is to start the object out nowhere (even if, in the model world, it’s supposed to be hidden in that place from the beginning) and then move it to the location when the action or event occurs. This saves the author from having to work to hide the object from the player before it’s discovered.

For the record, I know what “nowhere” means. I also know that moving objects in and out of play is a standard technique in IF. My only concern is that it might not be necessary for Alpha’s intended use (which I don’t know).

All these approaches are interesting and give me more insight on how to deal with things in Inform, so thanks! :slight_smile:
I’ll get back to you when I’ve tried some things with this.

I have finally found the time to continue with this and I’ve found out something really cool. Here is what I implemented and which actually works!

[code]To decide which text is the current-status of the shop owner:
if the shop owner is nowhere:
decide on “nowhere”;
if the wall of books is examined:
decide on “visited”;
if the shop owner is visible:
decide on “visible”.

Every turn when the player is in bookshop:
sort the Table of Idle Actions of the Shop Owner in random order;
let S be the current-status of the shop owner;
choose a row with status of S in the Table of Idle Actions of the Shop Owner;
if a random chance of 1 in 2 succeeds, say “[loop entry][line break]”.

Table of Idle Actions of the Shop Owner
status Loop
“nowhere” “A ring of smoke rises to the ceiling and evaporates, filling the air with sweet tobacco smell.”
“nowhere” “You hear the rustling of a page being turned.”
“visited” “[The shop owner] lets out a puff of smoke.”
“visited” “Another ring of smoke rises from [the shop owner]'s pipe to the ceiling and evaporates.”
“visible” “[The shop owner] takes a short, dismayed look at you, then continues to read.”
“visited” “[The shop owner] coughs quietly.”
“visible” “[The shop owner] perks his eyebrows, squinnies, then utters a faint expression of wonder.”
“visible” “[The shop owner] sniffs, scratches his nose and continues to read.”
“nowhere” “A sigh emmanates from behind the wall of books.”
“visible” “[The shop owner] looks up from his book and says ‘If you want to buy something, I don’t sell books to children.’ then continues to read.”
“visible” “[The shop owner] utters a sigh and turns a page of the book on his lap.”
“nowhere” “Somebody coughs quietly.”[/code]
As you can see there’s no need to sort the table. If I want, I could just add another line that comes to my mind. :slight_smile:

Thanks for the elaborations! :smiley: :smiley: :smiley:

Cool!

One piece of advice–you might want to put the “random chance of 1 in 2” check at the beginning of the whole code block, so you don’t have to sort and check the table on the turns when you’re not going to print the message. Just a little bit more efficient.

I’d do this:

[code]
The shopkeeper can be angry, busy, or bored. The shopkeeper is improper-named.

After examining the shopkeeper for the first time:
now the shopkeeper is proper-named;
now the printed name of shopkeeper is “Bob the shopkeeper”;
say “The shopkeeper introduces himself to you and you learn his name is Bob.”;

Every turn when the location of the shopkeeper is the location:
say "[shopidle] ".

To say shopidle:
if the shopkeeper is angry:
say "[angrySK] ";
if the shopkeeper is busy:
say "[busySK] ";
if the shopkeeper is bored:
say "[boredSK] ".

To say angrySK:
say “[The shopkeeper] [one of]blows his top[or]fumes angrily[or]glowers at the mess[cycling].”

To say busySK:
[…][/code]

Bracketing [The shopkeeper] will use the correct name wherever you want it.

That is one version but if I want to use completely different sentences written out during play, it will get confusing because everything is written in one line. I also wouldn’t use “cycling” because it will get bored after a short while. If I have 10 options of what to write and add a chance of writing something at all, it gets more interesting I think.
Nevertheless, thank you for the input!