Doors and displaying topics from tables.

Hello!

I have another few questions today that I hope you guys can help me for like that you had helped me last time :slight_smile:

One) I have a door created, as seen in this code:

Main hall is a room. Main hall is north of Rusty house door. “The main hall of the house.”

A door is a kind of thing. A door can be openable. A door can be open. A door is usually openable and closed.

Rusty front door is a door. Rusty front door is north of Outside House and south of Main Hall.

Carry out opening a door:
say “You slowly push open the door”;

Which works just fine. However a few things I am not sure to do/want to have happen. Firstly, I want the player to have a key in their inventory at the start of play (I know how to do that bit) but then I want it to only be openable with the key in ones inventory. I guess that’s a check rule? But not too sure what to put (as Check and carry out rules confuse the hell out of me for some reason). Also, I want it so the player HAS to type “Open rusty front door”, and that it shuts upon going through it either way. What’s happening right now is that the door stays open, and that if you’re in Outside House or Main hall and then type north or south respectively, it will automatically open the door and then go into the room. While this isn’t an issue, it just doesn’t sit right with me.

  1. In my game I have an archer that you can speak to. He has three topics that can be spoken about; Werewolves, Werewolf hunters and killing werewolves. I want to make a command that allows the player to see what topics are available to be spoken about to the archer (and then other characters later in the game as this is rather important to deepen the lore and story). I tried to make my own code for this but it doesn’t do anything. Did I do something wrong or is there another way to go around this?

Code:

list-asking is an action applying to one thing.
understand “ask [thing]” as list-asking

Check list-asking:
if the noun is not the Archer, say “You cannot ask any questions”;

After list-asking the archer:
say “[Topic entry]”;

(Table is called Table of Archer Responses)

Cheers!

You can make doors close behind you with an after rule:

After going through a door (called X):
          say "[The X] swings shut behind you.";
          now X is closed;
          now X is locked;
          continue the action.

Making it relock itself automatically will ensure that the player needs the key to get through it again.

But you might want to consider whether all this is really a good plan. Having the doors lock themselves behind you might be good atmospherically, but the player will quickly get fed up of unlocking the same door over and over. You could let the player automatically unlock doors (after the first time) if they have the right keys. (Emily Short’s extensions, Locksmith and Approaches, are good for handling this sort of thing.)

By the way, you don’t need to define doors. They’re built into the standard rules. There’s also a built in “matching key” relation.

The rusty door is a door. The rusty door is locked. The matching key of the rusty door is the square key. The player carries the square key. 

Edited to add a caution.

Cheers @Jrb! I’ll do that now, thanks again for helping me :slight_smile:

For your question about conversation: there are a few problems with your code. But the good news is that there is already an action built into Inform which will do what you want — the “asking it about” action.

See Section 16.13 of Writing with Inform for a simple way of getting a table-based conversation working. Here’s an example:

After asking the archer about a topic listed in the Table of Archer Reponses:
       say the response entry.

Table of Archer Responses
Topic    Response
"Werewolf/Werewolves"   "They come out at full moon."
"Killing werewolves"       "You'll need a silver dagger."    

(You need to use tabs to separate the columns.)

Edit: if you really wanted to set up a new “list-asking” action", this is possible, but will be hassle. First of all you’d need to destroy the existing “ask” command. Which will also destroy the command for the “asking it for” action, which you might want to put back.

Understand the command to ask as something new. 
Understand "ask [someone] for [something]" as asking it for.

Now your new command needs two nouns: a thing (actually a person, but that comes later), and a topic. Because it takes two nouns, you need to tell Inform how the syntax works; so the action should be called “list-asking it about”.

List-asking it about is an action applying to one person and one topic.

(Inform will understand that the “it” in the action name marks where the first noun belongs, so that we can write rules like “After list-asking the archer about something”.)

Next we define the command for this action.

Understand "ask [someone] about [text]" as list-asking it about.

And now we have a brand new action ready to have rules written about it.

But there’s no good reason I can think of to do all this, since the new “list-asking it about” action we’ve created is practically identical to the old “asking it about” action anyway. The only difference is that the default “asking it about” action comes with a check rule, the “block asking rule”. (This rule is the one that prints “There is no reply.”) If we don’t like that rule, we can easily get rid of it without going to the trouble of making a new action:

The block asking rule does nothing.

@Jrb the doors worked, but the way. So thanks! You are misunderstanding my second question. I have the table set up. I have the topics and the responses. What I want is for the player to try a command and for it to come up with the avalible topics so that the player knows what topics to ask.

Ah, sorry, my mistake. Something like this?

Carry out list-asking: 
	let N be the number of rows in the Table of Archer Responses;
	if N is 0:
		say "There is nothing to ask about.";
	otherwise:
		say "You could ask about ";
		repeat with X running from 1 to N minus 1:
			say  "[index in row X of the Table of Archer Responses][if N is greater than 2],[end if] ";
		if N is greater than 1: 
			say "or ";
		say "[index in row N of the Table of Archer Responses]."
	

Table of Archer Responses
Topic	Response	Index
"Werewolf/Werewolves"	"I hate them."	"werewolves"
"Bananas" 	"I eat them."	"bananas"

(more complicated than it needs to be perhaps, but you might want the number of rows in the table to vary.)

The “index” column is there because the “topic” column is special; the entries have the kind “topic” rather than “text” and can’t be printed directly.

@jrb that worked! And I don’t mind complex, especially in this scenario. If it works, it works. And it does! Thanks so much once again!

@jrb I need your help again! I am now trying to have a second character (White werewolf) for speech. However, my list-asking action is now clashing. I have this check rule:

Check list-asking:
if the noun is not the Archer, say “You cannot ask any questions” instead.

Which is great but then you can’t list topics of the White werewolf (and the other werewolves in the same room)

I tried this code but it didn’t want to know

(right under)

Check list-asking:
if the noun is not White Werewolf, say “You cannot ask questions” instead.

However this didn’t grant me anything.

When I take this rule out as well, it will display both the archer and the white werewolf topics.
Capture.PNG

You could write a check rule which covers all the cases. But probably the easiest way is to use instead rules to cover the cases you actually care about.

Check list-asking:
        say "You can't ask any questions."

Instead of list-asking the archer:
	let N be the number of rows in the Table of Archer Responses;
	if N is 0:
		say "There is nothing to ask about.";
	otherwise:
		say "You could ask about ";
		repeat with X running from 1 to N minus 1:
			say  "[index in row X of the Table of Archer Responses][if N is greater than 2],[end if] ";
		if N is greater than 1: 
			say "or ";
		say "[index in row N of the Table of Archer Responses]."

Instead of list-asking the white werewolf:
	let N be the number of rows in the Table of Werewolf Responses;
	if N is 0:
		say "There is nothing to ask about.";
	otherwise:
		say "You could ask about ";
		repeat with X running from 1 to N minus 1:
			say  "[index in row X of the Table of Werewolf Responses][if N is greater than 2],[end if] ";
		if N is greater than 1: 
			say "or ";
		say "[index in row N of the Table of Werewolf Responses]."

(Maybe there’s a straightforward way of rolling the two instead rules into one to avoid the repetition, but I don’t see it.)

The way I can think of would be something like this:

[code]A conversation partner is a kind of person. A conversation partner has a table name called the conversation table.

Instead of list-asking a conversation partner (called buddy):
let the current conversation table be the conversation table of the buddy;
let N be the number of rows in the current conversation table;
if N is 0:
say “There is nothing to ask about.”;
otherwise:
say "You could ask about ";
repeat with X running from 1 to N minus 1:
say "[index in row X of the current conversation table][if N is greater than 2],[end if] ";
if N is greater than 1:
say "or ";
say “[index in row N of the current conversation table].”[/code]

I’m not sure this counts as straightforward, though.

That’s exactly what I was after. I’d forgotten about “table name” variables.

I is now confused. Sorry, new to coding and slightly dumb ahaha.

Sorry! The point is that Inform has to be told somehow which table to consult for each person. In my code there’s a separate rule for each person. In matt w’s there’s only one rule, but every person carries round a table name variable which can be referred to.

A middle way would be something like this:

Instead of list-asking a person:
	if the noun is the archer:
		let T be the Table of Archer Responses;
		list options from T;
	otherwise if the noun is the white werewolf:
		let T be the Table of Werewolf Responses;
		list options from T;
	otherwise:
		say "You can't ask any questions."

To list options from (T - a table name):
	let N be the number of rows in T;
	if N is 0:
		say "There is nothing to ask about.";
	otherwise:
		say "You could ask about ";
		repeat with X running from 1 to N minus 1:
			say  "[index in row X of T][if N is greater than 2],[end if] ";
		if N is greater than 1: 
			say "or ";
		say "[index in row N of T]."

@jrb and @matt w thanks so much! This is now working, thanks to the middle code jrb put up! This is amazing, as it allows me to complete my first scene of this project I am doing.

I could probably work this out by myself but I am about to go to bed. I have my player bandaging (not using any health stuff, it’s just an action for text) and in the story the player has to bandage their wound. How could I have sleeping (of which I made an action called Player-sleeping because I couldn’t be asked to redefine Informs sleeping) be blocked until the player has bandaged.

Bandage action: Bandaging
Sleeping action: Player-Sleeping

Check player-sleeping when we have not bandaged:
      say "You can't sleep in this state!" instead.

Edit: I should mention, this might not work if your bandaging action doesn’t make it through all its rulebooks (i.e. if you cut it off with an instead rule.) In that case, you’d need to create a Boolean to track whether the player has bandaged.

Player-bandaged is a truth state that varies. Player-bandaged is false.
After bandaging:
      now player-bandaged is true.
Check player-sleeping when player-bandaged is false:
      say "Not in this state!"

By the way, all you’d have to do to use the built-in sleeping action is this:

The block sleeping rule does nothing.

You could always just model the bandages as a wearable thing. When someone is wearing bandages, they’d then count as bandaged, and the bandaging action would just make it more specific.

[rant]

The Outback is a room. "A desolate wasteland surrounds you on every side. Vultures patiently circle overhead, waiting for the rest of the wildlife to bring you down."

Some vultures are a scenery person in the Outback. The description of the vultures is "[if the player is wearing bandages]They look a bit put off[otherwise]Soaring on the updraft[end if]." Instead of doing something other than examining with the vultures, say "You give the vultures a [if the player wears the bandages]jaunty salute[otherwise]wave[end if]. '[if the player wears the bandages]Lucky bastard![run paragraph on][otherwise]Awright mate?[run paragraph on][end if]' comes the distant reply.[paragraph break] " 

A gaping wound is part of the player. The description is "[if the player is wearing bandages]It still feels raw and tender, but you reckon you can tough it out.[otherwise]The gash criss-crossing your torso is deep enough for you to see your own lunch. Crikey, that smarts![end if] ". Understand "gash" as the gaping wound.
Instead of doing something other than examining or bandaging with the gaping wound, say "[unless the player wears the bandages]That's a good way to get sepsis, kid.[otherwise]Don't fiddle with it, mate![end if] "

Some bandages are a wearable thing. 
The description of the bandages are "[if worn]Wrapped around your torso in a manly fashion[otherwise]It's a roll of clean bandages[end if]."
Instead of doing something other than examining with the worn bandages, try touching the gaping wound.
After wearing the bandages, say "You carefully unroll the spool of bandages and wrap it around your manly physique. There, much better."

Instead of taking off something, say "You don't really want to do that in this heat."

The description of the player is "You look like a million bucks[if the player wears the bandages]. If anything, the bandages just make you look more manly[otherwise]... oh, and you also have a gaping wound across your chest[end if]."

The player wears khakis and some Australian safety boots. The indefinite article of the safety boots is "a pair of".
The player carries the bandages and cheery optimism.
Before printing the name of the optimism while not taking inventory, say "your ".
Instead of doing something with cheery optimism, say "You can't really be [current action], mate, you were just born that way."
The description of the khakis is "Nice and stylish for a stroll."
The description of the boots is "Some might call them sandals, but what do they know?"

Bandaging is an action applying to one thing. Instead of bandaging the player, try bandaging the wound. Understand "bandage [something]" as bandaging.
Check bandaging something which is not the wound: say "You have better things to do, mate." instead.
Instead of bandaging when the player wears bandages: try touching the wound instead.
Check bandaging when the player does not carry the bandages: say "You have nothing to bandage with." instead.
Carry out bandaging the wound:
	try the player wearing the bandages.

Definition: a person is wounded if it incorporates the gaping wound.

Instead of sleeping when the player is wounded and the player is not wearing bandages: say "Naw mate, all the blood would attract the dingos."

Instead of sleeping: 
	say "You fall into a deep slumber.";
	end the story.

[/rant]