From chat: Letting the player name things in I7

Originally sent in LabBarAtory
pinkunz

My thought was this. If you can save world states to a table, could you have the player "name" an action, like let's say a magic spell, and have that name recorded into the table?

Like, let's say you capture an evil sprite in a bottle and you assert control by naming it. The player literally uses whatever name the want, which is saved into the table, and they can then summon the sprite to do their bidding at any point by using their name.

ArdiMaster

Perhaps I'm misunderstanding your intent here, but I feel like this should be covered by the "understanding things by their properties" mechanism...

pinkunz

But those properties are assigned by the author, not the player, no?

ArdiMaster

Not necessarily. You can put a text property and have some action that assigns it from the player's command and it will work

pinkunz

Is there an example of this in the Inform Recipe book?

Or anywhere, for that matter. I'm not picky.

Here you go @pinkunz (broken out into a forum thread for readability and for the benefit of anyone who might be interested:

"Testing Project" by Adrian

The lab is a room. "Bubbling retorts, that sort of thing."

The genie is in the lab.
The genie has some text called the given name.
Understand the given name property as describing the genie.

Genie-naming is a truth state that varies. Genie-naming is initially false.

When play begins:
	now the command prompt is "What shall be the name of your genie? >";
	now genie-naming is true.
	
After reading a command when genie-naming is true:
	let N be the substituted form of "[the player's command]";
	now the given name of the genie is N;
	now genie-naming is false;
	now the command prompt is ">";
	say "The genie shall be known as [N].";
	reject the player's command.

Produces:

lab
Bubbling retorts, that sort of thing.

You can see a genie here.

What shall be the name of your genie? >Bob
The genie shall be known as Bob.

>x bob
You see nothing special about the genie.

8 Likes

A technique famously used by the featureless white cubes in Spellbreaker, which you can write names on to keep them distinct. (Though of course that wasn’t in Inform 7.)

A cube is a kind of thing.
A cube has some text called the label.
Understand the label property as describing a cube.

And now you can label all your cubes differently if you like.

4 Likes

I actually took inspiration from the Spellbreaker approach and wrote up a take on this prompt that implemented a labeling action in some depth - cool that you did the asking-the-player approach!

3 Likes

Thank you, Adrian. I sincerely appreciate you writing that example for me. Would it be appropriate to ask a couple of questions?

I’m assuming the standard save function will retain these names. If you were using a non-standard save function, similar to Ryan Veeder’s custom save functions, how would this substitution of N best be saved?

( What are your thoughts on Organisation for Sandbox Style Gaming? - #6 by pinkunz )

Also, can you use this with a verb? Like let’s say you capture a water druid and gain power over it by naming it, meaning you can summon it by uttering it’s name, causing the focus of your attention to be inundated with water.

let N be the substituted form of “[the player’s command]”;
now the given name of water-druid-summoning is N;

1 Like

If you’re using an action applying to a topic (like WRITE BANANA ON CUBE), you can use [the topic understood] instead of [the player’s command] to get the part matched by a [text] token.

4 Likes

I’m assuming the standard save function will retain these names

Yes. The standard save function basically takes a snapshot of the VM’s memory, so this is included. (That’s also why regular save files are not at all portable between releases.)

If you were using a non-standard save function, similar to Ryan Veeder’s custom save functions, how would this substitution of N best be saved?

If you’re using this sort of save functionality, you probably already have a table that saves key-value-pairs of text. So you’d just have to come up with a new key to store this under. At the time the genie’s name is set, you also set the corresponding entry in the save data table. When you load this data back, it’s just one more value to restore.

3 Likes

Thank you both!

2 Likes

Saving custom texts with these external file-based save functions is covered in this blog post (but let me know if that post is missing anything important).

Letting the player name things is documented pretty well—there’s this example in the I7 documentation, there’s @DeusIrae’s example in the other thread, there’s the example in that blog post I already linked (which includes splitting up names so the parser will recognize individual words). But I find my brain to be very tickled by a sentence at the very beginning of this thread:

could you have the player “name” an action, like let’s say a magic spell, and have that name recorded into the table?
@pinkunz

To me this implies a game that works like this:

As long as you hold this magic scroll, you can give a name to your signature spell.

>NAME SPELL SMARGUS

Okay, your signature spell is Smargus! Have fun!

>SMARGUS

You cast the mighty spell of Smargus! The enemy crumbles before you!

But I can’t figure out how to name actions! I can’t do An action has a text called the custom-name. because actions can’t have properties. Is there a way around this? I don’t know.

Maybe I could satisfy myself with a custom argument for the >CAST action. I could >NAME FIREBALL FANTASTIC FIREBLITZ, and then the parser would know when I >CAST FANTASTIC FIREBLITZ it should treat that as >CAST FIREBALL.

Well,

A spell is a kind of value.
Fireball is a spell.
A spell has text called the custom name.
Understand the custom name property as describing a spell.

This doesn’t compile, because “a property can be understood as referring to a single object (or a kind of object) but not to something of any other kind.” So am I stuck?

(If I treat a spell as a kind of thing—which is not very satisfying–assigning a custom name works okay, but then I run into an unrelated issue where I can’t cast a spell that isn’t physically present, despite defining Understand "cast [any thing]" as casting. Has [any thing] been nerfed?)

1 Like

You may have defined the casting action as applying to “one thing”, which actually means one touchable thing. You have to use “one visible thing” to mean one thing that’s not necessarily touchable. This is, in my opinion, the single biggest issue with Inform’s terminology and the one I most hope gets fixed.

You can also make your spells be a special kind of object, if you don’t want them to be treated as “things”, but in practice this usually isn’t an issue. It’s mostly important if you need to avoid them getting caught up by [any thing] actions (say, if you have a lot of actions like GO TO and don’t want to write special rules for each one to prevent using them on spells).

1 Like

Thank you. I may have understood this “one visible thing” nonsense at some point and it slipped my mind. But not once have I ever had to care about the distinction between ‘thing’ and ‘object’!

1 Like

Things live in the world – they can be placed in a room, carried, contained, supported, etc. Objects have no location.

(This is not a rigid rule but it’s the simplest way to think about it.)

2 Likes

This is indeed the implementation I was imagining from the moment it was brought up in chat. I would imagine this would be fun to flesh out as the core mechanic of a game if I understood how to make it work. Thank you for articulating my thoughts better than I did.

2 Likes

This can be done without a lot of code…

(I cut corners and just made spell a kind of thing that’s either unnamed or named.)

5 Likes

I’m stealing both of these code examples (with credit to the authors) for the Handbook. Thanks, guys!

4 Likes

Note that ‘verbless grammar’ (i.e. 'Understand ... phrases that start with a [token in square brackets] rather than a verb word) is still not fully supported in Inform 10.1.2.

The bug in 9.3/6M62 that led to incorrect allocation of topic snippets after commands such as ‘Darcy, hello’ (see here) when a story included any verbless grammar has been fixed in 10.1.2, but it remains the case that if you have a word that is both a true recognised verb word and also a word that is recognised by your ‘verbless grammar’ token, the parser will try to parse it only as a true verb word and never as a match to the ‘verbless grammar’ token (see also here).

In this instance, if you name your spell as a word that is already a true recognised verb word, your spell will never fire because the parser gives up after having failed to match a correct grammar line to the recognised verb word without then going on to consider the possibility of matching to ‘verbless grammar’.

e.g.

Lab
 
>name spell answer
You name your spell Answer.
 
>answer
I didn't understand that sentence.
4 Likes

OK, so we’ll block existing command verbs and pseudo-verbs.

use DICT_WORD_SIZE of 15.

To say again-word: (- Glulx_PrintAnything(AGAIN1__WD); -).
To say again-alias: (- Glulx_PrintAnything(AGAIN2__WD); -).
To say oops-word: (- Glulx_PrintAnything(OOPS1__WD); -).
To say oops-alias: (- Glulx_PrintAnything(OOPS2__WD); -).
To say undo-word: (- Glulx_PrintAnything(UNDO1__WD); -).

Include (-
! 1-indexed for I7's convenience
[ printDictWord i;
print (address) #dictionary_table + WORDSIZE + ((i-1) * (DICT_WORD_SIZE + 7));
];
-)

To say dictionary entry (n - a number): (- printDictWord({n}); -)

To decide what number is the dictionary size: (- #dictionary_table-->0 -)

The dictionary list is a list of texts variable.

To build the dictionary list:
  if the dictionary list is empty begin;
    add the substituted form of "[again-word]" to dictionary list;
    add the substituted form of "[again-alias]" to dictionary list;
    add the substituted form of "[oops-word]" to dictionary list;
    add the substituted form of "[oops-alias]" to dictionary list;
    add the substituted form of "[undo-word]" to dictionary list;
    repeat with i running from 1 to the dictionary size begin;
      add the substituted form of "[dictionary entry i]" to dictionary list;
    end repeat;
  end if;

when play begins:
  build the dictionary list;

Last check naming something:
	if word number 1 in "[the topic understood]" is listed in the dictionary list, instead say "Try something a little more original and distinctive, wizard."

It’s that easy! In 6M62, at least. In 10.1, for your convenience, you can’t compile an inclusion using #dictionary_table and would have to write a kit.

4 Likes

Neat! I would have thought that you don’t need to build a copy of and exclude the whole dictionary- only those words flagged in the dictionary as being verb words?

1 Like

I suppose you don’t. But I’m still a bull in the parser’s china shop, so what’s a good way to get just the command verbs? (And don’t skimp on the directions and their abbreviations as pseudo-commands of interest!)

1 Like

Include (-
[ PrintCommandWords wd i j dictlen entrylen entry;
    dictlen = #dictionary_table-->0;
    entrylen = DICT_WORD_SIZE + 7;
    for (j=0 : j<dictlen: j++ ) {
        wd = #dictionary_table + WORDSIZE + entrylen*j; 
        entry = DictionaryWordToVerbNum(wd);
         if ((entry >= 0) && (entry < dictlen))
            print (address) wd, "^";
    }
];
-)



To say command words: (- PrintCommandWords(); -)

The dictionary list is a list of texts variable.

To decide what text is the expanded (T - a text) (this is expanded-text): decide on the substituted form of T.

To build the dictionary list:
  if the dictionary list is empty begin;
    now the dictionary list is { "[again-word]", "[again-alias]", "[oops-word]", "[oops-alias]", "[undo-word]" };
   repeat with dir running through the directions begin;
      add the substituted form of "[dir]" to dictionary list;
   end repeat;
   now dictionary list is expanded-text applied to dictionary list;
   let wordlist be the substituted form of "[command words]";
   repeat with i running from 1 to (the number of lines in wordlist) begin;
      add line number i in wordlist to dictionary list;
   end repeat;
   sort the dictionary list;
  end if;

lab is a room.

when play begins: build the dictionary list; say the dictionary list

Still need to get the direction abbreviations.

1 Like

A dictionary entry in Inform-generated code consists of the word itself, followed by three bytes of data. Bit 0 of byte 1 is set if the word can be used as a verb. I’m not sure if there’s a portable way to access this, though; you might have to write it differently for Z-machine and Glulx (since the word is stored differently in each).

2 Likes