Character/Player Pronouns using Custom Text Tags

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
Catt_
Newbie
Posts: 1
Joined: Mon Jan 29, 2024 9:33 am
Contact:

Character/Player Pronouns using Custom Text Tags

#1 Post by Catt_ »

I've been tinkering around with implementing variable pronouns for the last few days, and I've come up with a method that I think is worth sharing.

In the following example, character gender is determined by an integer value of 1, 2, or 3, corresponding to male, female, or nonbinary. You don't have to use these values or this order, just adjust the wording within your text tag and its function.

In the raw story text, the custom text tag looks like this:

Code: Select all

label start:
	"""
	{pr=pov1_He|She|They} walked down the road.
	
	{pr=pov2_He|She|They} walked down the road.
	
	{pr=pov3_He|She|They} walked down the road.
	"""
This is important to see before the text tag function itself as it will help explain what everything is doing. When implemented, this would be at the bottom of your file.

I store my variable characters' information in a nested dictionary structure. This is a personal preference thing, but it does mean everything is in one place ready to search and return information when necessary. In order for my code to work as intended without adjustment, you will need to use a similar system:

Code: Select all

init python:
	vch_m = {
		"vch_001" : {
			"tag_code" : "pov1",
			"gender" : 1
		},
		"vch_002" : {
			"tag_code" : "pov2",
			"gender" : 2
		},
		"vch_003" : {
			"tag_code" : "pov3",
			"gender" : 3
		}		
	}

And last but not least, the text tag function that determines how the tag works:

Code: Select all

init python:
	config.self_closing_custom_text_tags["pr"] = pron_tag
	
	def pron_tag(tag, argument):
	        a = argument.split("_") 
	        x = a[0]
	        y = a[1]
	        z = y.split("|")
	        for e in vch_m:
			for ie in vch_m[e]:
				if (vch_m[e][ie]) == x:
					w = e
	        n = vch_m[w].get("gender")      
	        n -= 1
	        r = z[n]
	        return [
	            (renpy.TEXT_TEXT, r)
	        ]

Let's go through the function a bit at a time. To begin, (tag, argument) is taking the 'pr' section from the text tag in 'tag', and all that comes after the '=' in 'argument', and divided the latter into temporary variables as determined by the '_' and '|'. So, according to first line of in-story the example I gave in the first bit of code in this post, the first four lines of the function would work like this:
a = ['pov1', 'He|She|They']
x = 'pov1'
y = 'He|She|They'
z = ['He', 'She', 'They']

Where as the second line from the in-story example would be like this:
a = ['pov2', 'He|She|They']
x = 'pov2'
y = 'He|She|They'
z = ['He', 'She', 'They']

Next, the function searches for the character in the nested dictionary that corresponds to the value extracted into 'x'. It does this using for loops, repeating the lines of code at first for every sub-dictionary in the vch_m dictionary. That in this case would mean it loops 3 times as there are 3 sub-dictionaries, vch_001, vch_002, vch_003. It then preforms the same for all the keys within each of the sub-dictionaries, so in this case twice as there are two keys in each sub-dictionary; 'tag_code', and 'gender'.
(This could probably be tidied up with alternative key and sub-dictionary names, requiring only one for loop instead of two, but this system works for me.)
The 'if' statement that follows comes into effect if the currently examined value within the nested dictionary, matches the value of 'x', in the first line from the in-story case, 'pov1'. When a match occurs, the sub-dictionary containing 'x' is preserved in the new temporary variable 'w'. So in this case 'w' will have the value of 'vch_001' as that is the sub-dictionary where the value of 'pov1' is found.

If this is all getting a bit much, I highly recommend having a quick readthrough of w3schools pages on Python Dictionaries, especially the sections on Access Items, Loop Dictionaries, and Nested Dictionaries. W3schools does a really good job of laying everything out and simplifying it into bite size concepts.

Back to the function. Now it collects the gender integer from the correct sub-dictionary for the character reference stored in 'x', using the results of the for loops, and stores it in another temporary variable 'n'. In the case of the first in-story line 'n' would be 1, as the character stored in the sub-dictionary 'vch_001' has a 'tag_code' of 'pov1' matching 'x', and a 'gender' value of 1.
In the next line the extracted integer in 'n' is reduced by 1 as we're going to use it as an index reference in order to extract the correct item from the list we stored in the temporary variable 'z', or ['He', 'She', 'They'] in this example.
(For more on index numbers and how they work with lists, I direct you once again to w3schools, this time to their page on Accessing List Items. You could cut this adjustment out by having 0 = male, 1 = female, 3 = nonbinary, in your character dictionaries. I don't do this because I like to preserve '0' as a non value in my code.)
The function creates a last temporary variable 'r' and assigns it a value according to the list stored in 'z' and index number stored in 'n'.
The final three lines return the outcome to the story text.

All of this outputs the following, with to recap the first tag assigned to 'pov1' who had a gender value of 1, the second 'pov2' with a gender value of 2, and third 'pov3' with a gender value of 3:
He walked down the road.
She walked down the road.
They walked down the road.
Due to the nature of the custom text tag and how its function organises the fed in argument, you can use anything you like as options for the gender value to determine. For example:

Code: Select all

label start:
	"""
	The {pr=pov_man|woman|person} was very angry today. 
	{pr=pov_His|Her|Their} friend had a wicked {pr=pov2_smile|grin|smirk}, 
	which {pr=pov2_he|she|they} shared with the {pr=pov3_man|woman|person} 
	stood beside {pr=pov2_him|her|them}.
	"""
Would output like this using the gender values of my example nested dictionaries:
The man was very angry today. His friend had a wicked grin, which she shared with the person stood beside her.
If you're interested in the detailed notes in the code itself, I've also included below a copy of the text tag function with some additional notes. I tend to find it helpful if I can see the 'gears' of how things work in situ.

Code: Select all

init python:
	config.self_closing_custom_text_tags["pr"] = pron_tag	#Implements the custom text tag and links it to the function below.

	def pron_tag(tag, argument):
	        a = argument.split("_")				#Divides the argument into a list of what comes before '_' and what comes after.
	        x = a[0]					#Extracts the first item from the 'a' list, this is our character reference.
	        y = a[1]					#Extracts the second item from the 'a' list, these are our possible words.
	        z = y.split("|")				#Splits the possible words into a list divided by '|'.
	        for e in vch_m:					#For every entry in the vch_m dictionary do the following:
			for ie in vch_m[e]:			#For every entry within the sub-dictionary within vch_m dictionary, do the following:
				if (vch_m[e][ie]) == x:		#If the value of the examined dictionary and sub-dictionary match the Character Reference we assigned to 'x', do the following:
					w = e			#Assigns the sub-dictionaries key/name to 'w'
		n = vch_m[w].get("gender")			#Gets the gender integer from the correct dictionary.
		n -= 1						#We do this so we can use the gender integer as the index reference for the correct word from our options.
		r = z[n]					#Extracts from our list of possible words the correct word as corresponds to 'n'.
		return [					#Contains the value we want returned to the story text.
			(renpy.TEXT_TEXT, r)			#Returns the desired text according to everything above.
		]

I hope folks find this helpful in their stories and games. Let me know if you have any questions.

Post Reply

Who is online

Users browsing this forum: Google [Bot]