User:Gaz Lloyd/Guides/Calculators

From the RuneScape Wiki, the wiki for all things RuneScape
Jump to: navigation, search

Gaz Lloyd
Talk
Level 99 Skills For Awesome People only
Calculator Guide Other Guides
More Links
Other Stuff: Header Name
Settings stuff: Common.css Common.js
Talk Page Archives: One Two Three Four Five Six Seven Eight Nine Ten
Not Subpages: All Subpages My Contributions My Editcount My Signature RfA Hiscores Ironman Hiscores Adventurer's Log Ironman Adventurer's Log

About[edit | edit source]

Calculators are a complex topic, since you're usually delving into code to make them and then testing them with various things. This guide is aimed at users with some experience in editing already - if you are new to editing, you might find this topic hard to get in to. If you want to help write a calculator but have no experience and don't know where to start, don't hesitate to contact me and I will help out however I can. In addition, if you see anything in this guide that is incorrect, poorly explained or you otherwise want clarification on, contact me.

If you just want to give an idea for a calculator, head over to RS:CI.

First off, there's a few things you should already know/have before we start (again, these are not hard requirements - if you want to help and have no experience, contact me):

  • You should be using the source editor, not the Visual Editor or the [[Help:Rich text editor|rich text editor]]. It can be set to always be used by visiting your preferences (editing tab) and selecting source mode from the Preferred editor dropdown. Source mode is essentially required for the technical work here, as the VE and RTE are not very good at handling template stuff. You'll only be able to make the most basic things with those, and it'd take longer
  • You should have basic editing skills in source mode - a cheatsheet is available at RuneScape:Editing, and a deeper tutorial is available at Wikipedia:Tutorial
  • You should understand how to create a table, customise it, etc; covered at [[Help:Tables#Wikitext Editor]] and in a lot of detail at [1]
  • You should be aware of our guidelines on calculator code

Additionally, having an understanding of some programming languages will be of significant use, and should help get to grips with the more complex topics. In particular, knowing HTML (yes, I know its not a 'true programming language') is a significant boon, since a lot of wikicode is just HTML anyway. CSS has its uses, as does javascript. Lua is also used on the wiki, so knowing that is a big help. Most other languages aren't of a particular help, but they can help in giving a good mindset and idea of what's going on even if you can't use any of the syntax directly.

Additional material[edit | edit source]

Here's some more links for things I'll be referencing later. Important parts will receive an explanation, so no need to memorise all the information for now. There links are also good for later reference when you're making a calculator, so bear them in mind (I actually have most of these bookmarked in my browser).

Wikicode

These links deal with advanced functions of standard wikicode; there's plenty of examples of these later

Lua

These links deal with writing lua modules, which can be used instead of templates.

  • Lua reference manual - this (combined with live examples) should be all you really need to work with modules
  • RuneScape:Lua - Information on the wiki's use of lua and lists of modules used on the wiki

For a breakdown of a calculator using a lua module, see User:Gaz Lloyd/exherbs which uses Module:Sandbox/User:Gaz Lloyd/exherbs. The module is very highly commented to explain basic lua.

Calculator APIs

If you're writing a dynamic calculator, you'll probably need one of these (if not, you'll be using bespoke javascript - see below).

HTML

Additional HTML things that can be used

  • CSS reference - the majority of these properties can be used in-line, so they're useful to know
  • Help:Colour codes - a simple list of example colours you could use
Other wikicode

Most of the time you won't need any of these, but they're here just in case you do.

  • Displaying a formula - if you ever want to write a mathematical formula on a page, you use <math> tags. These tags use TeX, which is documented at the link provided
  • DPL manual - Dynamic Page Lists (DPL) are very powerful, very complex, very frustrating, very laggy tools that generate a list of pages and data and then do something with that data (be that simply display it, or pass it into a tempate, or whatever). For example, the list of methods on Money making guide is DPL, Grand Exchange Market Watch/Alchemy is DPL, and much more.
Bespoke javascript

For some calculators, you may want to write them entirely in javascript. This is an advanced topic which is not covered here - you should contact me to discuss it if this is what you want to do. In order for your javascript to be added to the wiki, it'll need to be run past some administrators first (actually, on of the subset of admins who understands javascript), since one of them will be actually importing it to the sitewide script. Here's some useful links anyway, though (in addition to the above HTML links).

Other tools
  • Excel-to-Wiki converter - if you're lazy, and have a bunch of data in a spreadsheet (such as Excel or Google Docs) and want to put it on the wiki, you can use this tool to do the code conversion quickly
  • Notepad++ - my preferred code editor. If I'm doing anything other than basic code editing I'll work in this (using local saves) and then move back to the wiki.
  • Regular-Expressions.info - a good tutorial on regular expressions (regex/regexp), which can help you quickly reformat or extract data from things
    • RegExr - a live regex tester with a great cheatsheet. If you already know regex, this is a great place to test your regex if you're having issues with it, or to remind yourself of some specific syntax (I always forget lookarounds!)

How to make a calculator[edit | edit source]

I'm going to break it down into multiple steps, and work through each.

  1. Decide what to make a calculator on, and what it will do
  2. Decide whether to make a dynamic calculator (varies its result depending on user-given inputs) or static (has no user-given inputs and stays the same regardless of user)
  3. Decide what its inputs will be, what result it gives (and in what form), and how it will get to its result
  4. Write the code for the calculator:
    1. Determine if you want to write it in wikicode or in lua
    2. Actually write the code
  5. If dynamic;
    1. Write documentation for it
    2. Consider using a JS form for it
    3. Test, fix any bugs
  6. Finish up with some housekeeping

Decide what to do[edit | edit source]

This can be one of the hardest things to do. You need to identify a gap in the market, so to speak. Here's some examples to consider:

  • A skill level up calculator - how many of what items will I need to get from my current level/experience to a certain level/experience in this skill?
  • A profit calculator - if I obtain/make/process this item, how much profit/loss will I make and what is the cost per experience point I gain?
  • A miscellaneous calculator - these cannot be generalised as they vary a lot more. Some examples include: Calculators/Combat level, [[Calculators/Max hit]], Calculators/Food healed etc.

If you're stuck for what to do, you can take a look at the calculator ideas to give you an idea of what you could do. Be sure to check Calculators to see if its already been done, though.

If you have an idea but feel like you need additional thoughts on it, you can head into one of our chat media and see what people think: on-site chat, in-game clan chat, IRC channel. You can also contact me or one of many other active users to chat.

Dynamic or static?[edit | edit source]

This is actually more or less determined by what you choose to do. Skill level-up calculators will need some user inputs, so will be dynamic. Profit calculators work well static; they don't need a user input to work. It should be a simple matter of deciding which is which.

Inputs, results and how[edit | edit source]

Again, this is based on the function of your calculator. Inputs for dynamic calculators vary with the user, typically they'll be a user's level or experience, or some other choice that the user makes, such as wearing a specific item (like an XP-boosting set).

Don't think that static calculators don't have inputs! They do; they just don't vary with the user. Usually this is a the price of the item, but can also be the experience gained when obtaining/making/processing the item or the time needed to make the item. Dynamic calculators are likely to vary with these values too.

How the result looks is important. The user wants to be able to find what they're looking for easily, and be able to understand it. You may want to output a table - these are easily customised and can be made sortable; most skill and profit calculators will likely use tables. You can also output sentences or just a number. Depending on the calculator this can work well.

Deciding how your calculator does its function will depend on your knowledge of mediawiki and what it can do; see next section.

Writing your calculator code[edit | edit source]

I can't really provide a commentary for how to write your calculator, since they won't be the same. I can however provide some useful code for writing your calculator!

If you need ideas or help on how to implement your calculator, don't hesitate to contact me.

Template parameters[edit | edit source]

Dynamic calculators only. When you need to put in a user-defined variable, you need to use {{{variablename}}}, with variablename replaced by the name or number of the variable. The difference between a name and a number is its use: a name will need to be explicitly stated, while a number can be assumed from its position.

For example, a template needs 3 inputs. If you call them a, b, and c, to use the template you'll use {{templatename|a=pie|b=cheese|c=42}}. If you called them 1, 2, and 3, to use them you'll use {{templatename|pie|cheese|42}} (or you could use {{templatename|1=pie|2=cheese|3=42}}).

A simple way to do this is to make a mathematical formula to represent what you want to calculate, then convert it to wikicode bit by bit. For example, this accuracy bonus formula from Combat Stats: Accuracy is what your result is going to be, and L is the user's level, an input. The first step is to convert the mathematical representation into a programming representation: L^3/1250 + 4*L + 40 (notice the addition of ^, / and *). Next, we turn the input into a template parameter: {{{L}}}^3/1250 + 4*{{{L}}} + 40 (L has become {{{L}}}). Finally, we need to use the #expr: parser function (covered more later) to make it actually calculate, so we wrap that around the formula: {{#expr:{{{L}}}^3/1250 + 4*{{{L}}} + 40}}. Done! If you saved that to Template:Accuracy, you could call it for level 99 with {{Accuracy|L=99}}.

A parameter can be given a default value by using a pipe after its name: {{{L|10}}} would make L default to 10 if it was not given. This default can be different for each use of the parameter in the code, if necessary.

Magic words[edit | edit source]

These are functions, much like parser functions below, that do basic things. They usually follow the format {{name}} or {{name:input}}.

Pagename
  • {{PAGENAME}} - The name of the page without a namespace - Gaz Lloyd/Guides/Calculators
  • {{SUBPAGENAME}} - The name of the subpage - Calculators
  • {{BASEPAGENAME}} - The name of the base page - Gaz Lloyd/Guides
  • {{FULLPAGENAME}} - The full name of the page - User:Gaz Lloyd/Guides/Calculators

Useful for altering output based on the name of the page - though less used in calculators, it helps to be aware of them.

formatnum
  • Usage: {{formatnum:number}}
  • Function: Formats a number by adding commas every third digit from the left (thousands separator).

Often used with #expr: (see below), formatnum makes larger values more readable.

URLs
  • {{urlencode:string}} - encodes the string into URL-safe characters
  • {{fullurl:page|options}} - generates a long URL to a page. Most useful for providing edit this page links.

Often used in conjunction, these allow text-to-url manipulation. For fullurl, you'll need to wrap it in single square brackets, and use a space to provide a link title (acts as an external link. Example:

  • [{{fullurl:Pie}} Pie] - Pie (without any parameters, is equivalent to [[Pie]])
  • [{{fullurl:Pie|action=edit}} edit pie] - edit pie (the parameter action=edit opens the page in edit mode)
  • [{{fullurl:Pie|action=history&limit=100}} last 100 edits to pie] - last 100 edits to pie (notice that the first parameter doesn't need a &, but the second (and more) need one)
  • [{{fullurl:Pie|&action=watch}}#{{urlencode:See also}} Watch pie at see also] - Watch pie at see also (note that see also contains a space, which would be misinterpretted without the urlencode; with the urlencode, the space becomes a +)

Like pagenames above, less used in calculators but useful nonetheless.

Cases
  • {{lc:string}} - forces the entire the string to be lowercase
  • {{uc:string}} - forces the entire the string to be uppercase
  • {{lcfirst:string}} - forces the first letter of the string to be lowercase
  • {{ucfirst:string}} - forces the first letter of the string to be uppercase

Case modifiers are very useful for the text based parsers, as they're all case-sensitive. Its generally a good idea to choose one (either lc or uc) and use it for inputs.

Parser functions[edit | edit source]

The basis of calculators, most if not all will use some sort of parser function. Parser functions are things that will calculate or do something based on inputs. Here's some of the most useful ones.

All parsers use the format {{#name:input|param1|param2 ...}} etc, usage notes given for each. Where possible, I'll give a sentence form of each parser, which may help you remember it.

I shall refer to parser functions in sentences without the braces (unless giving an example), e.g. #name:. This saves using nowiki all the time.

Whitespace (spaces, linebreaks) in parsers are ignored, unless otherwise stated.

#expr:

  • Usage: {{#expr:expression}}
  • Function: calculates the result of an input mathematical expression

#expr: is one of the most commonly used parsers. It only has one input, and its output is the mathematical result of the input.

List of functions here.

#if:

  • Usage: {{#if:variableparameter|result if it exists|result if it does not}}
    • If variableparameter is not whitespace, output result if it exists, otherwise output result if it does not.
  • Function: check for existence of a parameter

#if: is a widely-used parser. It checks its first input for its existence - that is, is it not whitespace. If it isn't whitespace, it'll output its first parameter. Otherwise it'll output its second parameter. #if: will only be used in dynamic calculators. Using if on a plain text string will result in the first parameter always being output.

Using #if: to provide a default value isn't needed, and has been superseded by template defaults. e.g. {{#if:{{{1|}}}|{{{1}}}|pie}} is much better written as {{{1|pie}}}. If you need to put some formatting or text around the variable that should be blank if the variable is not defined, you should use #if: like so: {{#if:{{{1|}}}|we like to {{{1}}}, don't you?|}}.

An important note is that there is a significant output difference between {{#if:{{{1}}}|yes|no}} and {{#if:{{{1|}}}|yes|no}}, even though the only input difference is that parameter 1 has been given a default of an empty string in the second but not the first. This is because when called and 1 is not present, the first will input a literal {{{1}}} to the #if:, which results in yes being output; whereas the second will have its default called, so the #if: will evaluate to no. A different phenomena can occur with parameter defaults - if the parameter is specified, as the empty string, it will override the parameter's default. This is summarised in the following table:

Inputs {{#if:{{{1}}}|yes|no}} {{#if:{{{1|}}}|yes|no}} {{#if:{{{1|test}}}|yes|no}} {{{1}}} {{{1|test}}}
1 not present yes no yes {{{1}}} test
1= (empty string) no no no
1=test2 yes yes yes test2 test2

#ifeq:

  • Usage: {{#ifeq:variable|comparison|value if match|value if no match}}
    • Compare the variable to the comparison. If they are the same, output value if match, otherwise output value if no match.
  • Function: Directly compare to strings.

#ifeq: is a frequently used parser for comparing an input to a set value, or two inputs to each other. The inputs are compared directly, character to character. It is case-sensitive. Some ideas of usage:

  • {{#ifeq:{{{1|yes}}}|yes|cheese|pie}} - check for a value with the input default being that value
  • {{#ifeq:{{{1|no}}}|yes|cheese|pie}} - check for value with the input default not being that value
  • {{#ifeq:{{{1|yes}}}|{{{2|no}}|cheese|pie}} - comparison between two variables

As mentioned, this is case sensitive, so is best used with lc: to force the input(s) to lowercase, though it isn't necessary with a dynamic form if only specific values can be chosen - be aware that if you forget the casing of your variable you might end up with an error which takes awhile to find; using lc: can save yourself the headache later.

#ifexpr:

  • Usage: {{#ifexpr:mathematical comparison|value if correct|value if incorrect}}
    • If this expression is correct, output value if correct, otherwise output value if incorrect.
  • Function: Make a yes/no mathematical comparison (equality, inequality, logical) and base outputs on that.

#ifexpr: is used to make decisions based on numbers. It uses all the same functions as #expr:, but doesn't output the expression result. Typical uses include checking for correct inputs (making sure goal exp/level is higher than current exp/level), checking for profit/loss (if spending>selling, output 'loss', otherwise 'profit'), and validation (more on that later).

#iferror:

  • Usage: {{#iferror:test|value if error|value if no error}}
    • If there is an error with the functions in test, output value if error. Otherwise, output value if no error, or, if that is not given, output test.
  • Function: Check for an error in an input function.

#iferror: is largely used for validation. It checks for an error class in the test value - this is generated by bad expressions in #expr: or #ifexpr:, bad times in #time:, templates loops, recursions, etc. If it finds an error class, it will output whatever is in the first parameter - this can be left blank and nothing will be output. If there isn't an error, whatever is in the second parameter is output - if the second output is missing, the test is output instead. Therefore, the following examples do the same thing:

{{#iferror:{{#expr:{{{1|}}*2}}|[email protected]@@@@@@|{{#expr:{{{1|}}*2}}}}
{{#iferror:{{#expr:{{{1|}}*2}}|[email protected]@@@@@@}}

#switch:

  • Usage: {{#switch:variable to test|case1=result1|case2=result2|...|default value}}
    • Compare the variable to test to a list of cases. If there is a match, switch the case and output the corresponding result. If there is no match output a default value, if given.
  • Function: Comparing a variable to a list of set values and outputting a corresponding result if there's a match.

#switch: is used much like #ifeq: is, but when there's more than one thing to compare with. It is case-sensitive. Example:

{{#switch:{{{1|win}}}
|win=3
|loss=0
|draw=1
|pie=42
|0
}}

The input is compared one by one with the case strings (on the left of the =), and if a match is found the corresponding result (on the right of the =) is output. If it cannot find a match the default is output - which in this is the bottom result - it has not case or =. Note that the input parameter default - occurring when input 1 is missing (will treat input as win giving output 3) is different to the #switch: default - occurring when input 1 matches none of the cases (will output 0).

You can also explicitly define a default using #default=result, which can be placed anywhere in the switch, and works better with the fall-through mechanic.

The fall-through mechanic enables multiple inputs to take the same result concisely. Example:

{{#switch:{{{1|win}}}
|winrar
|win=3
|fail
|epic fail
|loss
|#default=0
|draw=1
|cheese
|pie=42
}}

In this example, both winrar and win give the same output of 3; fail, epic fail, and loss give 0, which is the #switch: default too; and cheese and pie give 42.

The input, the cases and the results can be more complex than just simple strings, for example:

{{#switch:{{{1|a}}}
|a={{#expr:{{{2}}}*100}}
|b={{#expr:{{{2}}}/100}}
}}

Or even this crazy example:

{{#switch:{{#expr:{{{1}}}*50}}
|{{#expr:{{{3}}}+1}}={{#expr:{{{2}}}*100}}
|{{#expr:{{{3}}}-1}}={{#expr:{{{2}}}*100}}
}}

I would advise against such constructs though.

You can also put switches inside switches, if needed:

{{#switch:{{{1|a}}}
|a={{#switch:{{{2|c}}}
    |c=e
    |d=f
   }}
|b=b
}}

Variables

  • Usage:
    • {{#vardefine:name|value}}
    • {{#vardefineecho:name|value}}
    • {{#var:name|default}}
  • Function: Store a variable for later use.

Variables are used to store some value for recall later. They store the literal value and don't do any evaluation on it (unless you also cache the appropriate functions) - if you store 6*7, when you recall it you will get the result 6*7, not 42; if you store {{#expr:6*7}} you will get the result 42.

  • #vardefine: is used to define variables. The value is stored under name. You can define more than one.
  • #var: is used to recall a variable that was set earlier. It will recall the value stored under name. You can recall a variable more than once.
  • #vardefineecho: is the same as #vardefine:, but also prints the value. It is equivalent to {{#vardefine:a|b}}{{#var:a}} for a variable of value b stored under name a.

Variables are extremely useful for setting up a calculator. For example, in a skill calculator you can set up a variable that calculates the experience remaining to goal. Then you no longer need to calculate that variable every time you need it.

You can redefine variables when needed. For example:

{{#vardefine:a|pie}}

{{#var:a}}

{{#vardefine:a|cheese}}

{{#var:a}}

gives


pie


cheese

You can also create an increasing variable:

{{#vardefine:a|42}}

{{#var:a}}

{{#vardefine:a|{{#expr:{{#var:a}}+42}}}}

{{#var:a}}

gives


42


84

Variables will carry into templates used on the page. For example, if you had a table row template similar to this:

|-
|{{{item}}}
|{{{xp}}}
|{{#expr:{{#var:xp}}/{{{xp}}}}}

Your calculator can be along the lines of:

{{#vardefine:xp|{{#expr:{{{goalxp}}} - {{{currxp}}}}}}}

{{TableHeadeTemplate}}
{{TableRowTemplate|item=bones|xp=4.5}}
{{TableRowTemplate|item=big bones|xp=15}}
{{TableRowTemplate|item=dragon bones|xp=72}}
|}

This will work just fine - defining the variable first then using it within a template on the page.

Templates[edit | edit source]

The wiki has many templates already created for a function, and you may find them useful in your calculators.

GEMW

The Grand Exchange Market Watch is our system of using Grand Exchange prices. Most calculators will utilise it.

  • {{GEPrice|item}} - retrieve the price for item
  • {{GEP|item}} - retrieve the price for item, without commas
  • {{item1|item2|...}} - retrieve total price of one of each of a number of items
  • {{name1=item1|qty1=quantity1|name2=item2|qty2=quantity2|...}} - retrieve total price of a number of items, with varying quantities of each item
  • {{Ovlcost|number of 3-doses}} - shortcut for the GE price of making overloads (without scroll of cleansing or other buffs); defaults to returning 4 doses (i.e. {{ovlcost}} = {{ovlcost|4/3}})

Modules:

Number manipulation
  • {{fe|number}} - bundles forumatnum: and #expr: into a short call for convenience
  • {{,|number}} - removes any commas from number
  • {{SF|number|places}} - rounds number to a places significant figures, rather than decimal places
  • {{Max|number1|number2}} - outputs the maximum of number1 and number2
  • {{Min|number1|number2}} - outputs the minimum of number1 and number2
  • {{Coins|number}} - formats a number by adding commas, adding an image of coins and colouring the text, based on the value (for use in tables)
  • {{NoCoins|number}} - as coins, but without the image (for use in prose)

Modules:

Experience
  • {{XP|level}} - returns the minimum experience for level
  • {{Level|experience}} - returns the level that experience corresponds to
  • {{XP to level|experience|level}} - returns the experience needed to get from experience to level
  • {{XP level to level|level1|level2}} - returns the experience difference from level1 to level2
  • {{Min XP for level|level}} - returns the minimum experience required for level - the same as {{XP|level}}
  • {{Max XP for level|level}} - returns the maximum experience required for level - same as {{XP|level+1}}-1
Formatting
  • {{plink|page}} - generates an image linking to the page followed by a link to the page, making it easy to link to things: {{plink|Abyssal whip}} = Abyssal whip.png: RS3 Inventory image of Abyssal whipAbyssal whip; see documentation for overrides
  • {{plinkp|page}} - plink but without the following link (so it is just an linking image)
  • {{chatl|page}} - plink but for chatheads
  • {{plinkseed}} - plink but for seeds
  • {{skill clickpic|skill}} - plinkp but for skills
  • {{colour|text colour (optional)|text|background colour (optional)}} - colours the text with the colour and/or background colour.
  • {{Hover|text|hover text}} - gives text a hover text with a consistent look
Tables
  • {{ctr}}, {{left}}, {{rt}} - aligns the table contents to the center, left, or right respectively.
  • {{hsk|value}} - place this at the beginning of a table cell to provide a hidden sortkey of value; this can be used to override or fix a table's sorting if it is not correct. Note that using data-sort-value is preferred to this.
Escapes

Sometimes you want/need a specific character, but can't use it because it has a special meaning in the wikicode at that point. These escapes are used for that function.

  • {{!}} - outputs a pipe | - parser functions cannot contain raw pipes, or else they are interpreted as part of the parser function; for example, if you need to build a table (or table row) inside a parser (if this variable exists, output this table, otherwise output nothing), you need to use this template in place of all table-structure-pipes
    • {{!!}} - outputs ||
  • {{=}} - outputs a =, useful if you want your switch case to contain a =
  • {{(}} and {{)}} - { and } respectively
  • {{nbsp}} - outputs a non-breaking space
  • {{comma}} - for a comma (mostly for use in DPL calls)

Check out Category:Mathematical templates and Category:Formatting templates for more

Pulling it together[edit | edit source]

Now you some useful code, what's important is arranging it so it interacts to produce what you want easily. Here's some tips on that.

Validation

Validation is the process of checking if the inputs are valid. Most of the time validation is a combination of parsers, templates and other things, and sometimes can be quite complex. Its a good idea to do this, especially in dynamic calculators.

Checking for correct item names and prices
If your calculator has input 1 an item name, and input 2 the number of that item, you could use something like {{coins|{{#iferror:{{#expr:{{GEP|{{{1}}}}}*{{,|{{{2}}}}}}}|0}}}} - this effectively validates that both 1 is the name of a tradeable item, and 2 is a proper number (accounting for formatted numbers). If one/both are bad, it outputs zero, otherwise it outputs the value. The entire thing is formatted nicely with coins.

This type of validation I like to call "on the spot validation", as its validating the inputs when they're occuring in the output.

I personally prefer using #iferror: for checking for the validity of an exchange page, rather than the expensive parser #ifexist: - you may unknowingly run into the expensive parser function limit of 100 per page, especially in a large calculator.


Checking that only one of multiple inputs are active
In dynamic calculators especially, you may have a situation where there are multiple things a user can do, but only one is allowed to be active - for example, when calculating a maximum hit with melee, you cannot have both a black mask and void melee active, as you cannot have 2 helmets on at once. In this sort of situation, you may opt for something like so:

{{#ifexpr:({{#ifeq:{{lc:{{{1|no}}}}}|yes|1|0}} and {{#ifeq:{{lc:{{{2|no}}}}}|no|0|1}})=1|Cannot have 1 and 2 active at the same time|Correct input}}

In this scenario, input 1 is a yes/no question, and input 2 may be yes/no, or may be multiple choice with no as a choice. None of the choices of 2 other than no can be active with 1, and 1 cannot be active with any of the choice of 2 other than no. The code first checks 1 to see if it matches yes, it is given an arbitrary (chosen as its a simple number) value of 1, otherwise its give 0. 2 is checked in a similar way, but compares to no, and outputs 0 is the match is correct, and 1 otherwise. An #ifexpr: is then used to check if both numbers equal 1 (via the logical operator and - if you prefer you could instead add them together and check if that equals 2), and if they do both equal 1, an error message is output. In a sentance: if both 1 is active and 2 is not inactive, there is an error.

This validation could be on the spot, but I think its more suited to "pre-calculation validation", in which the inputs are validated before any calculation is carried out. See the next point:


Pre-calculation validation
As said above, sometimes its better to validate the inputs before any calculation is carried out. You may choose to do this via layered parsers. For example, expanding on the above scenario so that if input 3 is active, input 1 must also be active (but 1 doesn't require 3 to be active):

{{#ifexpr:({{#ifeq:{{lc:{{{1|no}}}}}|yes|1|0}} and {{#ifeq:{{lc:{{{2|no}}}}}|no|0|1}})=1|Cannot have 1 and 2 active at the same time|{{#ifeq:{{lc:{{{3|no}}}}}|yes|{{#ifeq:{{lc:{{{1|no}}}}}|no|Error - if 3 is active 1 must also be active|rest of calculator here}}|rest of calculator here}}}}

This will get messy very quickly if there's many conditions that the inputs must meet. You may also notice that the rest of the calculator code is used twice, which is really nasty. Instead, a better way would be to use variables:

{{#vardefine:error1|{{#ifexpr:({{#ifeq:{{lc:{{{1|no}}}}}|yes|1|0}} and {{#ifeq:{{lc:{{{2|no}}}}}|no|0|1}})=1|Cannot have 1 and 2 active at the same time.}}}}

{{#vardefine:error2|{{#ifeq:{{lc:{{{3|no}}}}}|yes|{{#ifeq:{{lc:{{{1|no}}}}}|no|Error - if 3 is active 1 must also be active.}}}}}}

{{#if:{{#var:error1}}{{#var:error2}}|''{{#var:error1}} {{#var:error2}}''|calculator code}}

This way assigns a variable to each possible error (remember they must all be distinct names). Each error is now separate from each other, and readability is improved somewhat. In each case the validation code outputs a blank if there is no error - this then means we can use #if: to check both at once. If both error variables are blank (so both result in no error) then the calculator code is output. If one or both are present (one or both result in error) then it outputs the variables (bold, for emphasis), thereby displaying the what the error(s) is/are.


Table row templates

A useful thing to do to simplify making a table is to create a template for the row. This is made in the normal way a template is, but has formatting to make it a row. For example, if this was your row template:

|-
|{{{item}}}
|{{{level}}}
|{{{xp}}}
|{{coins|{{#iferror:{{#expr:{{GEP|{{{item}}}}}}}|0}}}}
|{{{finitem}}}
|{{coins|{{#iferror:{{#expr:{{GEP|{{{finitem}}}}}}}|0}}}}
|{{coins|{{#iferror:{{#expr:{{GEP|{{{finitem}}}}}}}|0}}-{{#iferror:{{#expr:{{GEP|{{{item}}}}}}}|0}}}}
|{{coins|({{#iferror:{{#expr:{{GEP|{{{finitem}}}}}}}|0}}-{{#iferror:{{#expr:{{GEP|{{{item}}}}}}}|0}})/{{{xp}}} round 2}}

You would use something like this on a calculator page:

{| class="wikitable sortable"
!Material
!Level
!Experience
!Material cost
!Product
!Product price
!Profit
!Profit per experience
{{table row template name|item=Uncooked berry pie|finitem=Redberry pie|level=10|xp=72}}
{{table row template name|item=Bucket of milk|finitem=Pat of butter|level=38|xp=40.5}}
|}

Which will result in:

Material Level Experience Material cost Product Product price Profit Profit per experience
Uncooked redberry pie 10 72 2,148 Redberry pie 1,475 -673 -9.35
Bucket of milk 38 40.5 388 Pat of butter 431 43 1.06

The row template makes generating tables easier.

Dynamic calculators[edit | edit source]

Documentation[edit | edit source]

Dynamic calculators can have many complex inputs that require specific formats, so its a good idea to write documentation for it. I usually follow this order.

Basic documentation

Basic documentation is the first documentation you write for the calculator. Commonly its just a list of the template parameters for it, so you can remember the names of them, though it may contain a short description of what the input requires. Not very user friendly, but its more for you (the creator) as a reference.

I highly recommend writing this as you write the base code. Each time you use a new template parameter, just add it to the left.

Example:

<noinclude><pre>{{template name
|param1=your exp
|param2=goal level
|param3=what food you're making
}}</ pre></noinclude>
Expanded documentation

Sometimes done at the same time as basic, expanded documentation provides a more detailed explanation of each parameter (e.g. the main cases any #switch: of a parameter accepts). It often uses an example, to reiterate the point. This is significantly more user

Example:

<noinclude><pre>{{template name
|param1=your exp; no commas
|param2=goal level
|param3=what you're making, one of 'pie', 'cheese' and 'beer'; case-insensitive
}}</ pre>

For example:
<pre>{{template name
|param1=1000
|param2=20
|param3=pie
}}</ pre>
gives
{{template name
|param1=1000
|param2=20
|param3=pie
}}
</noinclude>
Full documentation

Full documentation is most often created after the template's completion. It is placed on a "doc subpage"; that is, {{FULLPAGENAME}}/doc (or template:template name/doc) for that template. On the template itself, this code is placed at the end of the template:

<noinclude>{{/doc}}</noinclude>

This transcludes the documentation onto the page while both not transcluding it when the template is used, and using a lot less space.

The doc subpage is headed by {{documentation}}, typically followed by a short description of what the template does, along with notes of mistaken names (This template does blahblahblah. If you were looking for the similarly named template that does blehblehbleh, see Template:acb.), then followed by an adapted list of parameters.

The list of parameters is often similar to the list given by expanded documentation, maybe a little more descriptive, all in a pre tag. To be honest, I wouldn't call that full documentation.

What I'd call full is a list of parameters in a pre tag without description, then each parameter having a third-level section each, where they are described fully - including alternate inputs accepted as others (e.g. light and of light and staff of light all accepted as the same thing in a magic max hit calculator). For examples of this, see Template:Infobox Item, Template:Magic max hit and Template:CiteForum (there are many other good examples).

At the end of the documentation, the categories of the actual template are placed inside an includeonly bracket. In essence, the only thing on the template page is the template code and the transcluded doc page. Everything else that affects the template, such as construction tags, RfDs, categories and everything go on the doc subpages and are transcluded onto the page.

It is very discourteous to provide no documentation at all - users without the ability to interpret the template code won't be able to use the template without it! So I encourage you to document your templates.

Dynamic forms[edit | edit source]

For full reference, see User:Quarenon/Scripts/Calc

Creating the dynamic form for the completed calculator is easier than you might think. Normally, I just copy the code of one of the existing ones, then alter the values to reflect the calculator I'm writing. You do need a basic understanding of the code to do this however, so...

Input code
<pre class="jcConfig">
 template  =
 form      = 
 result    = 
 param     = ||||
</pre>
  • template is the name of the page where the calculator code actually is stored. It is the same as what you would put between the braces to use the template on a page normally (e.g. Template:Abc would be Abc, Abc (mainspace page) would be :Abc, User:Example/Abc would be User:Example/Abc)
  • form is the form identifier. This needs to be a unique name. A generally good idea is to use something related to your calculator, e.g cookingCalcForm, etc
  • result is the result identifier. Like form, this needs to be unique. An example would be cookingCalcResult
  • param is what defines the parameters for the calculator. Unlike the above three, you can have as many params as you need. param takes a specific syntax of input - Parameter Name|Displayed Name|Default Value|Input Type|Range. The pipes are required, though defining all the inputs is not.
    • Parameter Name is the name of the parameter that you are inputting - what you put inside the triple braces in the calculator code. This is required.
    • Displayed Name is the name of the parameter you want displayed to the user - leaving this blank will display Parameter Name instead.
    • Default Value is the value that will appear in the form field before the user changes it.
    • Input Type is the type of parameter that should be input - provides a basic level of validation. It can be one of the following:
      • string - any value (default)
      • article - any article name (autocomplete turns on; see full doc for more info)
      • number - any number (within range)
      • int - any integer (within range)
      • select - creates a drop-down box to select from a set of values
      • check - creates a checkbox
      • hs - hiscores lookup
      • fixed - the default value cannot be changed but is shown to the viewer
      • hidden - the default value cannot be changed and is not shown to the viewer
      • semihidden - the default value cannot be changed and is not shown to the viewer, but still creates a (hidden) box in the form, for inter-script usage
    • Range the range of values that are allowed. Depends on input type:
      • number and int - a range that the input is valid for given in the format min-max - if no value for min and/or max is given then ±infinity is assumed.
      • select - a comma-separated list of inputs that will appear in the drop-down box
      • check - value if selected,value if not selected
      • hs - see documentation

Putting this on a page won't do a lot. You'll need the following code also:

<div id="formvalue"><span style="color:red;">'''The calculator failed to load'''</span></div>
<div id="resultvalue">Please submit the form</div>

This defines where the form and result will appear. formvalue is whatever you input to form above, and similarly resultvalue is what you input to result. Whatever appears inside the div will be replaced when the calculator loads (form) or the form is submitted (result). It is a good idea to give a warning message, as I have done above, inside the form div which disappears when the calculator form loads.

You can place the two divs anywhere - inside a table so they line up next to each other, other ends of the page, whatever, as long as they both appear after the definition of the form in the pre tags.

Testing[edit | edit source]

Probably the most important part of the process. A calculator that doesn't work is no use to anyone!

You may ask "why testing is at the end of the page then, after making the form?" Thats because with the form, testing many values is significantly easier than using a series of previews.

Some good techniques:

  • If you're using #ifeq, then check that both ways work
  • If you're using #switch, then make sure that all values work
  • If you're using #ifexpr, then make sure that borderline values go the correct way, and that extreme values don't break the calculator
  • Make sure that the default values work
  • Make sure that mathematical errors, such as division by zero, square roots of negative numbers, arcsines and arccosines of numbers outside of the range of -1 to 1, etc, do not occur.
  • Get some known data and make sure it works
  • Get suggested data from other users and check that it doesn't break - work it out by hand and make sure it works out correctly
  • Get other users to have a go and get their opinion on it

Housekeeping[edit | edit source]

Finishing up

Add an introduction to the page, giving a basic explanation of what the calculator does. If it has any quirks or has any interesting things, mention and explain them. If its a more complex calculator, you might need more expansive documentation, for example Calculator:Revolution.

Guidelines

Following the guidelines, make sure to add the relevant template of {{StaticCalculator}} and {{JSCalculator}} to the page, and if you have a backend, also add {{calc use}}. Make sure to add Category:Calculators and the category relevant to the calculator (the skill, minigame, etc). See RS:CALC for more gudelines to check.

Directory

Probably the simplest step: go to Calculators, edit the appropriate section, add a new row with your calculator, provide a description and save. Done!

You may also want to add a mention or the {{HasCalculator}} template to a relevant page.

Examples[edit | edit source]

There's a number of examples available in the calculators category.

Final note[edit | edit source]

I hope this has helped you, feel free to contact me about either improving this page (if you think its poorly worded or whatever), or asking me for help on a calculator - I'll be happy to oblige.

Quest.png Gaz Lloyd 7:^]Events!99s