Character Listings#
One of the things NPC was created to do is to generate a public listing of characters. The listing system is a bit complex, but can output correctly formatted entries for every type of character in every system, with built-in support for hiding character attributes – and entire characters – from the output.
Listing Configuration#
Listing settings are stored within the campaign.characters namespace in the listing key. They define defaults, but most can be overridden by arguments to the list command.
Note
There is an additional listing.metadata key which is currently ignored.
Templates#
NPC 2.0 uses the Jinja template engine to render character listings. Each character is rendered using a template, which is looked up based on the character’s type and the campaign’s game system.
The inner workings of NPC’s templates are written entirely using Jinja’s template language, so it’s a good idea to familiarize yourself with it if you want to customize your templates.
Default Templates#
The default templates display all information for the Default Tags in NPC. Various type-specific templates exist for the character types of the built-in Game Systems. If you’re using these systems, you may be able to use the default templates without any changes.
Custom Templates#
If you make a new system, or want to change how a certain character type is displayed, you’ll need to make a new template file. Name it using the character type key and use either .html or .md for the file extension, depending on the output format you’re targeting.
Templates for a single campaign can go in the campaign’s settings directory at <campaign>/.npc/templates/characters. Shared templates should go in your user settings at <user settings>/templates/characters/<game system key>.
For example, if you’re making a new template for the Changeling type to be shared by multiple campaigns, you’d create the file <user settings>/templates/characters/nwod/changeling.html.
If you want to generate everything from scratch, that’s it! You can write Jinja code as normal.
See also
See the Jinja Template docs for information on how to write templates in general.
NPC supplies view objects to each template, along with some new filters. See Data and Helpers for details on what is available from NPC.
File Locations#
Templates are named using the character type key and the output format’s extension. To find the correct template to use, NPC will check these directories in order. If the expected file does not exist in that directory (or the entire directory is not found), NPC moves on to the next in the list.
<campaign>/.npc/templates/characters
<user settings>/templates/characters/<game system key>
<npc package>/templates/characters/<game system key>
<user settings>/templates/characters
<npc package>/templates/characters
This ensures the following order of precedence:
Campaign-specific template
System-specific user template
System-specific internal template
Generic user template
Generic internal template
If no file is found for the character type, then the same directories are checked again for the generic character.<ext> template.
Base Templates and Blocks#
If you don’t want to start from scratch, you can inherit from one of the base character templates:
{%- extends "character-base.html" -%}
Putting this at the top of the file will give you access to various blocks which you can extend with new tags, or replace with custom content. To extend a block, declare it in your file and call super() to render the default contents, then insert your own additions.
{%- extends "character-base.html" -%}
{%- block aka -%}
{{ super() }}
{%- if has("court") -%}
<div>
{{ character.court.first() | title }} {% if character.court.has("role") -%}
({{ character.court.role.all() | join(", ") }})
{%- endif -%}
</div>
{%- endif -%}
{%- endblock -%}
Tip
If you want your custom content to appear before the default block contents, just put your own code before the call to super(). If you want to hide the block, define it and don’t call super() at all.
These are the available blocks:
- name:
The character’s name and a marker if they are dead.
- portrait:
The portrait image, if @portrait is set.
- aka:
Titles and other names the character has.
- vitals:
Personal info, like race, age, location, and pronouns.
- orgs:
Organization membership.
- location:
Where the character is found.
- employment:
Details about where the character works and what they do.
- system:
Empty block for system-specific tags.
- appearance:
The character’s @appearance.
- description:
The character’s description.
- dead:
Details about the character’s death.
Data and Helpers#
NPC supplies these properties to every character template:
- header_level:
The current header level to use for this entry’s header text.
- character:
The CharacterView object whose data should be displayed.
- has:
A simple helper function to test if the character has a named tag.
The character is a CharacterView object with a few special conveniences to make writing templates less onerous.
The Character View#
Each template is passed a single character object, which is a CharacterView. This provides a read-only look at that character’s properties and tags, condensed down for ease of use.
On its own, printing the character will simply show its name. Convenient for indexes and the like. Added in NEW_VERSION
{{ character }}
Grete Mann
Each character will always have the following properties:
- type:
The type key
- description:
The description
- realname:
Full character name
- mnemonic:
Quick-reference mnemonic
Beyond these properties, a character is likely to have properties named after various tags. Since tags can (almost always) appear more than once, tag attributes are actually a collection of multiple tags. There are a number of convenience methods associated with these collections, as well as the tags they contain.
In addition, there are some helper methods on the character itself.
Tip
The global has() helper method is a shortcut for this same method, character.has().
Tag Collections#
When accessing a tag attribute on a character view, you get a tag collection. This special view contains a list of all tags with the given name. It has some specific behavior available to make views easier to write.
First, when printed, a tag collection displays the value of its first tag. For example:
@org Red Riders
@org Blue Busters
{{ character.org }}
Red Riders
Then there are its helper methods. First, to iterate over everything in the collection, you must use the all() method:
To get the first tag view alone, use first():
And to get all tag values after the first, use rest():
Tag Views#
Once you have a single tag object, things are simple again. Printing the tag view by itself will render its value. You can also access the tag name if needed.
Finally, tags can have subtags. Accessing them behaves identically to accessing the tags of a character, complete with a tag.has().
New Filters#
NPC provides a few additional filters that can be used in character templates.
md#
This filter converts a string of markdown to a block of HTML.
Example:
{{ character.description | md }}
<p>This character, is a character.</p>
mdi#
This filter converts a string of markdown into inline HTML. It uses trim_tags to do so and is not at all clever or safe about which tags are stripped.
Example:
<div>{{ character.description | mdi }}</div>
<div>This character, is a character.</div>
Showing and Hiding#
By default, all tags in a character are available to the template. However, since listings are intended to be viewable by your players, you may want to hide certain bits of information. Depending on what you’re hiding, there are a few different tags that can help.
Hiding a Character#
First is hiding an entire character. Adding @delist to a character file completely removes that character from all generated listings. This is ideal for characters whose very existence is secret: upcoming villains, sheets for the evil faceless army, etc.
Hiding the Character’s Type#
Next is hiding a character’s type. Putting @faketype type key in a character file causes all listings to show that type instead of the character’s real type. It’s useful for situations like when a powerful wizard is pretending to be a traveling fireworks salesman, or when a changeling’s Fetch is under cover as a mundane human.
Tip
Setting @faketype for a character changes the character’s apparent type throughout the entire listing process. This means that a different template may be used to render the character’s entry. However, it does not automatically hide any other tag values. Tags which are shared by the character’s real type and fake type will be available to the template. If those tags reveal secret info, use @hide to conceal them separately.