Sheena-Tiger's Semi-Random Naming
This is a small system I use to give a world some variation between playthroughs without having to leave the names of important characters entirely to the AI. It can be used for one important supporting character or for a larger, predefined cast.
The idea is simple: the world creator provides a selection of possible names, and a PawScript trigger selects the names once, when a new game begins. Afterwards the selected names are stored in Tracked items and can be referenced by the rest of the world. The characters can keep their roles, personalities and other predefined information; they just do not have to carry exactly the same names in every playthrough.
This is not intended to solve the general tendency of AI models to reuse popular names when inventing NPCs. It addresses a different problem: making a fixed or semi-fixed cast a little less predictable across new games. It does not guarantee that a name will never repeat in another playthrough.
The examples below use a Queen, a Handmaid and several palace positions because that is where I tested the more complex setup. They are examples, not requirements. The same system can assign names to a companion, an adventuring party, the officers of a spaceship, the management of a cyberpunk company or the leaders of an opposing faction.
Requirements: Access to Tracked items, Trigger events and PawScript. Some familiarity with the world editor is helpful. You do not need to be able to write complex scripts to use the first example.
Part 1: One randomized supporting character[edit]
The simplest version assumes that there is one playable main character and one important supporting character. For example, the player chooses a Queen from a set of character presets and may change her name, while the story includes her personal Handmaid. The Handmaid is not separately playable or fully predefined; the AI can develop her as the story progresses.
To do this, we need two Tracked Items and one start-of-game Trigger.
1. Create the name list[edit]
Create a new Tracked Item with these settings:
- Name: Handmaid Name Pool
- Variable name:
handmaid_name_pool - Data type: YAML
- Auto-update: Off
- Initial value: the list below
- Miyoko - Hana - Nomusa - Aisling - Yuna - Isla - Amara - Fiona
Each line starting with - is one entry in the YAML list. You can replace the names or add as many as you like. Do not remove the dashes or combine all names into a single text line.
You may want to hide the pool from normal player and AI display. Since it is source data used by PawScript, it does not need AI auto-updates.
2. Create the item that will hold the selected name[edit]
Create a second Tracked Item:
- Name: Handmaid Name
- Variable name:
handmaid_name - Data type: Text
- Auto-update: Off
- Initial value:
Unassigned(or another placeholder)
The important difference is that the first Tracked Item contains all the possible names, while the second contains only the chosen name. For initial testing it can be useful to keep the second item visible, so you can immediately see whether it changed.
3. Create the initialization Trigger[edit]
Create a Trigger named, for example, Initialize Handmaid Name.
- Set its condition to Start of Game.
- Add an effect: Run a script.
- Paste the following PawScript into the script field:
$handmaid_name_pool.remove($player.name) $handmaid_name = $handmaid_name_pool.random() $handmaid_name_pool.remove($handmaid_name)
What the three lines do:
.remove($player.name)removes the player character's selected name from the pool, if it is there. This is a precaution in case the player renamed the Queen to a name also found in the Handmaid list..random()randomly picks one entry from the remaining list and stores it in the Handmaid Name Tracked Item.- The last
.remove()removes the assigned name from the available list. This is not strictly needed when choosing only one character, but becomes useful if the system is later expanded.
Important: Make sure the pool contains at least one available name after removing the player's name. If the list becomes empty, the assignment cannot work as intended.
4. Use the selected name in your instructions[edit]
In an instruction or a background that supports PawScript expressions, write the following instead of a fixed name:
The player character has a personal Handmaid named <<$handmaid_name>>. She has worked in the royal household for several years.
PawScript replaces <<$handmaid_name>> with the value stored in the Tracked Item. If the script selected Nomusa, the AI receives the actual name Nomusa, not the expression itself. This works in supported background, first-action and instruction fields too.
The supporting character does not require a predefined entry under Other Characters for this simple example. The AI can develop an NPC from the role and the name, along with whatever additional information you have supplied. If the character's appearance, history or personality is important, you should still write those details into your world; a name alone is not a reliable replacement for character information.
Names and possible cultural associations[edit]
Choosing names from different languages or naming traditions can give an otherwise loosely defined supporting character some additional variety. A model may associate Aisling with Ireland or Nomusa with a Southern African background and develop the character accordingly. However, this is an AI interpretation, not a rule imposed by the script. The resulting appearance and background can differ depending on the model and instructions. If you require a specific background or appearance, define it explicitly instead of relying on a name alone.
5. Test the simple version[edit]
Start a new game and check the Handmaid Name Tracked Item. Start several new games and check whether different names are being selected. Also test a playable character renamed to one of the names in the pool: that name should be removed before the supporting character is selected.
Do not put the .random() expression directly into the normal story instructions if you want a permanent assignment. The initialization script is what chooses a name once and stores it for later use. Each new adventure starts with its own fresh pool; removing a name here does not remove it from every future playthrough.
Part 2: A randomized Core Cast[edit]
The more advanced version is for worlds with multiple important characters who already have defined roles, personalities, skills, backgrounds or story functions. Some of them may also be selectable as the player character. When not selected, they can still appear as NPCs.
Instead of creating one separate Text Tracked Item for every supporting character, we store the entire cast in one YAML Tracked Item. A second YAML Tracked Item holds separate name lists for each role. A start-of-game Trigger assigns the names, and character-specific starting Triggers replace the relevant assignment with the actual player's name.
The following is adapted directly from a working five-role setup. You can rename every role and every name to fit your own world, but then you must also adjust all corresponding PawScript references.
1. Create the Character Name Pool[edit]
Create a Tracked Item with these settings:
- Name: Character Name Pool
- Variable name:
character_name_pool - Data type: YAML
- Auto-update: Off
- Initial value:
Ruler: - Yuuki - Akari - Haruka - Sakura - Ayame Handmaid: - Miyoko - Hana - Yuna - Emi - Kaede Protocol: - Reika Kanzaki - Sayuri Takeda - Kaori Mizushima - Misaki Hayashi - Shiori Nakamura Guard: - Aglaia - Athena - Helena - Thalia - Cassandra Shrine: - Aiko Fujimori - Hina Moriyama - Yuzuki Amamiya - Koharu Minazuki - Nanami Hoshino
The headings Ruler, Handmaid, Protocol, Guard and Shrine are YAML keys. Each key has its own list of possible names. There is no requirement for the names to match the role culturally or thematically; it is up to the world creator.
This also means you can replace the five roles with Captain, Pilot, Engineer, Medic and Navigator, for example. If you do, update all five paths in the script and Core Cast accordingly.
2. Create the Core Cast Tracked Item[edit]
Create another Tracked Item:
- Name: Core Cast
- Variable name:
core_cast - Data type: YAML
- Auto-update: Off
- Initial value:
Ruler: Name: Yuuki Handmaid: Name: Miyoko Protocol: Name: Reika Kanzaki Guard: Name: Aglaia Shrine: Name: Aiko Fujimori
These are initial values. The initializer will replace them with the randomly selected names. The structure is what matters: each role has a Name field, accessible through a path such as $core_cast.Guard.Name.
For the name-related Tracked Items in the tested setup, I used a hidden, low-priority AI visibility option (ai_only_boring in the exported world). Their values are primarily there for scripts and expression references. During setup or testing, showing the items can make mistakes easier to identify.
3. Create the main Initializer Trigger[edit]
Create a Trigger called Initializer:
- Condition: Start of Game.
- Effect: Run a script.
- Place this Trigger above the character-specific starting Triggers in the Trigger list.
Paste the script:
$character_name_pool.Ruler.remove($player.name) $character_name_pool.Handmaid.remove($player.name) $character_name_pool.Protocol.remove($player.name) $character_name_pool.Guard.remove($player.name) $character_name_pool.Shrine.remove($player.name) $core_cast.Ruler.Name = $character_name_pool.Ruler.random() $core_cast.Handmaid.Name = $character_name_pool.Handmaid.random() $core_cast.Protocol.Name = $character_name_pool.Protocol.random() $core_cast.Guard.Name = $character_name_pool.Guard.random() $core_cast.Shrine.Name = $character_name_pool.Shrine.random() $character_name_pool.Ruler.remove($core_cast.Ruler.Name) $character_name_pool.Handmaid.remove($core_cast.Handmaid.Name) $character_name_pool.Protocol.remove($core_cast.Protocol.Name) $character_name_pool.Guard.remove($core_cast.Guard.Name) $character_name_pool.Shrine.remove($core_cast.Shrine.Name)
Again, the script has three parts:
- Safety: Remove the player character's name from each name list before any names are assigned. This allows for renaming of playable characters.
- Assignment: Randomly choose one name from the appropriate list for each Core Cast role.
- Cleanup: Remove the selected names from their respective lists.
This script runs at the start of the game. It does not ask the AI to select or remember a name, and it does not need to be executed again on every turn.
4. Handle selectable player characters[edit]
The initializer does not branch by player role; it first assigns names to all five roles. A character-specific starting Trigger then replaces the selected role's name with $player.name.
For example, the Trigger that starts the adventure when the Ruler preset was selected has this additional Run a script effect:
$core_cast.Ruler.Name = $player.name
The other roles use the corresponding line in their own character-specific starting Triggers:
$core_cast.Handmaid.Name = $player.name
$core_cast.Protocol.Name = $player.name
$core_cast.Guard.Name = $player.name
$core_cast.Shrine.Name = $player.name
Do not put all five of these overrides into one unconditional Trigger. Each is meant for the corresponding player character selection only. In the tested setup, all these Triggers use Start of Game together with a condition for the particular playable character preset, and the general Initializer is listed first.
The result: a player who chooses the Guard is recorded as $core_cast.Guard.Name, while the other four positions receive their names from their assigned pools. If the player changed her preset name, the recorded name matches that change.
If your world has only one possible player role, you can keep only the relevant override. If none of the Core Cast roles can be played, you do not need these overrides at all.
5. Refer to Core Cast names everywhere[edit]
Use the stored role references instead of hard-coding names into the world. For example:
<<$core_cast.Ruler.Name>> is the current ruler. <<$core_cast.Handmaid.Name>> serves as her personal attendant. <<$core_cast.Protocol.Name>> oversees court protocol. <<$core_cast.Guard.Name>> leads palace security. <<$core_cast.Shrine.Name>> serves at the palace shrine.
The same idea works outside a palace. For example, <<$core_cast.Guard.Name>> simply means "the name assigned to the Guard role". In a science-fiction world you might change that role to Security, and reference <<$core_cast.Security.Name>> instead.
You can also use these expressions in supported background texts, first actions, Extra Instruction Blocks, story events and other places where names should be inserted. This is especially useful when different playable characters begin from different perspectives.
6. Using predefined Other Characters[edit]
The advanced version becomes particularly useful with Other Characters entries. These characters can have predefined biographies, appearances, occupations, skills, secrets and relationships. Instead of assigning a permanent name in the character entry, use the appropriate expression in the Name field:
<<$core_cast.Ruler.Name>>
For the Guard entry, the Name field would contain:
<<$core_cast.Guard.Name>>
The character's other information can stay predefined. The Guard can still be the same experienced security officer, with the same personality and duties, regardless of whether her name happens to be Aglaia, Athena or Cassandra in a particular playthrough.
It is worth checking the rest of each entry for fixed references to the old names. If the biography calls the character "Aglaia" but the Name field now evaluates to "Thalia", the information may contradict itself. Replace name references with expressions where needed. Keep role titles and character names separate when appropriate; a character's title need not be part of their name.
This way, the selectable player characters can also exist in the story as regular NPCs when the player chooses somebody else. They are not created from nothing by the AI: most of their information is already there, while the assigned name can vary with a new playthrough.
Notes, limitations and troubleshooting[edit]
This is semi-random, not fully random[edit]
The creator decides which names may appear in each pool. PawScript decides which one is selected. The selected name does not alter the predefined character's personality or biography unless the world is specifically written to allow that.
Adding more names increases the number of possible combinations. With five roles and five names per role, there are theoretically 5 × 5 × 5 × 5 × 5 = 3125 combinations before considering the player-name exclusions and overrides. This is not a promise that every combination will appear equally often in actual play.
Duplicate names[edit]
The simple version removes the player character's name before selection. The advanced version does this in every role list, and then removes each assigned name from its own list.
This does not automatically prevent duplicates across different role pools. The tested example uses separate lists with no shared entries. If you deliberately put "Alex" into both Guard and Protocol, both roles might still receive that name. Either keep the role pools distinct or adapt the script to remove assigned names from every pool where they might appear.
Empty or too-small pools[edit]
Keep enough names in each list for the player-name exclusion and assignments. A one-name list that contains the player character's name will become empty before the random selection. If a script cannot complete, check the World Debug / PawScript log rather than assuming the AI ignored an instruction.
Initialization order[edit]
Place the general Initializer before the character-specific POV Triggers. Infinite Worlds processes Triggers in list order, so the later role-specific script can overwrite only the selected player's role. These scripts are intended for Start of Game, not a recurring every-turn Trigger.
Names changed during play[edit]
This setup assigns the names when the game begins. It does not automatically change core_cast if a player or a story event renames a character later. If you support in-story renaming, you may need an additional procedure to update the relevant Tracked Item and to keep character information consistent.
Testing[edit]
Before publishing, I would recommend at least these checks:
- Start several fresh adventures and verify that the values change between runs.
- Rename a playable character to a name that exists in one of the lists and verify that another role does not receive it from that list.
- Test every playable POV and confirm that only its own Core Cast entry is overwritten with
$player.name. - Verify that character entries and instructions reference the selected names rather than stale hard-coded ones.
- Confirm that the names remain consistent after several turns and, ideally, after saving and loading a game.
Further reading[edit]
- PawScript — overview and community examples
- PawScript Reference — functions such as
.random()and.remove() - Writing Scripts in PawScript — scripts and their trigger effects
- PawScript Expressions Guide — using values in text with
<<...>> - YAML Guide — formatting structured name lists
- Tracked items and Trigger events — relevant world-editor features
- Advanced Templates — more community-made systems