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 generates two categories for each pair, of the form:

and

And possibly a third category in certain circumstances. See example below.

If the class is a domain (a 3rd edition method of organizing spells of a similar nature or theme) or a sphere (a 2nd edition method of organizing priest spells), 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 two unique categories for them. The categories 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 example below.

Usage
Same as split table except for the addition of 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 and Ritual. 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).

This 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 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.

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, 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 and domains)
 * 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:{{lc:{{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:{{lc:{{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". 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:{{lc:{{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  ); lc 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
The next line of the code is the else branch of the if that checks to see if we were dealing with a ritual. Let's choose a different invocation of the template that would get us to this point:

In this case, variant is not set,  is   and   is 2. Since variant is not set, Power plural returns the default, spells and this is set as the value of the variable plural. The line of code is:

The only difference between this and our first ritual-related category is the rootlink function instead of the #sub: function. We start in the middle with

The stripref function removes the   and returns  . The rootlink function just removes everything to the right of a pipe symbol, "|", but since we don't have one, the string is still  . Unlink removes the square brackets leaving  . Finally, we convert everything to lower case and then capitalize the first character, yielding  . Adding plural and edition we get a complete category:

Now we come to another if statement. This one decides if the class (the value of ) is a spell domain or a spell sphere, and skips making an Nth-level category if so. Let's look and see how this works: {{#if:{{SpellCats|{{{1}}}}} The spellCats function looks for sphere, domain, circle, oath, expanded, or tradition in the class string. If it finds one (or more) of these, then it returns nothing and we skip the next line and take the else branch. If it does not find any of these keywords, it returns a value, we take the then branch, and we see

All of these elements have been explained previously, so suffice it to say that this generates