Template:Spell table/doc

This template was based on split table and modified so that it will automatically generate spell categories for the class/level pairs listed in the table. It typically generates two categories for each pair, of the form:

and

And possibly a third category in certain circumstances. The nth-level category is suppressed in some cases. See examples below.

If the class is a domain (a 3rd edition method of organizing spells of a similar nature or theme), a sphere (a 2nd edition method of organizing priest spells), or a quest spell (2nd edition spells that have no assigned level), the second category will not be generated as agreed upon in this forum discussion. Fifth edition added more cleric domains plus druid circles, paladin oaths, monastic traditions, and warlock patron-expanded spells. These are treated the same as 3rd edition domains and 2nd edition spheres.

Rituals have now been added as a variant and this template generates one or two unique categories for them. The categories for 4th edition rituals were agreed upon in this template talk discussion. Rituals were formalized in 4th edition but exist in all editions in one form or another. In 4th edition, rituals do not belong to a class but have a "category" that classifies one or more skills or powers that can be drawn upon to perform the ritual. To document a 4th edition ritual with this template, replace the spellcaster class with the "category" of the ritual, e.g., "Exploration", and specify the level as normal. The "category" can be entered in any of the following ways: Any other format may not generate the wiki categories correctly. The wiki categories generated by this template for an Exploration ritual would be:

and

Fifth edition decided to make ritual a flag that can be put on a spell, allowing characters to cast the spell in two different ways. Because spells are associated with certain classes, now rituals are also. However, some classes, like Rangers, can cast spells but not perform rituals (the Ritual Caster feat notwithstanding). So we still want to produce the two spell categories, but we do not have types of rituals like "Exploration" from 4th edition and do not want to produce a "Ranger rituals (5e)" category. This requires extra logic to determine if we have a 5th edition ritual or not. See examples below.

Usage
This template takes up to 20 class/level pairs, plus three parameters:
 * edition : Required. Value can be anything but by convention we are using 1e, 2e, 3e, 4e, or 5e. It will convert any input to lower-case.
 * variant : Optional. For 5th edition, known values are Cantrip, Ritual, and Channel Divinity. For 4th edition, known values are Discipline, Evocation, Exploit, Hex, Prayer, Channel Divinity Prayer, Spell, and Ritual. For 3rd edition the only known value is Mystery for shadow magic. The default is Spell. Not case-sensitive.
 * nocat : Optional. Setting this to true will suppress the generation of categories. Used mainly for documentation pages like this one.

Examples
This is an example of the template being used inside the Spell template (most parts of template not shown).

These three invocations of the template will generate the following categories: Note that the Spell template will generate additional categories not shown here.
 * Category:Druid spells (5e)
 * Category:2nd-level druid spells (5e)
 * Category:2nd-level rituals (5e) &larr; Note the extra category for the ritual
 * Category:Ranger spells (5e)
 * Category:2nd-level ranger spells (5e)
 * Category:Druid evocations (4e)
 * Category:2nd-level druid evocations (4e)
 * Category:Shaman evocations (4e)
 * Category:3rd-level shaman evocations (4e)
 * Category:Druid spells (3e)
 * Category:2nd-level druid spells (3e)

This is an example of the template being used inside the Ritual template (most parts of template not shown).

This will generate the following categories: Note that the Ritual template will generate additional categories not shown here.
 * Category:Exploration rituals (4e)
 * Category:4th-level rituals (4e)

Under the Hood
This template makes use of a number of helper templates that assist in breaking apart and formatting elements of the table data, namely the class (e.g., Wizard, Cleric), spell sphere, domain, ritual, oath, circle, or expanded category, and the level (a non-negative integer). The helper templates are:
 * Nth : Converts a number to its counting or ranking form.  returns .
 * Power plural : Returns the plural form of a power title.  returns '. Case is not preserved; it returns a lower-case string. If new powers are added, please add them to Power plural. The default value is '. The variable plural is typically set to the output of this template (see example below).
 * Stripref : Returns everything up to, but not including, the first "&lt;" symbol, if any. This will remove any &lt;ref&gt; tags or other HTML markup that might be appended to a string.
 * Rootlink : This template returns everything to the left of the first "|" in a string. If an alternate name is given to a link, e.g.,, then this template returns  
 * Unlink : Returns the string between square brackets.  returns . It shouldn't matter how many brackets are present, including zero.
 * SpellCats : With the addition of circles, oaths, patron-extended spells, and traditions, this template replaced a relatively simple #if: statement with a large Boolean expression that returns a value only if an nth-level category is to be generated.
 * Class cap : Returns the class name changed to lowercase unless it matches one listed in this template as containing a proper name.

Here is a pseudo-code explanation of what this template does for each row of the table:
 * if a class (or sphere or domain or ritual category) or a level are specified
 * then
 * if we have a 5th edition ritual or no ritual
 * then
 * Generate
 * if this is not a spell sphere, quest spell, domain, oath, circle, tradition, or extended spell
 * then
 * Generate
 * if this is a 5th edition ritual
 * then
 * Generate
 * else
 * Do nothing (i.e., suppress this type of category for spheres, domains, etc.)
 * else we have a non-5th edition ritual
 * Generate
 * Generate

Here is the implementation of the pseudo-code that operates on the first class/level pair, with spaces added to make it more readable:

The rest of the template is essentially 19 more repeats of this block of code. As you can see, the categories depend on both the class and level, so please make sure you specify the data in pairs.

Variables
There are three variables that are used to help simplify the logic and format the output. First, we have to know if we are dealing with a 5th edition ritual because it is a special case, so we define the variable like this:

The lc: function converts the value of parameters edition and variant to lower case (so you could specify  or   and it would still work) and the ifeq: compares edition to "5e". If it matches, then we proceed to the next ifeq and compare variant to "ritual". If both are true, then ritual5e will be set to true, otherwise it will be an empty string (interpreted as false).

Next we define notRitual as simply

If variant is not equal to "ritual" then notRitual gets the value true, otherwise an empty string.

And finally, plural is used to store the plural form of the power title (spells, hexes, rituals, evocations, etc.), but only if we are not dealing with a 5th edition ritual. In that case, we want to categorize them as spells and we will deal with the special case separately (see below).

4th Edition Rituals
Starting with this invocation of the template:

The value of  will be   and the value of   will be  . This is hopefully a worst case scenario: ritual categories don't have to be linked and the Ritual template has better ways to handle references in the infobox. Since both positional arguments have a value (which means  evaluates to a non-empty string), the first if statement evaluates to true and we take the then branch to arrive at the next if statement: {{#if:{{#var:ritual5e}}{{#var:notRitual}} If we have set our variables correctly, ritual5e should be false (an empty string) and notRitual should also be false, so we skip the then block and go all the way down to the last else statement and generate our first category. Breaking down the first Category line, start with this: [[Category:{{ucfirst:{{Class cap|{{unlink|{{#sub:{{stripref|{{{1}}}}}|0|{{#pos:{{stripref|{{{1}}}}}|ritual}}}} }} }} }} It's a lot of nested functions, so start with the deepest and work our way out: {{#pos:{{stripref|{{{1}}}}}|ritual}} Substituting the value of  we get {{#pos:{{stripref|Exploration}}|ritual}} Stripref removes any trailing &lt;ref&gt; tags, but there are none, so the unmodified string is returned: {{#pos: Exploration |ritual}} #pos: returns the (zero-based) starting position of a string within another string, in this case "ritual" within " ". The answer is {{#pos:Exploration|ritual}}. (Note that if the string is not found the answer is 0. This would be true if the ritual-category were given as "Exploration" instead of " ", for example). We take this answer and go up a couple levels in our deeply nested expression: {{#sub:{{stripref|{{{1}}}}}|0|14}} We already know that stripref doesn't find any &lt;ref&gt; tags, so we have: {{#sub:Exploration|0|14}} The #sub: function returns a substring starting at position 0 for a length of 14 characters and truncating the rest, which gives us {{#sub:[[Exploration ritual|Exploration]]|0|14}}. (Continuing the note above, if the length was 0, no truncation would take place, so "Exploration" would be unmodified.) Continuing from the inside out, we now have [[Category:{{ucfirst:{{Class cap|{{unlink|[[Exploration}} }} }} The unlink function removes square brackets from around a string, leaving Exploration. Finally, we convert what's left to lower case and then capitalize the first letter. For Exploration this doesn't change anything, but if the ritual type were "Shou Lung" then it would return "Shou lung". (If you want it to say "Shou Lung" then add this case to the {{tl|Class cap}} template.) So far, we have generated this much of a category: [[Category:Exploration Picking up the rest of the first category line, we have {{#var:plural}} ({{lc:{{{edition}}}}})]] The variable plural was set to rituals by calling the {{tl|Power plural}} template with the value of the variant variable (it was "ritual"), and edition was set to 4e in the invocation of {{tl|Spell table}} shown above. Putting it all together we get our first category:

Moving on to the next line

The part that is new is [[Category:{{nth|{{stripref|{{{2}}}}}}}-level Substituting the value of  we get: [[Category:{{nth|{{stripref|3 }}}}-level Stripref finally has something to do, and returns 3, which nth converts to 3rd, leaving [[Category:3rd-level Concatenating the rest of the line gives us our second category:

5th Edition Rituals
Starting with this invocation of the template:

The value of  will be   and the value of   will be   Since we have two valid arguments, the first if statement again evaluates to true and we take the then branch to arrive at the next if statement: {{#if:{{#var:ritual5e}}{{#var:notRitual}} This time, ritual5e is true and notRitual is false (an empty string), so the if evaluates to true and we take the corresponding then branch to generate our first category. Breaking down the first category line, we start with this: [[Category:{{ucfirst:{{Class cap|{{unlink|{{rootlink|{{stripref|{{{1}}} }} }} }} }} }} Substituting   in for the positional argument  and evaluating from inside out: stripref removes any &lt;ref&gt; tags (there are none); rootlink extracts the link from any display name (so   would become  ); unlink removes any square brackets (leaving  ); Class cap turns it into  ; and ucfirst turns it right back into   again. So far, this produces [[Category:Druid Then we add the rest of the first category line: {{#var:plural}} ({{lc:{{{edition}}}}})]] The variable plural was set to spells because ritual5e was true (see Variables above), and edition was set to 5e in the invocation of {{tl|Spell table}} shown above. Putting it all together we get our first category:

Now we come to another if statement: {{#if:{{SpellCats|{{{1}}}}} Spellcats is going to look at   to see if it contains "sphere", "domain", "circle", "oath", or any of the other names we use to group spells and, not finding any, will return a non-empty string which means true. We take the corresponding then branch and start generating our second category:

All the elements of this statement have been explained previously, so we can just jump straight to the result:

And now we come to the inner-most if statement that handles the special ritual5e case: {{#if:{{#var:ritual5e}} We know this is true, so we generate one last category:

Note that this one specifies "ritual" for the power name (which gets converted to "rituals"), giving us the special-case category:

There is nothing else to do, so we pop up out of all our nested if statements and exit.

Non-rituals
If notRitual is true but ritual5e is false, then we are dealing with a normal spell, spell group, or the unusual 4th edition types. The same path described in the 5th Edition Rituals section will be followed except for the innermost if statement which will be skipped. Here are some examples of what is generated in these cases:

Generates:

Generates:

Generates: