Xeno Series Wiki:Advanced editing

From Xeno Series Wiki
Jump to navigation Jump to search
Wiki icon - Help.svg This is a help page, intended to help users learn.
Be very sure that any prospective edits are informative and correct. If in doubt, discuss on the talk page.

This page is for those that have become comfortable with the basic editing and syntax and want to go even further beyond.

Game data[edit]

Discovering things in a game by experimentation will only get you so far. Strategy guides don't cover everything, aren't always perfectly accurate, and may not even exist. That's why on this wiki, we make extensive use of data taken from a game by dataminers, if and when we can.

Game data is obtained in two ways: either by dumping the ROM of (your own copy of) the game, or by going to xenobladedata.github.io, a website dedicated to storing the data for each of the Xenoblade games. The data is stored in tables; usually, each row in a table corresponds to a specific entity (for a very liberal definition of "entity"), and a column corresponds to each of their properties. Interpreting them by sight takes practice, but it's helped by the fact that for each row in many tables, there's a handy list of other table rows that reference that one.

Unfortunately, not all columns have human-readable headers, and not all tables have human-readable titles (especially for Xenoblade Chronicles 3). This is a matter of what high-level source code information Monolith Soft decided to keep in the final product, and we only have access to the final product, not the source code. If you need help reading stuff, people in the Discord server will either be able to answer your questions directly or point you to the people most likely to know.

The data in xenobladedata.github.io can be read off the site as HTML tables, or downloaded to your local system for easier manipulation. Those looking to get into automatic page creation and editing will probably be doing the latter option. If they're being downloaded and manipulated, it may be easier to convert the HTML tables to CSV format; many utilities can be found online for doing this. However, be warned that the tools used to generate the HTML tables are intended for viewing rather than usage, and so make some hidden transformations that we want to avoid - such as replacing certain numbers with text, or hiding some columns entirely.

Unfortunately, at the time of writing, tools for managing, interpreting, and even reading the data of the pre-Xenoblade games are just about nonexistent. So we're stuck with experimentation and strategy guides for the time being, until someone figures out the datamining for those games. (Who knows... maybe it'll even be you.)

Page data[edit]

When you look around the wiki, you will come across articles with large tables forming lists of links to other articles (e.g. Special (XC2)#List of Specials). Looking at the article's source code, though, the amount of code written to make the table looks to be way smaller than the size of the table that results, and you can't see anything that corresponds to the individual rows of the table. That's because the table is made by calling upon page data.

There are three main reasons to do this: it makes it much easier to change little things about the page which calls upon the data, it automatically updates all relevant pages if one edits or moves the page that sets the data, and it ensures that the page calling the data doesn't miss anything out.

Jargon: A page's data consists of a number of properties, each set to a specific value. For example, the Berryjammy page has the property Xc1 npc page set to 907, done by including the text {{#set:Xc1 npc page=907}} on the page.

Setting page data[edit]

To set data for a page, use the {{#set: function. The Berryjammy example above sets just one property, but multiple properties can be set at once, separated by pipes |:

{{#set:example property 1 = property 1 value
|example property 2 = property 2 value
...
|example property N = property N value
}}

This sets the page's "example property 1" property to the value "property 1 value", and so on.

In practice, page data is often set in an infobox template. This is because the infobox is already designed to take in a lot of parameters about the entity in question. Alternatively, if an entity's article has a "Data" section, the section will often be filled in with a bespoke template which (among other things) sets the page data. Either way, only one page needs to be edited to change how the data for many articles at once is handled, which is useful far more often than it is not. That's why page data for an article is very seldom set directly in the article itself.

In these (standard) situations, there are two steps to setting page data. First, the infobox template (or whatever template is used to set the data) has to have the {{#set: function (wrapped in <includeonly> tags, so the template page itself doesn't accidentally get properties set):

<includeonly>{{#set:example property 1 = {{{exampleproperty1}}}
|example property 2 = {{{exampleproperty2}}}
...
|example property N = {{{examplepropertyN}}}
}}</includeonly>

Note that in the example, the properties are "set" to a variable name in triple curly braces. Recall how template pages work: a variable name in triple curly braces means that the template calls that variable name as an argument.

Step two is to call the (infobox or other) template on the page with data you want to be included. The arguments to the template should be the aforementioned variable names which were wrapped in triple curly braces, and the values of said arguments should be whatever value you want the corresponding property to have on this page:

{{Template name
|exampleproperty1 = property 1 value
|exampleproperty2 = property 2 value
...
|examplepropertyN = property N value
}}

Let's look at an example. The XCX collectibles have their data set using Template:Infobox XCX collectible. The template page contains the following, wrapped in includeonly:

{{#set:pagename = {{PAGENAME}}
|Xcx collectible Name = {{{Name|}}}
|Xcx collectible ID = {{{ID|}}}
...
}}

Then, an XCX collectible article sets the data by providing the relevant arguments to the infobox. For example, in Strawlenny's case:

{{Infobox XCX collectible
|Name = Strawlenny
|ID = 30
...
}}

Thus, the infobox template is told that the ID argument should be 30, and therefore sets the Strawlenny article's Xcx collectible ID value to 30.

In this example (and almost any other example you'll find), note that the pagename property is set to {{PAGENAME}} in two curly braces, rather than three. PAGENAME isn't an argument of the infobox template; instead, it automatically returns the name of the page the template is included on. This is useful for linking, since the name of the page to be linked to won't always match the name of the collectible given in Xcx collectible Name (e.g. if disambiguation is needed).

For entities which aren't relevant enough to have articles but for which it'd be useful to call upon their data (such as individual enemy attacks), there is the "Extra data" namespace. Articles in this namespace exist solely to store data; while they should display as something useful, they aren't really intended to be looked at by ordinary wiki users.

Calling page data[edit]

Calling upon page data takes several forms. The most common form is that we want to make a list of all pages with a certain property. To do this we use the {{#ask: function. This function is made of several parts.

Query[edit]

The first part, the "query", determines which pages to include by specifying those with a certain property value; for example, [[xc1 pc art st_type::18]] asks for pages with xc1 pc art st_type set to 18. You can also specify a range of property values; for example, [[Xc3 discussion ID::>0]] asks for pages with Xc3 discussion ID greater than 0 (which returns all discussion pages, since they all have ID greater than 0). Replace the >0 with + to automatically return all pages with that property set. You can also look for pages in a category: putting [[Category:Level 4 Specials (XC2)]] asks for pages in the given category, or in one of its subcategories (note the single colon, as opposed to the double colon when querying for property values).

Concatenating two or more conditions makes the query only return pages that satisfy both (all) conditions. For example, the query [[Xcx enemy Resource TypeGenus::96]][[Xcx enemy enBook::False]] only gives pages that both have ...TypeGenus set to 96 and ...enBook set to False. To return results that satisfy at least one of two or more conditions, use the keyword OR: [[xc1 pc art st_type::18]] OR [[xc1 pc art sp_proc::1]][[xc1 pc art sp_val1::18]] returns all pages with ...st_type set to 18, as well as all pages that both have ...sp_proc set to 1 and ...sp_val1 set to 18.

If you query for a range of property values and the returned list isn't what you expected, check the below section on property types. See the documentation for more details on how to query for pages.

Returned properties[edit]

By default, ask just returns a list of links to the pages that satisfy the query. Usually, we want more information than that. Additional properties from the returned pages can be returned: this is done by including the property name as an argument to the ask function, prefixed with a question mark ?. For example, if the pages have a pagelink fancy property, have ?pagelink fancy be an argument to the ask function to return them.

Result formatting[edit]

Parameters to the ask function not prefixed with ? (aside from the query) impact how the results are displayed. In most cases, what one needs to do is manipulate the returned properties into something readable by wiki users. To do this, pass template=Template name as an argument, where Template name is a dedicated template designed to take in the property values as arguments and make them wiki-user-readable. For example, passing template=XC2 Special list row common calls Template:XC2 Special list row common for each returned page, with the additional returned properties as arguments for said template, then displays all of those template calls together on the page.

By far the most common use case for this on the wiki is to make a table where each row corresponds to one of the returned pages. This can be done by having the template in question be the code for a table row, and then putting the code for the table header and footer above and below the ask function respectively. This may require a number of other arguments to the ask function, to get the result display formatting just right. See the help article Xeno Series Wiki:Data templates for an in-depth example, or look at (and copy-paste from) other articles on the wiki that implement this technique. The documentation for doing this can be found here.

In simple cases, it may be that all the property values you want to show already look like how you want wiki users to see them, and you just want to have a table where each column is just displaying a single property for each page. When this is the case, you can get away with not having to make a row template to pass as an argument to the ask function. Alternatively, you may not want the results in table format at all; maybe you're looking for a comma-separated list, a bullet-point list, or even just want to return a single, raw property value for a query that you know will only have one page as a result. The Inline Queries documentation page shows how to do many of these simple cases, with examples.

The show function[edit]

If you know a page's name, and want to get one or more property values from that page, the {{#show: function is an easier and more concise alternative to the ask function. In practice, this happens much less than one might expect, because if the page is moved then the show will no longer work. It is in general only useful for extra data pages, which have next to no chance of ever needing to be moved. To get (just) the property propertyName from a page titled XYZ, use {{#show: XYZ |?propertyName | link=none }}.

Aside from the lack of a query, the show function behaves similarly to the ask function in terms of how it takes in parameters to display results. However, because of how the wiki typically uses the data from extra data pages, the typical usage pattern for show is different to that of ask. Often, what one does with the properties from an extra data page is to put them in an array (see below) for easy access elsewhere on the page. To do this, one can use format=array to return the properties as a list separated by the string <PROP> (by default), and then define an array with <PROP> as the separator, a la:

{{#arraydefine:properties |
{{#show: XYZ | ?propertyName1 | ?propertyName2 | ?propertyName3 |mainlabel=-|headers=hide|link=none|format=array }}
|<PROP>}}

Then, page XYZ's value for (say) propertyName2 can be obtained with {{#arrayindex:properties|1}} (the reason it's 1 and not 2 is because arrays are 0-indexed).

Common properties[edit]

There are several properties that pages will frequently have:

  • pagename: This property is just set to the raw name of the page. This can be different from the name of the entity; for example, Cloud Sea King Ken (normal) has pagename=Cloud Sea King Ken (normal) but Xc2 enemy Name=Cloud Sea King Ken. When setting properties, it's usually set using the keyword {{PAGENAME}} (see § Setting page data above), or {{FULLPAGENAME}} on non-mainspace articles to include the "Extra data:" or other namespace prefix.
  • pagelink: Given a pagename and some other property that gives an entity's name (e.g. Xc2 enemy Name), it's always possible to create a link to the relevant page with [[insert pagename here|insert name here]], and this will automatically get updated if the page is moved thanks to the pagename. It is so useful and so common to do so that a dedicated property is often set to be exactly this, so only one property needs to be called to get a link to a page rather than two. Setting it usually looks like pagelink = [[{{PAGENAME}}|{{{Name}}}]], where the "Name" in triple curly braces is the relevant argument of whatever template is setting the data.
  • pagelink fancy: A bit of eye candy can be added to a long list of pagelinks by using a "pagelink fancy" instead. This usually consists of a pagelink prefixed with a little icon (usually 20-30 pixels wide) of whatever is being linked to. Exactly what this icon is is situation-dependent; it's usually whatever icon is used for the relevant entity in the game's menu.
  • Alt pagelinks: Usually when linking to pages we don't want any disambiguation brackets — there's no need to specify "Territorial Rotbart (XC1)" in a list of the XC1 unique monsters. But sometimes we want just a bit of disambiguation, because there are actually two Territorial Rotbarts in XC1: one normally and one in the Time Attack. Removing all disambiguation from the XC1 unique monster list with the ordinary pagelink would seemingly result in two instances of the same enemy appearing in the list, but keeping all disambiguation in (via e.g. [[pagename]]) would also keep the unnecessary (XC1). To get around this, a "pagelink fancy alt 1" property can be made consisting of [[Territorial Rotbart (XC1) (normal)|Territorial Rotbart (normal)]], keeping exactly what disambiguation is necessary for this situation. Creating alt pagelinks can be a bit of a pain and usually requires some string parser functions, because there's seldom a fully-consistent way to get exactly what text should be displayed.
  • Pool properties: A single page can have a single property set to multiple values. Then, querying for any one of those values will return that page. Pool properties take all the values assigned to a bunch of other distinct properties and set them all together; this can be very useful if some situations don't really care exactly which of the distinct properties has exactly which value, only that a given value is there in at least one of the properties. For example, to get a list of which weapons in XCX can have a given Battle Trait, it doesn't matter if that Battle Trait appears in the first or the eighth internal "slot"; all that matters is that it's there for one of them.

Aside from the above, most pages with data just have a property corresponding to each of (or some of) the columns in the BDAT(s) listing the relevant entity. Other properties can in principle be made if it simplifies things; just make sure that the new property doesn't already exist and/or doesn't affect any queries elsewhere.

Property types[edit]

Sometimes you'll want to do an {{#ask: for which the output should be sorted in some manner, or for which you want to only ask for a subset of all pages with some data. If you go ahead and do this the "obvious" way, a la {{#ask:[[XC3 weapon BdatRow::<33]] (to get all weapons with BdatRow less than 33), you may find a completely different list appearing than what you intended.

The reason for this is because by default, a property is interpreted as a string of characters. The ordering associated with this string is lexicographic ordering rather than numerical ordering; so, for example, 1 < 10 < 11 < 2. To have the wiki backend parse the property as a number (or in general, anything other than a string), you need to give the property its own page and tell the wiki about the data type you want the property to have.

Such a page is at [[Property:Property name]], and the page's content needs to have [[Has type::number]] (or whatever type you want in place of "number") somewhere in it. It should also have a category. Aside from that, the page text can be whatever; usually some explanation of what the property is. For example, the page Property:Xc1 gem ID consists of the following:

A [[Has type::number]] that represents the ID of this gem in XC1.
[[Category:Gem properties]]

In an ideal world, every property would have its own page and explicitly say what its type is. This is not an ideal world, and the amount of extra editor effort this would require is not nearly enough to be worth the small benefits over just adding a property page when necessary to change the type.

Subobjects[edit]

Subobjects are a way of setting data in a more refined way than just having it be by page. Normally, when the same properties are set multiple times in a single page, the wiki backend can't tell which property values correspond to which instance of the properties being set. This can cause problems if a page corresponds to multiple entities, each with their own name and ID; if it's all set on the same page there's no way for the wiki backend to figure out which name it should return given one of its IDs.

Subobjects can be used to get around this difficulty. Each subobject of a page has its own set of properties and values. These can be queried like ordinary pages can, and one can also query across the subobjects of a given page and/or the page a given subobject belongs to. Thus, to avoid the above difficulty, one can create a subobject on the page for each entity, and then each subobject can have the ID and name set as properties. Thus, the wiki backend is able to distinguish which ID corresponds to which name, as they're each bundled into a subobject. An alternative is to give each entity an extra data page and then call upon each of those pages' data in the mainspace page; this is more flexible in some situations, but it can sometimes be more difficult to do things such as make pagelink properties. Which option is better is situation-dependent.

Another use case for subobjects is to simplify nested querying. Sometimes one is interested in seeing how two entities relate to one another (e.g. to get the chances that different enemies drop a given item), but this relation is buried within a complicated query on one of their pages (in this case, each enemy calls upon a number of "drop tables" which list out the possible items and their drop rates). It is in principle possible to query for all instances of the item in the drop tables, and then for all enemies that call upon one of the drop tables that have the item. However, a much simpler (and faster) method is to give each enemy page a subobject for each of the items they can drop (which the enemy page has to figure out in any case), with each subobject containing the item ID and its drop rate. Then, the problem reduces to simply querying for all such enemy-page subobjects that have the item ID.

The documentation for subobjects can be found here.

Programming[edit]

Wiki syntax is a markup language, not a programming language. That means it formats plaintext into something that looks nice; it doesn't calculate things. Nevertheless, sometimes you need to calculate things, so there are some functions that provide basic programming structures.

A couple of the most common ones are as follows.

Parser functions[edit]

{{#expr:Your mathematical expression here}}

"Your mathematical expression here" gets calculated and displayed. This is handy when interpreting and displaying data in a human-readable, intuitive way (e.g. finding the expected number of enemies you'll have to kill to get a specific drop), as well as updating variable values (see below).

{{#if:Your condition here|This text displayed if non-whitespace|This text displayed if whitespace}}

Displays one of two results based on whether the input is pure whitespace or not. Very handy in infobox templates to conditionally include specific arguments. Note that sometimes there's a difference between "space", "blank", and "not specified", while other times there is no difference. Yes this is annoying.

Some typical patterns for if statements include:

  • {{#if:{{{param1|}}}{{{param2|}}}|param1 OR param2 is provided|neither param1 nor param2 is provided}}
  • {{#if:{{{param1|}}}{{#if:{{{param2|}}}|param1 AND param2 are provided|param1 is provided, but not param2}}|neither param1 nor param2 is provided}}

There are of course many more complicated structures.

{{#ifeq:String 1|String 2|Displayed if identical|Displayed if not identical}}

This is a string comparison. It's commonly used in templates, to check if the value of a passed argument is equal to some predetermined value.

{{#ifexpr:Expression|Displayed if true|Displayed if false}}

"Expression" gets evaluated as a truth value (0 or empty input is false, any other valid expression output is true).

{{#switch:test string|case1 = value for case 1|case2|case3 = value for case 2 or 3|...|default value}}

If test string is identical to case1, "value for case 1" is displayed, and so on. If the string doesn't match any cases, "default value" is displayed. Entire templates ("enums") are built off this function, to conveniently map numbers to entities. Note that it goes through every item in order until it finds a match, so a switch with too many items will be pretty slow when it needs to work on one that appears late in the list. At this point, a module would be better.

The documentation can be found here.

Variables[edit]

Variables are necessary for loops, and they can also be used to clean up long repeated bits of wikicode (e.g. if a single query or its output needs to be used multiple times on a page). To declare a variable i and initialise it to 24, use {{#vardefine:i|24}}. Then, {{#var:i}} will return 24.

Variables can be changed (otherwise they wouldn't be variable). For example, if i is set to some numerical value, {{#vardefine: i | {{#expr: {{#var:i}} + 1 }} }} increments it by 1: it takes i's value, adds one, evaluates the result, then sets i to the result. (Whitespace was added for readability in this example; it does not affect the processing.)

Be wary that all variables are global; variable "i" refers to the same "i" whether you're on the page itself, or on a template eight layers deep. While this can be useful, it means you need to watch for and avoid a template chain all trying to use the same "i" for their looping.

Further documentation can be found here.

Arrays[edit]

If a variable is a box, arrays are a box of boxes. They're defined in much the same way: {{#arraydefine:theList|3,8,29|,}}, where the , tells the parser how to split up the given argument. The main usages after this are accessing a certain index with {{#arrayindex:theList|2}}, or printing the whole thing with {{#arrayprint:theList|-and-}}, which here would result in "3-and-8-and-29". Several other functions and array-manipulating templates are available.

Further documentation can be found here. #arrayunique is known to behave strangely; following it up with {{#arraymerge:theList|theList}} (which ordinarily does nothing) may fix some issues.

Loops[edit]

Loops can be used to help calculate and display a large number of values. There are several ways to do this; the following two are most useful.

{{#while:|condition text|output}}

If condition text is not whitespace, output is parsed and displayed. This repeats until the condition text is whitespace, so the output should have something that eventually changes the condition text to whitespace (probably using an if parser function or the like).

{{#loop:variable name|starting value|loop count|output}}

This automatically defines a variable variable name and initialises it to starting value. It parses and displays output, then repeats with the variable 1 higher. This continues for loop count cycles; it is similar to a "for loop" in many programming languages.

The variable in question can be used in the output (in this case with {{#var:variable name}}).

Be wary when attempting to use loops in tables (for example, to create multiple table rows at once). The output has a nasty tendency to strip leading and/or trailing whitespace, which can mess up the table's formatting. To force whitespace at the start or end of loop output, add it in nowiki HTML tags or use &#10; (ASCII code for the linefeed character).

The documentation for MediaWiki loops can be found here.

Automatic page creation and editing[edit]

Xeno games are complicated, and each one has a huge number of entities of all sorts of different types. The number of enemies, attacks, items of each type, NPCs, and the like often numbers in the hundreds if not thousands. Our goal is to have information on each entity, often a full page, but manually creating hundreds of articles and filling in all the relevant information for each one is not only prone to error - it can be mind-numbingly exhausting. That's why we like to automate our workflows whenever possible.

When there's a huge number of pages that need to be made for each entity in a large set, it's a good idea to set up some sort of script to write the pages for you. This is especially true in the likely scenario that data needs to be added to the pages (via an infobox template or otherwise).

Suppose there's a BDAT table where each row corresponds to an entity we'd like to have a page for (this happens a lot). A typical process for making the pages might look like this:

  1. Make a template with arguments corresponding to the columns of the BDAT table. The template should be written to add data to each page which includes it, and also showcases important data it takes in in a human-readable manner. (This is often an infobox template, or otherwise intended to simply take in data.)
  2. Write a program that does the following:
    1. Takes in a BDAT table (in some form, possibly HTML if obtained from xenobladedata.github.io) and parses it.
    2. Splits the table by row.
    3. For each row, creates the syntax for the template you made earlier, where the value for each argument in the template is the entry with the corresponding column and row in the BDAT table.
    4. Makes a text file for each row. Writes to each text file the syntax for a barebones wiki article about the corresponding entity, including the template with all the data. (You almost certainly won't be able to include detailed descriptions at this point; anything that can't be automatically generated will have to come later.)
  3. Choose an entity from your set, and create its wiki page by copy+pasting the corresponding text file your program created.
  4. Hit Show Preview (or, if necessary, Save Page). Check how the page looks, check how your template is presenting the data, check the properties that are being added to the page.
  5. If anything's incorrect with how the template is presenting the data, then modify the template, wait 15 or so seconds for the change to propagate through the wiki backend, then check the preview again. Rinse and repeat until the template is presenting the data how you want it.
  6. If anything's incorrect with any other aspect of the article, then go back and debug your program, and have it generate the text files again. Check what the page corresponding to the new text file looks like.
  7. Once you're happy, you may want to repeat the debugging process with any entities in your list that may cause weird behaviour, just to be absolutely sure your program is creating the text you want it to.
  8. When you're ready, go through the list of output text files. For each one, create the corresponding wiki page, copy+paste the contents of the text file in, and save the page. This step is usually done manually (although it can be automated; see below).

The idea is that you want to have as much of the process automated as possible; that means having all (or 99%) of the basic article be automatically generated by your program just as you want it to appear, and double-checking everything against one (or a small number of) articles so that you get the vast majority of them right the first time. Going back through every article in a set of hundreds to make a minor edit is never a fun time.

It may well be the case that the relevant data for an entity is spread across multiple BDAT rows in different tables, or consists of (one or more) entire BDAT tables. The basic process is the same; configure your program to take in and parse as many tables as are required, but it may be easiest to always output one text file per wiki article.

Sometimes you'll need to edit a lot of pages rather than create them. For example, maybe a lot of pages need Template:In other languages. The general idea is the same. Make a script that outputs the wiki text for each article (possibly to individual text files for each article, possibly all to one text file if the article is small enough), then manually copy+paste the relevant output text into each article.

Python and C++ are good languages to write your text-processing programs in. If you don't know how to program, unfortunately the only options at the moment are to either learn how to do so, or get someone else to write the program for you. The BDAT -> wiki page process is so dependent upon specifics that there's probably no way to make a one-size-fits-all program that you can download and run yourself without heavy tweaking. You can, however, ask other editors if they can send you their own programs as a starting point.

Using PyRikiBot[edit]

The wiki has a bot, User:PyRikiBot, to automate some tasks fully. Sadly, unless you are User:Sir Teatei Moonlight (the bot manager) or a bot yourself, you are probably not going to be able to fully automate page creation or editing all by yourself. That doesn't mean there's no way to do so; it just means you'll have to go through the bot manager as a middleman. Put in a request on his talk page or ask on the Discord server.

There are things that Riki can do much more easily than others. The main aspects to be kept in mind are making sure Riki knows where to place an edit, and making sure he can make the right change relevant to each page.

  • Generally speaking, Riki will naturally be able to make edits to all pages in a category, all pages that link to a page, or all pages that use an image or template. More specific sets of pages may or may not be possible.
  • Riki can easily find the start of a page, the end of a page, and headers. He can also find all instances of a given template, and argument calls to said template. In general, if you can find exactly where you want Riki to place/replace text by pressing Ctrl-F/Cmd-F and typing the same thing for every page Riki needs to change, Riki can probably find it; otherwise it'll be much harder. Riki understands regexes (well, as much as anyone can), but this greater complexity means greater chances of something going wrong.
  • The change being made typically should be basically the same text being placed/replaced for every page in the category. Slight deviations from this are possible; see User:PyRikiBot or talk to the bot manager for details.

If you make a page with the intention that Riki will later add something, make a header for it (probably with an incomplete tag). That way it'll be much easier for Riki to find the place on the page to add it.

It is possible to have Riki make pages. Doing so entails much of the same steps as above, but instead of making separate files for each page, you'll need to put them all in one file with specific formatting, and send that file to the bot manager. See the documentation for exactly what formatting is necessary. Making pages with Riki is ideal for extra data pages and other situations in which there's no fear of Riki trying to make a page that already exists.

Modules[edit]

Wikitext was never supposed to do any fancy programming, so it was never designed to be good or fast at it. Once a template becomes too slow or unworkable, it is probably a good idea to switch to a module.

The {{#invoke:module name|function name|param1|param2|param3}} syntax tells the wiki to go to the page called "Module:module name" and execute the "function name" function using "param1", "param2", and "param3" as its arguments. Modules are not written in wikitext, but in Lua, a dedicated programming language with entirely different syntax and gotchas.

The usage of modules is relatively new around here, so there's not too much in the way of specific advice yet. For the documentation, see here.