Using Neutral Language - ThePix/QuestJS GitHub Wiki

Often when creating a text adventure you will find you do not know what you are talking about! This is often the case with a command. Let us suppose we have an ATTACK command. In the command’s script, you have an object the player wants to attack, but what is it? It could be any item in your game!

You need your command to work - and the resultant text to read properly - whether the user did ATTACK ZOMBIE, ATTACK CROWD or ATTACK MARY - and even then we are assuming the script has already decided this is something you can attack. If the response is “You attack it. It looks angry.” for all three, the user will not be impressed. We need to make our response language neutral.

A Note About Pronouns

By default, items in QuestJS are referred to as "it", NPCs as "he" or "she" (depending on whether you use NPC(false) or NPC(true)) and the player as "you", but you can easily change any of them as it suits you by setting the "pronoun" attribute of the object.

It needs to be set to a dictionary that contains all the various forms of the pronouns. Here is an example:

pronouns:{
  subjective:"I",
  objective:"me", 
  possPro: "mine", 
  possAdj: "my", 
  reflexive:"myself", 
  handleAs:'me',
},

In fact, all the standard ones are built-in to Quest 6, so we can instead do this:

pronouns:lang.pronouns.firstperson,

Here is the full list (and I appreciate it is not comprehensive).

lang.pronouns.firstperson
lang.pronouns.secondperson
lang.pronouns.thirdperson
lang.pronouns.massnoun
lang.pronouns.male
lang.pronouns.female
lang.pronouns.nonbinary
lang.pronouns.neNem
lang.pronouns.veVer
lang.pronouns.spivak
lang.pronouns.xeXem
lang.pronouns.perPer
lang.pronouns.zeHir
lang.pronouns.zheZhir
lang.pronouns.zeZem
lang.pronouns.faeFaer
lang.pronouns.aeAer
lang.pronouns.plural

Some examples

This first example is set to use "they":

createItem("boots", WEARABLE(),{
   loc:"lounge",
   pronouns:lang.pronouns.plural,
   examine:"Some old boots.",
})

A mass noun is something that is a little odd; the pronouns are the same as third person singular, but it does not use "a" or "an" for the indefinite article.

createItem("underwear", WEARABLE(1, ["lower"]), { 
  loc:"bedroom",
  pronouns:lang.pronouns.massnoun,
  examine:"Clean!",
})

Here is a "non-binary" character who prefers to be referred to as "they". Note that the reflexive is "themself" and verb conjugation will be as for the third person singular.

createItem("Leslie", NPC(),{
  loc:"lounge",
  properName:true, 
  pronouns:lang.pronouns.nonbinary,
  examine:"They looks happy to see you.",
})

Adding further pronoun sets

You can add additional pronoun sets by adding to the lang.prounouns dictionary.

lang.prounouns.xheXhir =  {
  subjective:"xhe",
  objective:"xhim",
  possAdj: "xher",
  possPro: "xhers",
  reflexive:"xhimself",
  handleAs:'it',
}

The "handleAs" attribute will cause verbs to be conjugated as they would for "it".

Changing pronouns during play

Because of how QuestJS saves games, you have to use the "changePronouns" function to change the pronouns of an NPC (or indeed any item) while the game is underway.

  w.Kyle.changePronouns(lang.pronouns.female)

Changing the player to first or third person

Traditionally interactive fiction uses the second person ("you"), but literature uses first person ("I") or more commonly third person ("he or "she"). By default QuestJS follows the standard convention, using the second person, but you can change that in exactly the same way as above.

createItem("Buddy", PLAYER(),{
  loc:"lounge",
  properName:true, 
  pronouns:lang.pronouns.thirdperson,
  examine:"Looking good!",
})

You should also change the room template. For example.

settings.roomTemplate = [
  "#{cap:{hereName}}",
  "{terse:{hereDesc}}",
  "{objectsHere:She can see {objects} here.}",
]

Responses

With that out of the way, we can now look at how to give our commands language-neutral responses.

We can set the response to:

"You attack " + object.pronouns.subjective + "; " + object.pronouns.objective + " look angry.”

Now if the player attacks the crowd, she will see "You attack them; they look angry."

Names

When you want to refer to an object’s name, use the "lang.getName" function, which will sort out exactly what it should be called, according to the options you give it. The most important option is "article", which can be "DEFINITE", to have "the" added, or INDEFINITE, to have "a" added - but only if appropriate for the object.

To illustrate, here are three objects.

Name teapot shoes Zoe
alias Zoë
pronouns thirdperson plural female
INDEFINITE a teapot some shoes Zoë
DEFINITE the teapot the shoes Zoë

So back to attacking the crowd and Mary, we can now do this:

"You can see " + lang.getName(object, {article:INDEFINITE}) + "."
-> You can see a crowd.
-> You can see Mary.

"You attack " + lang.getName(object, {article:DEFINITE}) + ". " + object.gender + " look angry."
-> You attack the crowd. they look angry.
-> You attack Mary. she look angry.

Capitalisation

We need a capital at the start of the second sentence. We can use the sentenceCase function.

"You attack " + lang.getName(object, {article:DEFINITE}) + ". " + sentenceCase(object.gender) + " look angry."
-> You attack the crowd. They look angry.
-> You attack Mary. She look angry.

Conjugation

We also need to conjugate the verb so it is of the correct form. Quest has the lang.conjugate function for that, it takes the object that is doing the verb, followed by the verb as a string (use "be" for the verb "to be", by the way).

"You attack " + lang.getName(object, {article:DEFINITE}) + ". " + sentenceCase(object.gender) + " " + lang.conjugate(object, look) + " angry."
-> You attack the crowd. They look angry.
-> You attack Mary. She looks angry.

Because we often want to start a sentence with the object doing the verb, Quest has a lang.pronounVerb function that will get the gender of the object and add the conjugated verb. Setting the third parameter to true capitalises the phrase for us.

"You attack " + lang.getName(object, {article:DEFINITE}) + ". " + lang.pronounVerb(object, "look", true) + " angry."

Using Text Processor Directives

Having said all that, a better way - in my opinion - is to use the text processor. So why did I bother writing all that? Well, the text processor uses those same constructs in the background, and I think it is easier to understand the directives if we work our way to them slowly.

Here is what it looks like:

"You attack {nm:object:the}. {pv:object:look:true} angry."

The first directive is "nm", which inserts the object's name, with the option "the". The second directive is "pv", which inserts the pronoun and verb, and requires the object, the verb (in the infinitive form). Both of these optionally take "true" as a last parameter if we want it capitalised.

More details here; there are a lot of directives available to hopefully cover all eventualities.

For this to work, you need to send the text processor some parameters - it needs to know what the object is. This is done as a dictionary of name-value pairs, and can be done in the msg command. There is only one entry in this case, but you can have as many as you like:

msg("You attack {nm:object:the}. {pv:object:look:true} angry.", {object:object})

Sometimes it is more convenient to set up the params at the start of the command script, so it can be used in several responses. Numerous built-in commands do this:

const tpParams = {object:object}
msg("You attack {nm:object:the}. {pv:object:look:true} angry.", tpParams)

A note about conjugation

The verb "to be" is a bit odd in English in that the conjugated forms are very different. You may be tempted to do this:

msg("{nv:object:is:true} carrying a rabbit.", {object:object})

Quest is going to see "is" and conjugate it as a regular verb, and you will get something like "Mary isses carrying a rabbit." You need the infinitive form, i.e., "be" for this to work properly.

msg("{nv:object:be:true} carrying a rabbit.", {object:object})

You can use an apostrophe to indicate you want a verbal contraction. This example will give "She's carrying a rabbit.".

msg("{pv:object:'be:true} carrying a rabbit.", {object:object})