Best way to handle prefix's

So I have the ability for the end user to name enemies they can encounter during the adventure.
This does however throw a small can of worms into the mix though as that can range from a general creature, to a specific person.

At the moment my descriptions are written under the assumption of general creature.
So an enemy encounter might look like:

“Ahead, you see a [giant spider] that starts walking towards you.”
“You hit the [Giant Spider] with your axe.”

[Giant Spider] being what the user called that monster.

That sentence doesn’t read well however if they get specific.

“Ahead, you see a [Godzilla] that starts walking towards you.”
“You hit the [Godzilla] with your axe.”

In that case, there should be no prefix.
I could have the user specify if the thing should have a prefix when they enter it, but i’m just wondering if there’s a way to try and interpret if there should/shouldn’t be an “a” or “the” before a name.

For example, although not fool proof, detecting an ‘s’ at the end of a name COULD (not always) mean it’s plural.

I wonder if there’s something like that for names and prefix’s.
But i’d imagine this is harder to get right.
A name could be anything…how do you distinguish “Vampire” from “Dracula”?
You see A Vampire. You hit THE Vampire
You see Dracula. You hit Dracula.

See WWI 7.10 The noun and the second noun.

The issue is this isn’t a case of a person or a thing.
This is the case of a thing being named a person.
Part of the problem of allowing customisability is predicting how it could be used.

If a fork is renamed to ‘forkie’ it’s still a fork.
But in this case, if the player was to then find it, the text should read:
“In the drawer, you see Forkie.”

Can inform detect that or will I just need to ask the user if what they entered is a name rather than a thing.

You might find it easier to understand some of the documentation if you note that it uses the grammatical term “article,” not “prefix” (which, in grammatical contexts, really means a part of the word at the beginning of the word, not a separate word that comes before it: -fix means “attached to”).

You’re actually conflating two different things here: how Inform will print the names of objects, and what text in player commands Inform’s parser will understand as referring to that object.

To handle the printed names of objects, you can use the printed name property in constructions like now the printed name of the vampire is "Dracula". You might also need to say now the vampire is proper-named to avoid having Inform print the Dracula in various places – this depends on exactly how you’re coding your say phrases, though.

So if you write a phrase like

say "You drive your ash stake through [the vampire]'s chest!".

the the is part of the text substitution, because it appears inside the brackets, and Inform will drop it when evaluating that text substitution if the noun it describes is proper-named; so you’ll get outputs like

You drive your stake through the vampire's chest!
You drive your stake through Dracula's chest!

Inform knows to drop the the from the second phrase because (a) you put that the inside the brackets, to make it part of the text substitution, and (b) the vampire is proper-named, so it gets the relevant article-dropping handling.

But if your say phrase looks like

say "You drive your ash stake through the [vampire]'s chest!".

Then the the there isn’t inside the brackets, and not part of the text substitution; Inform will always print it, because it always prints everything inside a string but not inside text-substitution brackets exactly as you typed it. Inform won’t know to drop the the unless you make it part of the substitution.

If what you’re doing when the player renames something is just changing its printed name property, then you should be able to get that working, I think (though I haven’t tested this) by saying

Understand the printed name property as describing a thing.

Words like “the” are called indefinite articles (EDIT: articles, which can be definite or indefinite). The Inform 7 property that determines whether something is printed with an article is “proper-named.” So if you want an object to be referred to as “Forkie” instead of “the Forkie” you could write the following code:

After renaming: now the noun is proper-named.

The actual logic for deciding whether something should be proper-named or not is a little more finicky. The foolproof way to do this is to just ask the player directly, perhaps with a yes or no prompt:

After renaming:
    say "Is '[the text understood]' a proper name? >";
    if the player consents:
        now the noun is proper-named;
    otherwise:
        now the noun is improper-named.

So in my case, I have given the monster’s generic ‘code names’ when defining them.

Monster1 is a monster.

The player gives them names via a command prompt.

Now the printed name of Monster1 is the player’s command;

so proper-named sounds like what I need.
Is it then enough to make each monster proper-named when defined?

It all depends on your desired behavior. If you telegraph to the player that they should be using proper names like Fred and Forkie, that’s what they are likely to try, and so it would make sense for all named monsters to be proper-named. But if you cast the player as an explorer naming new species like “the blue monkey-spider” that rule may not make sense.

well in this case, both are the correct choice.

The player is choosing what monsters they wish to encounter during their play session.
That could be a Giant Walrus…but it could also be Freddy Krueger.

So whatever they type, unless there’s a way to detect if that should be a proper name then i will have to ask after.

After renaming:
    say "Is '[the text understood]' a proper name? >";
    if the player consents:
        now the noun is proper-named;
    otherwise:
        now the noun is improper-named.

On a side note, I think I just learnt something new and useful.

I’ve been handling Yes/No’s with:

After Reading a command when prompt is “Y/N”…
And then checking if the command matches “yes” or “no” lol

I wish I knew about “if the player consents” before just now lol should help reduce some of my code.

1 Like

Sure! If everything is going to be proper-named from the beginning, no need to switch it on or off.

It sounds to me like having monsters named by taking the whole command might be cumbersome, so you might get some mileage out of understand phrases here, too, along with creating a new kind of action. So this might work:

A monster is a kind of animal.
Renaming it to is an action applying to one visible thing and one topic. Understand "name [a monster] as [text]" as renaming it to.
Carry out renaming it to:
	now the printed name of the noun is the topic understood.

This avoids needing to set up all monsters at the beginning and allows the player to rename monsters at will when s/he can see them, though that may not be what you want. But it all depends on exactly how you want things to work.

There is no good way to determine whether something ‘should be a proper name’; even humans do a poor job of performing this task outside of their own cultural backgrounds. (Can you tell whether words, from, say, Maori, or Cherokee, or Japanese are proper or improper nouns? Would you recognize Big Giant Head as the name of a specific individual if you’d never watched Third Rock from the Sun?)

You might get some mileage, though, out of just scanning for whether the player’s entry starts with “a” or “the”; though that might not pay off for everyone. It’s hard to say without trying it.

hmm…you’ve got me thinking.

I might go about this in reverse.
Assume a proper-name, but instruct them when naming to use “a” before if it’s simply the descriptive name of a noun, or whatever you call it, so “a skeleton”.

I could then do a string search later for “a” at the start although I shouldn’t need to because if they type “a skeleton” then [the noun] will write that.
if they write “Freddy” [the noun] will write that.

So my say’s can just assume proper-named things:
“Ahead, you see [the noun]”.

thinking about it, I would need to check if there’s an "a " in the name in order to print “the” at relevant times instead.

if they type “a skeleton” then [the noun] will write that.

Well. Depending on exactly what you’re doing, Inform might say the a skeleton instead, which is probably not desirable.

The basic problem is that Inform pre-processes the user’s command in various ways, and it’s difficult (maybe impossible?) to just get the entire text exactly as the user entered it.

A related problem that you may run into: is Inform pre-processing capitalization in a way that harms you? Will you wind up getting output like you drive the ash stake into dracula's chest?

All that being said, scanning for a (or an), followed by a space, at the beginning of the player’s entry might be a decently good heuristic.

You might also look at Michael Callaghan’s Questions extension: I haven’t used it, but it might be a decent way to get away from using the normal parsing mechanisms while asking the user questions.

To be pedantic, ‘the’ in English is the definite article. That’s not entirely pedantry, because in Inform you can supply an indefinite article for an object to use instead of a/an/some. ‘The indefinite article of an object’ will if defined substitute for a/an/some in contexts where Inform would otherwise use the appropriate one of these default indefinite articles, but it won’t affect the use of ‘the’.

In English, proper names take neither definite or indefinite articles. They are also usually distinguishable by being capitalised even when not starting a sentence. Unfortunately, Inform routinely switches the player’s input entirely to lower case immediately after it is read in, so to allow the player to indicate proper names by capitalisation would require an I6-level hack.

There is certainly no way to determine whether a word is a proper name just from the letters of the word itself, so there is no easy alternative but to ask the player directly if it’s a proper name, or ask them to use a/an/some before the name if it’s not. You’ll want to strip away the a/an/some from the input name before allocating it to the printed name of your object so that you don’t get duplicate articles in places where Inform would naturally insert one before the name of an object.

2 Likes

There are many challenges to be faced on this path. As @patrick_mooney pointed out, it’s best to take advantage of what you can by using the built-in say phrases that handle article and proper names. Even so, that just shifts your need to getting the various grammar settings for the monster set correctly.

Irregular plurals in English and assorted bits of common knowledge both add difficulty. You may find some use in the built-in regular expression matching features. Here’s a brief attempt at the basics of guessing automatically, but it will be far from perfect.

Sample Code
”Naming Names”

Place is a room.

A monster is a kind of thing.

A monster called a generic monster is in Place.

To name (X - thing) to (T - text): [graft this into your code as appropriate]
	[change printed name]
	now the printed name of X is T;
	let keep initial article flag be false;
	[reset default grammar properties]
	now X is improper-named; 
	now X is singular-named;
	now the indefinite article of X is "";
	let given name be the printed name of X; [see WWI 20.6 Regular expression matching for the following]
	if given name matches the regular expression "^<A-Z>.*": [capitalized name]
		now X is proper-named;
	if given name matches the regular expression "^The (<A-Z>.*)":
		now X is proper-named;
		now keep initial article flag is true;
	if given name matches the regular expression "^<Ss>ome (.*)":
		now the indefinite article of X is "some";
	if given name matches the regular expression ".*s$":
		now X is plural-named;
	if (given name matches the regular expression "^<Aa> (.*)" or
		given name matches the regular expression "^<Ss>ome (.*)" or
		given name matches the regular expression "^<Tt>he (.*)") and
		keep initial article flag is false:
		now the printed name of X is the text matching subexpression 1.

Name selector is initially 1.

After jumping:
	if name selector is:
		-- 1: name generic monster to "Dracula";
		-- 2: name generic monster to "a gremlin";
		-- 3: name generic monster to "some rabid squirrels";
		-- 4: name generic monster to "the shadows";
		-- 5: name generic monster to "The Justice League";
		-- 6: name generic monster to "The Replacements";
		-- 7: name generic monster to "tiny monkeys";
		-- 8: name generic monster to "some pistachio mint pudding";
		-- 9: name generic monster to "oxen"; [English is a poor choice of language for this exercise!]
		-- otherwise: name generic monster to "thorny natural language issues";
	increment name selector;
	say "Name changed."

Test me with "l / showme monster / jump / l / showme monster / jump / l / showme monster / jump / l / showme monster / jump / l / showme monster /  jump / l / showme monster / jump / l / showme monster / jump / l / showme monster / jump / l / showme monster / jump / l / showme monster / jump / l / showme monster". 

If you’re hoping that the player will draw on pop culture when naming the monster, you might be better off just building a library of famous monsters, give them plenty of variant names, and allow them to be summoned by the naming command.

1 Like

This works for your source-generated list of monsters, but commands entered at the prompt by the player will uniformly have all capitals converted to lower-case as they are processed and added to the parse array. So this will only stand a chance of working via a custom text-input routine separate to the usual ‘parse command’ rule. perhaps via 'Rule for reading a command when… ’ This would involve using some arcane I6 VM machine code hackery, since even the I6 command ‘read’ renders all input to lower case.

1 Like

That doesn’t seem to be the case. The topic understood preserves any capital letters entered (though this is not apparent when using the >TEST functionality). So a command that makes use of the topic understood can do a straightforward reassignment.

A more formal prompt can be done with I6 hackery, too, if preferred.

>rename monster to The Justice League
Now the monster is The Justice League.

>look
Place
You can see The Justice League here.

>moniker
ENTER NAME: Dracula
CAPTURED: Dracula
OK.

>look
Place
You can see Dracula here.

Example code follows.

Naming Names II: Revenge of the Interface
”Naming Names II: Revenge of the Interface”

Place is a room.

A monster is a kind of thing.

A monster called a generic monster is in Place.

To name (X - thing) to (T - text): [graft this into your code as appropriate]
    [change printed name]
    now the printed name of X is T;
    let keep initial article flag be false;
    [reset default grammar properties]
    now X is improper-named; 
    now X is singular-named;
    now the indefinite article of X is "";
    let given name be the printed name of X; [see WWI 20.6 Regular expression matching for the following]
    if given name matches the regular expression "^<A-Z>.*": [capitalized name]
	    now X is proper-named;
    if given name matches the regular expression "^The (<A-Z>.*)":
	    now X is proper-named;
	    now keep initial article flag is true;
    if given name matches the regular expression "^<Ss>ome (.*)":
	    now the indefinite article of X is "some";
    if given name matches the regular expression ".*s$":
	    now X is plural-named;
    if (given name matches the regular expression "^<Aa> (.*)" or
	    given name matches the regular expression "^<Ss>ome (.*)" or
	    given name matches the regular expression "^<Tt>he (.*)") and
	    keep initial article flag is false:
	    now the printed name of X is the text matching subexpression 1.

To capture text accurately:
    (- CaptureTrueText(); -).

To say captured text:
    (- PrintTrueText(); -).

Renaming it to is an action applying to one thing and one topic. Understand "rename [something] to [text]" as renaming it to.

Carry out renaming something to:
    name noun to the substituted form of "[topic understood]".

Report renaming something to:
    say "Now the monster is [a noun]."


Name entry prompt is initially "ENTER NAME: ".

Try entry again message is initially "[line break](I can't handle backspaces, so please try again.)[paragraph break][name entry prompt]".


Difficult renaming is an action applying to one topic. Understand "moniker" as difficult renaming.

Carry out difficult renaming:
    say "[name entry prompt]";
    capture text accurately;
    say "[line break]CAPTURED: [captured text]";
    let given name be the substituted form of "[captured text]";
    name generic monster to given name.

Report difficult renaming:
    say "OK."

Include
(-

Array true_input buffer 128;

[ WaitForKey kp ;
    kp = VM_KeyChar();
    return kp;
];

[ IsNonTerminating chr   tc i ;
    if (chr == 13 or 10) rfalse; ! disallow enter
    tc = $2E-->0; ! this line corrected since original post
    while (tc->i++ ~= 0)
        if (chr == tc->i) rfalse;
    rtrue;
];

[ IsAllowed chr ;
    if ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z') || (chr == ' ' or '-'))
        rtrue;
    rfalse;
];

[ CaptureTrueText   chr i ;
    .Retry;
    while (true) {
        chr = WaitForKey();
        ! print "<chr ", i, ": ", chr, ">";
        if (chr ~= 0 && IsNonTerminating(chr) && IsAllowed(chr)) {
                print (char) chr;
                true_input->((i++)+WORDSIZE) = chr;
        }
        else
            break;
    }
    if (chr == 8 or -7) { ! backspace 
        print (TEXT_TY_Say) (+ try entry again message +);
        i = 0;
        jump Retry;
     }
    true_input->(i+WORDSIZE) = 0;
    true_input-->0 = i;
];

[ PrintTrueText   i ;
    while (i < true_input-->0)
        print (char) true_input->((i++)+WORDSIZE);
];


-).

Test difficult with "moniker / l / moniker / l / moniker / l".

Test easy with "this looks like capitals don't work but try typing the commands in manually / rename monster to vampire / rename monster to Dracula / rename monster to a gremlin / rename monster to some rabid squirrels / rename monster to the shadows / rename monster to The Justice League / rename monster to The Replacements / rename monster to Will Ferrel / rename monster to tiny monkeys / rename monster to some pistachio mint pudding / rename monster to oxen / rename monster to thorny natural language issues".  [Capitals are not preserved when using >TEST functionality but these commands work as expected if actually typed in.]
2 Likes

This varies with VM. The Z-machine lowercases the input line in “hardware”, so topic understood is necessarily lowercase. Glulx preserves the case in the input buffer (and topic understood); it case-folds in the next step, when tokenizing.

2 Likes

Aha! That’s good to know. I can confirm that Otistdog’s code works as (now) expected: ‘difficult renaming’ via machine-code per-character entry allowing capitals to be captured in both Z-machine and glulx, while ‘easy renaming’ via line entry and ‘the topic understood’ allows capitals in glulx but not in Z-machine :grinning:

1 Like