<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://159.203.101.162/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tom+Parker</id>
	<title>PCGen Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://159.203.101.162/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tom+Parker"/>
	<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php/Special:Contributions/Tom_Parker"/>
	<updated>2026-05-18T12:55:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.31.1</generator>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4350</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4350"/>
		<updated>2018-11-13T02:17:31Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* getOther */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
The getOther function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getOtherfunction is:&lt;br /&gt;
  getOther(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables and CAN have MODIFY/MODIFYOTHER tokens.&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)|PRIORITY=1000&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;br /&gt;
&lt;br /&gt;
===Scope Change===&lt;br /&gt;
&lt;br /&gt;
Effective in about April 2018, the scopes changed.  What was originally just EQUIPMENT became PC.EQUIPMENT.  This was done in preparation for things that are not the PC (think familiars, among other things).&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4349</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4349"/>
		<updated>2018-11-13T02:17:15Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* getOther */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getOther(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables and CAN have MODIFY/MODIFYOTHER tokens.&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)|PRIORITY=1000&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;br /&gt;
&lt;br /&gt;
===Scope Change===&lt;br /&gt;
&lt;br /&gt;
Effective in about April 2018, the scopes changed.  What was originally just EQUIPMENT became PC.EQUIPMENT.  This was done in preparation for things that are not the PC (think familiars, among other things).&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4348</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4348"/>
		<updated>2018-11-13T01:54:46Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* DYNAMIC (PCC File) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables and CAN have MODIFY/MODIFYOTHER tokens.&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)|PRIORITY=1000&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;br /&gt;
&lt;br /&gt;
===Scope Change===&lt;br /&gt;
&lt;br /&gt;
Effective in about April 2018, the scopes changed.  What was originally just EQUIPMENT became PC.EQUIPMENT.  This was done in preparation for things that are not the PC (think familiars, among other things).&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4347</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4347"/>
		<updated>2018-11-13T01:45:51Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Material Changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)|PRIORITY=1000&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;br /&gt;
&lt;br /&gt;
===Scope Change===&lt;br /&gt;
&lt;br /&gt;
Effective in about April 2018, the scopes changed.  What was originally just EQUIPMENT became PC.EQUIPMENT.  This was done in preparation for things that are not the PC (think familiars, among other things).&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4346</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4346"/>
		<updated>2018-11-13T01:44:34Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* An Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)|PRIORITY=1000&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4345</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4345"/>
		<updated>2018-11-13T01:43:19Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* CHANNEL (VARIABLE File) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   CHANNEL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4344</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4344"/>
		<updated>2018-11-13T01:42:11Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* To be completed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==Channels==&lt;br /&gt;
&lt;br /&gt;
The internal processing system in general needs a method of communicating with the user interface.  Traditionally we have done this through hard-coded systems, but with increased flexibility of the formula system, it makes less and less sense to have hard-coded capabilities.  We also have scenarios such as Gender (and a few cursed objects) where an object needs to override user input (at least temporarily).&lt;br /&gt;
&lt;br /&gt;
In order to do this, we are enabling items in the UI to communicate directly to the formula system.  This will allow one to alter the other.  There are two ways this is done:&lt;br /&gt;
* Channels&lt;br /&gt;
* Input function&lt;br /&gt;
&lt;br /&gt;
Channels are the actual storage location (think of it as a special type of variable) that holds the information that is communicated between the core and the user interface. If either the core or the UI changes the value, it is changed.  Channels can be created by the CHANNEL: token in the variable file.  &lt;br /&gt;
&lt;br /&gt;
As special variables, Channel names do NOT conflict with variable names, but they also have conflict rules that are identical to the variable naming rules as shown elsewhere on this page.&lt;br /&gt;
&lt;br /&gt;
Note that some CodeControls ask for a Channel.  This allows the data team to override the internal (and non-accessible) channel with one the data team can then use.&lt;br /&gt;
&lt;br /&gt;
The new formula system can read a channel by using the input(x) function.&lt;br /&gt;
&lt;br /&gt;
===CHANNEL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* CHANNEL defines a channel, usable from anywhere within the UI&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the Channel&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the channel name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   CHANNEL:PC.STAT|NUMBER=StatInput&lt;br /&gt;
&lt;br /&gt;
A CHANNEL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===input Function===&lt;br /&gt;
&lt;br /&gt;
The input function returns the value of a given channel.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  input(x)&lt;br /&gt;
&lt;br /&gt;
* x is a Channel name.&lt;br /&gt;
&lt;br /&gt;
Note: You may be caught off guard here by the simplicity of this method [you aren't providing a scope].  If the Channel is defined locally to an object, such as the StatInput example above, then input(&amp;quot;StatInput&amp;quot;) will only work if called from the stat. So in equipment, calling input(&amp;quot;StatInput&amp;quot;) would generate an error, as there isn't a &amp;quot;StatInput&amp;quot; Channel in PC.EQUIPMENT.  However, there are ways around that, such as:&lt;br /&gt;
  getOther(&amp;quot;PC.STAT&amp;quot;,&amp;quot;Dex&amp;quot;,input(&amp;quot;StatInput&amp;quot;))&lt;br /&gt;
...which would grab the &amp;quot;StatInput&amp;quot; channel from the Stat with the abbreviation &amp;quot;Dex&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===An Example===&lt;br /&gt;
&lt;br /&gt;
In practice, Gender might be controlled with the following:&lt;br /&gt;
&lt;br /&gt;
In the DataControl file:&lt;br /&gt;
   DYNAMICSCOPE:GENDER&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
   GENDER:Male &amp;lt;&amp;gt; MODIFY:Reversed|SET|Female&lt;br /&gt;
   GENDER:Female &amp;lt;&amp;gt; MODIFY:Reversed|SET|Male&lt;br /&gt;
In the Variable file:&lt;br /&gt;
   CHANNEL:PC|GENDER=InputGender&lt;br /&gt;
   GLOBAL:GENDER=ActualGender&lt;br /&gt;
   LOCAL:GENDER|GENDER=Inverted&lt;br /&gt;
Then in the global Modifier file:&lt;br /&gt;
   MODIFY:ActualGender|SET|input(&amp;quot;InputGender&amp;quot;)&lt;br /&gt;
A cursed object would have:&lt;br /&gt;
   MODIFY:ActualGender|SET|getFact(&amp;quot;GENDER&amp;quot;,value(),Reversed)&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4343</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4343"/>
		<updated>2018-11-13T01:18:20Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Built in Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
====key====&lt;br /&gt;
&lt;br /&gt;
This function returns the key of an object (must be a CDOMObject)&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  key(x)&lt;br /&gt;
&lt;br /&gt;
* x is an Object (like a skill)&lt;br /&gt;
&lt;br /&gt;
Example: key(myFavoredClass)&lt;br /&gt;
[This assumes myFavoredClass is a legal variable name that probably contains a CLASS]&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==To be completed==&lt;br /&gt;
* Channels&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4342</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4342"/>
		<updated>2018-11-13T01:15:44Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
====get====&lt;br /&gt;
&lt;br /&gt;
This function returns an actual object of the given type (such as retrieving a SKILL or ALIGNMENT).  This is useful for other functions where this object is used.&lt;br /&gt;
&lt;br /&gt;
The format of the get function is:&lt;br /&gt;
  get(x,y)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
&lt;br /&gt;
Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getFact====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a FACT.  &lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is an Object type (like &amp;quot;SKILL&amp;quot;) [technically this is the FORMAT, but not all are enabled as formats yet]&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
Example: getFact(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,&amp;quot;IsExclusive&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
====getOther====&lt;br /&gt;
&lt;br /&gt;
This function returns the value of a remote local variable.&lt;br /&gt;
&lt;br /&gt;
The format of the getFact function is:&lt;br /&gt;
  getFact(x,y,z)&lt;br /&gt;
&lt;br /&gt;
* x is the remote scope from which an object is being retrieved (e.g. &amp;quot;PC.SKILL&amp;quot;)&lt;br /&gt;
* y is a CDOMObject OR the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
* z is the name of the variable to be returned... note this is NOT in quotes&lt;br /&gt;
&lt;br /&gt;
Example: getOther(&amp;quot;PC.SKILL&amp;quot;,&amp;quot;Hide&amp;quot;,IsExclusive)&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==To be completed==&lt;br /&gt;
* Channels&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4341</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4341"/>
		<updated>2018-11-13T01:07:24Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Understanding SubScopes in relation to MODIFYOTHER */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
Additional functions specifically related to PCGen are available:&lt;br /&gt;
* get: This function takes two arguments.  The first is an Object type (like &amp;quot;SKILL&amp;quot;), the second is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
**Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
* getFact: This function returns the value of a FACT.  The first two arguments are much like the two arguments of &amp;quot;get&amp;quot;, the third argument is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==To be completed==&lt;br /&gt;
* getOther&lt;br /&gt;
* Channels&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4340</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4340"/>
		<updated>2018-11-13T01:06:14Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* No Overlapping */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an PC.EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an PC.EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local PC.STAT variable and a local PC.CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
Additional functions specifically related to PCGen are available:&lt;br /&gt;
* get: This function takes two arguments.  The first is an Object type (like &amp;quot;SKILL&amp;quot;), the second is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
**Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
* getFact: This function returns the value of a FACT.  The first two arguments are much like the two arguments of &amp;quot;get&amp;quot;, the third argument is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==To be completed==&lt;br /&gt;
* getOther&lt;br /&gt;
* Channels&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4339</id>
		<title>Setting up the new Formula System</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Setting_up_the_new_Formula_System&amp;diff=4339"/>
		<updated>2018-11-13T01:04:49Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=The basics=&lt;br /&gt;
&lt;br /&gt;
The new formula system is designed to do a few things relative to data:&lt;br /&gt;
* Validate formulas at LST load instead of runtime&lt;br /&gt;
* Dramatically increase flexibility&lt;br /&gt;
* It will replace many tokens, including all the BONUS tokens&lt;br /&gt;
* It allows a sensible location for global modifications (things generally related to rule book type modifications that impact all objects of a given type)&lt;br /&gt;
&lt;br /&gt;
==Key concepts==&lt;br /&gt;
&lt;br /&gt;
To use the new system a few key things need to be remembered:&lt;br /&gt;
* It is possible to have local variables&lt;br /&gt;
* All variables must be defined prior to use&lt;br /&gt;
* Variables are not only numbers, but can be Strings, Dice, etc.&lt;br /&gt;
** We call this the variable FORMAT&lt;br /&gt;
&lt;br /&gt;
You will want to keep track of what these key terms mean as you learn the new formula system:&lt;br /&gt;
* FORMAT: The type of variable, e.g. NUMBER, BOOLEAN, ORDEREDPAIR.&lt;br /&gt;
* SCOPE: The part of the data in which a (local) variable is available&lt;br /&gt;
* MODIFIER: An argument to MODIFY* tokens, specifically the &amp;quot;command&amp;quot; of what the modification represents&lt;br /&gt;
* OPERATOR: A mathematical operator as you would see in a formula (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, etc.)&lt;br /&gt;
* GROUPING: A name for a set of objects in PCGen&lt;br /&gt;
* ASSOCIATION: An additional set of information attached to a MODIFY* token.  This is a key-value pair of information, e.g. PRIORITY=100&lt;br /&gt;
&lt;br /&gt;
=Creating and Using Variables=&lt;br /&gt;
&lt;br /&gt;
==Required Setup==&lt;br /&gt;
&lt;br /&gt;
Every format that needs to be used requires a default value. This value is shared throughout an entire system (it CANNOT be redefined to a different value).  This is placed into a file referred to in a PCC file from the DATACONTROL: token.&lt;br /&gt;
&lt;br /&gt;
===DATACONTROL (PCC File)===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: is a new Campaign file token (for PCC files).  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   DATACONTROL:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a DATACONTROL file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
===DEFAULTVARIABLEVALUE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The Format is:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:X|Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the default value&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   DEFAULTVARIABLEVALUE:NUMBER|0&lt;br /&gt;
&lt;br /&gt;
It is a best practice to always define a DEFAULTVARIABLEVALUE for every FORMAT regardless of whether the data uses that FORMAT.  The internal parts of PCGen may use it, so a default value may be required.&lt;br /&gt;
&lt;br /&gt;
Note: it IS safe to &amp;quot;redefine&amp;quot; a DEFAULTVARIABLEVALUE to the same value.  So if multiple datasets are loaded and they all had DATACONTROL: and all defined the default value for NUMBER to be 0, they will all happily load as the system is capable of recognizing the defaults are the same&lt;br /&gt;
&lt;br /&gt;
==How to define a variable==&lt;br /&gt;
&lt;br /&gt;
===VARIABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
To define a variable, you need to add an LST file that is referred to in a PCC file from the VARIABLE: token.  It is treated &amp;quot;recursively&amp;quot; like other tokens, e.g. TEMPLATE.  &lt;br /&gt;
&lt;br /&gt;
   VARIABLE:x&lt;br /&gt;
&lt;br /&gt;
* x is the file to be loaded as a VARIABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
There are 2 basic tokens for the VARIABLE file: GLOBAL and LOCAL.&lt;br /&gt;
&lt;br /&gt;
===GLOBAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* GLOBAL defines a global variable, usable from anywhere within the PlayerCharacter.&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   GLOBAL:X=Y&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   GLOBAL:ORDEREDPAIR=Face&lt;br /&gt;
&lt;br /&gt;
A GLOBAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===LOCAL (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
* LOCAL defines a local variable, usable only within the object on which the variable exists (or its children)&lt;br /&gt;
** The place where a local variable is usable is called the SCOPE.  This could include a STAT (such as the stat's SCORE or STATMOD) or EQUIPMENT.  The scopes possible in PCGen are hard-coded (see below for more info)&lt;br /&gt;
&lt;br /&gt;
The format is:&lt;br /&gt;
   LOCAL:W|X=Y&lt;br /&gt;
* W is the SCOPE of the variable&lt;br /&gt;
* X is the format name&lt;br /&gt;
* Y is the variable name&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
   LOCAL:PC.STAT|NUMBER=Score&lt;br /&gt;
&lt;br /&gt;
A LOCAL token can take additional token on the line called EXPLANATION, which it is advisable to use to communicate to other data monkeys (and it is likely any future editor will also draw on this information).&lt;br /&gt;
&lt;br /&gt;
===EXPLANATION (VARIABLE File)===&lt;br /&gt;
&lt;br /&gt;
EXPLANATION: is a free-text token (no parsing is really done) that is designed to describe why a variable exists&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   EXPLANATION:x&lt;br /&gt;
&lt;br /&gt;
* x is the text of the Explanation&lt;br /&gt;
* Limitations: By Design: Must not appear as the first token on a line&lt;br /&gt;
* Behavior: Overwrites (as if someone would use it twice??)&lt;br /&gt;
&lt;br /&gt;
===Defaults in the VARIABLE file===&lt;br /&gt;
&lt;br /&gt;
A few notes about the VARIABLE files:&lt;br /&gt;
If you see an item without a leading token, e.g.:&lt;br /&gt;
   ORDEREDPAIR=Face&lt;br /&gt;
...then the system is using the default (GLOBAL).  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
If you see an item without a leading format (&amp;quot;X&amp;quot; in both GLOBAL and LOCAL above), e.g.:&lt;br /&gt;
   LOCAL:STAT|Score&lt;br /&gt;
...then the format is a NUMBER.  For now, the data standard is to avoid using this shortcut (as far as I know)&lt;br /&gt;
&lt;br /&gt;
Note both defaults can be combined, so a variable name with no other information on that line is a Global NUMBER&lt;br /&gt;
&lt;br /&gt;
===No Overlapping===&lt;br /&gt;
&lt;br /&gt;
In most programming languages, it is legal to have local variable share the same name as the global variable and thus &amp;quot;override&amp;quot; it in that context (although it is considered less than ideal, and in some languages it will now produce a warning).  It is not legal in PCGen.&lt;br /&gt;
&lt;br /&gt;
If a Global variable called &amp;quot;Hands&amp;quot; exists, then NO local variable IN ANY SCOPE can be &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Similar restrictions exist for scopes and SubScopes.  If &amp;quot;CritMult&amp;quot; is an EQUIPMENT variable, then &amp;quot;CritMult&amp;quot; can't be an EQUIPMENT.PART variable.  &lt;br /&gt;
&lt;br /&gt;
Non-overlapping (when the Scopes do not interact) is legal.  &amp;quot;Score&amp;quot; can be a local STAT variable and a local CHECK variable, for example.&lt;br /&gt;
&lt;br /&gt;
For clarity: &lt;br /&gt;
* This occurs regardless of the FORMAT of the variables - tokens will infer the format from the variable name, so you can't have overlapping variables even of different FORMAT.&lt;br /&gt;
* Two variables of the same name but different FORMAT in the same SCOPE will cause an error as well, because that is effectively overlapping, and those variables can't be distinguished in most circumstances.&lt;br /&gt;
&lt;br /&gt;
===Identical Duplication Legal===&lt;br /&gt;
&lt;br /&gt;
It is legal for a load to include one or more PCC files that have one or more VARIABLE: files that redefine the same variables.  As long as they are the same format and scope, they are not considered an error.  If either the scope or format differs, then the &amp;quot;No Overlapping&amp;quot; rules above are applied.&lt;br /&gt;
&lt;br /&gt;
A difference in the &amp;quot;Explanation&amp;quot; text is not considered a difference in the variables significant enough to trigger an error. (In fact, the last loaded Explanation will &amp;quot;win&amp;quot; -&amp;gt; it is overwritten each time it is encountered for redefined but identical variables)&lt;br /&gt;
&lt;br /&gt;
==Setting and Modifying a variable==&lt;br /&gt;
&lt;br /&gt;
===MODIFY (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFY token is used to set a variable that is accessible in the current SCOPE.  (Note: It could be local to the current scope or any ancestor of the current scope... so modifying a global variable always just requires MODIFY)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFY:V|W|X|Y=Z|Y=Z&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the current scope.  Therefore, it must be either a global variable or a local variable on the current object or its parents.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Give a Player Character 2 hands:&lt;br /&gt;
   MODIFY:Hands|SET|2&lt;br /&gt;
&lt;br /&gt;
===MODIFYOTHER (LST files)===&lt;br /&gt;
&lt;br /&gt;
The MODIFYOTHER token is used to set a variable that is not accessible in the current SCOPE.  Beyond what is necessary in MODIFY, this token also requires the &amp;quot;address&amp;quot; of where to go before it runs the modification.  Think of it as the ability to remotely place a MODIFY on another object (but revoke that MODIFY if the current object is no longer granted to the PC)&lt;br /&gt;
&lt;br /&gt;
The format of the token is: &lt;br /&gt;
   MODIFYOTHER:T|U|V|W|X|Y=Z|Y=Z&lt;br /&gt;
* T is the SCOPE of the object on which the resulting MODIFY (as defined by V-Z) should occur.  This is closely related to the format of the object.&lt;br /&gt;
* U is the object or GROUPING of objects on which the MODIFY (as defined by V-Z) should occur&lt;br /&gt;
** Note that this does not and will not support TYPE.&lt;br /&gt;
* V is the Variable name for which the value will be modified&lt;br /&gt;
**  This variable MUST be visible in the scope of the addressed object.  Therefore, it is likely to be a local variable on the remote object or its parents.  &lt;br /&gt;
** In rare cases, a remote modification of a global variable is useful.  It effectively adds to that global variable only if both objects are granted to the PC.&lt;br /&gt;
* W is the MODIFIER to be taken on the variable (e.g. SET)&lt;br /&gt;
** There can be multiple actions (more below), but SET will ALWAYS be available for any format.&lt;br /&gt;
* X is the value related to the action.  If the action is set, the variable will be set to the value in this part of the token.&lt;br /&gt;
** Note: The value CAN be a formula.  It is possible, for example, to SET a variable to OtherVar+4 ... the system will solve that formula.  For legal OPERATORS (e.g. &amp;quot;+&amp;quot;) , see below.&lt;br /&gt;
* Y is the name of an (optional) ASSOCIATION.  For now, PRIORITY (more below) is the only available association.&lt;br /&gt;
* Z is the value of the association.&lt;br /&gt;
&lt;br /&gt;
Note: If a PRIORITY is not set it is assumed to be ZERO.&lt;br /&gt;
&lt;br /&gt;
Example: Reduce the HandsRequired on all Weapons by 1:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|GROUP=Weapon|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
Note this assumes GROUP:Weapon is in the LST line of every Weapon... PCGen can't guess or derive what a weapon is :)&lt;br /&gt;
&lt;br /&gt;
==Formulas==&lt;br /&gt;
&lt;br /&gt;
SET as a MODIFIER allows the use of a formula for the value.  This follows many mathematical systems of using parenthesis - &amp;quot;(&amp;quot; and &amp;quot;)&amp;quot; to be precise - to group (and thus prioritize parts of the calculation). &lt;br /&gt;
There are a number of built in OPERATORs (see below).  The system can also use functions, which use parenthesis to contain their arguments.  For example:&lt;br /&gt;
* min(this,that)&lt;br /&gt;
Would return the minimum of the two variables &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Built in Functions===&lt;br /&gt;
&lt;br /&gt;
The system also has a series of built-in functions that work with the NUMBER format:&lt;br /&gt;
* abs: calculates the absolute value of the one argument.&lt;br /&gt;
* ceil: calculates the next integer that is &amp;gt;= the value of the one argument.&lt;br /&gt;
* floor: calculates the next lower integer that is &amp;lt;= the value of the one argument&lt;br /&gt;
* if: conditionally performs an operation.  The first argument must resolve to a BOOLEAN.  If true, the second argument is evaluated; if false, the third argument is evaluated.&lt;br /&gt;
* max: calculates the maximum of the provided two or more comma-separated arguments&lt;br /&gt;
* min: calculates the minimum of the provided two or more comma-separated arguments&lt;br /&gt;
* round: calculates the closest integer to the value of the one argument.  Exactly 0.5 is rounded up.&lt;br /&gt;
* value: returns the value of the calculation before the current modification was started (no arguments)&lt;br /&gt;
&lt;br /&gt;
Additional functions specifically related to PCGen are available:&lt;br /&gt;
* get: This function takes two arguments.  The first is an Object type (like &amp;quot;SKILL&amp;quot;), the second is the key of a CDOMObject (like a Skill) (also in quotes)&lt;br /&gt;
**Example: get(&amp;quot;SKILL&amp;quot;,&amp;quot;Hide&amp;quot;)&lt;br /&gt;
* getFact: This function returns the value of a FACT.  The first two arguments are much like the two arguments of &amp;quot;get&amp;quot;, the third argument is the name of the FACT to be returned&lt;br /&gt;
&lt;br /&gt;
=Legal Values=&lt;br /&gt;
&lt;br /&gt;
==FORMATs==&lt;br /&gt;
&lt;br /&gt;
Currently, the following are built-in formats:&lt;br /&gt;
* NUMBER: This is a mathematical value.  Note that integer arithmetic is done if possible, so if you have an integer 6 and an integer 3, 6/3 will be an integer 2.  If the 6 or 3 is a decimal value (double), then integer arithmetic was not possible and thus rounding may occur.&lt;br /&gt;
* STRING: A String&lt;br /&gt;
* BOOLEAN: A True/False value&lt;br /&gt;
* ORDEREDPAIR: An ordered pair of numbers.  This could be an X,Y point (or in a game system more like a FACE)&lt;br /&gt;
* DICE: A value that takes the form AdB+C.  A is the number of rolls of the die, B is the number of sides on the die, and C is the value to be added afterwords&lt;br /&gt;
* ALIGNMENT: An alignment object (None is default typically)&lt;br /&gt;
&lt;br /&gt;
==OPERATORs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* +: performs addition&lt;br /&gt;
* -: performs subtraction (or is the unary minus operator to make a value negative)&lt;br /&gt;
* *: performs multiplication&lt;br /&gt;
* /: performs division&lt;br /&gt;
* %: performs a remainder function&lt;br /&gt;
* ^: performs an exponential calculation&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;: Checks for greater than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;: Checks for less than (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;gt;=: Checks for greater than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
* &amp;lt;=: Checks for less than or equal to (NOTE: Returns a BOOLEAN, not a NUMBER)&lt;br /&gt;
&lt;br /&gt;
For BOOLEAN, the following modifiers are available:&lt;br /&gt;
* ==: Checks for equality&lt;br /&gt;
* !=: Checks for inequality&lt;br /&gt;
* &amp;amp;&amp;amp;: Performs a logical AND&lt;br /&gt;
* ||: Performs a logical OR&lt;br /&gt;
* !: Negates the value&lt;br /&gt;
&lt;br /&gt;
For other formats, the following operators are always available:&lt;br /&gt;
* ==: Checks for equality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
* !=: Checks for inequality (NOTE: Returns a BOOLEAN, not the compared format)&lt;br /&gt;
&lt;br /&gt;
==MODIFIERs==&lt;br /&gt;
&lt;br /&gt;
For NUMBER, the following modifiers are available:&lt;br /&gt;
* SET: This sets the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* ADD: This adds the current value of the variable to the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* MAX: This takes the maximum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. min(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MIN: This takes the minimum value of the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter (i.e. max(current value, &amp;quot;X&amp;quot;))&lt;br /&gt;
* MULTIPLY: This multiplies the current value of the variable and the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
* DIVIDE: This divides the current value of the variable by the value provided in the &amp;quot;X&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
For other Formats, the SET modifier will always be available&lt;br /&gt;
&lt;br /&gt;
==GROUPINGs==&lt;br /&gt;
&lt;br /&gt;
At present, the second argument of MODIFYOTHER supports 3 possible values:&lt;br /&gt;
* ALL&lt;br /&gt;
** This means the MODIFYOTHER will impact ALL objects of that type.  This is useful for setting a general default for that value (e.g. you could default &amp;quot;HandsRequired&amp;quot; on weapons to 1)&lt;br /&gt;
* GROUP=X&lt;br /&gt;
** This is set by the GROUP token in LST data&lt;br /&gt;
* A specific object KEY&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
==SCOPEs==&lt;br /&gt;
&lt;br /&gt;
The following are the legal scopes (not including GLOBAL):&lt;br /&gt;
* PC.EQUIPMENT: This is a variable local to equipment&lt;br /&gt;
** PC.EQUIPMENT.PART: This is a variable local to an equipment PART (or in older terms, an Equipment HEAD).  Note that due to double sided weapons, Damage, CritMult and other items are generally on an equipment PART, not on the Equipment itself.  Note also that this is a SUBSCOPE of the EQUIPMENT scope (so all variables in the EQUIPMENT scope can also be seen in the EQUIPMENT.PART scope)&lt;br /&gt;
* PC.SAVE: This is a variable local to Save (or if you prefer, Check)&lt;br /&gt;
* PC.SIZE: This is a variable local to the Size of a PC&lt;br /&gt;
* PC.SKILL: This is a variable local to a Skill&lt;br /&gt;
* PC.STAT: This is a variable local to a Stat&lt;br /&gt;
&lt;br /&gt;
Note that all of these start with &amp;quot;PC.&amp;quot; because they are impacting the current Player Character.&lt;br /&gt;
&lt;br /&gt;
More will be added over time.&lt;br /&gt;
&lt;br /&gt;
DYNAMIC can also be used to create a Scope and Object Type (see below)&lt;br /&gt;
&lt;br /&gt;
=Examples=&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope in practice==&lt;br /&gt;
&lt;br /&gt;
To understand how local variables work in SubScopes, consider the following (note this is not all the variables we will use but a critical set to define the scope):&lt;br /&gt;
   GLOBAL:NUMBER=Hands&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|NUMBER=HandsRequired&lt;br /&gt;
   LOCAL:PC.EQUIPMENT|BOOLEAN=Penalized&lt;br /&gt;
   LOCAL:PC.EQUIPMENT.PART|NUMBER=CritMult&lt;br /&gt;
&lt;br /&gt;
The Equipment part is what the traditional system called a &amp;quot;head&amp;quot; (so a double headed axe has two &amp;quot;parts&amp;quot; in the new system - this was done since in some game systems, an item could have more than 2)&lt;br /&gt;
&lt;br /&gt;
To understand how variables are available and how they get modified consider this:&lt;br /&gt;
&lt;br /&gt;
Inside of a piece of equipment it could do something like:&lt;br /&gt;
   MODIFY:Penalized|SET|HandsRequired&amp;gt;Hands&lt;br /&gt;
&lt;br /&gt;
This would be &amp;quot;true&amp;quot; if HandsRequired on the Equipment were more than the Hands on the PC.  The &amp;quot;Hands&amp;quot; variable is Global, so it is available anywhere.  A Template of &amp;quot;Extra Hands&amp;quot; could do something like: &lt;br /&gt;
   MODIFY:Hands|ADD|2 &lt;br /&gt;
... and that adds to the Global variable &amp;quot;Hands&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Now consider an Equipment Modifier that was something like &amp;quot;Lighter Than Normal&amp;quot;.  Assume the game benefit was one less hand is required.  This would look like:&lt;br /&gt;
   Lighter Than Normal   MODIFY:HandsRequired|ADD|-1&lt;br /&gt;
(This ignores for the moment any situation like &amp;quot;can't be reduced to below one&amp;quot;.)&lt;br /&gt;
&lt;br /&gt;
Note that the EquipmentModifier falls into EQUIPMENT.PART, so that it has access to the HandsRequired variable from the EQUIPMENT scope and can modify it.  Note that this change could then impact the result of the BOOLEAN variable Penalized, since HandsRequired changed.  Note also that &amp;quot;HandsRequired&amp;quot;, when evaluated anywhere in that Equipment is now 1 less.  Even if another EquipmentModifier evaluates HandsRequired, it is analyzing the variable from its parent scope, so that value on a variable from EQUIPMENT is the same in every EquipmentModifier (in the EQUIPMENT.PART scope) of that piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScope on Equipment==&lt;br /&gt;
&lt;br /&gt;
Since variables like CritMult and Damage would be on an Equipment &amp;quot;part&amp;quot; it is important to understand how to get access to that &amp;quot;part&amp;quot; from the LST code.  If a single-headed weapon wanted a larger CritMult, it would be silly to have to add a Dummy EquipmentModifier just to modify the CritMult on the part.  (Much of the point of the new system is to make things more direct)&lt;br /&gt;
&lt;br /&gt;
There is a token for Equipment called PART.  This effectively takes 2 arguments: A number (today 1 for the primary head, 2 for the secondary head) and a full token otherwise valid on a plain object.  MODIFY and MODIFYOTHER will both work in that situation, so for a piece of Equipment to set its own CritMult to 3 on its primary (and perhaps only) head, it would do:&lt;br /&gt;
   PART:1|MODIFY:CritMult|SET|3&lt;br /&gt;
&lt;br /&gt;
Note since the MODIFY is a &amp;quot;real&amp;quot; token call it uses &amp;quot;:&amp;quot; after the MODIFY which makes PART look slightly different to most tokens which use | as an internal separator.  Since PART is effectively calling a &amp;quot;real&amp;quot; token, we need to use the inner &amp;quot;:&amp;quot; in order to have it pass through the same code/parsing system.&lt;br /&gt;
&lt;br /&gt;
==Understanding SubScopes in relation to MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
* Note Jan 29 2018: There is a possibility of a solution for this issue that would allow MODIFYOTHER to do direct addressing of sub-objects under certain conditions&lt;br /&gt;
&lt;br /&gt;
Normally MODIFYOTHER allows you to &amp;quot;address&amp;quot; another scope.  For example:&lt;br /&gt;
   MODIFYOTHER:PC.EQUIPMENT|Bastard Sword|HandsRequired|ADD|-1&lt;br /&gt;
&lt;br /&gt;
However, since items like Damage and CritMult are actually on the EQUIPMENT.PART, that is different.  If you consider how you would have to &amp;quot;address&amp;quot; the first head on &amp;quot;Bastard Sword&amp;quot;, you would need something like:&lt;br /&gt;
   SOMEWEIRDTOKEN:PC.EQUIPMENT|Bastard Sword|PART|1|CritMult|ADD|1&lt;br /&gt;
&lt;br /&gt;
Note that this requires both a primary and secondary address.  No token like this exists (at the moment).  To alter items in a SubScope, you need to pass them down to the SubScope.  An attempt to modify it at the Equipment level, such as:&lt;br /&gt;
   MyAbility   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMult|ADD|1&lt;br /&gt;
... will fail (at LST load) because CritMult was on EQUIPMENT.PART, so it is not visible to the EQUIPMENT scope.  Said another way, you can't universally modify all EQUIPMENT.PART variables by attempting to use that variable at a higher scope.&lt;br /&gt;
&lt;br /&gt;
A more appropriate method (since this is relevant to a Feat that might alter CritMult) is to add another variable at the EQUIPMENT level:&lt;br /&gt;
   LOCAL:EQUIPMENT|NUMBER=CritMultAdder&lt;br /&gt;
If all the heads then get&lt;br /&gt;
   MODIFY:CritMult|ADD|CritMultAdder&lt;br /&gt;
... you can have the Feat do a MODIFYOTHER to alter CritMultAdder and the MODIFY will &amp;quot;pull&amp;quot; that into each PART:&lt;br /&gt;
   SomeFeat   MODIFYOTHER:PC.EQUIPMENT|ALL|CritMultAdd|ADD|1&lt;br /&gt;
So the data can be set up to only require one modification from a Feat and each Equipment Part can pull that modification down into the part.  (A tangential note for those objecting that the known modifiers of CritMult select a specific weapon type: Yep, got it.  That's not possible yet, so not documented yet.  Suspend disbelief on the examples - Imagine a more powerful Feat for now)&lt;br /&gt;
&lt;br /&gt;
==Understanding PRIORITY and processing of MODIFY and MODIFYOTHER==&lt;br /&gt;
&lt;br /&gt;
When a PlayerCharacter has multiple items that attempt to modify a variable, they are sorted by two systems:&lt;br /&gt;
* First, they are sorted by their user priority.  This is provided in the PRIORITY=Z association.  Lower PRIORITY will be processed first.&lt;br /&gt;
* Second, they are sorted by their inherent priority.  This is a built-in system that approximates mathematical priority rules. It ensures, for example, that a SET will occur before ADD if they both have a matching user priority.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Assume we had the following items:&lt;br /&gt;
   MODIFY:Hands|MULTIPLY|2|PRIORITY=100&lt;br /&gt;
   MODIFY:Hands|SET|2|PRIORITY=50&lt;br /&gt;
   MODIFY:Hands|ADD|1|PRIORITY=50&lt;br /&gt;
&lt;br /&gt;
The first thing is that we can tell from the PRIORITY items that the SET and ADD will both occur BEFORE the multiply (because 50 &amp;lt; 100).  For the SET and ADD, we would need to know the inherent priority (For what it's worth, SET is 0, ADD is 3, MULTIPLY and DIVIDE are 1 and 2 since they are higher priority than ADD in traditional math).  This means the SET will happen first.  So the result is Hands is SET to 2, then ADD 1 to get 3, then MULTIPLY by 2 to get 6.&lt;br /&gt;
&lt;br /&gt;
By controlling the PRIORITY, the data team can reorder any calculation and perform much more complicated calculations than was possible with BONUS (where movement, for example, had multiple different BONUS tokens to try to do adding before and after a multiply).  This is much the same as using parenthesis in a formula in normal math, but this allows you trigger any required ordering even if the MODIFY statements are in different objects.&lt;br /&gt;
&lt;br /&gt;
==Using the previous value in a more complex calculation==&lt;br /&gt;
&lt;br /&gt;
Take a modification that, for example, wishes to perform a calculation such as: &amp;quot;Reduce the value by 1, but to no less than 1&amp;quot;.  We could write this as two MODIFY statements, but that is probably undesirable for a few reasons: &lt;br /&gt;
* If the book states it as one sentence, it would be preferable to write it as one MODIFY&lt;br /&gt;
* It makes the calculation a bit harder to follow as to what is going on&lt;br /&gt;
* If the items are different PRIORITY, there is a risk of another dataset attempting to (or accidentally) putting something in between those two steps, resulting in an incorrect calculation.  &lt;br /&gt;
&lt;br /&gt;
Therefore, we need a method of drawing on the current value in a formula.  To do that we use the value() function.  The calculation above then becomes:&lt;br /&gt;
   max(value()-1,1)&lt;br /&gt;
...and we can use it in a MODIFY as such:&lt;br /&gt;
   MODIFY:HandsRequired|SET|max(value()-1,1)&lt;br /&gt;
&lt;br /&gt;
Note that we are using SET here - if a formula is used, it is likely to be best done as a SET, since that will be much more clear than calculating a formula and then immediately applying another MODIFICATION.  Note that some modifications may also prohibit a formula depending on their underlying behavior.&lt;br /&gt;
&lt;br /&gt;
=Global Modifier File=&lt;br /&gt;
&lt;br /&gt;
There is a new file type that is defined in the PCC files with GLOBALMODIFIER.&lt;br /&gt;
&lt;br /&gt;
This file allows for a centralized (and clear to the data user) location for global modifications (don't hide things on stats or elsewhere anymore).  This supports MODIFY for global variables (if you want to start all PCs with 2 hands for example) or MODIFYOTHER for local variables.&lt;br /&gt;
&lt;br /&gt;
==GLOBALMODIFIER (PCC File)==&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   GLOBALMODIFIER:x&lt;br /&gt;
* x is the file to be loaded as a GLOBALMODIFIER file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
=Advanced Topics=&lt;br /&gt;
&lt;br /&gt;
==Dynamic Objects and Scope==&lt;br /&gt;
&lt;br /&gt;
This set of features allows the data to supplement the defined SCOPEs with new object types not originally comprehended in PCGen. Within a Dynamic Scope, the data can produce objects.  &lt;br /&gt;
&lt;br /&gt;
Warning: Attempts to define a SCOPE that overlaps with existing objects (e.g. LANGUAGE) will not produce a warning today but will get you in trouble long term.  It won't work in the way you would like it to work (it won't attach a SCOPE to that object type), so just avoid those overlapping names.  Basically if you can CHOOSE it, or use it with FACT, don't DYMAMICSCOPE it.&lt;br /&gt;
&lt;br /&gt;
===DYNAMICSCOPE (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
The DYNAMICSCOPE token (used in files referred to by the DATACONTROL: token in PCC files) can define a Dynamic Scope.&lt;br /&gt;
&lt;br /&gt;
   DYNAMICSCOPE:x&lt;br /&gt;
&lt;br /&gt;
*x is the new scope&lt;br /&gt;
**Any argument to DYNAMICSCOPE becomes a legal &amp;quot;scope&amp;quot; in LOCAL: in the variable definition file&lt;br /&gt;
**Limit of one new scope per line.  (No delimiter on this token)&lt;br /&gt;
*Like other LST tokens, this is case insensitive, but usage in later tokens is always capitalized, so I suspect the data standard should be ALL CAPS&lt;br /&gt;
&lt;br /&gt;
===DYNAMIC (PCC File)=== &lt;br /&gt;
&lt;br /&gt;
In order to create objects within the defined DYNAMICSCOPE, DYNAMIC: becomes a new token legal in PCC files. It's format is:&lt;br /&gt;
&lt;br /&gt;
   DYNAMIC:x&lt;br /&gt;
&lt;br /&gt;
* x is the file just as in tokens like DEITY or DOMAIN&lt;br /&gt;
* INCLUDE/EXCLUDE on the line are are legal.&lt;br /&gt;
&lt;br /&gt;
Within the Dynamic file, the Scope of the new objects being created MUST appear as a prefix token on the line.  For example, if there was a DYNAMICSCOPE:VISION, then the following would be legal in a DYNAMIC file:&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
* The &amp;quot;Token Name&amp;quot; (what appears before the ':') is the DYNAMICSCOPE name.&lt;br /&gt;
* These are created as basically hollow, simple objects.  &lt;br /&gt;
* These objects CAN contain variables.&lt;br /&gt;
(It is the intent to allow these at some point to also have MODIFY* tokens, but that is not currently supported)&lt;br /&gt;
&lt;br /&gt;
===GRANT (LST files)===&lt;br /&gt;
&lt;br /&gt;
A Dynamic object MUST be granted in order to have its local variables modified or to have its modifiers have an impact (just like any other object) &lt;br /&gt;
&lt;br /&gt;
    GRANT:x|y&lt;br /&gt;
&lt;br /&gt;
* x is a DYNAMICSCOPE&lt;br /&gt;
* y is the name of the dynamic object.&lt;br /&gt;
&lt;br /&gt;
===Export===&lt;br /&gt;
&lt;br /&gt;
Dynamic items can be exported in Freemarker using the &lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.x as y&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x is the name of the DYNAMICSCOPE&lt;br /&gt;
* y is the local variable within the #list that the output team wants to use to access the dynamic object&lt;br /&gt;
* It is likely for ease of use by the output team, x and y will be identical&lt;br /&gt;
&lt;br /&gt;
For a complete example using output, see below&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
DATACONTROL: file:&lt;br /&gt;
   DYNAMICSCOPE:VISION&lt;br /&gt;
&lt;br /&gt;
DYNAMIC: file:&lt;br /&gt;
   VISION:Normal&lt;br /&gt;
   VISION:Darkvision&lt;br /&gt;
   VISION:Low-Light Vision&lt;br /&gt;
&lt;br /&gt;
VARIABLE: File:&lt;br /&gt;
   LOCAL:VISION|NUMBER=Range&lt;br /&gt;
&lt;br /&gt;
GLOBALMODIFIERFILE:&lt;br /&gt;
    MODIFYOTHER:PC.VISION|ALL|Range|Set|60&lt;br /&gt;
&lt;br /&gt;
Sets a &amp;quot;default&amp;quot; range for any VISION, to avoid setting on each VISION object&lt;br /&gt;
&lt;br /&gt;
RACE LST file:&lt;br /&gt;
   Human &amp;lt;&amp;gt; GRANT:VISION|Normal&lt;br /&gt;
&lt;br /&gt;
Export:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;#list pc.dynamic.vision as vision&amp;gt;&lt;br /&gt;
    ${vision.name} ${vision.val.range}&lt;br /&gt;
   &amp;lt;/#list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(this ignores converting the range to local units and all that, but you get the idea)&lt;br /&gt;
&lt;br /&gt;
==ARRAY Format==&lt;br /&gt;
&lt;br /&gt;
In addition to the base formats, there is an ARRAY[x] format:&lt;br /&gt;
   ARRAY[x]&lt;br /&gt;
* x is an existing valid Format&lt;br /&gt;
** x CANNOT be ARRAY (multi-dimensional arrays not supported&lt;br /&gt;
** Just to be precise, yes DYNAMIC formats are legal&lt;br /&gt;
&lt;br /&gt;
(Note: This may get renamed - we need to decide on a few things for how this will work vs other types of collections)&lt;br /&gt;
&lt;br /&gt;
===Modifiers===&lt;br /&gt;
&lt;br /&gt;
There are two valid MODIFIERs for ARRAY:&lt;br /&gt;
* ADD: This adds a value to the ARRAY&lt;br /&gt;
** Mathematically, ARRAY acts as an ordered set of objects.  Therefore, if you add an item to an array more than once it is ignored.&lt;br /&gt;
* SET: This sets the contents of the ARRAY&lt;br /&gt;
&lt;br /&gt;
==Custom Functions==&lt;br /&gt;
&lt;br /&gt;
Within certain game systems, there are calculations that are likely to be repeated.  In order to simplify the calculation of these items, there is an ability to create custom functions.&lt;br /&gt;
&lt;br /&gt;
A function can have zero or more arguments.  The number is defined by what appears in the VALUE token (see below).&lt;br /&gt;
&lt;br /&gt;
Note that the function actually has to be *used in the data* (not just defined) for most errors to be caught (since the system can't guess at overall context before a function is used and it would be possible to write a function that would work in more than one FORMAT).&lt;br /&gt;
&lt;br /&gt;
===Function (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   FUNCTION:x&lt;br /&gt;
* This token must appear as the first token on a line in a DATACONTROL file.&lt;br /&gt;
* x is the name of the function.  This name must starts with a letter, e.g. A-Z, additional legal characters are 0-9 and _ (none of those additional legal characters as the first character)&lt;br /&gt;
** x must not contain spaces, no other special characters.&lt;br /&gt;
** Function names are case insensitive (as many other things in LST files) &lt;br /&gt;
&lt;br /&gt;
A Function MUST also contain a VALUE, which defines how the function is calculated.&lt;br /&gt;
&lt;br /&gt;
If a FUNCTION appears more than once, the other characteristics (VALUE) must be identical. &lt;br /&gt;
&lt;br /&gt;
===Value (DATACONTROL LST)===&lt;br /&gt;
&lt;br /&gt;
   VALUE:x&lt;br /&gt;
* Must appear as an additional token on the line of a FUNCTION: in the data control file&lt;br /&gt;
* x is a valid formula.  &lt;br /&gt;
** This means it must have valid variable names, valid function names, matching parenthesis, etc. &lt;br /&gt;
&lt;br /&gt;
In addition to all of the built-in functions (e.g. if, ceil, round), two additional items can be used:&lt;br /&gt;
* the arg(n) function (see below).&lt;br /&gt;
* Any previously defined FUNCTION. This MUST appear in the file before the current Function or in a file processed before the current file.&lt;br /&gt;
&lt;br /&gt;
===arg (Function)===&lt;br /&gt;
&lt;br /&gt;
The arg function is a &amp;quot;local&amp;quot; function to the VALUE: part of a FUNCTION (it can not generally be used in LST files). The arg function takes one argument. It MUST be a Integer &amp;gt;= 0.&lt;br /&gt;
&lt;br /&gt;
   arg(x)&lt;br /&gt;
* x is an integer number (zero-indexed)&lt;br /&gt;
&lt;br /&gt;
When arg(x) is used in value, the function pulls from the arguments that were provided to the original function in the data.  &lt;br /&gt;
&lt;br /&gt;
===Using a Function===&lt;br /&gt;
&lt;br /&gt;
When a function is used in LST data, it is called by the name provided in the FUNCTION token. It requires a certain number of arguments. This exactly matches the integer one greater than the highest number of the arg(n) function provided in the VALUE part of a FUNCTION (In computer science terms, the arg(n) function is zero-indexed). The provided arguments can be any legal formula, so:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
   d20Mod(INT+4)&lt;br /&gt;
&lt;br /&gt;
...are both perfectly legal.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
The modification calculation in most d20 games is fairly easy to calculate, but is repeated very often.  It basically takes (ability score - 10)/2.&lt;br /&gt;
&lt;br /&gt;
Here is how we would define a new function d20Mod in the DATACONTROL file:&lt;br /&gt;
   FUNCTION:d20Mod    VALUE:floor((arg(0)-10)/2)&lt;br /&gt;
&lt;br /&gt;
This would then be used in LST data as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(n)&lt;br /&gt;
&lt;br /&gt;
The system will catch both of these as errors:&lt;br /&gt;
&lt;br /&gt;
   d20Mod()&lt;br /&gt;
   d20Mod(14,5) &lt;br /&gt;
&lt;br /&gt;
These have too few or too many arguments, respectively. It would also catch:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(&amp;quot;mystring&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
...as an error (wrong format - requires a Number, found a String). &lt;br /&gt;
&lt;br /&gt;
The n is substituted where &amp;quot;arg(0)&amp;quot; appears in the &amp;quot;VALUE&amp;quot;... so a statmod would be as easy as:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(INT)&lt;br /&gt;
&lt;br /&gt;
or some such... Direct values can also be used, e.g.:&lt;br /&gt;
&lt;br /&gt;
   d20Mod(10)&lt;br /&gt;
&lt;br /&gt;
...would return 0.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Performance Considerations==&lt;br /&gt;
&lt;br /&gt;
It is possible to write two identical modifiers that perform the same net calculation on a PC.  For example:&lt;br /&gt;
   MODIFY:Age|ADD|2&lt;br /&gt;
   MODIFY:Age|SET|value()+2&lt;br /&gt;
&lt;br /&gt;
...perform the same calculation (adding 2 to Age).&lt;br /&gt;
&lt;br /&gt;
Why have ADD at all?  Answer: These are NOT AT ALL equivalent in memory use or speed/performance.&lt;br /&gt;
&lt;br /&gt;
The ADD (Since it's adding an integer) occupies approximately 40 bytes of memory and is an extremely rapid calculation: If it took 200 nanoseconds I'd be surprised. This is because ADD is using a number. If it was a formula, even 1+2, it would load the formula parser. This special case on constants allows the modification system to modify a value without loading a much larger infrastructure, and this is valuable as a large majority of our calculations are simple modifications of values.&lt;br /&gt;
&lt;br /&gt;
The SET shown above (since it has an operator) loads the formula system, and thus may occupy 500 (or more) bytes of memory (&amp;gt;10x), so it could take 100 times as long to process as the ADD (it also took longer during LST load).&lt;br /&gt;
&lt;br /&gt;
Thus: When possible the data standards should be written to use numeric modifiers and no operator.  (Think &amp;quot;static&amp;quot; modifiers ... that only use numbers) rather than a formula.&lt;br /&gt;
&lt;br /&gt;
==Lookup and Tables==&lt;br /&gt;
&lt;br /&gt;
For some situations, it makes more sense to have a lookup table rather than attempting to have a set of tokens or calculations perform processing.  This also allows for much cleaner translation from books when the books are using tables to organize information.&lt;br /&gt;
&lt;br /&gt;
The Table file format is designed to allow you to use a spreadsheet program to modify the tables and export the table in CSV format.  While we don't strictly follow full CSV rules, as long as you avoid embedded quotes and embedded return carriage/line feed, it should be safe.&lt;br /&gt;
&lt;br /&gt;
More than one table is allowed per file (to avoid sprawl and help simplify modification/management of tables).&lt;br /&gt;
&lt;br /&gt;
===TABLE (PCC File)===&lt;br /&gt;
&lt;br /&gt;
   TABLE:x&lt;br /&gt;
* x is the file to be loaded as a TABLE file&lt;br /&gt;
* Limitations: It does not support PRExxx or INCLUDE/EXCLUDE.&lt;br /&gt;
&lt;br /&gt;
====Table LST file format====&lt;br /&gt;
&lt;br /&gt;
File formatting considerations:&lt;br /&gt;
* Trailing commas will not impact any TABLE, and will be ignored&lt;br /&gt;
* Blank lines will be ignored.  This includes lines with commas but without content. (allows tables to be separated by blank lines or lines of all commas)&lt;br /&gt;
* Attempts to use embedded line breaks or embedded quotes may or may not be supported by the parsing system, but certainly aren't supported for purposes of PCGen.&lt;br /&gt;
* Lines that have the first cell starting with &amp;quot;#&amp;quot; are considered comment lines and will be ignored.  This will likely need to include if the first cell is escaped in quotes, just for protection from any tools that quote by default.&lt;br /&gt;
* Since the CSV format ignores leading/trailing spaces, one can easily have a spaced out version that is a table in a text editor if folks don't want to edit in a spreadsheet.  (Having someone write a &amp;quot;PrettyTable&amp;quot; ... a trivial perl or python program to do that for the data team seems fairly easy)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A TABLE starts with STARTTABLE:&lt;br /&gt;
   STARTTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the STARTTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If a STARTTABLE is encountered when another Table is active, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A TABLE ends with ENDTABLE:&lt;br /&gt;
   ENDTABLE:x&lt;br /&gt;
* x is the name of the Table.  Most characters are allowed, avoiding quotes is advisable.&lt;br /&gt;
* Allowing Trailing commas allows the ENDTABLE lines to have blank cells where the rest are the table contents... we don't want to complain on minor things that may tools will do.&lt;br /&gt;
&lt;br /&gt;
If an ENDTABLE is encountered without a STARTTABLE, an LST load error will occur.&lt;br /&gt;
&lt;br /&gt;
A Table must have a minimum of 3 rows, NOT counting the STARTTABLE and ENDTABLE tokens.&lt;br /&gt;
&lt;br /&gt;
The First row:&lt;br /&gt;
   x,x&lt;br /&gt;
* x is the column name.  These are always the first line of the table after STARTTABLE:&lt;br /&gt;
&lt;br /&gt;
Any column which has data MUST have a name.&lt;br /&gt;
&lt;br /&gt;
The Second row:&lt;br /&gt;
   y,y&lt;br /&gt;
* y is the format for the column.  Any column that was named must have a FORMAT.&lt;br /&gt;
&lt;br /&gt;
Additional rows:&lt;br /&gt;
   z,z&lt;br /&gt;
* z represents contents of the table.  These must be in the FORMAT provided for the appropriate column.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
   STARTTABLE:Carrying Capacity,&lt;br /&gt;
   Strength,Capacity&lt;br /&gt;
   NUMBER,NUMBER&lt;br /&gt;
   1,10&lt;br /&gt;
   2,20&lt;br /&gt;
   ...&lt;br /&gt;
   29,1400&lt;br /&gt;
   ENDTABLE:Carrying Capacity,&lt;br /&gt;
&lt;br /&gt;
===TABLE[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a TABLE is created, it implicitly picks up a FORMAT based on the FORMAT of the first column of the Table.  &lt;br /&gt;
Unlike basic FORMATs shown above, TABLE has a SUBFORMAT (in brackets).&lt;br /&gt;
&lt;br /&gt;
   TABLE[x]&lt;br /&gt;
* x is the SUB-FORMAT of the TABLE (this is the format of the first column of the Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  It certainly is prohibited to create a TABLE[TABLE[x]], but other situations the behavior may not be prohibited by the code (but the behavior is also not guaranteed)&lt;br /&gt;
&lt;br /&gt;
===COLUMN[x] Format===&lt;br /&gt;
&lt;br /&gt;
When a Column needs to be referred to in the data, it has a special format as well:&lt;br /&gt;
&lt;br /&gt;
Unlike basic FORMATs shown above, COLUMN has a SUBFORMAT (in brackets).&lt;br /&gt;
   COLUMN[x]&lt;br /&gt;
* x is the SUB-FORMAT of the COLUMN (this is the format of the data that appears in that column in a Table)&lt;br /&gt;
** x must be an otherwise valid FORMAT, and it is advised to avoid any FORMAT that has a SUB-FORMAT&lt;br /&gt;
*** This limitation may be inconsistently enforced.  Such behavior may not be prohibited by the code (but avoiding bad behavior is also not guaranteed in a situation where embedded brackets occur)&lt;br /&gt;
&lt;br /&gt;
===Using Tables===&lt;br /&gt;
&lt;br /&gt;
With MODIFY, a TABLE[x] variable doesn't look any different.  It's still:&lt;br /&gt;
   MODIFY:TableNameVar|SET|&amp;quot;SomeTable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;SomeTable&amp;quot; is still a string to a naive reader, but what the system will do at that point is make sure that SomeTable can actually be interpreted as a TABLE[x]... rather than just treating it as a String.  Similar for column names when they are encountered (see below).&lt;br /&gt;
&lt;br /&gt;
In that way, the sub variable will allow multiple tables to be swapped in, AS LONG AS they are the right format.  If the format is not compatible, then all bets are off and you'll get an error.&lt;br /&gt;
&lt;br /&gt;
===lookup() Function===&lt;br /&gt;
&lt;br /&gt;
The major consideration is how to do the lookup in data.  We can borrow some inspiration from things like Excel and Google Docs:&lt;br /&gt;
&lt;br /&gt;
   lookup(X,Y,Z)&lt;br /&gt;
&lt;br /&gt;
* X is a table.  This must resolve in the formula system to a valid table.  For now, a get(...) function may be required.&lt;br /&gt;
* Y is the lookup value in the table.  It must match the format of the first column in the table.  At this time, it does an EXACT match.&lt;br /&gt;
* Z is the target column.  This must resolve in the formula system to a valid table column. It must appear in the table named by the contents of the first argument of lookup.&lt;br /&gt;
&lt;br /&gt;
Example: Max load calculation would be something like:&lt;br /&gt;
   lookup(&amp;quot;Carrying Capacity&amp;quot;,floor(StrScore),&amp;quot;Capacity&amp;quot;)*SizeMult&lt;br /&gt;
We have to do the floor due to the exact name of the lookup&lt;br /&gt;
&lt;br /&gt;
Note: The format of both TABLE &amp;quot;Carrying Capacity&amp;quot; and COLUMN &amp;quot;Capacity&amp;quot; can be derived by PCGen internally and thus are no longer required to have a get (current as of Jan 30, 2018)&lt;br /&gt;
&lt;br /&gt;
Note that this function allows some runtime errors, but catches a lot of possible issues.  It is still possible to do a lookup on a Table that doesn't contain a specific column of the given name or format, simply because those items can be variables resolved at runtime.  For example, if the third variable is COLUMN[NUMBER], we can check at load that the TABLEFORMAT has columns of FORMAT=NUMBER, but we can't guarantee the variable will resolve to a name actually in that table... that will have to wait for a runtime error.  That's life, but it does allow us to know the formats at load time, so we do get a lot of error checking in the context of the usage, if not the exact table and column names.&lt;br /&gt;
&lt;br /&gt;
Note you can do some really dynamic behaviors to have folks override game mode behaviors.  For example, one neat item would be that we could alter a query for dice steps to extract the table name into the Global Modifier file:&lt;br /&gt;
   MODIFY:DiceStepTable|SET|&amp;quot;Dice Step&amp;quot;&lt;br /&gt;
   lookup(get(&amp;quot;TABLE[NUMBER]&amp;quot;,DiceStepTable),BaseDamage,get(&amp;quot;COLUMN[NUMBER]&amp;quot;,lookup(&amp;quot;Step Column&amp;quot;,CurrentSize-BaseSize,&amp;quot;Name&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
Note: In both cases here, the &amp;quot;get&amp;quot; is shown for completeness.  In the case of DiceStepTable - it MAY be required or prohibited - it depends on what the Format is of the &amp;quot;DiceStepTable&amp;quot; variable.  If it's TABLE, then the get is not necessary (and is actually prohibited).  The example shown above assumes DiceStepTable is a String.  The better design would be for it to be a TABLE (specifically TABLE[NUMBER]).  For the &amp;quot;get&amp;quot; after the lookup, that is required - the lookup value will return a STRING, and as such, will needs to be converted to a COLUMN.&lt;br /&gt;
&lt;br /&gt;
Now, if someone needs different dice steps for some reason... they can override the DiceStepTable variable and it will look up in a different table... so expansions could truly be expansions and not have to reach back into core PCC files in order to change key behaviors.&lt;br /&gt;
&lt;br /&gt;
Consider also that spell tables can be shared across classes, or if a subclass alters the default, just create a new table rather than having to BONUS/MODIFY all the numbers in a table with adding and subtracting...&lt;br /&gt;
&lt;br /&gt;
==To be completed==&lt;br /&gt;
* getOther&lt;br /&gt;
* Channels&lt;br /&gt;
&lt;br /&gt;
=Material Changes=&lt;br /&gt;
&lt;br /&gt;
==lookup function simplification==&lt;br /&gt;
&lt;br /&gt;
Effective January 30, 2018, tables and columns can be referred to directly in lookup().  This is actually a &amp;quot;broad&amp;quot; change to how strings are interpreted.  The system - when possible - fully asserts a FORMAT, and first attempts to convert the given String per the rules of that FORMAT.  This also means an assignment of an ALIGNMENT, by key, will not require a &amp;quot;get&amp;quot;:&lt;br /&gt;
   MODIFY:Alignment|SET|&amp;quot;LE&amp;quot;&lt;br /&gt;
...will be fully legal.  (This assumes Alignment is FORMAT: of ALIGNMENT)&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4337</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4337"/>
		<updated>2018-11-10T22:03:12Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* What is the solution? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Note: Strictly the new method in Step 1 of Phase 1 is not necessary, although it may help you identify places to look.  Longer term it may make sense either to not do the new method and place things directly into the initComponents method, or to do the two phases below and then inline those initializeStaticModel methods at the end.  Either way, the target here is the createModels, restoreModels and storeModels methods.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=UI Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of the XInfoHandler methods in various tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of availPanel and selPanel, built in the initializers of the classes for various tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
# Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;br /&gt;
# For the XInfoHandler classes, you may have to construct it with a few things, but still consolidation is possible&lt;br /&gt;
# For the Avail/Sel panel items, create two new classes, the boxes, glue, addAction and lots of other stuff can be isolated from each of the tabs.&lt;br /&gt;
&lt;br /&gt;
Note: Each of these new classes probably belongs in elsewhere... e.g. pcgen.gui2.util (or in pcgen.gui2.handler, etc) not in tabs.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4336</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4336"/>
		<updated>2018-11-10T21:59:24Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* What is the solution? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Note: Strictly the new method in Step 1 of Phase 1 is not necessary, although it may help you identify places to look.  Longer term it may make sense either to not do the new method and place things directly into the initComponents method, or to do the two phases below and then inline those initializeStaticModel methods at the end.  Either way, the target here is the createModels, restoreModels and storeModels methods.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=UI Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of the XInfoHandler methods in various tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of availPanel and selPanel, built in the initializers of the classes for various tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
# Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;br /&gt;
# For the XInfoHandler classes, you may have to construct it with a few things, but still consolidation is possible&lt;br /&gt;
# For the Avail/Sel panel items, create two new classes, the boxes, glue, addAction and lots of other stuff can be isolated from each of the tabs.&lt;br /&gt;
&lt;br /&gt;
Note: Each of these new classes probably belongs in pcgen.gui2.util not in tabs.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4335</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4335"/>
		<updated>2018-11-10T21:58:43Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* UI Consolidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Note: Strictly the new method in Step 1 of Phase 1 is not necessary, although it may help you identify places to look.  Longer term it may make sense either to not do the new method and place things directly into the initComponents method, or to do the two phases below and then inline those initializeStaticModel methods at the end.  Either way, the target here is the createModels, restoreModels and storeModels methods.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=UI Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of the XInfoHandler methods in various tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of availPanel and selPanel, built in the initializers of the classes for various tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;br /&gt;
For the XInfoHandler classes, you may have to construct it with a few things, but still consolidation is possible&lt;br /&gt;
For the Avail/Sel panel items, create two new classes, the boxes, glue, addAction and lots of other stuff can be isolated from each of the tabs.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4334</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4334"/>
		<updated>2018-11-10T21:54:41Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Filter Consolidation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Note: Strictly the new method in Step 1 of Phase 1 is not necessary, although it may help you identify places to look.  Longer term it may make sense either to not do the new method and place things directly into the initComponents method, or to do the two phases below and then inline those initializeStaticModel methods at the end.  Either way, the target here is the createModels, restoreModels and storeModels methods.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=UI Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
The same is true of the XInfoHandler methods in various tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;br /&gt;
For the XInfoHandler classes, you may have to construct it with a few things, but still consolidation is possible&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4333</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4333"/>
		<updated>2018-11-10T21:52:48Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* What is scope of work? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Note: Strictly the new method in Step 1 of Phase 1 is not necessary, although it may help you identify places to look.  Longer term it may make sense either to not do the new method and place things directly into the initComponents method, or to do the two phases below and then inline those initializeStaticModel methods at the end.  Either way, the target here is the createModels, restoreModels and storeModels methods.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=Filter Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4332</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4332"/>
		<updated>2018-11-10T21:48:34Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;br /&gt;
&lt;br /&gt;
=Filter Consolidation=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
QualifiedFilterHandler is (to within generics) identical between Race, Template, Domain, and potentially other tabs.&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
pcgen.gui2.tabs.*  QualifiedFilterHandler is, today, an inside class&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Extract one of them into its own class, make them all shared, slightly expanding generics if necessary.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4331</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4331"/>
		<updated>2018-11-10T21:08:47Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Eliminate Facades */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
Good places to start: RaceFacade, DeityFacade, HandsFacade, GenderFacade&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4330</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4330"/>
		<updated>2018-11-10T20:13:33Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=A COMMENT OVERALL=&lt;br /&gt;
&lt;br /&gt;
It is very helpful for us reviewing the code if you check these in in small pieces and not one massive bulk update.  That is one reason why I suggest incremental changes.&lt;br /&gt;
&lt;br /&gt;
=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;br /&gt;
&lt;br /&gt;
=Move UI to Dependency Injection model=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Currently, there are a set of models in the UI that are swapped out for each character.  These are done passively on swap, and force many items to have knowledge of CharacterFacade. &lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# We only want to build UI items once, and swap the model underneath&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# We want to move toward a &amp;quot;dependency injection&amp;quot; model&lt;br /&gt;
# We want to lower dependencies on runtime calls up and down a stack (there are classes in a tangle that DI can eliminate)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# pcgen.gui2.tabs for the most part&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
Convert these items to dependency injection and eliminate the model swapping effects in the UI.&lt;br /&gt;
&lt;br /&gt;
==Is an example shown today?==&lt;br /&gt;
&lt;br /&gt;
No.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
&lt;br /&gt;
# Start with code/src/java/pcgen/gui2/tabs/CharacterInfoTab.java ... Add a method: public void initializeStaticModel(Supplier&amp;lt;CharacterFacade&amp;gt; supplier);&lt;br /&gt;
# Add an empty version of the method above to all classes that implement CharacterInfoTab&lt;br /&gt;
# pcgen.gui2.tabs.InfoTabbedPane needs to be modified.  It:&lt;br /&gt;
## Owns the Supplier&lt;br /&gt;
## Must call the method above in initComponent()&lt;br /&gt;
## May need to initialize the Supplier object and the value of the Supplier in its constructor (depending on how the Supplier is written)&lt;br /&gt;
## Note: Null must be a legal return value for the supplier, and it should be initialized to null.&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
# For each of the classes where initializeStaticModel was added, look at the following method: public ModelMap createModels(CharacterFacade character)&lt;br /&gt;
# For each of the values of a put statement adding to the ModelMap, do the following:&lt;br /&gt;
## Evaluate if that subclass needs the CharacterFacade.  If so, provide that subclass the supplier in the constructor to that object and alter the class to use the Supplier.&lt;br /&gt;
## Delete the put, rather taking the construction of that object (which now uses the supplier) and place it into initializeStaticModel.&lt;br /&gt;
## Delete the &amp;quot;install&amp;quot; in restoreModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall&amp;quot; out of saveModels(...)&lt;br /&gt;
## Delete the &amp;quot;uninstall()&amp;quot; method on modified subclass&lt;br /&gt;
## Take the items from the &amp;quot;install()&amp;quot; method on the modified subclass and add those to initializeStaticModel (correcting for the difference in location)&lt;br /&gt;
# It is almost certain you will run into side effects where the Supplier will need to be passed into a constructor at some point - this is the idea, and part of DI.&lt;br /&gt;
WARNING: For your own sake, do these in small pieces, one target at a time.  You will rapidly find a few (QualifiedTreeCellRenderer comes to mind) that will have a wide ranging impact.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4329</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4329"/>
		<updated>2018-11-10T19:24:49Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;br /&gt;
&lt;br /&gt;
=Eliminate Facades=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facades (e.g. RaceFacade) that provide an interface on the core object for use by the UI.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, the facades are isolation of behavior between the core and the UI.&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# This forces the UI awareness back into the core, forcing the core to have methods from the Facade Interfaces it doesn't really &amp;quot;want&amp;quot; (and are only there to serve the UI)&lt;br /&gt;
# This is very design-specific.  Every behavior (Race has Hands) is a game-dependent piece of information that makes PCGen less flexible.  While we primarily handle d20, it still is a tight tie that makes it hard to get the UI dynamic to the data.&lt;br /&gt;
# This is removing a level of indirection that is necessary preparation for later work that will completely change how we access information in the UI (see below)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facade interfaces are in pcgen.facade.core&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
For now, this step is to delete the interfaces and directly use the objects.  The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes and more.  PC Alignment is now controlled through a channel... but that setup is more than this step is asking at the moment.&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
# Delete the WhateverFacade and directly use the object to get information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Create Channels/Delete Facets=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
There are a series of Facets that store the primary information for the model storing the PC.  These are in pcgen.cdom.facet&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
# The Facets are small containers for specific sets of information about a PlayerCharacter.  These were part of the process of reducing the &amp;quot;god object&amp;quot; behavior of PlayerCharacter.&lt;br /&gt;
#: In a larger picture, Facets are going away.  There are different types of facets, but in general, the new formula system can take over most of the behaviors of facets.  (There are exceptions we will eventually address).&lt;br /&gt;
&lt;br /&gt;
This design has a few limitations that we want to get rid of:&lt;br /&gt;
# The facets are still operating in a model where the UI has to go order the core to do things.  This is *really* challenging for things that have interacting behaviors. Gender, for example, is usually PC controlled, but there are some (cursed) magic items that can override it.  This really means our solving system (the formula system) needs to be UI- AND object-aware, and we want it to do the resolution of what the current situation is on a PC.&lt;br /&gt;
# We want to pass control of ALL of these items that touch the new formula system over to the data.  Eventually, the data should know the variable is &amp;quot;PCsAlignment&amp;quot; and then the HTML (or whatever) that displays the PC should be told it's &amp;quot;PCsAlignment&amp;quot;.  In this way, the variable name from the data can match the HTML and NO code modifications are necessary to change what or how it is displayed.  This completes a significant portion of our &amp;quot;separation of duties&amp;quot; to reduce the amount of code change necessary for minor items in game systems, and allows us to focus on larger issues.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The facets are in pcgen.cdom.facet, more specifically the ones relevant here are mostly in pcgen.cdom.facet.model&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The strategic direction is to use channels.  See pcgen.output.channel&lt;br /&gt;
&lt;br /&gt;
==Is this shown today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  PC Alignment is now controlled through a channel.  You can see some compatibility work (aka temporary code) in pcgen.output.channel.ChannelCompatibility &lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
Step 1: Move from using the facet to using the new formula system, while Enabling Data to control the channel/variable.  This actually takes some interacting work with data.&lt;br /&gt;
# We need to set up a system that tells us whether we (code) control the variable name for an item or whether data has asserted IT controls the name.  These are called &amp;quot;CodeControls&amp;quot; (see pcgen.cdom.util.CControl for the names, such as ALIGNMENTINPUT)&lt;br /&gt;
# If we control the name, we need to create the channel.  See SourceFileLoader.defineBuiltinVariables for how alignment works.&lt;br /&gt;
# Depending on the complexity, we may need ChannelCompatibility items.  Arguably, the Alignment work is not complete, but it is at least functional.&lt;br /&gt;
# Delete the facet.  There may be other facets using the one you deleted.  If so, you will need something like: In PlayerCharacter.doFormulaSetup, you will need soemthing like: VariableChannelFactoryInst.watchChannel(id, &amp;quot;DeityInput&amp;quot;, activeSpellsFacet);&lt;br /&gt;
If there is a priority [a number] when the listener is set up, you will need to use that as well - please see the other watchChannel method in VariableChannelFactoryInst&lt;br /&gt;
# If there is a new format involved (things like DEITY), then you probably need to work with the data team to have that variable defined in all data modes OR you need some method for figuring out where it is/is not legal.&lt;br /&gt;
&lt;br /&gt;
Step 2: Unwind most of CharacterFacade (a bit of a concentrated set of behavior), and reduce the breadth of usage of the pcgen.facade.core.CharacterFacede object within the UI. (.getCharID() usage is good, others to be eliminated)&lt;br /&gt;
&lt;br /&gt;
Note: Step 2 in some cases may be VERY hard.  Alignment is an example, where changing Alignment can have side effects.  We don't currently have a great design for that scenario, in that checking for qualification of the alignment, checking EX_CLASS, etc. are not behaviors we yet have a design to handle in the formula system.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4328</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4328"/>
		<updated>2018-11-10T19:17:04Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* What is one possible path? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
## If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4327</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4327"/>
		<updated>2018-11-10T19:16:15Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* What is scope of work? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
* Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
* The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
* A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
*: This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token). &lt;br /&gt;
*: If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
*: We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
*: We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
* It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4326</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4326"/>
		<updated>2018-11-10T19:12:55Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
# The tokens are in plugin.lsttokens&lt;br /&gt;
# The contexts are in pcgen.rules.context&lt;br /&gt;
# Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is the solution?==&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
==Is an example in the code today?==&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
# Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
# The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
# A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token).&lt;br /&gt;
If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
## We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
## We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
# It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4325</id>
		<title>Working Projects</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Working_Projects&amp;diff=4325"/>
		<updated>2018-11-10T19:10:05Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot;=Token Rebuilds to Interface=  ==What is the situation today?==  Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL d...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Token Rebuilds to Interface=&lt;br /&gt;
&lt;br /&gt;
==What is the situation today?==&lt;br /&gt;
&lt;br /&gt;
Our loading tokens are using a form of commitment process (evaluate then commit or rollback) much like a SQL database.&lt;br /&gt;
&lt;br /&gt;
This process today uses things like AbstractObjectContext (which inside it has an ObjectCommitStrategy) in order to do this level commitment process.&lt;br /&gt;
&lt;br /&gt;
==Why do we do this?==&lt;br /&gt;
&lt;br /&gt;
# Primarily, if there is a token that has a bad syntax, we don't want a partial data structure to get into the core code.  This causes a tremendous amount of &amp;quot;what if&amp;quot; scenarios in our code that means folks (a) write a ton of error checking code (b) catch and silently consume errors&lt;br /&gt;
# We want to catch LST errors at load and report that ASAP to the data team.  If they have to actually USE a token in order to make sure it is valid, that is a HUGE testing burden on the data team.&lt;br /&gt;
&lt;br /&gt;
This commit process has been VERY valuable (we want to keep it!), but also challenging.  There are a few limitations we want to get rid of:&lt;br /&gt;
# This forces us to only do things that ObjectCommitStrategy knows about.  There is a huge centralized code dependency (high workload, fragile)&lt;br /&gt;
# This forces us to remember never to write to a specific object, but always through the Context (annoying, fragile)&lt;br /&gt;
# This forces a design where &amp;quot;everything is a CDOMObject&amp;quot;, which creates a form of demi-god object (PlayerCharacter is still our &amp;quot;God Object&amp;quot; ;)&lt;br /&gt;
&lt;br /&gt;
==Where do I see this stuff?==&lt;br /&gt;
&lt;br /&gt;
The tokens are in plugin.lsttokens&lt;br /&gt;
The contexts are in pcgen.rules.context&lt;br /&gt;
Some abstract items are in pcgen.rules.persistence.token&lt;br /&gt;
&lt;br /&gt;
An actual example of how the token loading works is in pcgen.rules.persistence.TokenSupport.processClassTokens(...)... that will return success or failure and capture any messages in case of failure into a set of parsed messages.&lt;br /&gt;
&lt;br /&gt;
The actual commit/rollback process can be seen in pcgen.persistence.lst.LstUtils.processToken(...)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What is the solution?&lt;br /&gt;
&lt;br /&gt;
The best way to get around this is to &amp;quot;properly&amp;quot; use reflection, which was really not a thing comfortable for many developers in about 2006 when we started down the token path.  Thankfully this can be abstracted into a library, so the reflection is well hidden from most users/developers.&lt;br /&gt;
&lt;br /&gt;
The reflection code is StagingInfo, and it exits in our Base PCGen library (pcgen-base repository) in pcgen.base.proxy.  &lt;br /&gt;
&lt;br /&gt;
Is this shown today?&lt;br /&gt;
&lt;br /&gt;
Yes.  This staging is used for a limited number of tokens and you can find the process in pcgen.rules.persistence.TokenSupport.processInterfaceToken(...)&lt;br /&gt;
&lt;br /&gt;
==What is scope of work?==&lt;br /&gt;
&lt;br /&gt;
At this point, some folks may be thinking things like &amp;quot;Hey - I can have a getAlignment and putAlignment method on Deity.class!&amp;quot;.  That may be literally true, but there are a few considerations to that:&lt;br /&gt;
# One step at a time&lt;br /&gt;
# There are things outside the scope of this description that are also changing and make the first step as described here valuable and a dramatic step to completely eliminate the abstraction in CDOMObject to be potentially undoing other things we value&lt;br /&gt;
&lt;br /&gt;
The scope of work here is to change indirect calls through an object context, e.g.:&lt;br /&gt;
context.getObjectContext().put(deity, ObjectKey.ALIGNMENT, al);&lt;br /&gt;
...into direct calls on the object, e.g.:&lt;br /&gt;
deity.put(ObjectKey.ALIGNMENT, al);&lt;br /&gt;
&lt;br /&gt;
This directly meets requirements #1 and #2 above.&lt;br /&gt;
&lt;br /&gt;
In order to do this a few things need to happen:&lt;br /&gt;
# Read and write interfaces need to be defined, so they can be passed to a StagingInfo&lt;br /&gt;
It is my belief that the interface would work best right now if the scope was a single behavior.  So the put and get just for ObjectKey.* would be processed separately.&lt;br /&gt;
# The tokens that are using ObjectContext to use those methods need to call items directly on the object&lt;br /&gt;
# A method needs to be defined that will appropriately limit usage of the object&lt;br /&gt;
This may require a bit of explanation.  Let's use plugin.lsttokens.deity.AlignToken. Today, this keys directly off the object, Deity, using CDOMPrimaryToken as the interface (the parent interface CDOMToken actually defines how TokenSupport will process that token).&lt;br /&gt;
If we create interfaces ReadObjectKey and WriteObjectKey, those can be reused across all of the same types of methods, but it places us in a situation where we have lost the ability to enforce ALIGN:x only works on a Deity.  So there is a balancing act here:&lt;br /&gt;
## We probably don't want to have interfaces directly for each type of object (readDeity and writeDeity), as that creates interface proliferation (and we want to get away from that level of specific behavior anyway)&lt;br /&gt;
## We probably want to think about how we can have tokens actually work on Dynamic objects - this relates to (A) above... the dynamic objects are all the same class, and thus a different validation method is necessary than one based on class or the interfaces implemented by that class.  (see pcgen.cdom.inst.Dynamic)&lt;br /&gt;
# It is likely that a new interface beyond CDOMPrimaryToken / CDOMInterfaceToken needs to be defined.  It is possible CDOMInterfaceToken could be enhanced with a default method that always passes, but could be overridden with a method that would check for legality from #3 above in cases where it is necessary.&lt;br /&gt;
&lt;br /&gt;
==What is one possible path?==&lt;br /&gt;
&lt;br /&gt;
WARNING: Any mixed tokens that still use the context probably don't want to be converted, so two of these actions will be reverted at the end&lt;br /&gt;
&lt;br /&gt;
# Take the import for ObjectKey out of ObjectCommitStrategy and find the errors&lt;br /&gt;
# Delete all the methods that are then errors from those methods being removed from the interface&lt;br /&gt;
# A whole bunch of tokens now have errors.  Those need to be checked.  If they are just a simple use of the interface then:&lt;br /&gt;
## changed to direct calls rather than through the objectcontext&lt;br /&gt;
## converted to the new load method (not CDOMPrimaryToken)&lt;br /&gt;
## Have the limit from #3 (limit where it is legal) added&lt;br /&gt;
If they are complicated (FavoredClass), then I'd leave as-is for the moment.&lt;br /&gt;
# Revert the changes made in #1 and #2&lt;br /&gt;
&lt;br /&gt;
Lather, rinse, repeat for ObjectKey, IntegerKey, ListKey, StringKey, FactKey, FactSetKey&lt;br /&gt;
&lt;br /&gt;
You can skip VariableKey, FormulaKey, MapKey for now.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Code&amp;diff=4324</id>
		<title>Code</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Code&amp;diff=4324"/>
		<updated>2018-11-10T18:36:40Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Coding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Welcome to the Wiki section for the Code Monkey team!&lt;br /&gt;
&lt;br /&gt;
=Mission Statement=&lt;br /&gt;
'''TBA'''&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
* [[Developers Meeting]]&lt;br /&gt;
* [[Dev Meeting Log 20090429]]&lt;br /&gt;
* [[Dev Meeting Log 20090815]]&lt;br /&gt;
* [[Dev Meeting Log 20090911]]&lt;br /&gt;
* [[Dev Meeting Log 20091017]]&lt;br /&gt;
* [[Dev Meeting Log 20091114]]&lt;br /&gt;
* [[Dev Meeting Log 20120309]]&lt;br /&gt;
* [[Dev Meeting Log 20120429]]&lt;br /&gt;
* [[Dev Meeting Log 20121103]]&lt;br /&gt;
* [[Dev Meeting Log 20140627]]&lt;br /&gt;
&lt;br /&gt;
==For New Starters==&lt;br /&gt;
* [[Joining the Code Team]] General steps to take to prepare yourself&lt;br /&gt;
* [[Code Monkey Introduction]]&lt;br /&gt;
&lt;br /&gt;
==Developer Environment==&lt;br /&gt;
* [[Basic Developer Setup]]&lt;br /&gt;
* [[Git Setup]]&lt;br /&gt;
* [[Subversion Setup]]&lt;br /&gt;
* [[Merging]] with SVN&lt;br /&gt;
* [[Building PCGen]], also see [[Gradle]]&lt;br /&gt;
* [[Continuous Integration]]&lt;br /&gt;
* [[Autobuilds for Libraries]]&lt;br /&gt;
* [[launch4j]]&lt;br /&gt;
&lt;br /&gt;
==Coding==&lt;br /&gt;
* [[Coding Standards]]&lt;br /&gt;
* [[Deprecating a Token]]&lt;br /&gt;
* [[Explanation of the Code Base]]&lt;br /&gt;
* [[PCGen Code Exploration Almanac]]&lt;br /&gt;
* [[Graph Theory]]&lt;br /&gt;
* [[Logging in the Code Base]]&lt;br /&gt;
* [[Unit Testing]]&lt;br /&gt;
* [[Removing Libraries]]&lt;br /&gt;
* [[Unnecessary Code Detector]]&lt;br /&gt;
* [[Working Projects]]&lt;br /&gt;
&lt;br /&gt;
=Completed Sub Projects=&lt;br /&gt;
* [[Ability Object TODO List]]&lt;br /&gt;
* [[LST_Editor_Verification]]&lt;br /&gt;
&lt;br /&gt;
=Open Sub Projects=&lt;br /&gt;
* [[UI HTML Extraction]]&lt;br /&gt;
* [[Internationalization]]&lt;br /&gt;
* [[CDOM]]&lt;br /&gt;
* [[UI Overhaul]]&lt;br /&gt;
* [[LST_Editor]]&lt;br /&gt;
* [[Major Code Projects]]&lt;br /&gt;
* [[Template Engine]]&lt;br /&gt;
* [[Enhanced Networking Features]]&lt;br /&gt;
&lt;br /&gt;
=Active Team Members=&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Silverback|Silverback]]===&lt;br /&gt;
* Connor Petty&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Second|2nd]]===&lt;br /&gt;
* TBA&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Chimp|Chimp]]===&lt;br /&gt;
* [[Tom Parker]]&lt;br /&gt;
* [[Stefan Radermacher]]&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Gibbon|Gibbon]]===&lt;br /&gt;
* Jayme Cox&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Tamarin|Tamarin]]===&lt;br /&gt;
* [[Andrew Wilson]]&lt;br /&gt;
* [[Martijn Verburg]]&lt;br /&gt;
* [[Connor Petty]]&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Lemur|Lemur]]===&lt;br /&gt;
* [[Eddy Anthony]]&lt;br /&gt;
* Per Christian Henden&lt;br /&gt;
* Thomas Cooper &lt;br /&gt;
* [[Tod Milam]] - Mac Developer&lt;br /&gt;
* [[Kim Winz]]&lt;br /&gt;
* Eitan Adler&lt;br /&gt;
&lt;br /&gt;
===[[X-Terminator Mark II]]===&lt;br /&gt;
* [[Greg Bingleman]] - [http://www.codemonkeypublishing.com Code Monkey Publishing]&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* Brad Stiles, SVN advice&lt;br /&gt;
* Jason Buchanan, Advice on old code&lt;br /&gt;
* [[Jonas Karlson]], Advice on old code&lt;br /&gt;
&lt;br /&gt;
=Passive Team Members=&lt;br /&gt;
&lt;br /&gt;
* B. K. Oxley (Provides IntelliJ licenses)&lt;br /&gt;
&lt;br /&gt;
=Inactive Team Members=&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#2nd|2nd]]===&lt;br /&gt;
* Devon Jones&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Chimp|Chimp]]===&lt;br /&gt;
* Aaron Divinsky&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Tamarin|Tamarin]]===&lt;br /&gt;
* Andriy Sen&lt;br /&gt;
* [[Kevin Fernandes]]&lt;br /&gt;
* [[Koen Van Daele]]&lt;br /&gt;
* [[Joe Frazier, Jr.]]&lt;br /&gt;
* Per Christian Henden&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Lemur|Lemur]]===&lt;br /&gt;
* Bill Neumann&lt;br /&gt;
* Dan Parks&lt;br /&gt;
* [[Eduard Martinescu]]&lt;br /&gt;
* Eric Jarman&lt;br /&gt;
* Jasper Spaans&lt;br /&gt;
* Julio Esslinger Viegas&lt;br /&gt;
* Peter Barker&lt;br /&gt;
* [[Rick Ryker]]&lt;br /&gt;
* Thomas Clegg&lt;br /&gt;
* Tony Lavalle&lt;br /&gt;
* Hades Lucifer [7/20/10]&lt;br /&gt;
* Josh Johnston [7/20/10]&lt;br /&gt;
* MotorViper    [7/20/10]&lt;br /&gt;
* [[Steven West]] [7/20/10]&lt;br /&gt;
* [[Alec Ross]] [7/20/10]&lt;br /&gt;
* [[Tir Gwaith]] [7/20/10]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* [[Andargor]], Suggestions&lt;br /&gt;
* [[Bryan McRoberts]], Advice on old code&lt;br /&gt;
* Kurt Wimmer, Suggestions&lt;br /&gt;
* Walter Duncan, Held the old pcgen_autobuild user&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=UI_HTML_Extraction&amp;diff=4293</id>
		<title>UI HTML Extraction</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=UI_HTML_Extraction&amp;diff=4293"/>
		<updated>2018-03-26T21:19:48Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot;{| align=&amp;quot;right&amp;quot;   | __TOC__   |}  =Purpose= This project externalizes a number of items in the PCGen UI into something that is outside the code.    This WILL require some dis...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Purpose=&lt;br /&gt;
This project externalizes a number of items in the PCGen UI into something that is outside the code.  &lt;br /&gt;
&lt;br /&gt;
This WILL require some discussion with members of the team (code, data, and output, release).&lt;br /&gt;
&lt;br /&gt;
==Reasoning==&lt;br /&gt;
&lt;br /&gt;
We are moving this out of the code because they are closely tied to the data.  By moving them out, we can accomplish a number of things:&lt;br /&gt;
# Have different display in different game modes, depending on the content of an item&lt;br /&gt;
# Have the display be able to be updated when data changes are made, rather than requiring code/data co-dependence&lt;br /&gt;
# Leverage a common system for output&lt;br /&gt;
# Prepare for a future UI change by extracting behavior that will be needed regardless of the presentation location&lt;br /&gt;
&lt;br /&gt;
=Process=&lt;br /&gt;
&lt;br /&gt;
Right now the vast majority of our items that are text descriptions in the UI (info about an object that is clicked on) are done from an InfoFactory, specifically Gui2InfoFactory.  This will replace the behavior in those methods.&lt;br /&gt;
&lt;br /&gt;
These items should be converted one at a time, so code reviews can  be done in between each item, so that we know certain automation (macros, etc) are being appropriately produced.  (This isn't to say we won't discover things later, but let's catch what we can by inspection).&lt;br /&gt;
&lt;br /&gt;
=Success=&lt;br /&gt;
&lt;br /&gt;
This includes:&lt;br /&gt;
# The HTML elements are externalized from Gui2InfoFactory&lt;br /&gt;
# The HTML is processed through FreeMarker before it is written into the UI&lt;br /&gt;
## Place the Freemarker processing into pcgen.io for now - probably into a new class.&lt;br /&gt;
## Please reuse your freemarker.template.Configuration.&lt;br /&gt;
## Consider reusing the freemarker.template.Template objects - if you don't, have a reasoning for why not.&lt;br /&gt;
# All of the getHTMLInfo methods that build HTML are modified and have the source HTML extraced to external files.  &lt;br /&gt;
## Note: After those methods are complete, it can be evaluated what other methods it is valuable to extract as a &amp;quot;Phase 2&amp;quot;.&lt;br /&gt;
## Note: Communication with the release team will be necessary to make sure these files are included in the release&lt;br /&gt;
# For purposes of this project the *Facade objects should not be used during export.  If you look at how the wrappers in pcgen.output work, the UI Facades are not used, so pass in a &amp;quot;real&amp;quot; object to the output system when building the Map (or whatever style you use).&lt;br /&gt;
# You SHOULD be writing Freemarker macros, and it's okay to require importing of some macro files at the top of the HTML files.  &lt;br /&gt;
## Formatting PI strings should not be done brute force every time, but SHOULD be done in Freemarker (not the code).&lt;br /&gt;
## Handling Yes/No for boolean objects should also be a macro handled in Freemarker.&lt;br /&gt;
## Other items like gathering Facts may also be useful to have macros.  Don't go crazy, but make the info files easy to write as well.  Yes, in certain points of view, this means the project has imprecise requirements.  Get opinions and justify the decision. &lt;br /&gt;
# The Gui2InfoFactory knowledge is limited to a specific file name.  &lt;br /&gt;
## For now, this file name can be hardcoded, and one file can exist for all of PCGen. It will be a follow-on project to make that file specific to a game mode and copied into the game mode directories.  I would rather do that all at once across a number of files, so that the imposition on the system directory is in one PR.&lt;br /&gt;
## Share the actual export process and only have the file name determination be part of the Gui2InfoFactory.&lt;br /&gt;
&lt;br /&gt;
=Implicit Design=&lt;br /&gt;
&lt;br /&gt;
In addition to the macros pointed out above, there are a number of items that must implicitly be designed to be successful here.  This includes (but may not be limited to):&lt;br /&gt;
# Determining how to communicate the SourceFormat preferences to the output.  Note that today this is a SourceFormat object returned by Globals&lt;br /&gt;
## There should probably be multiple formatting macros in Freemarker that can be selected?&lt;br /&gt;
## This also needs consideration of how to keep this reasonable both short and long term, with the understanding that use of Globals strategically isn't a preferred practice.&lt;br /&gt;
# Dealing with prerequisites and Freemarker output.  &lt;br /&gt;
## You should be aware Prerequisites in their current form are NOT strategic.  Therefore, you should probably just leverage the existing HTML that they produce and figure out a way to get that to the Freemarker output without worrying about any clever redesign.&lt;br /&gt;
# How will you pull an internationalized string from the core code (assuming the HTML knows the internatinoalization key)?&lt;br /&gt;
&lt;br /&gt;
=Documentation Required=&lt;br /&gt;
You will need to document at least:&lt;br /&gt;
# What is the active object is called in the HTML?  It should be self-consistent across the files.  Note that this does not mean it always has to be &amp;quot;active&amp;quot; or some such, it could be &amp;quot;race&amp;quot; and &amp;quot;template&amp;quot; for different object types.  Both are self-consistent under this definition.  Feedback from the wider team (especially data/output) is encouaged.&lt;br /&gt;
# Where are the files placed?&lt;br /&gt;
# What are the files called?&lt;br /&gt;
# What files need to be included in the release (if not obvious from the above)&lt;br /&gt;
&lt;br /&gt;
=Other Notes=&lt;br /&gt;
You WILL run into items which are not currently exported in the Freemarker output system.  We WILL need to talk about these.&lt;br /&gt;
&lt;br /&gt;
=Pointers=&lt;br /&gt;
You should read pcgen.io.ExportHandler.exportCharacterUsingFreemarker to see what is done there since you will need a simpler version of that process.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Code&amp;diff=4292</id>
		<title>Code</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Code&amp;diff=4292"/>
		<updated>2018-03-26T21:19:13Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Open Sub Projects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
Welcome to the Wiki section for the Code Monkey team!&lt;br /&gt;
&lt;br /&gt;
=Mission Statement=&lt;br /&gt;
'''TBA'''&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
* [[Developers Meeting]]&lt;br /&gt;
* [[Dev Meeting Log 20090429]]&lt;br /&gt;
* [[Dev Meeting Log 20090815]]&lt;br /&gt;
* [[Dev Meeting Log 20090911]]&lt;br /&gt;
* [[Dev Meeting Log 20091017]]&lt;br /&gt;
* [[Dev Meeting Log 20091114]]&lt;br /&gt;
* [[Dev Meeting Log 20120309]]&lt;br /&gt;
* [[Dev Meeting Log 20120429]]&lt;br /&gt;
* [[Dev Meeting Log 20121103]]&lt;br /&gt;
* [[Dev Meeting Log 20140627]]&lt;br /&gt;
&lt;br /&gt;
==For New Starters==&lt;br /&gt;
* [[Joining the Code Team]] General steps to take to prepare yourself&lt;br /&gt;
* [[Code Monkey Introduction]]&lt;br /&gt;
&lt;br /&gt;
==Developer Environment==&lt;br /&gt;
* [[Basic Developer Setup]]&lt;br /&gt;
* [[Git Setup]]&lt;br /&gt;
* [[Subversion Setup]]&lt;br /&gt;
* [[Merging]] with SVN&lt;br /&gt;
* [[Building PCGen]], also see [[Gradle]]&lt;br /&gt;
* [[Continuous Integration]]&lt;br /&gt;
* [[launch4j]]&lt;br /&gt;
&lt;br /&gt;
==Coding==&lt;br /&gt;
* [[Coding Standards]]&lt;br /&gt;
* [[Deprecating a Token]]&lt;br /&gt;
* [[Explanation of the Code Base]]&lt;br /&gt;
* [[PCGen Code Exploration Almanac]]&lt;br /&gt;
* [[Graph Theory]]&lt;br /&gt;
* [[Logging in the Code Base]]&lt;br /&gt;
* [[Unit Testing]]&lt;br /&gt;
* [[Removing Libraries]]&lt;br /&gt;
* [[Unnecessary Code Detector]]&lt;br /&gt;
&lt;br /&gt;
=Completed Sub Projects=&lt;br /&gt;
* [[Ability Object TODO List]]&lt;br /&gt;
* [[LST_Editor_Verification]]&lt;br /&gt;
&lt;br /&gt;
=Open Sub Projects=&lt;br /&gt;
* [[UI HTML Extraction]]&lt;br /&gt;
* [[Internationalization]]&lt;br /&gt;
* [[CDOM]]&lt;br /&gt;
* [[UI Overhaul]]&lt;br /&gt;
* [[LST_Editor]]&lt;br /&gt;
* [[Major Code Projects]]&lt;br /&gt;
* [[Template Engine]]&lt;br /&gt;
* [[Enhanced Networking Features]]&lt;br /&gt;
&lt;br /&gt;
=Active Team Members=&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Silverback|Silverback]]===&lt;br /&gt;
* Connor Petty&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Second|2nd]]===&lt;br /&gt;
* TBA&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Chimp|Chimp]]===&lt;br /&gt;
* [[Tom Parker]]&lt;br /&gt;
* [[Stefan Radermacher]]&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Gibbon|Gibbon]]===&lt;br /&gt;
* Jayme Cox&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Tamarin|Tamarin]]===&lt;br /&gt;
* [[Andrew Wilson]]&lt;br /&gt;
* [[Martijn Verburg]]&lt;br /&gt;
* [[Connor Petty]]&lt;br /&gt;
&lt;br /&gt;
===[[Explanation of Teams#Lemur|Lemur]]===&lt;br /&gt;
* [[Eddy Anthony]]&lt;br /&gt;
* Per Christian Henden&lt;br /&gt;
* Thomas Cooper &lt;br /&gt;
* [[Tod Milam]] - Mac Developer&lt;br /&gt;
* [[Kim Winz]]&lt;br /&gt;
&lt;br /&gt;
===[[X-Terminator Mark II]]===&lt;br /&gt;
* [[Greg Bingleman]] - [http://www.codemonkeypublishing.com Code Monkey Publishing]&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* Brad Stiles, SVN advice&lt;br /&gt;
* Jason Buchanan, Advice on old code&lt;br /&gt;
* [[Jonas Karlson]], Advice on old code&lt;br /&gt;
&lt;br /&gt;
=Passive Team Members=&lt;br /&gt;
&lt;br /&gt;
* B. K. Oxley (Provides IntelliJ licenses)&lt;br /&gt;
&lt;br /&gt;
=Inactive Team Members=&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#2nd|2nd]]===&lt;br /&gt;
* Devon Jones&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Chimp|Chimp]]===&lt;br /&gt;
* Aaron Divinsky&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Tamarin|Tamarin]]===&lt;br /&gt;
* Andriy Sen&lt;br /&gt;
* [[Kevin Fernandes]]&lt;br /&gt;
* [[Koen Van Daele]]&lt;br /&gt;
* [[Joe Frazier, Jr.]]&lt;br /&gt;
* Per Christian Henden&lt;br /&gt;
&lt;br /&gt;
===[[Explanation_of_Teams#Lemur|Lemur]]===&lt;br /&gt;
* Bill Neumann&lt;br /&gt;
* Dan Parks&lt;br /&gt;
* [[Eduard Martinescu]]&lt;br /&gt;
* Eric Jarman&lt;br /&gt;
* Jasper Spaans&lt;br /&gt;
* Julio Esslinger Viegas&lt;br /&gt;
* Peter Barker&lt;br /&gt;
* [[Rick Ryker]]&lt;br /&gt;
* Thomas Clegg&lt;br /&gt;
* Tony Lavalle&lt;br /&gt;
* Hades Lucifer [7/20/10]&lt;br /&gt;
* Josh Johnston [7/20/10]&lt;br /&gt;
* MotorViper    [7/20/10]&lt;br /&gt;
* [[Steven West]] [7/20/10]&lt;br /&gt;
* [[Alec Ross]] [7/20/10]&lt;br /&gt;
* [[Tir Gwaith]] [7/20/10]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* [[Andargor]], Suggestions&lt;br /&gt;
* [[Bryan McRoberts]], Advice on old code&lt;br /&gt;
* Kurt Wimmer, Suggestions&lt;br /&gt;
* Walter Duncan, Held the old pcgen_autobuild user&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4281</id>
		<title>Race Racial Trait Swapping</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4281"/>
		<updated>2018-03-09T03:22:53Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Considerations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Race is granted 'default' traits as a standard. Paizo has introduced two systems of concern:&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race is granted specific non-default traits&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race if granted a choice between two or more additional choices&lt;br /&gt;
# Racial Trait that is chosen by the player actually removes 2 or more existing default traits&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #1=&lt;br /&gt;
&lt;br /&gt;
This seems straight-forward to me.  The Race Package can simply have:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|DifferentFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable assignments are very similar to what is shown in [[Replacing Archetype Controls]].&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #2=&lt;br /&gt;
&lt;br /&gt;
This involves a choice, thus interacts with [[SELECTION - A CHOOSE Replacement]].  This section is deferred until some changes and clarifications are made on that page with respect to how instances will work (there are multiple methods of causing instances and that is not currently clear).&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #3=&lt;br /&gt;
&lt;br /&gt;
I'm not sure there are multiple possible solutions here.  I think this is straightforward.  &lt;br /&gt;
&lt;br /&gt;
==Filler Object==&lt;br /&gt;
&lt;br /&gt;
Let's assume we have a Racial Trait &amp;quot;Super&amp;quot; that replaces &amp;quot;Good&amp;quot; and &amp;quot;Lucky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This presumes we have done:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYNAMICSCOPE:RACEFEATURE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Lucky&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Feature_Lucky|SET|Default_Feature_Lucky&lt;br /&gt;
MODIFY:Feature_Good|SET|Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we need to remove Default_L3_Feature_Lucky.  I would probably recommend something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Lucky|SET|EmptyFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EmptyFeature would then be an object with nothing in it.&lt;br /&gt;
&lt;br /&gt;
===Justification===&lt;br /&gt;
&lt;br /&gt;
Keep in mind if we have a DYNAMIC of RACEFEATURE (which Default_Feature_Lucky is one implementation) then we need a default value for that object type.  So it's already likely that we have an &amp;quot;EmptyFeature&amp;quot; set up to be the default value for a variable of the RACEFEATURE FORMAT.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
One possible alternative would be to have an ARRAY[RACEFEATURE] that contains all of the traits for a given level.&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:RACE|ARRAY[RACEFEATURE]=Features&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Features|ADD|Default_Feature_Lucky+Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Considerations===&lt;br /&gt;
&lt;br /&gt;
In this case, we need to look at what it would be like for a class to replace only one of the features.&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|SET|value()-Default_Feature_Good+Default_Feature_Better|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or alternatively:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|ADD|Default_Feature_Better|PRIORITY=400&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|REMOVE|Default_Feature_Good|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Considerations:&lt;br /&gt;
# We have avoided adding an empty shell to the PC&lt;br /&gt;
# We are making (risky?) assumptions of what we are replacing&lt;br /&gt;
# We start to get into order of operations problems between features that touch different features (think of this more broadly in terms of Archetypes that can impact different items at the same level both being usable together), so it increases the cross-data interaction&lt;br /&gt;
&lt;br /&gt;
In general, I think this is a bad idea due to the built-in assumptions.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4280</id>
		<title>Race Racial Trait Swapping</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4280"/>
		<updated>2018-03-09T03:22:08Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Array */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Race is granted 'default' traits as a standard. Paizo has introduced two systems of concern:&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race is granted specific non-default traits&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race if granted a choice between two or more additional choices&lt;br /&gt;
# Racial Trait that is chosen by the player actually removes 2 or more existing default traits&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #1=&lt;br /&gt;
&lt;br /&gt;
This seems straight-forward to me.  The Race Package can simply have:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|DifferentFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable assignments are very similar to what is shown in [[Replacing Archetype Controls]].&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #2=&lt;br /&gt;
&lt;br /&gt;
This involves a choice, thus interacts with [[SELECTION - A CHOOSE Replacement]].  This section is deferred until some changes and clarifications are made on that page with respect to how instances will work (there are multiple methods of causing instances and that is not currently clear).&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #3=&lt;br /&gt;
&lt;br /&gt;
I'm not sure there are multiple possible solutions here.  I think this is straightforward.  &lt;br /&gt;
&lt;br /&gt;
==Filler Object==&lt;br /&gt;
&lt;br /&gt;
Let's assume we have a Racial Trait &amp;quot;Super&amp;quot; that replaces &amp;quot;Good&amp;quot; and &amp;quot;Lucky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This presumes we have done:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYNAMICSCOPE:RACEFEATURE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Lucky&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Feature_Lucky|SET|Default_Feature_Lucky&lt;br /&gt;
MODIFY:Feature_Good|SET|Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we need to remove Default_L3_Feature_Lucky.  I would probably recommend something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Lucky|SET|EmptyFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EmptyFeature would then be an object with nothing in it.&lt;br /&gt;
&lt;br /&gt;
===Justification===&lt;br /&gt;
&lt;br /&gt;
Keep in mind if we have a DYNAMIC of RACEFEATURE (which Default_Feature_Lucky is one implementation) then we need a default value for that object type.  So it's already likely that we have an &amp;quot;EmptyFeature&amp;quot; set up to be the default value for a variable of the RACEFEATURE FORMAT.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
One possible alternative would be to have an ARRAY[RACEFEATURE] that contains all of the traits for a given level.&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:RACE|ARRAY[RACEFEATURE]=Features&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Features|ADD|Default_Feature_Lucky+Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Considerations===&lt;br /&gt;
&lt;br /&gt;
In this case, we need to look at what it would be like for a class to replace only one of the class features at that level.&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|SET|value()-Default_Feature_Good+Default_Feature_Better|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or alternatively:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|ADD|Default_Feature_Better|PRIORITY=400&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Features|REMOVE|Default_Feature_Good|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Considerations:&lt;br /&gt;
# We have avoided adding an empty shell to the PC&lt;br /&gt;
# We are making (risky?) assumptions of what we are replacing&lt;br /&gt;
# We start to get into order of operations problems between features that touch different features (think of this more broadly in terms of Archetypes that can impact different items at the same level both being usable together), so it increases the cross-data interaction&lt;br /&gt;
&lt;br /&gt;
In general, I think this is a bad idea due to the built-in assumptions.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4279</id>
		<title>Race Racial Trait Swapping</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4279"/>
		<updated>2018-03-09T03:19:25Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Filler Object */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Race is granted 'default' traits as a standard. Paizo has introduced two systems of concern:&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race is granted specific non-default traits&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race if granted a choice between two or more additional choices&lt;br /&gt;
# Racial Trait that is chosen by the player actually removes 2 or more existing default traits&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #1=&lt;br /&gt;
&lt;br /&gt;
This seems straight-forward to me.  The Race Package can simply have:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|DifferentFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable assignments are very similar to what is shown in [[Replacing Archetype Controls]].&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #2=&lt;br /&gt;
&lt;br /&gt;
This involves a choice, thus interacts with [[SELECTION - A CHOOSE Replacement]].  This section is deferred until some changes and clarifications are made on that page with respect to how instances will work (there are multiple methods of causing instances and that is not currently clear).&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #3=&lt;br /&gt;
&lt;br /&gt;
I'm not sure there are multiple possible solutions here.  I think this is straightforward.  &lt;br /&gt;
&lt;br /&gt;
==Filler Object==&lt;br /&gt;
&lt;br /&gt;
Let's assume we have a Racial Trait &amp;quot;Super&amp;quot; that replaces &amp;quot;Good&amp;quot; and &amp;quot;Lucky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This presumes we have done:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYNAMICSCOPE:RACEFEATURE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Lucky&lt;br /&gt;
LOCAL:RACE|RACEFEATURE=Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Feature_Lucky|SET|Default_Feature_Lucky&lt;br /&gt;
MODIFY:Feature_Good|SET|Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we need to remove Default_L3_Feature_Lucky.  I would probably recommend something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Lucky|SET|EmptyFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EmptyFeature would then be an object with nothing in it.&lt;br /&gt;
&lt;br /&gt;
===Justification===&lt;br /&gt;
&lt;br /&gt;
Keep in mind if we have a DYNAMIC of RACEFEATURE (which Default_Feature_Lucky is one implementation) then we need a default value for that object type.  So it's already likely that we have an &amp;quot;EmptyFeature&amp;quot; set up to be the default value for a variable of the RACEFEATURE FORMAT.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
One possible alternative would be to have an ARRAY[CLASSFEATURE] that contains all of the traits for a given level.&lt;br /&gt;
&lt;br /&gt;
So on our class we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Level_3_Features|ADD|Default_L3_Feature_Lucky+Default_L3_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Considerations===&lt;br /&gt;
&lt;br /&gt;
In this case, we need to look at what it would be like for a class to replace only one of the class features at that level.&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|value()-Default_L3_Feature_Good+Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or alternatively:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|ADD|Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|REMOVE|Default_L3_Feature_Good|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Considerations:&lt;br /&gt;
# We have avoided adding an empty shell to the PC&lt;br /&gt;
# We are making (risky?) assumptions of what we are replacing&lt;br /&gt;
# We start to get into order of operations problems between Archetypes that both touch the same level, but different parts, so it increases the cross-data interaction&lt;br /&gt;
&lt;br /&gt;
In general, I think this is a bad idea due to the built-in assumptions.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4278</id>
		<title>Race Racial Trait Swapping</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4278"/>
		<updated>2018-03-09T03:18:16Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Filler Object */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Race is granted 'default' traits as a standard. Paizo has introduced two systems of concern:&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race is granted specific non-default traits&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race if granted a choice between two or more additional choices&lt;br /&gt;
# Racial Trait that is chosen by the player actually removes 2 or more existing default traits&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #1=&lt;br /&gt;
&lt;br /&gt;
This seems straight-forward to me.  The Race Package can simply have:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|DifferentFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable assignments are very similar to what is shown in [[Replacing Archetype Controls]].&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #2=&lt;br /&gt;
&lt;br /&gt;
This involves a choice, thus interacts with [[SELECTION - A CHOOSE Replacement]].  This section is deferred until some changes and clarifications are made on that page with respect to how instances will work (there are multiple methods of causing instances and that is not currently clear).&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #3=&lt;br /&gt;
&lt;br /&gt;
I'm not sure there are multiple possible solutions here.  I think this is straightforward.  &lt;br /&gt;
&lt;br /&gt;
==Filler Object==&lt;br /&gt;
&lt;br /&gt;
Let's assume we have a Racial Trait &amp;quot;Super&amp;quot; that replaces &amp;quot;Good&amp;quot; and &amp;quot;Lucky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
So on our race we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Feature_Lucky|SET|Default_Feature_Lucky&lt;br /&gt;
MODIFY:Feature_Good|SET|Default_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we need to remove Default_L3_Feature_Lucky.  I would probably recommend something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Lucky|SET|EmptyFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EmptyFeature would then be an object with nothing in it.&lt;br /&gt;
&lt;br /&gt;
===Justification===&lt;br /&gt;
&lt;br /&gt;
Keep in mind if we have a DYNAMIC of RACEFEATURE (which Default_Feature_Lucky is one implementation) then we need a default value for that object type.  So it's already likely that we have an &amp;quot;EmptyFeature&amp;quot; set up to be the default value for a variable of the RACEFEATURE FORMAT.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
One possible alternative would be to have an ARRAY[CLASSFEATURE] that contains all of the traits for a given level.&lt;br /&gt;
&lt;br /&gt;
So on our class we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Level_3_Features|ADD|Default_L3_Feature_Lucky+Default_L3_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Considerations===&lt;br /&gt;
&lt;br /&gt;
In this case, we need to look at what it would be like for a class to replace only one of the class features at that level.&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|value()-Default_L3_Feature_Good+Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or alternatively:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|ADD|Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|REMOVE|Default_L3_Feature_Good|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Considerations:&lt;br /&gt;
# We have avoided adding an empty shell to the PC&lt;br /&gt;
# We are making (risky?) assumptions of what we are replacing&lt;br /&gt;
# We start to get into order of operations problems between Archetypes that both touch the same level, but different parts, so it increases the cross-data interaction&lt;br /&gt;
&lt;br /&gt;
In general, I think this is a bad idea due to the built-in assumptions.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4277</id>
		<title>Race Racial Trait Swapping</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Race_Racial_Trait_Swapping&amp;diff=4277"/>
		<updated>2018-03-09T03:15:56Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Race is granted 'default' traits as a standard. Paizo has introduced two systems of concern:&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race is granted specific non-default traits&lt;br /&gt;
# &amp;quot;Race Package&amp;quot; where a race if granted a choice between two or more additional choices&lt;br /&gt;
# Racial Trait that is chosen by the player actually removes 2 or more existing default traits&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #1=&lt;br /&gt;
&lt;br /&gt;
This seems straight-forward to me.  The Race Package can simply have:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:RACE|Elf|Feature_Good|SET|DifferentFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable assignments are very similar to what is shown in [[Replacing Archetype Controls]].&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #2=&lt;br /&gt;
&lt;br /&gt;
This involves a choice, thus interacts with [[SELECTION - A CHOOSE Replacement]].  This section is deferred until some changes and clarifications are made on that page with respect to how instances will work (there are multiple methods of causing instances and that is not currently clear).&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions Challenge #3=&lt;br /&gt;
&lt;br /&gt;
I'm not sure there are multiple possible solutions here.  I think this is straightforward.  &lt;br /&gt;
&lt;br /&gt;
==Filler Object==&lt;br /&gt;
&lt;br /&gt;
Let's assume we have a Racial Trait &amp;quot;Super&amp;quot; that replaces &amp;quot;Good&amp;quot; and &amp;quot;Lucky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
So on our class we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Level_3_Feature_Lucky|SET|Default_L3_Feature_Lucky&lt;br /&gt;
MODIFY:Level_3_Feature_Good|SET|Default_L3_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Feature_Good|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we need to remove Default_L3_Feature_Lucky.  I would probably recommend something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Feature_Lucky|SET|EmptyFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EmptyFeature would then be an object with nothing in it.&lt;br /&gt;
&lt;br /&gt;
===Justification===&lt;br /&gt;
&lt;br /&gt;
Keep in mind if we have a DYNAMIC of CLASSFEATURE (which Default_L3_Feature_Lucky is one implementation) then we need a default value for that object type.  So it's already likely that we have an &amp;quot;EmptyFeature&amp;quot; set up to be the default value for a variable of the CLASSFEATURE FORMAT.&lt;br /&gt;
&lt;br /&gt;
==Array==&lt;br /&gt;
&lt;br /&gt;
One possible alternative would be to have an ARRAY[CLASSFEATURE] that contains all of the traits for a given level.&lt;br /&gt;
&lt;br /&gt;
So on our class we had:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFY:Level_3_Features|ADD|Default_L3_Feature_Lucky+Default_L3_Feature_Good&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|SuperFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Considerations===&lt;br /&gt;
&lt;br /&gt;
In this case, we need to look at what it would be like for a class to replace only one of the class features at that level.&lt;br /&gt;
&lt;br /&gt;
On our Trait we can do:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|SET|value()-Default_L3_Feature_Good+Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or alternatively:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|ADD|Default_L3_Feature_Better|PRIORITY=400&lt;br /&gt;
MODIFYOTHER:CLASS|Fighter|Level_3_Features|REMOVE|Default_L3_Feature_Good|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Considerations:&lt;br /&gt;
# We have avoided adding an empty shell to the PC&lt;br /&gt;
# We are making (risky?) assumptions of what we are replacing&lt;br /&gt;
# We start to get into order of operations problems between Archetypes that both touch the same level, but different parts, so it increases the cross-data interaction&lt;br /&gt;
&lt;br /&gt;
In general, I think this is a bad idea due to the built-in assumptions.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Archetype_Swapping_Concerns&amp;diff=4276</id>
		<title>Archetype Swapping Concerns</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Archetype_Swapping_Concerns&amp;diff=4276"/>
		<updated>2018-03-09T02:54:28Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Background=&lt;br /&gt;
&lt;br /&gt;
Note that the basics for [[Replacing Archetype Controls]] is available&lt;br /&gt;
&lt;br /&gt;
=Challenge=&lt;br /&gt;
&lt;br /&gt;
Class Archetypes: in some instances a Class Feature is not replaced, but a portion of the feature is negated in order to gain another new feature.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Rogue gains Sneak Attack (Class Feature), which has level dependent gains.&lt;br /&gt;
&lt;br /&gt;
Every odd level, the rogue gains an additional +1d6 to the Sneak Attack Damage.&lt;br /&gt;
&lt;br /&gt;
Broken down:&lt;br /&gt;
   1 = 1d6&lt;br /&gt;
   3 = 2d6&lt;br /&gt;
   5 = 3d6&lt;br /&gt;
&lt;br /&gt;
However, we encounter this:&lt;br /&gt;
   1 = 1d6&lt;br /&gt;
   3 = New Class Feature&lt;br /&gt;
   5 = 2d6&lt;br /&gt;
&lt;br /&gt;
===This section is not well understood how it relates to the example===&lt;br /&gt;
&lt;br /&gt;
We need to manage several things:&lt;br /&gt;
# When a new bonus is applied (We cannot remove/negate a bonus until the correct level is reached)&lt;br /&gt;
# We cannot grant new features until the minimum level has been reached&lt;br /&gt;
# And in odd cases, when features are granted, there can be level dependent bonuses on those as well...&lt;br /&gt;
&lt;br /&gt;
=Principles &amp;amp; Discussion=&lt;br /&gt;
&lt;br /&gt;
I've articulated a number of different principles that will come into play here.  These include, but are not limited to:&lt;br /&gt;
# Be direct.  Don't set a variable to go do something somewhere else, rather, directly set the variable needed&lt;br /&gt;
# Keep things as aligned as possible to how the rule construct actually works.  &lt;br /&gt;
&lt;br /&gt;
This example is useful, because it clarifies what I mean by &amp;quot;direct&amp;quot;, in that it is still the owning object making the modification, but that being super-literal about being direct being the actual *result* can have bad implications.&lt;br /&gt;
&lt;br /&gt;
As a note, in the Example provided above, we should go back to how the rule is actually designed.&lt;br /&gt;
&lt;br /&gt;
I believe in this case it's something like &amp;quot;At level 1, you are granted 1d6 Sneak Attack Damage&amp;quot;.  At Level 3 it's &amp;quot;An additional 1d6&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
There are 2 possible interpretations of what to do at level 3:&lt;br /&gt;
* Think in Set Dice: Set the total directly to 2d6&lt;br /&gt;
* Add a Die: Add 1 additional die to the running total&lt;br /&gt;
&lt;br /&gt;
Unfortunately, I'm not sure I understand all of the listed things that need to be managed (since I'm not sure they are all handled in the example, and generalizations about things I don't understand are dangerous... :) )... so it's probable that other examples need to be provided so that additional implementations can be provided.&lt;br /&gt;
&lt;br /&gt;
=Potential Solutions=&lt;br /&gt;
&lt;br /&gt;
Note: This presumes you are familiar with how items would be replaced, since it will work in a similar fashion to other Archetype replacements.  This is only dealing with the incremental dice and how it would be managed to have a &amp;quot;middle one&amp;quot; replaced.&lt;br /&gt;
&lt;br /&gt;
==Thinking in Set Dice==&lt;br /&gt;
&lt;br /&gt;
One solution is to think fully in set values of dice:&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:CLASS|DICE=SneakAttack&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On some class feature:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DoAtLevel3 &amp;lt;&amp;gt; MODIFY:SneakAttack|SET|2d6|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I think this has a critical flaw:&lt;br /&gt;
# If there needs to be an interrupt (as in the example above), then this will fail (or there will need to be some variable passing around what did or didn't happen earlier).  In general, while this is &amp;quot;brute force&amp;quot; correct, it fails to have any flexibility and thus can't meet the requirements.&lt;br /&gt;
&lt;br /&gt;
I happen to think this also fails to follow the principle summarized as &amp;quot;do directly what the book says&amp;quot;.  While direct, this is direct to the *result*, not to the *operation specified by the book* (the operation being add 1d6)&lt;br /&gt;
&lt;br /&gt;
==Adding a Die==&lt;br /&gt;
&lt;br /&gt;
One solution is to think in modifying dice:&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:CLASS|DICE=SneakAttack&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DoAtLevel3 &amp;lt;&amp;gt; MODIFY:SneakAttack|ADDDIE|1|PRIORITY=300&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some considerations:&lt;br /&gt;
# This solves the issue in the first example, in that missing a class feature at a given level will not cause the total to be incorrect.&lt;br /&gt;
# This is flexible to different sizes of dice, so if for some reason there is a method of increasing the die size of Sneak Attack, then this will still succeed.&lt;br /&gt;
&lt;br /&gt;
=Other Commentary=&lt;br /&gt;
&lt;br /&gt;
==Why doesn't Dice support ADD?==&lt;br /&gt;
&lt;br /&gt;
Based on the literal rules of adding 1d6, you might ask why you can't do this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DoAtLevel3 &amp;lt;&amp;gt; MODIFY:SneakAttack|ADD|1d6|PRIORITY=300&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ADD was supported for DICE, this would solve the issue in the first example, in that missing a class feature at a given level will not cause the total to be incorrect.&lt;br /&gt;
&lt;br /&gt;
However, this introduces a major problem.&lt;br /&gt;
&lt;br /&gt;
Remember that the DICE format is equal to:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
XdY+Z&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we allow ADD, we end up with a problem.  What if we SET it to 1d8 and then try to add 1d6?  We now have two different values for Y, so it can't be processed with the format DICE.&lt;br /&gt;
&lt;br /&gt;
===So wait, what about my sword damage?!?===&lt;br /&gt;
&lt;br /&gt;
I need 1d8+1d6(fire).  How do I get that?&lt;br /&gt;
&lt;br /&gt;
The answer is the damage on a sword will be FORMAT of ARRAY[DICE].&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=6.08_Documentation&amp;diff=4269</id>
		<title>6.08 Documentation</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=6.08_Documentation&amp;diff=4269"/>
		<updated>2018-03-08T18:26:54Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* New Documentation Repository for 6.08 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New Documentation Repository for 6.08==&lt;br /&gt;
&lt;br /&gt;
[[Setting up the new Formula System]] - How to set up and use variables (MODIFY, MODIFYOTHER, DYMAMIC, GRANT, FUNCTION, VALUE)&lt;br /&gt;
&lt;br /&gt;
[[Lookup &amp;amp; TABLE 6.08]] - Lookup is used with Table&lt;br /&gt;
&lt;br /&gt;
[[INFO &amp;amp; INFOVARS 6.08]] - Dynamic Text Display (Replaces DESC, BENEFIT, ASPECT, QUALITY, SPROP)&lt;br /&gt;
&lt;br /&gt;
[[DICE in Formula 6.08]] - New System for handling Dice Formats&lt;br /&gt;
&lt;br /&gt;
[[CODE CONTROLS]] - Disable specific tags and replaces it with a FORMULA Version (For output sheets integration)&lt;br /&gt;
&lt;br /&gt;
[[Replacing Archetype Controls]] - Some initial thoughts on how to use the formula system to make Archetypes easier&lt;br /&gt;
&lt;br /&gt;
[[OUTPUT for 6.08]] - Formats for output into Freemarker&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Replacing_Archetype_Controls&amp;diff=4268</id>
		<title>Replacing Archetype Controls</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Replacing_Archetype_Controls&amp;diff=4268"/>
		<updated>2018-03-08T18:26:51Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot;{| align=&amp;quot;right&amp;quot;   | __TOC__   |}   =Current State=  Archetype prerequisites are fairly complex.  Currently, there are a tremendous number of FACTS (literally thousands) used...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Current State=&lt;br /&gt;
&lt;br /&gt;
Archetype prerequisites are fairly complex.  Currently, there are a tremendous number of FACTS (literally thousands) used to control what Archetype can be taken.  More items are then used to determine how to apply each item.  Much of this depends on the Default object and trailing PRExxx.  Following the logic is ... difficult, and the performance is probably not great, due to lots and lots of trailing PRExxx.&lt;br /&gt;
&lt;br /&gt;
=Using the new formula system=&lt;br /&gt;
&lt;br /&gt;
==Limiting Selection==&lt;br /&gt;
&lt;br /&gt;
First of all, we define a new type of object called LOCK:&lt;br /&gt;
&lt;br /&gt;
In a DATACONTROL file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYNAMICSCOPE:LOCK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We then define each type of lock:&lt;br /&gt;
&lt;br /&gt;
In a DYNAMIC File:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCK:Fighter_3_SomethingOrOther&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we want a place to store all the locks we have encountered on the PC:&lt;br /&gt;
&lt;br /&gt;
In a VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
GLOBAL:ARRAY[LOCK]=AllLocks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we recognize that we want 2 things to happen:&lt;br /&gt;
# If an Archetype needs a Lock that someone else already has it should not be allowed&lt;br /&gt;
# An Archetype should grant all of the locks it needs (to &amp;quot;claim&amp;quot; them)&lt;br /&gt;
&lt;br /&gt;
Note: At this point, we need to suspend disbelief for a moment, since it's not quite defined if Archetypes will be Ability objects or if they are better served as something else.  For the rest of this explanation, it assumes there is a type called ARCHETYPE to avoid too much complexity in the example.&lt;br /&gt;
&lt;br /&gt;
There are 2 things that need the locks, and in software development, it tends to be useful to type things once and use them in two places, to avoid things becoming inconsistent.  In this case, we can use a FACTSET to do that:&lt;br /&gt;
&lt;br /&gt;
We define the FACTSET:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
FACTSETDEF:ARCHETYPE|Locks &amp;lt;&amp;gt; DATAFORMAT:LOCK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we put the locks in a FACTSET on the Archetype:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MyArchetype &amp;lt;&amp;gt; FACTSET:Locks|Fighter_3_SomethingOrOther&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to use that FACTSET.  To avoid allowing the Archetype to be used if any of its Locks are already claimed we use this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALLOW:isEmpty(overlap(AllLocks,getFactSet(&amp;quot;ARCHETYPE&amp;quot;, this(), &amp;quot;Locks&amp;quot;)))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is very much new relative to other formulas so let's explain this in a bit of detail.&lt;br /&gt;
&lt;br /&gt;
This uses the &amp;quot;this()&amp;quot; function.  We could have hardcoded the FACTSET to look up the Archetype itself, e.g.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
getFactSet(&amp;quot;ARCHETYPE&amp;quot;, &amp;quot;MyArchetype&amp;quot;, &amp;quot;Locks&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
...however that encounters a problem if we .COPY MyArchetype... so we don't want that hardcoding.  We use the this() function to allow the reference to automatically update to the object on which the item is applied.&lt;br /&gt;
&lt;br /&gt;
Second, it performs the function overlap:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
overlap(X,Y)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This hasn't been seen in previous examples.&lt;br /&gt;
&lt;br /&gt;
This will take two arrays and return a subset of items that are in both arrays.&lt;br /&gt;
&lt;br /&gt;
So AllLocks is ARRAY[LOCK], and the getFactSet call will also return an ARRAY[LOCK].  Any LOCK in both arrays (which indicates a conflict which should prohibit application of the Archetype) will be in the returned array.&lt;br /&gt;
&lt;br /&gt;
We then ensure that array is empty:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
isEmpty(...)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If it's empty, taking the Archetype is allowed.&lt;br /&gt;
&lt;br /&gt;
Lastly, we need to have the Archetype grant its locks.  We can do this without having a token on each Archetype by using the Global Modifier file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MODIFYOTHER:ARCHETYPE|ALL|AllLocks|ADD|getFactSet(target(),&amp;quot;Locks&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This uses the &amp;quot;target()&amp;quot; function.  We want to avoid placing this MODIFYOTHER on every Archetype - ANNOYING.  We want to do that once, so we put it in the Global Modifier file and it will apply to all Archetypes.  Note just like the logic on &amp;quot;this()&amp;quot; earlier, we have a function called &amp;quot;target()&amp;quot; (which is where the MODIFYOTHER is applied) which is generic enough that we can write this token ONCE and have it apply to every Archetype.&lt;br /&gt;
&lt;br /&gt;
So here is what we have:&lt;br /&gt;
# We've reduced each Archetype to having only two tokens to work on overlap (the FACTSET and the APPLY limitation)&lt;br /&gt;
# We have used a separate object type LOCK in order to have the FACTSET be typo-safe.  &lt;br /&gt;
## Meaning it's not just general String in the FACTSET, so you have to consciously put the FACT in one file and then use it in other LST files&lt;br /&gt;
&lt;br /&gt;
==Overriding the Feature==&lt;br /&gt;
&lt;br /&gt;
Now each Archetype needs to override a class feature.  To do that, we simply want to treat each class feature as a variable, so it can be easily overridden using the MODIFY* system:&lt;br /&gt;
&lt;br /&gt;
In VARIABLE file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LOCAL:CLASS|ARCHETYPE=Level_3_Feature&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In CLASS LST file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CLASS:Fighter &amp;lt;&amp;gt; MODIFY:Level_3_Feature|SET|Default_L3_Feature_Fighter&lt;br /&gt;
CLASS:Fighter &amp;lt;&amp;gt; GRANTVAR:Level_3_Feature&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this puts an Archetype into a Variable and then &amp;quot;grants&amp;quot; the contents of that variable to the PC.  If we want to change what is granted, we simply need to change the contents of that variable:&lt;br /&gt;
&lt;br /&gt;
In ARCHETYPE LST file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MyArchetype &amp;lt;&amp;gt; MODIFYOTHER:CLASS|Fighter|Level_3_Feature|SET|SomeCustomFeature|PRIORITY=400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note a few advantages here as well:&lt;br /&gt;
# This is all DIRECTLY in the objects either owning (CLASS) or modifying (ARCHETYPE) the situation.  No setting variables to go trigger a PRExxx that is somewhere over on a Default object.  If you can't write something directly in the new system, SPEAK UP. The goal is for it to be very straightforward.&lt;br /&gt;
# This is now all in &amp;quot;forward logic&amp;quot; - there are no trailing PRExxx here that can &amp;quot;turn things on or off&amp;quot; (and have a performance impact because they have to constantly be tested).  Either the base feature is present, or it's overridden - reconsideration is only necessary at the moment a new Archetype is applied, and then we &amp;quot;know&amp;quot; with certainty whether the base or custom feature is present.&lt;br /&gt;
&lt;br /&gt;
==Gaps as of March 8 2018==&lt;br /&gt;
&lt;br /&gt;
In short, this is close to being doable, but not doable with the current master branch.  It is hoped that this is doable by the time we reach 6.8.  What specifically is needed:&lt;br /&gt;
# Currently isEmpty(X) is implemented but has not yet been merged with the master branch.  It is currently flowing through from the Formula library, and should be merged well before the 6.8 release.&lt;br /&gt;
# Currently GRANTVAR exists in a local branch, but has not yet been submitted for a PR due to complexity and lots of other competing PRs.&lt;br /&gt;
# Currently this() and target() are in a pending PR that has received comments and is not yet merged.&lt;br /&gt;
# Currently overlap(X,Y) is not implemented.  It is fairly trivial, but will be done in the formula system and take a library update integration to occur.  It should occur by the 6.8 release.&lt;br /&gt;
# We need to have a discussion over what ARCHETYPE is (and whether it must be an Ability).  GRANTVAR and Abilities are likely to not get along well (due to Category/Nature/etc).  So we need to decide if these HAVE to be Ability objects&lt;br /&gt;
## If so, we will need GRANTVAR to support Abilities, or some other alternative&lt;br /&gt;
### This may require COMPOUND objects to be merged into the master branch (a local branch, not submitted for a PR yet)&lt;br /&gt;
## If not, we need to understand what features are required, since it will likely be a DYNAMIC&lt;br /&gt;
### This will require Interface Tokens to be merged into the master branch (a local branch, not submitted for a PR yet), so that DYNAMIC objects can contain MODIFY* tokens.&lt;br /&gt;
### This may also require additional features to be implemented on DYNAMIC objects&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Tags_and_Tokens&amp;diff=4267</id>
		<title>Tags and Tokens</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Tags_and_Tokens&amp;diff=4267"/>
		<updated>2018-03-05T02:26:49Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Data that defines the rule constructs of a Class, Race, Language, and other characteristics and attributes of a PlayerCharacter are stored in LST files. These LST files are parsed to import the information from those LST files into objects within the PCGen program. &lt;br /&gt;
&lt;br /&gt;
For purposes of the architecture descriptions here on the Wiki, the individual entries in the data persistence files will be referred to as &amp;quot;Tags&amp;quot;. To store information, these tags separate the &amp;quot;key&amp;quot; (used to indicate the tag name) and the &amp;quot;value&amp;quot; (the information the tag is conveying to PCGen) by a colon.  A simple example can be taken from the Common Language in the Language LST file from SRD 3.0:&lt;br /&gt;
 TYPE:Spoken&lt;br /&gt;
This indicates the &amp;quot;TYPE&amp;quot; tag is indicating a value of &amp;quot;Spoken&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For purposes of this document, the code that parses the value of a tag and translates the tag syntax into the internal data structure of PCGen is called a Token.&lt;br /&gt;
&lt;br /&gt;
Occasionally, you fill find these the terms &amp;quot;tag&amp;quot; and &amp;quot;token&amp;quot; used differently; which name is used will likely depend on the perspective of the speaker. The Wiki makes effort to use the terms Tag and Token in the context they are defined in this section.  This is a decision for clarity, and is not a judgement of the &amp;quot;best&amp;quot; method for referring to the items in the data persistence format or the code.&lt;br /&gt;
&lt;br /&gt;
Types of tokens (meaning the Interfaces that describe the behavior for each type of token) are located in &amp;lt;i&amp;gt;pcgen.rules.persistence.token&amp;lt;/i&amp;gt;.  &lt;br /&gt;
&lt;br /&gt;
Tokens that implement these interfaces, which are effectively extensions to the [[Rules Persistence System]], are found in the &amp;lt;i&amp;gt;plugin.lsttokens&amp;lt;/i&amp;gt; package.&lt;br /&gt;
&lt;br /&gt;
==Types of Tokens==&lt;br /&gt;
&lt;br /&gt;
===CDOMToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; is a PCGen 5.16 token that has a &amp;lt;i&amp;gt;parse()&amp;lt;/i&amp;gt; method for processing the value of a tag and a &amp;lt;i&amp;gt;getTokenName()&amp;lt;/i&amp;gt; method  to identify the name of the tag the Token can process.  Note that a &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; does not require &amp;lt;i&amp;gt;unparse()&amp;lt;/i&amp;gt;, as compatibility tokens from previous revisions would not implement that behavior. &lt;br /&gt;
&lt;br /&gt;
===CDOMPrimaryToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMPrimaryToken&amp;lt;/i&amp;gt; is a &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; that is active (not deprecated) in the current version of PCGen, and thus implements the &amp;lt;i&amp;gt;unparse()&amp;lt;/i&amp;gt; method. &lt;br /&gt;
&lt;br /&gt;
===CDOMSubToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMSubToken&amp;lt;/i&amp;gt; is a &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; that is designed to operate for [[Rules_Persistence_System#Subtokens|Subtokens]]&lt;br /&gt;
&lt;br /&gt;
===CDOMSecondaryToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMSecondaryToken&amp;lt;/i&amp;gt; is a &amp;lt;i&amp;gt;CDOMSubToken&amp;lt;/i&amp;gt; that is active (not deprecated) in the current version of PCGen, and thus implements the &amp;lt;i&amp;gt;unparse()&amp;lt;/i&amp;gt; method. &lt;br /&gt;
&lt;br /&gt;
===CDOMCompatibilityToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMCompatibilityToken&amp;lt;/i&amp;gt; is a &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; that implements a tag syntax from a previous version of PCGen, see [[Rules_Persistence_System#Token Compatibility|Token Compatibility]]. Once deprecated, a &amp;lt;i&amp;gt;CDOMPrimaryToken&amp;lt;/i&amp;gt; would become a &amp;lt;i&amp;gt;CDOMCompatibilityToken&amp;lt;/i&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
===CDOMCompatibilitySubToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;CDOMCompatibilitySubToken&amp;lt;/i&amp;gt; is a CDOMSubToken that implements a tag syntax from a previous version of PCGen, see [[Rules_Persistence_System#Token Compatibility|Token Compatibility]]. Once deprecated, a &amp;lt;i&amp;gt;CDOMSecondaryToken&amp;lt;/i&amp;gt; would become a &amp;lt;i&amp;gt;CDOMCompatibilitySubToken&amp;lt;/i&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
===ClassWrappedToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;ClassWrappedToken&amp;lt;/i&amp;gt; is a specialized &amp;lt;i&amp;gt;CDOMToken&amp;lt;/i&amp;gt; designed to provide compatibility for using CLASS tokens on the level 1 CLASSLEVEL line, see [[Rules_Persistence_System#Class Wrapped Token|Weaknesses of Class Wrapped Tokens]].&lt;br /&gt;
&lt;br /&gt;
===PreCompatibilityToken===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;i&amp;gt;PreCompatibilityToken&amp;lt;/i&amp;gt; is a token for wrapping the PCGen 5.14-type Prerequisite tokens into 5.16-type tokens, see [[Rules_Persistence_System#Prerequisite Tags|Weaknesses of Prerequisite Tokens]]. &lt;br /&gt;
&lt;br /&gt;
===DeferredToken===&lt;br /&gt;
&lt;br /&gt;
===PostValidationToken===&lt;br /&gt;
&lt;br /&gt;
===PostDeferredToken===&lt;br /&gt;
&lt;br /&gt;
===PrimitiveToken===&lt;br /&gt;
&lt;br /&gt;
===QualifierToken===&lt;br /&gt;
&lt;br /&gt;
==Note about Token Behavior==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A Note of Caution on Tags/Tokens: Different tags have different behavior with respect to overwriting or appending values.  Some tags may only allow a single value (e.g. RACETYPE from Race LST files), and subsequent references to that tag in the same object will overwrite the original value. Other tags are effectively lists (e.g. the Global TYPE tag), and subsequent calls to that tag will append values to the list.  The behavior is noted within the tag documentation distributed with PCGen.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Formula_Systems&amp;diff=4266</id>
		<title>Formula Systems</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Formula_Systems&amp;diff=4266"/>
		<updated>2018-03-05T02:25:30Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* New Capabilities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=JEP Formula System=&lt;br /&gt;
&lt;br /&gt;
==What it is==&lt;br /&gt;
&lt;br /&gt;
The formula system is embedded within the &amp;quot;core&amp;quot; of PCGen to do mathematical calculations.  It is used internally as well as exposed in a limited fashion to the data developers through tokens.  Specifically, both data defined variables and BONUS values depend on the formula calculations performed by this subsystem.&lt;br /&gt;
&lt;br /&gt;
==Licensing==&lt;br /&gt;
&lt;br /&gt;
The licensing for JEP changed and we have targeted it for replacement.  When we originally integrated JEP, it was licensed under a dual commercial/GPL license.  We received (and still operate under) a special exception to use JEP with our code.  This has the side effect of limiting the use of our code outside of our distribution.  Subsequent to our initial use of JEP, the GPL option was dropped, and JEP is now a commercial product.  This means we no longer have updates available to us, and we are using a stagnant library.&lt;br /&gt;
&lt;br /&gt;
==Performance==&lt;br /&gt;
&lt;br /&gt;
We want to improve the performance of formula calculation.  Today, each time a formula is processed, we re-parse the formula (which redoes all of the validation and other checks).  This is CPU intensive for complex formulas, and should be something we can cache and re-use.  We therefore want a system where we can parse the formula early in the process and store the parsed formula, using that &amp;quot;binary&amp;quot; version for evaluation.&lt;br /&gt;
&lt;br /&gt;
We want to improve performance around BONUSes.  The major performance bottleneck we now have is around the loop of &amp;quot;Variables can be modified by BONUSes, which can be conditional upon Prerequisites, which can use variables&amp;quot;.  This loop is currently &amp;quot;lookback&amp;quot; in that things are calculated as necessary and a large resolution loop is required to ensure the system reaches stability. We want to shortcut this when possible to reduce looping and overall calculation of values that do not change.&lt;br /&gt;
&lt;br /&gt;
==Current Status==&lt;br /&gt;
&lt;br /&gt;
We are working to remove JEP from PCGen.  This is a result of&lt;br /&gt;
# JEP is now a closed source library, so we cannot continue to benefit from future releases/bug fixes&lt;br /&gt;
# JEP is a license exception in our code, which restricts our license flexibility&lt;br /&gt;
# JEP has more features than we need (some of which get in our way)&lt;br /&gt;
&lt;br /&gt;
A new set of code (imported as the PCGen-Formula library, stored in a separate GitHub project called PCGen-Formula) is the replacement.  It addressed many of the requirements we are working to get, including local variables and validation at LST load (rather than runtime).  By also maintaining an awareness of direct dependencies, it can perform a dramatically smaller number of calculations when any value is changed.&lt;br /&gt;
&lt;br /&gt;
==Format==&lt;br /&gt;
&lt;br /&gt;
The Format of a variable is the java &amp;quot;Class&amp;quot; it contains.  In JEP, all variables are numbers.&lt;br /&gt;
&lt;br /&gt;
==Parsing==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system:&lt;br /&gt;
* Formulas have functions (delimited by parenthesis)&lt;br /&gt;
* Formulas have both built-in terms as well as user defined variables (DEFINE: token)&lt;br /&gt;
* All user defined variables are global in scope&lt;br /&gt;
* All user defined variables are provided a starting value on definition&lt;br /&gt;
* User defined variables are assumed to be zero if no DEFINE is ever encountered&lt;br /&gt;
* User defined variables may be defined in more than one location&lt;br /&gt;
* Some terms may be local in scope (e.g. spells have unique terms), but these are fragile and not thread safe.&lt;br /&gt;
* Diagnostic tools in the UI allow presentation of the current value of a variable (or really any formula)&lt;br /&gt;
* Formulas are NOT parsed for significant levels of validity at data load.  They are given basic checks (to ensure parenthesis match, for example), but a full validity check is not possible.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
Currently, the use of JEP requires a multi-pass resolution.  The formula is parsed, then it is processed/queried in order to determine any variables or terms it contains, and then those values are loaded into the formula and the formula is resolved.  (see VariableProcessor.processJepFormula() )&lt;br /&gt;
&lt;br /&gt;
This (JEP) method of resolution comes with some challenges and risks.&lt;br /&gt;
&lt;br /&gt;
The parsed version of a JEP formula (a PJEP) ends up with a lot of complexity.  It is a controller of sorts, rather than just a framework for a formula. &lt;br /&gt;
&lt;br /&gt;
Also, the parsed version of a JEP formula has a set of awareness.  The variable/term values are loaded into it, meaning a contract is placed on the programmer to &amp;quot;clean that up&amp;quot; so those values do not pollute other, later calculations.  (This is generally not an issue based on how it is otherwise used, but may not be initially clear to an uninformed reader)&lt;br /&gt;
&lt;br /&gt;
=How we use JEP=&lt;br /&gt;
&lt;br /&gt;
==Term==&lt;br /&gt;
&lt;br /&gt;
For purposes of this document, a term is a &amp;quot;built in&amp;quot; value that can be used in a formula.  These are a subset of the items currently documented in the &amp;quot;Pre-defined Variables&amp;quot; or &amp;quot;System-Defined Variables&amp;quot; section of the docs (depending on how you get to that section)&lt;br /&gt;
&lt;br /&gt;
An example of this include (but are certainly not limited to) BAB, BASECR, CASTERLEVEL, CL, SR, and TL.&lt;br /&gt;
&lt;br /&gt;
Note that some terms can possess context.  For example, CASTERLEVEL is valid only in SPELL objects, as it requires the &amp;quot;context&amp;quot; of the castable spell (which implicitly includes the class level, DC, # of times usable, etc... it is more than the Spell object defined in the LST file)&lt;br /&gt;
&lt;br /&gt;
Some built-in variables look to the user as if they are a function, and are often treated by users as functions even though they are terms.  These include square brackets in the pre-defined variable name.  (e.g. COUNT[SKILLS]).&lt;br /&gt;
&lt;br /&gt;
==Variable==&lt;br /&gt;
&lt;br /&gt;
For purposes of this document, a variable is a data-defined value.  Using today's data, this means it was defined by the DEFINE: token being encountered in the data.  Obviously, due to the nature of formulas and ambiguity, there is limitation on variable names in that they must not conflict with a pre-defined term.&lt;br /&gt;
&lt;br /&gt;
===Global Variable===&lt;br /&gt;
&lt;br /&gt;
Global variables are variables that exist across the entire set of data.  A global variable can be defined in one object and used in another.  This is currently the case for all variables in PCGen, as they are all created with the DEFINE: token.&lt;br /&gt;
&lt;br /&gt;
==Paren Function==&lt;br /&gt;
&lt;br /&gt;
A paren function is a function that uses parenthesis () to contain the arguments to the function.  An example of this is var(&amp;quot;CL=Fighter&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
&amp;quot;var&amp;quot; is the function, &amp;quot;CL=Fighter&amp;quot; is the (one) argument to the function.&lt;br /&gt;
&lt;br /&gt;
Called &amp;quot;paren functions&amp;quot; to avoid confusion with the &amp;quot;terms&amp;quot; that contain brackets.&lt;br /&gt;
&lt;br /&gt;
==Ambiguity over a value==&lt;br /&gt;
&lt;br /&gt;
We want to avoid some situations of ambiguity.  The current system for variables takes a &amp;quot;largest wins&amp;quot; argument when multiple definitions are encountered.  This leads to potential confusion (and potentially debate over whether such an implicit decision should be allowed).  It has also led to the adoption of a &amp;quot;data standard&amp;quot; that all values should be defined at zero and modifications provided as a BONUS:VAR|...  Our redesign looks to eliminate the confusion over multiple conflicting definitions by providing a global definition characteristic and preventing otherwise identical variable definitions from having different starting values.&lt;br /&gt;
&lt;br /&gt;
=The new Formula parser=&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
The new formula parser is a JavaCC (well, technically, JJTree) defined syntax.  It is held separately in the PCGen-Formula library, which is one of our two [[PCGen Libraries]]&lt;br /&gt;
&lt;br /&gt;
==Removed Characteristics==&lt;br /&gt;
&lt;br /&gt;
===Boolean-aware calculation===&lt;br /&gt;
&lt;br /&gt;
Boolean and Numeric values will be calculated in their own domain. It will NOT be assumed that TRUE is 1 and FALSE is 0 as some other formula systems assume.  A Boolean value here will be a Boolean and only usable where a Boolean is legal.&lt;br /&gt;
&lt;br /&gt;
Therefore, the common operations that are Boolean operations such as AND (&amp;amp;&amp;amp;) and OR (||) will only operate on Boolean values.  If a Function requires a Boolean value (such as the first argument to an IF function), then it must validate the semantics of the subformula.&lt;br /&gt;
&lt;br /&gt;
This was based on team feedback as the formula system was originally designed.&lt;br /&gt;
&lt;br /&gt;
==Shared Characteristics==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system that are similar to the existing implementation:&lt;br /&gt;
# Formula Functions are stored as plugins, so that new functions would not necessarily force a full rebuild of PCGen.&lt;br /&gt;
&lt;br /&gt;
==Changed Characteristics==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system that are major modifications of the existing implementation:&lt;br /&gt;
# Formats other than numbers are supported.&lt;br /&gt;
# Starting value for a variable is based on the variable format (e.g. zero for numbers), so multiple defines do not &amp;quot;compete&amp;quot; [new: Define does not have a definition per DEFINE: token, but rather a DEFAULTVARIBLEVALUE once per game mode for a variable format (numbers being one possible variable format).  This is consistent with and thus formalizes the data best practice of defining variables to zero].&lt;br /&gt;
# Terms are eliminated.  They should be replcaed by functions or user variables.&lt;br /&gt;
# BONUS:VAR is eliminated and replaced with Modifiers (see below) [and in general ALL BONUS tokens will eventually disappear].&lt;br /&gt;
# The new system will not have any terms.  All items will be a function or a user defined variable.  This will dramatically simplify dependency analysis.&lt;br /&gt;
# The system does &amp;quot;integer aware&amp;quot; arithmetic, meaning 2+3=5 (not 5.0 or 4.999999999 or 5.000000001 as we might have today).&lt;br /&gt;
&lt;br /&gt;
==New Capabilities==&lt;br /&gt;
Major characteristics of this system that are new capabilities:&lt;br /&gt;
# Diagnostic tools in the UI should provide the ability to expose the entire calculation, from default value through all modifications (and source of those modifications).&lt;br /&gt;
## It is important to recognize that the data practice of indirection (e.g. one object awards a Template called FACE_20 that sets the FACE:) is STRONGLY discouraged in the new system.  That indirection makes it A LOT harder to figure out what modified a variable - something that the new system can make VERY clear, but that the data can hide and make difficult.&lt;br /&gt;
# Formulas are validated at data load to ensure good syntax, and that any functions that are used exist (and are valid) and variables are nominally defined somewhere in the data.&lt;br /&gt;
## There are a few rare excpetions to full validation, because they really occur at runtime... so just like we can't automatically detect that a divide by zero will occur, we can't detect that a Table provided to a lookup() function will actually have the necessary values and columns for the incoming variables.&lt;br /&gt;
# Dependencies are tracked and any circular logic will be identified as such during calculation (it is expected that this is not possible to catch at LST load due to formulas on impossible data combinations leading to false positives).  This is done in the specific Solver.&lt;br /&gt;
# Local Variables (see below)&lt;br /&gt;
&lt;br /&gt;
===Local Variables===&lt;br /&gt;
&lt;br /&gt;
Local Variables are variables that exist in only a portion of the data.  They possess context.  They can only be used within that context.  For example, a local variable defined on a piece of Equipment could only be used within that piece of equipment.  Since Equipment can &amp;quot;own&amp;quot; Equipment Modifiers, EqMods could also modify or evaluate the local variable.  However, an attempt to interpret the value of the local variable in a Spell (for example) should produce an error, since there is no known context of Equipment within a spell.&lt;br /&gt;
&lt;br /&gt;
Given that they have (per-item) context to a specific instance (such as &amp;quot;Longsword +1&amp;quot; and &amp;quot;Shortbow +2&amp;quot;), local variables have independent values on each instance (so MyPlusValue on the Longsword could be 1, and MyPlusValue on the Shortbow could be 2).&lt;br /&gt;
&lt;br /&gt;
Like global variables, local variables are on a per-character basis (so local variables are per-character, per-item).  A Longsword on one character has a value N and a Longsword on a second character has a value M.  N may or may not be equal to M (there is no linkage - it is based on whether the two Longswords have identical EqMods).&lt;br /&gt;
&lt;br /&gt;
==Modifiers==&lt;br /&gt;
&lt;br /&gt;
The MODIFY and MODIFYOTHER tokens replace BONUS:VAR. These provide a significantly enhanced experience from using BONUS, specifically:&lt;br /&gt;
# Specific values calculated by the formula system&lt;br /&gt;
# No implicit stacking rules.  All stacking is explicit by the data owner&lt;br /&gt;
# No implicit replacement rules.  All replacement is explicit by the data owner&lt;br /&gt;
# Dependency will be explicit and calculation will be carefully managed.  (A graph of dependencies between variables is maintained by a SolverManager)&lt;br /&gt;
&lt;br /&gt;
==Single Pass Evaluation==&lt;br /&gt;
&lt;br /&gt;
Unlike JEP where a pass is made to determine the variables and then load those into the object, the new formula system is capable of doing an evaluation in a single pass.&lt;br /&gt;
&lt;br /&gt;
Having a single-pass resolution by a visitor to the tree, with the context passed in as a parameter, has a number of functional advantages:&lt;br /&gt;
* This effectively makes a formula &amp;quot;immutable&amp;quot; in the sense that the context is passed in during resolution and thus can be evaluated in multiple threads without causing issues.  Note this is a necessary consideration if we want to reuse formulas that are in the data multiple times, as the UI demonstrably triggers evaluation of items from multiple threads.  The visitors are also &amp;quot;immutable&amp;quot; (they are in fact, fully stateless), and thus reusable without being concerned about thread safety.&lt;br /&gt;
* This keeps the formula as light-weight as possible (The tree structure is still a bit expensive, but better than a PJEP).&lt;br /&gt;
* The context can be set based on what is passed in, meaning evaluation locality is driven by the caller (knowing the locality) rather than forcing the formula to evaluate some string to figure out where it is.&lt;br /&gt;
* The entire concept of a PJEP pool goes away (in exchange we effectively have a context, but those are reusable so we don't ever have the lock/free necessity of PJEP).  (For specificity, those solving contexts are called &amp;quot;DependencyManager&amp;quot;, &amp;quot;EvaluationManager&amp;quot;, and &amp;quot;FormulaSemantics&amp;quot;, and can currently be found in the PCGen-formula library.&lt;br /&gt;
* We actually prohibit any funky hoop-jumping.  By only providing the context in the sense of a variable library, we can accurately handle things like spell-localized items (e.g. today's CASTERLEVEL term) without having a temporarily set global item.&lt;br /&gt;
&lt;br /&gt;
=Further Reading=&lt;br /&gt;
&lt;br /&gt;
For more detailed information on setting up the new formula system, see [[Setting up the new Formula System]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=PCGen_Libraries&amp;diff=4265</id>
		<title>PCGen Libraries</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=PCGen_Libraries&amp;diff=4265"/>
		<updated>2018-03-05T02:21:25Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot; =On Why they exist=  There are two major reasons the new formlua system was put in a library: # None of it needs to be PCGen-specific, and the separate library forces that mo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=On Why they exist=&lt;br /&gt;
&lt;br /&gt;
There are two major reasons the new formlua system was put in a library:&lt;br /&gt;
# None of it needs to be PCGen-specific, and the separate library forces that more gereric design thinking&lt;br /&gt;
#  Eliminate the complexity of having JJTree/JavaCC within the primary code base.  The jjtree/javacc calls required to build .java files make a more complex build cycle (the challenge being that you have to do a build, then actually select the project and cause it to refresh in order for it to correctly compile the java files to the current version).  The number of times we used to require a form of refresh to the project after a JavaCC compile occurred was confusing a large portion of our population of code/data folks that build their own version of PCGen.  We therefore extracted that complexity out so that only the code team working on the formula system will experience any of that.&lt;br /&gt;
&lt;br /&gt;
Note that this had the effect of breaking a reasonable portion of the pcgen.base.* also into a separate (and different) sub-project since they are shared dependencies of the core and the formula parser.  Since these items are reasonably stable (most have had no more than cosmetic changes in years), it is also a reasonable separation.&lt;br /&gt;
&lt;br /&gt;
=On the Library Contents=&lt;br /&gt;
&lt;br /&gt;
Early PCGen used almost fully reference semantic lists for storing information.  This produced a number of really bad headaches, because folks felt the lists could be modified at any time and the calculations could come out correct.  This was patently false, but it didn't prevent it from happening widely across the code base.&lt;br /&gt;
&lt;br /&gt;
Much of the work in 5.8/5.10/5.12 was a very &amp;quot;hard&amp;quot; change to a value-semantic infrastructure.  This means any list returned by CDOMObject and its descendents is simply a snapshot of the values at that time - the list was copied and ownership of the list was transferred to the caller to do with it whatever they want.&lt;br /&gt;
&lt;br /&gt;
The reason I bring this up is I frequently get comments on the contents of PCGen-base and &amp;quot;you should go use Google Collections&amp;quot; or whatever.  I appreciate the comments, but (a) maintaining these items is not where I'm spending my time (b) it's not where are problems are and (c) the semantics of those classes are almost universally reference semantics, so they are very different to use in an object-oriented system that expects to maintain appropriate behavior and isolation (and difficult to use less experienced developers who don't actually understand semantic differences).&lt;br /&gt;
&lt;br /&gt;
In short, when our system is smaller, and we have the legacy systems removed so that we have a code base in the hundreds of classes (so folks can understand it much easier), then I think that is a viable and valuable discussion to have about the code base.  Until then, I think the semantics of PCGen-base are required.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4264</id>
		<title>Index to Architecture Documents</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4264"/>
		<updated>2018-03-05T02:21:22Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is effectively a &amp;quot;shorthand&amp;quot; list of documents (and a tiny bit of context around the links) for &amp;quot;A Day in the Life of PCGen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
&lt;br /&gt;
Before reading about the details of the PCGen architecture, it is likely helpful to understand our key [[Design Concepts for PCGen]] and [[Architecture Document Conventions]]&lt;br /&gt;
&lt;br /&gt;
=Building=&lt;br /&gt;
&lt;br /&gt;
# You should understand we have [[PCGen Libraries]]&lt;br /&gt;
&lt;br /&gt;
=Loading=&lt;br /&gt;
&lt;br /&gt;
# The [[Startup System]] initializes PCGen and loads the initial user interface&lt;br /&gt;
# Files from Disk are loaded by the [[Rules Persistence System]]&lt;br /&gt;
# These files use [[CDOM References Concept Document|CDOM References]] to resolve order of operations conflicts during load and [[Referring to Groups in LST Data|Refer to Groups in LST Data]] to identify multiple possible objects (for say, a choice)&lt;br /&gt;
# The [[Load Commit Subsystem]] is used to commit information into the [[Rules Data Store]]&lt;br /&gt;
# Post Processing is completed as described in the [[Full Load Order Detail]]&lt;br /&gt;
&lt;br /&gt;
=Using Data=&lt;br /&gt;
&lt;br /&gt;
# When retrieving items from the Rules Data Store, it's important to [[Identifying Objects|Identify the right Object]]&lt;br /&gt;
# You will also need to know about [[Accessing Information]]&lt;br /&gt;
# And strategically, it's good to know how we are [[Becoming Data Driven]]&lt;br /&gt;
&lt;br /&gt;
=Processing a PC=&lt;br /&gt;
&lt;br /&gt;
# After [[Adding items to the PC]], we begin [[Calculating Items on the PC]]&lt;br /&gt;
# This calculation heavily depends on the [[Formula Systems]]&lt;br /&gt;
# Some of the items on a PC can be conditional, so it's valuable to understand [[Prerequisites and Requirements]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Formula_Systems&amp;diff=4263</id>
		<title>Formula Systems</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Formula_Systems&amp;diff=4263"/>
		<updated>2018-03-05T02:21:17Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* The new Formula parser */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=JEP Formula System=&lt;br /&gt;
&lt;br /&gt;
==What it is==&lt;br /&gt;
&lt;br /&gt;
The formula system is embedded within the &amp;quot;core&amp;quot; of PCGen to do mathematical calculations.  It is used internally as well as exposed in a limited fashion to the data developers through tokens.  Specifically, both data defined variables and BONUS values depend on the formula calculations performed by this subsystem.&lt;br /&gt;
&lt;br /&gt;
==Licensing==&lt;br /&gt;
&lt;br /&gt;
The licensing for JEP changed and we have targeted it for replacement.  When we originally integrated JEP, it was licensed under a dual commercial/GPL license.  We received (and still operate under) a special exception to use JEP with our code.  This has the side effect of limiting the use of our code outside of our distribution.  Subsequent to our initial use of JEP, the GPL option was dropped, and JEP is now a commercial product.  This means we no longer have updates available to us, and we are using a stagnant library.&lt;br /&gt;
&lt;br /&gt;
==Performance==&lt;br /&gt;
&lt;br /&gt;
We want to improve the performance of formula calculation.  Today, each time a formula is processed, we re-parse the formula (which redoes all of the validation and other checks).  This is CPU intensive for complex formulas, and should be something we can cache and re-use.  We therefore want a system where we can parse the formula early in the process and store the parsed formula, using that &amp;quot;binary&amp;quot; version for evaluation.&lt;br /&gt;
&lt;br /&gt;
We want to improve performance around BONUSes.  The major performance bottleneck we now have is around the loop of &amp;quot;Variables can be modified by BONUSes, which can be conditional upon Prerequisites, which can use variables&amp;quot;.  This loop is currently &amp;quot;lookback&amp;quot; in that things are calculated as necessary and a large resolution loop is required to ensure the system reaches stability. We want to shortcut this when possible to reduce looping and overall calculation of values that do not change.&lt;br /&gt;
&lt;br /&gt;
==Current Status==&lt;br /&gt;
&lt;br /&gt;
We are working to remove JEP from PCGen.  This is a result of&lt;br /&gt;
# JEP is now a closed source library, so we cannot continue to benefit from future releases/bug fixes&lt;br /&gt;
# JEP is a license exception in our code, which restricts our license flexibility&lt;br /&gt;
# JEP has more features than we need (some of which get in our way)&lt;br /&gt;
&lt;br /&gt;
A new set of code (imported as the PCGen-Formula library, stored in a separate GitHub project called PCGen-Formula) is the replacement.  It addressed many of the requirements we are working to get, including local variables and validation at LST load (rather than runtime).  By also maintaining an awareness of direct dependencies, it can perform a dramatically smaller number of calculations when any value is changed.&lt;br /&gt;
&lt;br /&gt;
==Format==&lt;br /&gt;
&lt;br /&gt;
The Format of a variable is the java &amp;quot;Class&amp;quot; it contains.  In JEP, all variables are numbers.&lt;br /&gt;
&lt;br /&gt;
==Parsing==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system:&lt;br /&gt;
* Formulas have functions (delimited by parenthesis)&lt;br /&gt;
* Formulas have both built-in terms as well as user defined variables (DEFINE: token)&lt;br /&gt;
* All user defined variables are global in scope&lt;br /&gt;
* All user defined variables are provided a starting value on definition&lt;br /&gt;
* User defined variables are assumed to be zero if no DEFINE is ever encountered&lt;br /&gt;
* User defined variables may be defined in more than one location&lt;br /&gt;
* Some terms may be local in scope (e.g. spells have unique terms), but these are fragile and not thread safe.&lt;br /&gt;
* Diagnostic tools in the UI allow presentation of the current value of a variable (or really any formula)&lt;br /&gt;
* Formulas are NOT parsed for significant levels of validity at data load.  They are given basic checks (to ensure parenthesis match, for example), but a full validity check is not possible.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
Currently, the use of JEP requires a multi-pass resolution.  The formula is parsed, then it is processed/queried in order to determine any variables or terms it contains, and then those values are loaded into the formula and the formula is resolved.  (see VariableProcessor.processJepFormula() )&lt;br /&gt;
&lt;br /&gt;
This (JEP) method of resolution comes with some challenges and risks.&lt;br /&gt;
&lt;br /&gt;
The parsed version of a JEP formula (a PJEP) ends up with a lot of complexity.  It is a controller of sorts, rather than just a framework for a formula. &lt;br /&gt;
&lt;br /&gt;
Also, the parsed version of a JEP formula has a set of awareness.  The variable/term values are loaded into it, meaning a contract is placed on the programmer to &amp;quot;clean that up&amp;quot; so those values do not pollute other, later calculations.  (This is generally not an issue based on how it is otherwise used, but may not be initially clear to an uninformed reader)&lt;br /&gt;
&lt;br /&gt;
=How we use JEP=&lt;br /&gt;
&lt;br /&gt;
==Term==&lt;br /&gt;
&lt;br /&gt;
For purposes of this document, a term is a &amp;quot;built in&amp;quot; value that can be used in a formula.  These are a subset of the items currently documented in the &amp;quot;Pre-defined Variables&amp;quot; or &amp;quot;System-Defined Variables&amp;quot; section of the docs (depending on how you get to that section)&lt;br /&gt;
&lt;br /&gt;
An example of this include (but are certainly not limited to) BAB, BASECR, CASTERLEVEL, CL, SR, and TL.&lt;br /&gt;
&lt;br /&gt;
Note that some terms can possess context.  For example, CASTERLEVEL is valid only in SPELL objects, as it requires the &amp;quot;context&amp;quot; of the castable spell (which implicitly includes the class level, DC, # of times usable, etc... it is more than the Spell object defined in the LST file)&lt;br /&gt;
&lt;br /&gt;
Some built-in variables look to the user as if they are a function, and are often treated by users as functions even though they are terms.  These include square brackets in the pre-defined variable name.  (e.g. COUNT[SKILLS]).&lt;br /&gt;
&lt;br /&gt;
==Variable==&lt;br /&gt;
&lt;br /&gt;
For purposes of this document, a variable is a data-defined value.  Using today's data, this means it was defined by the DEFINE: token being encountered in the data.  Obviously, due to the nature of formulas and ambiguity, there is limitation on variable names in that they must not conflict with a pre-defined term.&lt;br /&gt;
&lt;br /&gt;
===Global Variable===&lt;br /&gt;
&lt;br /&gt;
Global variables are variables that exist across the entire set of data.  A global variable can be defined in one object and used in another.  This is currently the case for all variables in PCGen, as they are all created with the DEFINE: token.&lt;br /&gt;
&lt;br /&gt;
==Paren Function==&lt;br /&gt;
&lt;br /&gt;
A paren function is a function that uses parenthesis () to contain the arguments to the function.  An example of this is var(&amp;quot;CL=Fighter&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
&amp;quot;var&amp;quot; is the function, &amp;quot;CL=Fighter&amp;quot; is the (one) argument to the function.&lt;br /&gt;
&lt;br /&gt;
Called &amp;quot;paren functions&amp;quot; to avoid confusion with the &amp;quot;terms&amp;quot; that contain brackets.&lt;br /&gt;
&lt;br /&gt;
==Ambiguity over a value==&lt;br /&gt;
&lt;br /&gt;
We want to avoid some situations of ambiguity.  The current system for variables takes a &amp;quot;largest wins&amp;quot; argument when multiple definitions are encountered.  This leads to potential confusion (and potentially debate over whether such an implicit decision should be allowed).  It has also led to the adoption of a &amp;quot;data standard&amp;quot; that all values should be defined at zero and modifications provided as a BONUS:VAR|...  Our redesign looks to eliminate the confusion over multiple conflicting definitions by providing a global definition characteristic and preventing otherwise identical variable definitions from having different starting values.&lt;br /&gt;
&lt;br /&gt;
=The new Formula parser=&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
The new formula parser is a JavaCC (well, technically, JJTree) defined syntax.  It is held separately in the PCGen-Formula library, which is one of our two [[PCGen Libraries]]&lt;br /&gt;
&lt;br /&gt;
==Removed Characteristics==&lt;br /&gt;
&lt;br /&gt;
===Boolean-aware calculation===&lt;br /&gt;
&lt;br /&gt;
Boolean and Numeric values will be calculated in their own domain. It will NOT be assumed that TRUE is 1 and FALSE is 0 as some other formula systems assume.  A Boolean value here will be a Boolean and only usable where a Boolean is legal.&lt;br /&gt;
&lt;br /&gt;
Therefore, the common operations that are Boolean operations such as AND (&amp;amp;&amp;amp;) and OR (||) will only operate on Boolean values.  If a Function requires a Boolean value (such as the first argument to an IF function), then it must validate the semantics of the subformula.&lt;br /&gt;
&lt;br /&gt;
This was based on team feedback as the formula system was originally designed.&lt;br /&gt;
&lt;br /&gt;
==Shared Characteristics==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system that are similar to the existing implementation:&lt;br /&gt;
# Formula Functions are stored as plugins, so that new functions would not necessarily force a full rebuild of PCGen.&lt;br /&gt;
&lt;br /&gt;
==Changed Characteristics==&lt;br /&gt;
&lt;br /&gt;
Major characteristics of this system that are major modifications of the existing implementation:&lt;br /&gt;
# Formats other than numbers are supported.&lt;br /&gt;
# Starting value for a variable is based on the variable format (e.g. zero for numbers), so multiple defines do not &amp;quot;compete&amp;quot; [new: Define does not have a definition per DEFINE: token, but rather a DEFAULTVARIBLEVALUE once per game mode for a variable format (numbers being one possible variable format).  This is consistent with and thus formalizes the data best practice of defining variables to zero].&lt;br /&gt;
# Terms are eliminated.  They should be replcaed by functions or user variables.&lt;br /&gt;
# BONUS:VAR is eliminated and replaced with Modifiers (see below) [and in general ALL BONUS tokens will eventually disappear].&lt;br /&gt;
# The new system will not have any terms.  All items will be a function or a user defined variable.  This will dramatically simplify dependency analysis.&lt;br /&gt;
# The system does &amp;quot;integer aware&amp;quot; arithmetic, meaning 2+3=5 (not 5.0 or 4.999999999 or 5.000000001 as we might have today).&lt;br /&gt;
&lt;br /&gt;
==New Capabilities==&lt;br /&gt;
Major characteristics of this system that are new capabilities:&lt;br /&gt;
# Diagnostic tools in the UI should provide the ability to expose the entire calculation, from default value through all modifications (and source of those modifications).&lt;br /&gt;
## It is important to recognize that the data practice of indirection (e.g. one object awards a Template called FACE_20 that sets the FACE:) is STRONGLY discouraged in the new system.  That indirection makes it A LOT harder to figure out what modified a variable - something that the new system can make VERY clear, but that the data can hide and make difficult.&lt;br /&gt;
# Formulas are validated at data load to ensure good syntax, and that any functions that are used exist (and are valid) and variables are nominally defined somewhere in the data.&lt;br /&gt;
## There are a few rare excpetions to full validation, because they really occur at runtime... so just like we can't automatically detect that a divide by zero will occur, we can't detect that a Table provided to a lookup() function will actually have the necessary values and columns for the incoming variables.&lt;br /&gt;
# Dependencies are tracked and any circular logic will be identified as such during calculation (it is expected that this is not possible to catch at LST load due to formulas on impossible data combinations leading to false positives).  This is done in the specific Solver.&lt;br /&gt;
&lt;br /&gt;
==Modifiers==&lt;br /&gt;
&lt;br /&gt;
The MODIFY and MODIFYOTHER tokens replace BONUS:VAR. These provide a significantly enhanced experience from using BONUS, specifically:&lt;br /&gt;
# Specific values calculated by the formula system&lt;br /&gt;
# No implicit stacking rules.  All stacking is explicit by the data owner&lt;br /&gt;
# No implicit replacement rules.  All replacement is explicit by the data owner&lt;br /&gt;
# Dependency will be explicit and calculation will be carefully managed.  (A graph of dependencies between variables is maintained by a SolverManager)&lt;br /&gt;
&lt;br /&gt;
==Single Pass Evaluation==&lt;br /&gt;
&lt;br /&gt;
Unlike JEP where a pass is made to determine the variables and then load those into the object, the new formula system is capable of doing an evaluation in a single pass.&lt;br /&gt;
&lt;br /&gt;
Having a single-pass resolution by a visitor to the tree, with the context passed in as a parameter, has a number of functional advantages:&lt;br /&gt;
* This effectively makes a formula &amp;quot;immutable&amp;quot; in the sense that the context is passed in during resolution and thus can be evaluated in multiple threads without causing issues.  Note this is a necessary consideration if we want to reuse formulas that are in the data multiple times, as the UI demonstrably triggers evaluation of items from multiple threads.  The visitors are also &amp;quot;immutable&amp;quot; (they are in fact, fully stateless), and thus reusable without being concerned about thread safety.&lt;br /&gt;
* This keeps the formula as light-weight as possible (The tree structure is still a bit expensive, but better than a PJEP).&lt;br /&gt;
* The context can be set based on what is passed in, meaning evaluation locality is driven by the caller (knowing the locality) rather than forcing the formula to evaluate some string to figure out where it is.&lt;br /&gt;
* The entire concept of a PJEP pool goes away (in exchange we effectively have a context, but those are reusable so we don't ever have the lock/free necessity of PJEP).  (For specificity, those solving contexts are called &amp;quot;DependencyManager&amp;quot;, &amp;quot;EvaluationManager&amp;quot;, and &amp;quot;FormulaSemantics&amp;quot;, and can currently be found in the PCGen-formula library.&lt;br /&gt;
* We actually prohibit any funky hoop-jumping.  By only providing the context in the sense of a variable library, we can accurately handle things like spell-localized items (e.g. today's CASTERLEVEL term) without having a temporarily set global item.&lt;br /&gt;
&lt;br /&gt;
=Further Reading=&lt;br /&gt;
&lt;br /&gt;
For more detailed information on setting up the new formula system, see [[Setting up the new Formula System]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4262</id>
		<title>Index to Architecture Documents</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4262"/>
		<updated>2018-03-04T21:06:47Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is effectively a &amp;quot;shorthand&amp;quot; list of documents (and a tiny bit of context around the links) for &amp;quot;A Day in the Life of PCGen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
&lt;br /&gt;
Before reading about the details of the PCGen architecture, it is likely helpful to understand our key [[Design Concepts for PCGen]] and [[Architecture Document Conventions]]&lt;br /&gt;
&lt;br /&gt;
=Loading=&lt;br /&gt;
&lt;br /&gt;
# The [[Startup System]] initializes PCGen and loads the initial user interface&lt;br /&gt;
# Files from Disk are loaded by the [[Rules Persistence System]]&lt;br /&gt;
# These files use [[CDOM References Concept Document|CDOM References]] to resolve order of operations conflicts during load and [[Referring to Groups in LST Data|Refer to Groups in LST Data]] to identify multiple possible objects (for say, a choice)&lt;br /&gt;
# The [[Load Commit Subsystem]] is used to commit information into the [[Rules Data Store]]&lt;br /&gt;
# Post Processing is completed as described in the [[Full Load Order Detail]]&lt;br /&gt;
&lt;br /&gt;
=Using Data=&lt;br /&gt;
&lt;br /&gt;
# When retrieving items from the Rules Data Store, it's important to [[Identifying Objects|Identify the right Object]]&lt;br /&gt;
# You will also need to know about [[Accessing Information]]&lt;br /&gt;
# And strategically, it's good to know how we are [[Becoming Data Driven]]&lt;br /&gt;
&lt;br /&gt;
=Processing a PC=&lt;br /&gt;
&lt;br /&gt;
# After [[Adding items to the PC]], we begin [[Calculating Items on the PC]]&lt;br /&gt;
# This calculation heavily depends on the [[Formula Systems]]&lt;br /&gt;
# Some of the items on a PC can be conditional, so it's valuable to understand [[Prerequisites and Requirements]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Becoming_Data_Driven&amp;diff=4261</id>
		<title>Becoming Data Driven</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Becoming_Data_Driven&amp;diff=4261"/>
		<updated>2018-03-04T21:06:45Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot;{| align=&amp;quot;right&amp;quot;   | __TOC__   |}  =Input=  ==Historical/Original==  Originally PCGen had a series of tokens that imported information into specific locations within the objec...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Input=&lt;br /&gt;
&lt;br /&gt;
==Historical/Original==&lt;br /&gt;
&lt;br /&gt;
Originally PCGen had a series of tokens that imported information into specific locations within the objects within PCGen.  These objects were highly specialized and in somecases very long (PCTemplate was at one point well over 10,000 lines of code).&lt;br /&gt;
&lt;br /&gt;
In the long term, however, we end up in a situation where the disadvantages outweigh the clarity of this architecture, so this design is deprecated and largely removed from PCGen.  (The major exception is Equipment, where you can see this design in full use).&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
&lt;br /&gt;
The hardcoding to specific methods made defaults fairly easy to understand - they were hardcoded in the specific method, if no other value was set by the data.&lt;br /&gt;
&lt;br /&gt;
===Limitations===&lt;br /&gt;
&lt;br /&gt;
This hardcoding has some limitations:&lt;br /&gt;
&lt;br /&gt;
# The original designs were directly aligned to how things were originally in the SRD (3.0) and RSRD (3.5).  The result was that certain features could only be reached from certain objects.&lt;br /&gt;
# The original designs presumed certain features, meaning that it was assumed that &amp;quot;Hands&amp;quot; was a relevant characteristic.  In a system like MSRD, where all creatures are human, those methods are either unused, or worse, have to be turned off so they aren't processing and checking for data that may not be present.&lt;br /&gt;
## Alignment is a specific example where there is specific code that has to turn OFF certain features if there is not an Alignment in a specific game mode&lt;br /&gt;
## This turn on/turn off is inflexible and really not scalable.&lt;br /&gt;
# In general every new characteristic not only drives a new token but it drives a new set of methods on the underlying objects.&lt;br /&gt;
# From an output perspective, specific output tokens must call the exact methods, so significant code is requried in the output system as well.&lt;br /&gt;
&lt;br /&gt;
===Advantages===&lt;br /&gt;
&lt;br /&gt;
This hardcoding is nice for certain things:&lt;br /&gt;
&lt;br /&gt;
# It makes it clear to a reader what is being processed, since there is a direct method on an object of, for example, getHands()&lt;br /&gt;
&lt;br /&gt;
==Indirect Storage==&lt;br /&gt;
&lt;br /&gt;
As we began a transition in reducing duplicate code and making PCGen more flexible, we got to where many of the items are now resolved indirectly.  Instead of getHands() for example, we now do: getInteger(IntegerKey.HANDS).  These generic storage methods are on CDOMObject.&lt;br /&gt;
&lt;br /&gt;
This has a number of benefits, specifically that adding additional characteristics to an object does not require new methods (there is an ability to store integers, Objects, Lists, etc.).  However, a new token is still requried, since there is not a generic method of getting at those put* and get* methods from the data tokens.&lt;br /&gt;
&lt;br /&gt;
The Keys for these indirect storage methods are generally in pcgen.cdom.enumeration&lt;br /&gt;
&lt;br /&gt;
===Defaults===&lt;br /&gt;
&lt;br /&gt;
The lack of specific methods for any given behavior then leave the question of where defaults should be stored... To provide that behavior, we allow each Key to hold a default value.  Then a resolution can use the default value if no other value exists.&lt;br /&gt;
&lt;br /&gt;
You can see the Defaults in places like IntegerKey, where the constructor takes 2 arguments (The name and the default value).&lt;br /&gt;
&lt;br /&gt;
===Design Choice===&lt;br /&gt;
&lt;br /&gt;
Note that there is a specific set of methods that handle Lists and more complex data structures on objects like Race, et al.  This is conscious, in order to fully protect the contents of the list held internally to the CDOMObject from being modified outside that CDOMObject.  As mentioned elsewhere, this is a defensive coding syle based on past problems in PCGen and hedging against similar issues.&lt;br /&gt;
&lt;br /&gt;
==Indirect with a Generic Token==&lt;br /&gt;
&lt;br /&gt;
The next progression in improving how PCGen can be data driven was enabling a token that allowed the Data team to not only define their own content, but define their own &amp;quot;Key&amp;quot; as well.&lt;br /&gt;
&lt;br /&gt;
To do this, there are two new tokens, FACT and FACTSET.  Much of the rest of this section refers to &amp;quot;FACT&amp;quot;, but is using that as a generic term for both FACT and FACTSET. Few features only support FACT, and in those situations, it will be clearly stated.&lt;br /&gt;
&lt;br /&gt;
===Design choice: Predefinition===&lt;br /&gt;
&lt;br /&gt;
Note that it would be possible to simply have a generic method that would automatically generate a *Key and inject objects using the same methods as in &amp;quot;Indirect Storage&amp;quot; above.  However, this could be highly error-prone.  A small typo of &amp;quot;Hadns&amp;quot; would result in data never actually controlling the right value.  We therefore made a conscious decision to force the pre-definition of the key values.  This is done through FACTDEF and FACTSETDEF tokens in the Data Control file.&lt;br /&gt;
&lt;br /&gt;
===Design Choice: Static===&lt;br /&gt;
&lt;br /&gt;
An almost immediate response upon the introduction of FACT and FACTSET was: &amp;quot;Why can't I change them&amp;quot;.  Answer: Facts shouldn't change, so semantically the behavior matches the name.&lt;br /&gt;
&lt;br /&gt;
Well, on a more-useful answer (of why FACT in the first place), there are practical reasons to have them not be modifiable.  The first is that we encounter many items that are not-PC specific that can therefore be cached.  To guarantee we can cache that information, we need to know we will not be PC dependent.  The design of this makes that guarantee.&lt;br /&gt;
&lt;br /&gt;
Second, this was design was done in context to the new variable system being in the design pipeline, so we clearly didn't want to duplicate efforts of a variable system with local variables.  If the data team needs to modify something, then clearly it's a local variable, not a FACT.&lt;br /&gt;
&lt;br /&gt;
===Data Driven Grouping===&lt;br /&gt;
&lt;br /&gt;
When a FACT is provided, if it is something that is known to be universal (or nearly so) it is possible to use that to group objects.  Groups are usable in places like CHOOSE:.  To enable the use of a FACT in a Grouping situation, it needs to be enabled, by using the GROUPABLE: token on the FACTDEF.&lt;br /&gt;
&lt;br /&gt;
===Data Driven Output===&lt;br /&gt;
&lt;br /&gt;
A FACT can also be enabled so the information is visible to output.  This is also controlled on the FACTDEF line.&lt;br /&gt;
&lt;br /&gt;
=Output=&lt;br /&gt;
&lt;br /&gt;
Traditional output was done using a custom PCGen output system.  Some time ago, we adopted Freemarker, and many of our output sheets now use Freemarker to do output&lt;br /&gt;
&lt;br /&gt;
==Traditional==&lt;br /&gt;
&lt;br /&gt;
Traditional output uses the Tokens generally in plugin.export.  A number of them are in the core, in pcgen.io.exporttoken.  These items process information read from the output sheet and process it into the appropriate String.&lt;br /&gt;
&lt;br /&gt;
===Challenges===&lt;br /&gt;
&lt;br /&gt;
# Many of these tokens take a significant amount of processing and keep it within PCGen.  The weapon and ability output tokens both are extremely large.&lt;br /&gt;
## The ability tokens require a cache to have reasonable performance.  Because of how the traditional output system works, the tokens become re-entrant, and have to continually build the same ordered list.  Since that is not in the core, some of the tokens cache the list and it can be confusing about why the cache exists to an unaware reader of the code.&lt;br /&gt;
## The weapon tokens have a ton of processing, much of it very specific to d20 systems.&lt;br /&gt;
# The tokens themselves are not at all modular - they are all generally independent and are a huge source of duplicated code. Others have to be held in the core so that derivative tokens can have them as a parent class.&lt;br /&gt;
# The traditional output tokens can be used in the traditional variable system as a value.  &lt;br /&gt;
## You probably can't imagine how difficult this makes following what is possible in the old variable system in terms of how much code will be called when a formula is processed&lt;br /&gt;
&lt;br /&gt;
==Freemarker Compatible==&lt;br /&gt;
&lt;br /&gt;
As we transitioned to using Freemarker, we were able to stop using a number of the control tokens we used to have (IF, etc).  Others we continued to use in a fashion that was very similar to their existing usage.  This still carries with it many of the existing issues articulated above.&lt;br /&gt;
&lt;br /&gt;
==Freemarker Native==&lt;br /&gt;
&lt;br /&gt;
Going forward, we are moving toward a Freemarker-native form of output.  You can find this in pcgen.output.  Instead of doing custom String processing relative to PCGen, these classes provide TemplateModel objects that are fully compatible with Freemarker's internal knowledge.  This will provide a number of advantages:&lt;br /&gt;
# Since the values are effectively native to Freemarker, they will require no caching, et al.  (Freemarker will capture and reuse the list while it is in scope)&lt;br /&gt;
# There is a huge ability to be modular in terms of reuse when certain things show up in different places.  &lt;br /&gt;
## For example, the PC's Alignment may desire certain features (showing the abbreviation, etc.).  This may also be true of the Deity's alignment.  Under the old system, this would have required duplicate code or some very clever hoop jumping in the old tokens.  In the Freemarker native system, we well Freemarker how to wrap an Alignment, get back a TemplateModel, and then regardless of the method used to get to an Alignment, we can provide all of the features of an Alignemnt all of the time.  IT naturally reuses code.&lt;br /&gt;
&lt;br /&gt;
===Challenges===&lt;br /&gt;
&lt;br /&gt;
Right now a limited set of items are available in Freemarker-native output.  Some of this is conscious, since the desire to bring across a lot of the custom code in things like weapon output tokens is low... we want to drive those into the data and into the new formula system.&lt;br /&gt;
&lt;br /&gt;
=Design=&lt;br /&gt;
&lt;br /&gt;
The various methods of input and output hav esome consequences going forward.  One of those in understanding what choices to make in being data driven is in using Variables vs Objects.&lt;br /&gt;
&lt;br /&gt;
The example used here relates to Movement.&lt;br /&gt;
&lt;br /&gt;
It is definitely possible to have new variables like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Movement_Normal&lt;br /&gt;
Movement_Fly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We could perhaps start these at -1 to indicate no movement is available, or even have boolean values like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Has_Movement_Fly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, this quickly breaks down for a number of reasons:&lt;br /&gt;
# It gets very difficult to increment across all Movement. &lt;br /&gt;
## The output sheets will need to do that, and if it was strictly variables in the new system, the output sheet would need to check all the variables.  &lt;br /&gt;
## This potentially traps all games modes into using the same variable names (and potentially other dynamics), which is a bit rediculous.  If data driven means there are handcuffs on the data, it may be worse than having magical code.&lt;br /&gt;
# It hardcodes values like &amp;quot;Fly&amp;quot; into variable names, and those are things that should eventually be localized (meaning translated)&lt;br /&gt;
## This would thus demand unique infrastructure for translating variable names&lt;br /&gt;
# An item that attempted to modify all movement of any type would have to know all the variables and would thus be fragile (meaning you'd have to constantly be modifying that object).&lt;br /&gt;
## This indicates an underlying architecture failure of the design if a simple change results in breakage elsewhere.&lt;br /&gt;
&lt;br /&gt;
To get around these items, it is recommended that items of this nature (Movement and Vision being the most obvious) use a separate object type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DYNAMICSCOPE:MOVEMENT&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This then gives an object type of &amp;quot;Movement&amp;quot;, and new items can be defined:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MOVEMENT:Normal&lt;br /&gt;
MOVEMENT:Fly&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we end up with a few neat characteristics:&lt;br /&gt;
# Since these are objects, we can still focus on translating info about objects and we will thus capture and be able to define how to translate these&lt;br /&gt;
# We can have a local variable on each item, and thus address that from various locations&lt;br /&gt;
## It's no longer a series of global variables, so we have reduced the number of global variables&lt;br /&gt;
## If we have something that ever modifies all movement of a given type, it is as simple as a MODIFYOTHER:MOVEMENT|ALL|... so it's not fragile to introduction of a new type of movement.&lt;br /&gt;
# We can easily increment across all objects of that type. It can easily be exposed on &amp;quot;pc&amp;quot; as something like &amp;quot;movement&amp;quot;, and thus flows directly into the same process as other items that are Freemarker-native output.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=SELECTION_-_A_CHOOSE_Replacement&amp;diff=4260</id>
		<title>SELECTION - A CHOOSE Replacement</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=SELECTION_-_A_CHOOSE_Replacement&amp;diff=4260"/>
		<updated>2018-03-04T19:13:05Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
&lt;br /&gt;
First draft proposal for SELECTION (replaces CHOOSE/supports multiple CHOOSE).&lt;br /&gt;
&lt;br /&gt;
Please note that the token names here are for example purposes.  Some discussion has taken place but they are not &lt;br /&gt;
finalized.  They are here to show the concepts and how the structures of this new system would work in LST files.&lt;br /&gt;
&lt;br /&gt;
=Code Concepts=&lt;br /&gt;
&lt;br /&gt;
==Current Issues==&lt;br /&gt;
&lt;br /&gt;
===Multiple Methods===&lt;br /&gt;
&lt;br /&gt;
There are currently 4 different methods for how CHOOSE operates in the code&lt;br /&gt;
* Abilities&lt;br /&gt;
* Race and Template&lt;br /&gt;
* Language&lt;br /&gt;
* Temporary Bonuses&lt;br /&gt;
&lt;br /&gt;
The desire is to reduce this to one methodology (or two at worst if temporary bonuses need to be separate)&lt;br /&gt;
&lt;br /&gt;
===Single Selection===&lt;br /&gt;
&lt;br /&gt;
CHOOSE currently supports only one selection.  In many cases this produces a challenging format that is forced into the &lt;br /&gt;
code.  If multiple selections were allowed, this would not be necessary, as one could be CLASS and the other LEVEL for &lt;br /&gt;
example.&lt;br /&gt;
&lt;br /&gt;
===Automatic Expansion===&lt;br /&gt;
&lt;br /&gt;
CHOOSE currently automatically expands items.  If you CHOOSE:FEAT, you get things like Weapon Proficiency(x) and Weapon &lt;br /&gt;
Proficiency (y).  This also then creates an interesting visual challenge if there are multiple tiers.  If a Feat allows &lt;br /&gt;
a selection from another MULT:YES feat, then you get Something(a(b)) and Something(a(c)).  This can rapidly proliferate &lt;br /&gt;
into a huge list to scroll through.  It would be visually cleaner to select &amp;quot;a&amp;quot; and then select &amp;quot;b or c&amp;quot; within the &lt;br /&gt;
context of &amp;quot;a&amp;quot; being selected under &amp;quot;something&amp;quot;.  This requires a new UI to handle this hierarchical behavior.&lt;br /&gt;
&lt;br /&gt;
(This item is not currently addressed further here, as I would like to talk to some of our UI folks before I propose &lt;br /&gt;
too much here)&lt;br /&gt;
&lt;br /&gt;
===CHOOSE:NOCHOICE===&lt;br /&gt;
&lt;br /&gt;
Simply shouldn't have to exist.&lt;br /&gt;
&lt;br /&gt;
===Stacking Ambiguities===&lt;br /&gt;
&lt;br /&gt;
This is true more for MULT:YES than CHOOSE in particular, but imagine something like this:&lt;br /&gt;
&lt;br /&gt;
ABILITY:FEAT|VIRTUAL|Dodge&lt;br /&gt;
&lt;br /&gt;
Now put that on a MULT:YES Feat and select it twice.&lt;br /&gt;
&lt;br /&gt;
Do you get 2 copies of Dodge or 1 copy?&lt;br /&gt;
&lt;br /&gt;
This has already been encountered in the past and discussed on the -dev list.  The BONUSes also suffer from the same &lt;br /&gt;
issue and there have been a few debates over proper behavior.&lt;br /&gt;
&lt;br /&gt;
The solution to this problem is eliminate all ambiguity.  We should to distinguish between the ability itself (applied &lt;br /&gt;
only once ever) and what I will call the &amp;quot;instances&amp;quot; of the ability (applied once per time taken by the user).  Note &lt;br /&gt;
that I do NOT say &amp;quot;per selection&amp;quot; or &amp;quot;per choice&amp;quot; because if an item has 3 choices, we still have struggles.  There are &lt;br /&gt;
ways to apply once per choice as well, but we need ALL of the capabilities, so we have to have a method to do once per &lt;br /&gt;
time taken by the user).&lt;br /&gt;
&lt;br /&gt;
From this point onward, I will have an INSTANCE: token that then refers to instances rather than the parent object.  &lt;br /&gt;
This is much like the current &amp;quot;PART:x|...&amp;quot; token that can appear on equipment to handle equipment heads.  Just like &lt;br /&gt;
PART, it will have an argument (as to where it is applied) followed by another full token.&lt;br /&gt;
&lt;br /&gt;
==Current Quirks==&lt;br /&gt;
&lt;br /&gt;
===Stacking===&lt;br /&gt;
&lt;br /&gt;
Currently the system defaults to STACK:NO.  Should this be the default behavior when a lot more control exists for the &lt;br /&gt;
data to define what is selectable?&lt;br /&gt;
&lt;br /&gt;
===Race Conditions===&lt;br /&gt;
&lt;br /&gt;
Part of the reason we have multiple different selection methods is that the code has certain race conditions (two &lt;br /&gt;
actions that need to happen in a certain order).  &lt;br /&gt;
&lt;br /&gt;
For Race and Template, they get added to the PC first, THEN the selection is made.  This means they have to be &lt;br /&gt;
defending against undefined choices. &lt;br /&gt;
&lt;br /&gt;
For Abilities, they only get added to the PC when an AbilitySelection object (an ability with its selection) is added &lt;br /&gt;
to the PlayerCharacter.  This means the selection occurs BEFORE the object is added.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other Considerations==&lt;br /&gt;
&lt;br /&gt;
===Conversion===&lt;br /&gt;
&lt;br /&gt;
No conversion will be automated, as the semantics here are completely different than the old system.&lt;br /&gt;
&lt;br /&gt;
Also, since backwards compatibility will not be supported (CHOOSE will not be available in the new formula system at &lt;br /&gt;
least under the current plan), we will need a new token name.  From this point onward, it will be called SELECTION.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
===Instances===&lt;br /&gt;
&lt;br /&gt;
As mentioned above, the Selections will be placed into instances.  These instances are separate objects with a separate &lt;br /&gt;
SCOPE.  For Skills (For example), the scope will be SKILL.INSTANCE&lt;br /&gt;
&lt;br /&gt;
===Aligning Concepts to the new Formula System===&lt;br /&gt;
&lt;br /&gt;
In general, the new formula system uses the concept of a Scope to determine where a variable is processed.  &lt;br /&gt;
&lt;br /&gt;
A naive design would be to keep two lists on the main object.  That way, the first set of choices are [0] in the lists, &lt;br /&gt;
the next set [1].  While I don't have a specific rule associated to this, I can quickly come up with some plausible use &lt;br /&gt;
cases where that would break.  For example: Imagine a feat that allows you to select a class and make 2 skills from the &lt;br /&gt;
classskilllist of that class get +1 bonus rank.&lt;br /&gt;
&lt;br /&gt;
Therefore, we delegate containing the result of the selection down into an instance object.  We then make that a &lt;br /&gt;
subscope of the main scope for that object type.  Consider the CHOOSE on skills for Speak Language.  We then get &lt;br /&gt;
something like:&lt;br /&gt;
   INSTANCE:ALL|SELECTION:SpokenLanguage|LANGUAGE|getAll(&amp;quot;LANGUAGE&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Now, every time a new instance of that Skill is selected (which happens to be from getting a new rank of that skill), a &lt;br /&gt;
new Instance will be added to the PC and a new selection will need to be made.&lt;br /&gt;
&lt;br /&gt;
It could then be added to a list of languages via:&lt;br /&gt;
   INSTANCE:ALL|MODIFY:LanguageList|ADD|getSelection(&amp;quot;SpokenLanguage&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
(This assumes LanguageList is a global variable of Format &amp;quot;ARRAY[LANGUAGE]&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
To be VERY CLEAR: getSelection(&amp;quot;SpokenLanguage&amp;quot;) MUST BE USED IN AN INSTANCE.  If you attempt to use it up at the &lt;br /&gt;
parent ability/skill/whatever, it will either (a) fail or (b) be empty.  (It should fail, and we will endeavor to do &lt;br /&gt;
that, but there will need to be enhancements to have functions available only in a limited scope... that's new effort)&lt;br /&gt;
&lt;br /&gt;
===Resolving the Race Condition===&lt;br /&gt;
&lt;br /&gt;
The race condition is particularly problematic for the new formula system.  Consider a naive design like this:&lt;br /&gt;
&lt;br /&gt;
   MODIFY:MyList|ADD|Foo&lt;br /&gt;
   SELECTION:MySelection|STUFF|myList&lt;br /&gt;
&lt;br /&gt;
This immediately sets up a problem based on how the formula system works.  Because it only processes items that are &lt;br /&gt;
actually &amp;quot;granted&amp;quot; to the PC, the MODIFY of MyList would not happen unless the object itself was already granted.  This &lt;br /&gt;
traps us (a bit) in making sure the object is added to the PC BEFORE a selection is made, so that if it chooses to do &lt;br /&gt;
any list modifications, they can be done BEFORE the selection.&lt;br /&gt;
&lt;br /&gt;
To resolve this race condition, we put the MODIFY on the parent object, which is granted BEFORE any selection.  We then &lt;br /&gt;
put the SELECTION in the INSTANCE, which is granted AFTER any selection.  Note this also means that if (for some &lt;br /&gt;
reason) the data team to have the MODIFY occur AFTER the selection, they have that power.  This gives the data team &lt;br /&gt;
full feature, supporting add both BEFORE and AFTER selection:&lt;br /&gt;
&lt;br /&gt;
   MODIFY:MyList|ADD|AddBeforeSelection&lt;br /&gt;
   INSTANCE:1|MODIFY:MyList|Add|AddAfterSelection&lt;br /&gt;
&lt;br /&gt;
As a nice side effect, this actually gives us full power to avoid ANY popup windows in a new UI should that be a &lt;br /&gt;
feature we want to implement.  Because all instance applications can be deferred, they could be &amp;quot;TODOs&amp;quot; on the PC &lt;br /&gt;
rather than stopping for user input.&lt;br /&gt;
&lt;br /&gt;
===Replicating NUMCHOICES===&lt;br /&gt;
&lt;br /&gt;
To replicate the behavior of NUMCHOICES, we then need to control the number of instances that we are allowed to apply.  &lt;br /&gt;
&lt;br /&gt;
This is a new token, MAXINSTANCES.&lt;br /&gt;
&lt;br /&gt;
===Replicating SELECT===&lt;br /&gt;
&lt;br /&gt;
To replace the behavior of SELECT, we need to control the number of actual selections that exist in an instance for &lt;br /&gt;
that SELECTION.  Since this is associated to the SELECTION, we need to keep it local to that token, so it is appended &lt;br /&gt;
as an optional control on the SELECTION:&lt;br /&gt;
   SELECTION:MySelection|LANGUAGE|getAll(&amp;quot;LANGUAGE&amp;quot;)|SELECT=2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Happy Side Effects of INSTANCE===&lt;br /&gt;
&lt;br /&gt;
Please note: ALL objects that are instance-able ALWAYS will produce an instance.  This is true REGARDLESS of whether &lt;br /&gt;
there is a SELECTION on the object.  Many of these Instances will be empty shell objects, but they can also have some &lt;br /&gt;
interesting uses.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;At Rank 5 this skill adds 2 legs to the PC&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   INSTANCE:5|MODIFY:Legs|ADD|2&lt;br /&gt;
&lt;br /&gt;
Note that this means there is no equivalent PRERANK: needed on a MODIFY.  It is directly applied to the &amp;quot;5&amp;quot; instance as &lt;br /&gt;
a MODIFY, and when the Rank hits 5, that INSTANCE will be granted and the MODIFY will be applied.  (If you are thinking &lt;br /&gt;
this could be useful for how pathfinder handles Skill Focus... yes, possibly... stay tuned :) )&lt;br /&gt;
&lt;br /&gt;
===Using a Selection as a Target===&lt;br /&gt;
&lt;br /&gt;
In some cases, we end up in situations like &amp;quot;This will increase the range of one type of weapon by 5'&amp;quot;.  Today there is &lt;br /&gt;
&lt;br /&gt;
BONUS:WEAPONPROF=%LIST|RANGE|5&lt;br /&gt;
&lt;br /&gt;
The %LIST here is actually in the target, which is a bit of a problem!  The second argument to MODIFYOTHER is &lt;br /&gt;
definitely NOT a formula, so we need to address that somehow.  In the future, there may be elegant ways of doing this.  For right now, we end up with a not-so-great method, which looks like:&lt;br /&gt;
&lt;br /&gt;
   MODIFYOTHER:EQUIPMENT.PART|ALL|Range|ADD|if(getFact(parent(),&amp;quot;WEAPONPROF&amp;quot;)==getSelection(&amp;quot;MySelection&amp;quot;),5,0)&lt;br /&gt;
&lt;br /&gt;
=Data Information=&lt;br /&gt;
&lt;br /&gt;
==New Tokens==&lt;br /&gt;
&lt;br /&gt;
===INSTANCE===&lt;br /&gt;
&lt;br /&gt;
INSTANCE is only supported on object types that are INSTANCE-able.  This will require code support for all existing &lt;br /&gt;
Formats.  &lt;br /&gt;
&lt;br /&gt;
Note: It is the intent to allow DYNAMIC to be instance-able if the data team so specifies.  More on this later.&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   INSTANCE:x|y&lt;br /&gt;
&lt;br /&gt;
* x is the instances to which the token given in y should be applied.  Currently this supports either an integer value or &amp;quot;ALL&amp;quot;&lt;br /&gt;
* y is a full token to be applied to that instance.  &lt;br /&gt;
&lt;br /&gt;
Please note INSTANCE objects are NOT full CDOMObjects.  They cannot support arbitrary tokens.  Only a limited set &lt;br /&gt;
(defined here) will be supported.&lt;br /&gt;
&lt;br /&gt;
===SELECTION===&lt;br /&gt;
&lt;br /&gt;
SELECTION will ONLY be available on INSTANCE objects.  This means it needs to appear as a subtoken to INSTANCE (which &lt;br /&gt;
itself must only appear on instance-able objects).&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   SELECTION:w|x|y|z|z&lt;br /&gt;
&lt;br /&gt;
* w is the name of the selection.  This is relevant when the data is using the value of the selection in the data&lt;br /&gt;
* x is the FORMAT of the selection.  See the [[Setting up the new formula system]] for more information on formats.&lt;br /&gt;
* y is the array of available objects for the selection. &lt;br /&gt;
* z is an optional set of controls for the selection.&lt;br /&gt;
&lt;br /&gt;
====Selection Control: SELECT====&lt;br /&gt;
&lt;br /&gt;
This replaces the SELECT: token in the current CHOOSE System.  It is a z value for SELECTION:&lt;br /&gt;
   SELECT=x&lt;br /&gt;
&lt;br /&gt;
* x is a formula for the number of selections to be made.&lt;br /&gt;
&lt;br /&gt;
====Selection Control: ORDER====&lt;br /&gt;
&lt;br /&gt;
In the scenario where two SELECTION items would interact (such as choosing a level of spell for a given class, where &lt;br /&gt;
the class would need to be selected first), there is an ORDER control:&lt;br /&gt;
   ORDER=x&lt;br /&gt;
&lt;br /&gt;
* x is an integer constant.  The SELECTION with the lowest ORDER will be processed first (just like PRIORITY on &lt;br /&gt;
MODIFY).  If two SELECTION items have the same ORDER, the system will not guarantee which is processed first.  If it &lt;br /&gt;
matters, specify it.  The default value is zero.&lt;br /&gt;
&lt;br /&gt;
===getAll(x) Function===&lt;br /&gt;
&lt;br /&gt;
getAll will be a function in the new formula system.&lt;br /&gt;
&lt;br /&gt;
Format of this function:&lt;br /&gt;
   getAll(&amp;quot;x&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* x is the name of a FORMAT from the new formula system.&lt;br /&gt;
** Note: This format MUST be an limited format, in that you can't do getAll(&amp;quot;NUMBER&amp;quot;) as that is an unbounded set.&lt;br /&gt;
&lt;br /&gt;
Note also this function will take some cleanup - we eventually need to figure out how to do the things that the &lt;br /&gt;
existing items in the CHOOSE system do... this is a patch for now to get the discussion started&lt;br /&gt;
&lt;br /&gt;
===getSelection(x) Function===&lt;br /&gt;
&lt;br /&gt;
getSelection will be a function in the new formula system.&lt;br /&gt;
&lt;br /&gt;
Format of this function:&lt;br /&gt;
   getSelection(&amp;quot;x&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* x is the name of the selection from the SELECTION token. &lt;br /&gt;
&lt;br /&gt;
NOTE: The FORMAT that getSelection will return will depend on the SELECTION token.  It also depends on whether there is &lt;br /&gt;
a SELECT=x control on the SELECTION&lt;br /&gt;
&lt;br /&gt;
===MAXINSTANCES LST Token===&lt;br /&gt;
&lt;br /&gt;
This token will be usable on any format which is instance-able.&lt;br /&gt;
&lt;br /&gt;
Format:&lt;br /&gt;
   MAXINSTANCES:x&lt;br /&gt;
&lt;br /&gt;
* x is a formula in the new formula system to identify the maximum number of instances allowed for that item.&lt;br /&gt;
&lt;br /&gt;
=Issues=&lt;br /&gt;
&lt;br /&gt;
# The current design of tokens shown for instances assumes one instance type per object type, which is actually not true&lt;br /&gt;
# The current design does not consider how to process ALLOWED/ENABLED for selections - is that a filter, or not - it should be clear and under control of the data team&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4259</id>
		<title>Index to Architecture Documents</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4259"/>
		<updated>2018-03-04T18:23:04Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is effectively a &amp;quot;shorthand&amp;quot; list of documents (and a tiny bit of context around the links) for &amp;quot;A Day in the Life of PCGen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
&lt;br /&gt;
Before reading about the details of the PCGen architecture, it is likely helpful to understand our key [[Design Concepts for PCGen]] and [[Architecture Document Conventions]]&lt;br /&gt;
&lt;br /&gt;
=Loading=&lt;br /&gt;
&lt;br /&gt;
# The [[Startup System]] initializes PCGen and loads the initial user interface&lt;br /&gt;
# Files from Disk are loaded by the [[Rules Persistence System]]&lt;br /&gt;
# These files use [[CDOM References Concept Document|CDOM References]] to resolve order of operations conflicts during load and [[Referring to Groups in LST Data|Refer to Groups in LST Data]] to identify multiple possible objects (for say, a choice)&lt;br /&gt;
# The [[Load Commit Subsystem]] is used to commit information into the [[Rules Data Store]]&lt;br /&gt;
# Post Processing is completed as described in the [[Full Load Order Detail]]&lt;br /&gt;
&lt;br /&gt;
=Using Data=&lt;br /&gt;
&lt;br /&gt;
# When retrieving items from the Rules Data Store, it's important to [[Identifying Objects|Identify the right Object]]&lt;br /&gt;
# You will also need to know about [[Accessing Information]]&lt;br /&gt;
&lt;br /&gt;
=Processing a PC=&lt;br /&gt;
&lt;br /&gt;
# After [[Adding items to the PC]], we begin [[Calculating Items on the PC]]&lt;br /&gt;
# This calculation heavily depends on the [[Formula Systems]]&lt;br /&gt;
# Some of the items on a PC can be conditional, so it's valuable to understand [[Prerequisites and Requirements]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Accessing_Information&amp;diff=4258</id>
		<title>Accessing Information</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Accessing_Information&amp;diff=4258"/>
		<updated>2018-03-04T18:23:01Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: Created page with &amp;quot;{| align=&amp;quot;right&amp;quot;   | __TOC__   |}  =Levels of Information=  As we have separated information inherent to data from data related to a specific PC, we have had more ability to s...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
=Levels of Information=&lt;br /&gt;
&lt;br /&gt;
As we have separated information inherent to data from data related to a specific PC, we have had more ability to separate out information and keep it at the level where it is defined.  To do that, we now end up accessing information within different scopes.&lt;br /&gt;
&lt;br /&gt;
==Game Mode==&lt;br /&gt;
&lt;br /&gt;
Some information is set in the Game Mode, and we store/access that information by Game Mode.  Game Modes are loaded once when PCGen is booted, and not reloaded.  Therefore, this information is generally static/persistent information.&lt;br /&gt;
&lt;br /&gt;
==Data Set==&lt;br /&gt;
&lt;br /&gt;
When a set of campaigns is loaded by a user (or implied by opening a specific PC), we call that set of Campaigns a &amp;quot;Data Set&amp;quot;.  Many items (list of available Races, Languages, etc.) are inherent to the Data Set.  Much of this information will need to make its way out to the UI to be displayed to the user.  For the most part, this information is stored today in the LoadContext and its children.&lt;br /&gt;
&lt;br /&gt;
==Player Character==&lt;br /&gt;
&lt;br /&gt;
When a PC is created, there is a set of information related to the PC.  This information is stored in various places, but in general it is stored within the Facets and new formula system.  More detail is available in [[Adding items to the PC]].&lt;br /&gt;
&lt;br /&gt;
=Architectural Musings=&lt;br /&gt;
&lt;br /&gt;
This is one of the areas where the default design methodology of Dependency Injection (DI) doesn't work well if you consider the base design of a DI system (pre-wiring objects).  While the Facets themselves today are static, MANY of them are dependent upon assumptions about the data we load, and the fact that many of our game systems are d20 systems.  Some of them are idle Facets (and thus shouldn't have been loaded under ideal circumstances) for non-d20 systems.  This area needs some help.&lt;br /&gt;
&lt;br /&gt;
There are also aspects of DI systems that are highly interesting given the different scopes of information shown above.  The ability to define an information &amp;quot;scope&amp;quot; (in the case of Spring an org.springframework.beans.factory.config.Scope), is definitely along the lines of what would help keep information loadable one time while &amp;quot;guaranteeing&amp;quot; that the scopes of information cannot leak.  This would be of significant benefit to a desire to load multiple systems or multiple PCs at the same time without the significant complexity we currently bear from that situation.&lt;br /&gt;
&lt;br /&gt;
After having read through how the HTTP (request/session) scopes work in Spring, I find it highly intriguing to implement a similar design.  My primary concern is that I'm not sure anyone currently active really understands the multiple threads generated by the UI, which could cause a significant amount of damage if not handled correctly.&lt;br /&gt;
&lt;br /&gt;
More on this later...&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Adding_items_to_the_PC&amp;diff=4257</id>
		<title>Adding items to the PC</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Adding_items_to_the_PC&amp;diff=4257"/>
		<updated>2018-03-04T17:42:06Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
In the process of adding items to a Player Character, an Object (like a Language) can be in a number of possible states. &lt;br /&gt;
&lt;br /&gt;
First, it can be &amp;quot;Available&amp;quot;.  This is possible with things like the list of Bonus Languages, Class Skill Lists, and Class Spell Lists.  Things can also be prohibited with items like [[Prerequisites and Requirements]].&lt;br /&gt;
&lt;br /&gt;
=Granting=&lt;br /&gt;
&lt;br /&gt;
When an object is attached enough to the Player Character in order to change that PC, we refer to that as &amp;quot;granting&amp;quot; the object to the PC.  Items like stats (PCStat objects) are universally granted; Skills are granted if they have at least one rank; other objects like Race are granted directly.&lt;br /&gt;
&lt;br /&gt;
=Spell Life Cycle=&lt;br /&gt;
&lt;br /&gt;
Spells are not granted, they have a different life cycle, which involves known and memorized.&lt;br /&gt;
&lt;br /&gt;
=Selections=&lt;br /&gt;
&lt;br /&gt;
Certain types of objects may need a choice to be made as they are added to a PC.  Abilities, for example, use a CHOOSE: token and MULT:YES to indicate this situation.  Templates and Races use CHOOSE: (no MULT: allowed).  Equipment Modifiers also can use a different set of CHOOSE: tokens.&lt;br /&gt;
&lt;br /&gt;
==Template/Race==&lt;br /&gt;
&lt;br /&gt;
When a Template or Race is added to the PC, it is checked to determine if it has a CHOOSE: token.  If it does, a chooser is fired, and the user is forced to make a selection.&lt;br /&gt;
&lt;br /&gt;
It is currently not possible to assign the result of a CHOOSE: to a Race or Template when applying the Race or Template in a non-interactive fashion.  (Meaning you can't do TEMPLATE:MyTemplate(ChooseResult) and expect it to make the ChooseResult selection from the CHOOSE: token... Templates are NOT Abilities)&lt;br /&gt;
&lt;br /&gt;
===Warnings around use===&lt;br /&gt;
&lt;br /&gt;
Note that there is some inherent danger in this design: If the system is trying to add a Race or a Template to a PC in a moment when it is not interactive with the user, then the result is not defined, and may result in a crash.  &lt;br /&gt;
&lt;br /&gt;
Note also with CHOOSE: on Race that certain information may not yet exist in the PC in order to make certain choices available.  This is a race condition we do not intend to fix, as in many cases, the question tryign to be answered cannot be rationally answered at that point in the code.&lt;br /&gt;
&lt;br /&gt;
===Storage===&lt;br /&gt;
&lt;br /&gt;
When a selection is made, the result is stored as an association to the Race or Template.  From a code perspective, it is effectively a Map&amp;lt;Race, Object&amp;gt; or Map&amp;lt;PCTemplate, Object&amp;gt; (although the actual location of the association is in a Facet, e.g. RaceSelectionFacet).&lt;br /&gt;
&lt;br /&gt;
==EquipmentModifiers==&lt;br /&gt;
&lt;br /&gt;
When an EquipmentModifier is interactively added to a piece of Equipment (in the Equipment Builder), the user is forced to make a choice, if necessary.&lt;br /&gt;
&lt;br /&gt;
When an EquipmentModifier is added through the EQMOD tokens on Equipment, then the result of the selection is provided in brackets in the token, e.g. &amp;quot;MyEqMod[MySelection]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Storage===&lt;br /&gt;
&lt;br /&gt;
Since Equipment is still cloned between instances, EquipmentModifiers are stored on the Equipment.  Technically, they are actually stored on the EquipmentHead objects, since the modifiers like +1 (or whatever) are technically attached to the Head, and not to the entire piece of Equipment.&lt;br /&gt;
&lt;br /&gt;
==Ability Selections and Ability Life Cycle==&lt;br /&gt;
&lt;br /&gt;
We start with an &amp;quot;Ability&amp;quot;.  An &amp;quot;ability&amp;quot; is a named entry in an Ability file.&lt;br /&gt;
&lt;br /&gt;
If the Ability has a chooser within it, the product of executing the chooser on the Ability is an &amp;quot;AbilitySelection&amp;quot;, which contains the result of the choice. If it doesn't, there is still one default &amp;quot;AbilitySelection&amp;quot;, with a null choice.  There are both UI and LST data file methods of getting to an AbilitySelection - these are described below.&lt;br /&gt;
&lt;br /&gt;
Once a Category and Nature are added, we successfully have a CategorizedNaturedAbilitySelection or CNAS.  That can be applied to a PC.&lt;br /&gt;
&lt;br /&gt;
===An Example on Terminology===&lt;br /&gt;
&lt;br /&gt;
Let's assume there are 2 TYPE=DragonForm abilities:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BasicDragonForm &amp;lt;&amp;gt; TYPE:DragonForm &amp;lt;&amp;gt; MULT:NO&lt;br /&gt;
AdvancedDragonForm &amp;lt;&amp;gt; TYPE:DragonForm &amp;lt;&amp;gt; MULT:YES &amp;lt;&amp;gt; CHOOSE:PCSTAT|ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are 2 abilities here:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BasicDragonForm&lt;br /&gt;
AdvancedDragonForm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are 7 AbilitySelections here:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BasicDragonForm()&lt;br /&gt;
AdvancedDragonForm(STR)&lt;br /&gt;
AdvancedDragonForm(INT)&lt;br /&gt;
AdvancedDragonForm(WIS)&lt;br /&gt;
AdvancedDragonForm(CON)&lt;br /&gt;
AdvancedDragonForm(DEX)&lt;br /&gt;
AdvancedDragonForm(CHA)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note I'm writing even MULT:NO stuff with a trailing set of () to try to distinguish the AbilitySelection from the Ability. The user never sees that thought process (it's internal to the code)&lt;br /&gt;
&lt;br /&gt;
There are many combinations of CNAS that are possible; they are not all articulated here.  (There are, at a minimum, 21 possible combinations.  3 natures for each of the 7 AbilitySelection items listed above assuming there are no child Category objects for the Ability... 7 more for each child category where these items could be selected [child categories only use NORMAL nature].)&lt;br /&gt;
&lt;br /&gt;
===Granting an Ability to a PC===&lt;br /&gt;
&lt;br /&gt;
Abilities are not directly granted due to their structure.  In order for an Ability (e.g. Feat) to be applied to a PC, it requires:&lt;br /&gt;
# A Category (either the parent Category or a child Category - in this case to indicate which &amp;quot;pool&amp;quot; is charged for taking the Ability)&lt;br /&gt;
# A Nature (Virtual, Automatic, Normal)&lt;br /&gt;
# The Ability itself&lt;br /&gt;
# Any Selection on the Ability.  The Selection is the result of a CHOOSE token being present on the Ability.  If no CHOOSE is present, the the selection is null, but still required to be present in order for an Ability to be applied to the PC.&lt;br /&gt;
&lt;br /&gt;
As much as this might make the data team's head hurt, at the end of the day a character can never have an Ability applied to the character. It's always a CNAS.  It's just a matter of how you get the full CNAS.&lt;br /&gt;
&lt;br /&gt;
Usually it starts with an AbilitySelection.  When combined with a specific Category and Nature, the AbilitySelection can be granted to a PC.  (a CNAS can be granted)&lt;br /&gt;
&lt;br /&gt;
===From the UI===&lt;br /&gt;
&lt;br /&gt;
Even when you select BasicDragonForm from an Ability Pool or the Feat screen or whatever, the system internally evaluates it's MULT:NO and expands it to BasicDragonForm() to get the AbilitySelection. When you select AdvancedDragonForm from a pool, the system evaluates that it's MULT:YES, determines there are multiple possible answers, and makes you pick before it has the AdvancedDragonForm(target stat).  &lt;br /&gt;
&lt;br /&gt;
Either way, you have generated an AbilitySelection.  The screen/pool you are in defines the Category, and the nature is inherently NORMAL for items selected in the UI - so the system can generate the full CNAS to be applied to the PC.  It's just that most of the work is transparent to the data team.&lt;br /&gt;
&lt;br /&gt;
===In LST Data===&lt;br /&gt;
&lt;br /&gt;
CHOOSE:ABILITY returns an Ability:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BasicDragonForm&lt;br /&gt;
AdvancedDragonForm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So at any point, I can select an Ability with that... but the only thing I can GRANT to a character (what ABILITY: does) is an AbilitySelection.&lt;br /&gt;
&lt;br /&gt;
Form of the Dragon II&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CHOOSE:ABILITYSELECTION|Special Ability|TYPE=DragonForm&lt;br /&gt;
ABILITY:Special Ability|AUTOMATIC|%CHOICE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This needs to be CHOOSE:ABILITYSELECTION and not CHOOSE:ABILITY because CHOOSE:ABILITY selects an ABILITY and ABILITY: applies a CNAS (so the %LIST must provide an ABILITYSELECTION).&lt;br /&gt;
&lt;br /&gt;
====An Example showing the subtlety====&lt;br /&gt;
&lt;br /&gt;
To understand the distinction, consider a Feat like Martial Weapon Proficiency.&lt;br /&gt;
&lt;br /&gt;
The Ability is Martial Weapon Proficiency.  This appeared in the LST file as an Ability.&lt;br /&gt;
Applying the first to a character is not meaningful (and reintroduces bugs we had with Martial Weapon Proficiency in the past that we fixed by introducing CHOOSE:FEATSELECTION).&lt;br /&gt;
&lt;br /&gt;
An AbilitySelection is Martial Weapon Proficiency (Longsword).  This was the result of the CHOOSE:ABILITYSELECTION and is the piece of information transferred from the CHOOSE to the ABILITY token&lt;br /&gt;
Applying the second might be possible, but would not know what pool to deduct the application from or where it should be displayed in the UI (or in what color)&lt;br /&gt;
&lt;br /&gt;
A CNAS is FEAT::NORMAL::Martial Weapon Proficiency (Longsword).  This was the result of combining the AbilitySelection with the other information provided in the ABILITY: token.&lt;br /&gt;
The last one (which is effectively generated from all the information provided to the ABILITY token) is grantable (because that's what the ABILITY token does).&lt;br /&gt;
&lt;br /&gt;
===A Countercase to using CHOOSE:ABILITY===&lt;br /&gt;
&lt;br /&gt;
From an older conversation on pcgen_experimental:&lt;br /&gt;
&lt;br /&gt;
The concern: If none of the abilities-of-interest have choosers within them (so they are like your BasicDragonForm example - in fact, they are BlackDragonForm, BlueDragonForm etc.), it's counterintuitive that I can't grant the ability from the CHOOSE:ABILITY result, as it seems a small leap to the non-coder from the ability BlackDragonForm to its abilityselection BlackDragonForm()!&lt;br /&gt;
&lt;br /&gt;
Let's walk through the scenarios:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CHOOSE:ABILITY|Special Ability|TYPE=DragonForm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume you start with all of the TYPE=DragonForm items being MULT:NO, so you can infer the AbilitySelection from the Ability. One could assert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ABILITY|Special Ability|AUTOMATIC|%LIST should work.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now someone comes along and adds a MULT:YES item. What do we do?&lt;br /&gt;
# Error on data load&lt;br /&gt;
# Don't let the CHOOSE:ABILITY present it&lt;br /&gt;
# Let the user select it, but it never gets applied to the PC.&lt;br /&gt;
&lt;br /&gt;
In case #1, the code needs to recognize that a catcher (%LIST) is asking for an AbilitySelection, and a thrower (CHOOSE) is producing an Ability. Then it needs to check for auto conversion. At each load, all items of that TYPE (or listed individually) need to be checked to ensure they are MULT:NO. So we've spent a bunch of time iterating across the data.&lt;br /&gt;
&lt;br /&gt;
Also, we can produce some nasty cases here. Imagine that a data monkey puts in &amp;quot;hollow&amp;quot; Abilities with only a DESC (which will happily take either Ability or AbilitySelection) to produce output in order to test their data. It has MULT:YES. The system will work with CHOOSE:ABILITY. They then go back and put in an ABILITY token to &amp;quot;do it for real&amp;quot; and the data breaks. Well, &amp;quot;obviously&amp;quot; that's a code problem (when in fact, they have changed what they are targeting).&lt;br /&gt;
&lt;br /&gt;
So this scenario is (a) costly to enforce (b) fragile [meaning it produces non-intuitive errors and small extensions (creating a new Ability) will cause errors to be reported on unrelated objects]&lt;br /&gt;
&lt;br /&gt;
Case #2 suffers from similar issues except that the checks are performed at runtime. If I ask for TYPE=DragonForm in CHOOSE:ABILITY, I expect it to be TYPE=DragonForm not &amp;quot;TYPE=DragonForm if and only if it's MULT:NO&amp;quot;. The latter to me is what I would refer to as &amp;quot;magic&amp;quot; and something I generally try to avoid.&lt;br /&gt;
&lt;br /&gt;
Case #3 also seems to suffer some nasty side effects. &amp;quot;I selected BasicDragonForm and it applies, but AdvancedDragonForm won't apply (and by the way, as part of your &amp;quot;code bug&amp;quot; it didn't provide me the ability to select my stat). I really don't want these &amp;quot;support calls&amp;quot; to the code team to fix things that aren't broken.&lt;br /&gt;
&lt;br /&gt;
So we are strict. When a CHOOSE produces an Ability, you can do something with an Ability, when a CHOOSE produces an AbilitySelection, you can do something with the AbilitySelection. We are getting to the point where we actually produce errors about that today if you try to target the wrong type. (Go try CHOOSE:STAT|ALL and FAVOREDCLASS:%LIST in a Template and see what happens... 6.0.0 will silently consume that data. 6.1.x-dev, not so much :) )&lt;br /&gt;
&lt;br /&gt;
===Another example using CHOOSE===&lt;br /&gt;
&lt;br /&gt;
Reviewing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ABILITY:FEAT|AUTOMATIC|%LIST wants to &amp;quot;catch&amp;quot; an AbilitySelection.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the model where parens indiate an AbilitySelection, this is attempting to catch something of the form:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
???(?!?)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the ?!? may be null in the case of MULT:NO, but there may be 2 unknowns.&lt;br /&gt;
&lt;br /&gt;
This case:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ABILITY:FEAT|AUTOMATIC|Weapon Proficiency (%LIST)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This wants to &amp;quot;catch&amp;quot;... well, we don't necessarily know without looking.&lt;br /&gt;
What we do know know is the Ability, it's called Weapon Proficiency.&lt;br /&gt;
So our AbilitySelection is effectively &amp;quot;Weapon Proficiency (?!?)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
What we need to fill in is a single unknown, the Selection.&lt;br /&gt;
&lt;br /&gt;
CHOOSE:WEAPONPROFICIENCY chooses a Weapon Proficiency. So we are &amp;quot;throwing&amp;quot; a Weapon Proficiency... but are we catching the right thing?&lt;br /&gt;
&lt;br /&gt;
What the code has to do is go peel back at the Feat Weapon Proficiency.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Weapon Proficiency &amp;lt;&amp;gt; MULT:YES &amp;lt;&amp;gt; CHOOSE:???|...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
??? had *better* be WEAPONPROFICIENCY, so that the &amp;quot;catcher&amp;quot; is catching the appropriate type. If not, an error should be thrown at data load.&lt;br /&gt;
&lt;br /&gt;
If the CHOOSE *does* match up, then effectively the ABILITY token in this case catches the Selection, plugs that into the Weapon Proficiency to produce Weapon Proficiency(known selection) [aka an AbilitySelection] and can grant that to the PC.&lt;br /&gt;
&lt;br /&gt;
So another way of looking at CHOOSE:ABILITY is that is answers one unknown: The Ability.&lt;br /&gt;
The CHOOSE:ABILITYSELECTION is actually a hybrid CHOOSE that (somewhere under the covers) answers two questions at once, effectively giving you the Ability and the Selection in one choice.&lt;br /&gt;
&lt;br /&gt;
=Pools=&lt;br /&gt;
&lt;br /&gt;
In some cases, numerical items are placed into pools.  Skills, and a few other items work this way.  This can be rather challenging when items are subsequently removed from a PC, since we don't necessarily associate which point added to a pool resulted in which item selected by the user.  We want to improve this awareness (and need to do so in order to resolve several bugs).&lt;br /&gt;
&lt;br /&gt;
Longer term, this is going to be a problem, as we will want to store those details, and the result is that the contents of the current PCG file format will be insufficient to rebuild a PC to the full internal state.  This transition will need to be managed carefully.&lt;br /&gt;
&lt;br /&gt;
=Old Storage=&lt;br /&gt;
&lt;br /&gt;
Traditionally, the metadata and implemenation of objects was mixed.  (Meaning it was very difficult to distinguish what a Race meant in the rules and what characteristics of that Race pertained to the actual active PlayerCharacter.  This behavior was facilitated by cloning of all of the objects before they were added to the PC.&lt;br /&gt;
&lt;br /&gt;
This resulted in a number of issues, including that the clone was not always complete, the clone was not always sufficiently deep to separate PCs from each other (so they didn't collide in updating internal objects), extra memory use and understanding of what was going on for new developers.&lt;br /&gt;
&lt;br /&gt;
A significant portion of the late 5.x series of releases separated the two sets of behaviors within PCGen.  However, Equipment still retains the full clone design due to the complexity of Equipment.  This means the Equipment object still has a significant number of internal methods and fields that contain the information about the equipment (both from the rules and reslated to the current PC).&lt;br /&gt;
&lt;br /&gt;
==Equipment and Heads==&lt;br /&gt;
&lt;br /&gt;
It is noted that one of the items that makes Equipment particularly difficult to deal with is the concept of &amp;quot;Primary&amp;quot; and &amp;quot;Secondary&amp;quot; Heads on Equipment.  We have instantiated these as separate objects (EquipmentHead) so that the items that are duplicated can be more easily managed, and to prepare for future expansion.&lt;br /&gt;
&lt;br /&gt;
This internal hierarchy has multiple sets of issues associated with it, including:&lt;br /&gt;
# MSRD and some other sets have a desire to have more than one additional component (so an arbitrary number of heads)&lt;br /&gt;
# This is a more difficult design to avoid cloning, since the depth of association required is much higher&lt;br /&gt;
&lt;br /&gt;
=Current Storage=&lt;br /&gt;
&lt;br /&gt;
For most other objects, the rules information has been separated from information related to any given PlayerCharacter.  &lt;br /&gt;
&lt;br /&gt;
The dynamic information related to a specific PlayerCharacter is now stored in a series of Facet objects (pcgen.cdom.facet).  &lt;br /&gt;
&lt;br /&gt;
==Facets==&lt;br /&gt;
&lt;br /&gt;
Simply stated, we called these &amp;quot;facets&amp;quot; because we started to run out of other words in the English language for &amp;quot;part&amp;quot; or &amp;quot;component&amp;quot; or &amp;quot;aspect&amp;quot; (since those words are all &amp;quot;loaded terms&amp;quot; when thinking about the rules we handle in PCGen). &lt;br /&gt;
&lt;br /&gt;
Facets are constructed by Spring, so that they are properly initialized.  Currently we do that through XML.  This is currently the only real &amp;quot;static&amp;quot; part of PCGen, thus the only part where we are using Spring to load classes.&lt;br /&gt;
&lt;br /&gt;
Each Facet is designed to be a rather simple service for a PlayerCharacter or for a loaded DataSet.&lt;br /&gt;
&lt;br /&gt;
===IDs===&lt;br /&gt;
&lt;br /&gt;
If storage is provided as part of that services, we store things based on a CharID (character ID), so that we are not using the very heavy-weight PlayerCharacter object as the key.  (The goal was to transition to a very small primary key, while slowly chipping away at the amount of &amp;quot;stuff&amp;quot; in &amp;quot;PlayerCharacter&amp;quot;).  Each Facet should provide one service (storing the Race, storing Skill Ranks, etc.)&lt;br /&gt;
&lt;br /&gt;
Each CharID is aware of it's &amp;quot;parent&amp;quot; DataSetID, so that if Data Set/Game Mode information is required from such a Facet, it can be easily accessed if the CharID is known.&lt;br /&gt;
&lt;br /&gt;
===DataSet Facets===&lt;br /&gt;
&lt;br /&gt;
A number of facets store information related to a particular Data Set - more like storing information about the Game Mode than about an individual PC.  When we encounter these types of information, we don't store it by the PC, we store it by the DataSet.  These all have a registration occur in their init() method that registers them with the DataSetInitializationFacet for a later callback when a Data Set is fully loaded.  This callback is one of the last steps in the [[Full Load Order Detail|Load Process]].&lt;br /&gt;
&lt;br /&gt;
===Copying===&lt;br /&gt;
&lt;br /&gt;
In addition to storage, each Facet is responsible for defining how it needs to copy information from one PlayerCharacter to another.  If, for example, it uses an internal structure for storage of complex sets of information, it will need to have a method that performs a proper deep-copy if a PC is cloned.  (Unfortunately, there is still something in the old-style output that requires a clone, so unfortunately, we have to be prepared to clone PCs).&lt;br /&gt;
&lt;br /&gt;
===Filters===&lt;br /&gt;
&lt;br /&gt;
Some facets only provide a filter service, meaning they are reducing items passed to a later Facet.  &lt;br /&gt;
&lt;br /&gt;
===Facet Chain===&lt;br /&gt;
&lt;br /&gt;
In many cases, the Facets provide a chain of services, each providing one simple service with others providing later processing, until we settle upon the information that is actually attached to the PC.  For the primary object types (Race, Templates, etc.), the items attached the PC settle into Facets within the &amp;quot;pcgen.cdom.facet.model&amp;quot; package.&lt;br /&gt;
&lt;br /&gt;
The reason there is a neeed Facet Chain is because of a number of characteristics of our current data.  These include (but are certainly not limited to):&lt;br /&gt;
# The possibility for Languages to be granted MANY different ways and wanting to ensure that they can only be removed from the PC the same way they were granted to the PC&lt;br /&gt;
# Need to process MULT:NO Abilities to avoid granting them from multiple locations&lt;br /&gt;
# Need to process STACK:NO Abilities to avoid granting the same choice from multiple locations&lt;br /&gt;
# Need to Handle multiple methods of spells being made avaialble to a PC.&lt;br /&gt;
&lt;br /&gt;
In general, this Facet chain is set up either in dependencies in the XML file defining the Spring configuration or in FacetInitialization.&lt;br /&gt;
&lt;br /&gt;
===Bridge Facets===&lt;br /&gt;
&lt;br /&gt;
Note that in some cases there are facets that perform certain services (and that link other facets in their init(), which are not otherwise called (meaning they would never activate if no one ever constructs them).  We call these &amp;quot;Bridge Facets&amp;quot; and explicitly contruct them once in the doBridges() method of FacetInitialization.&lt;br /&gt;
&lt;br /&gt;
===Priority===&lt;br /&gt;
&lt;br /&gt;
Note that there are a few situations where Facets need to learn of changes in a certain order, so a number of the Facets support a priority associated with a listener.&lt;br /&gt;
&lt;br /&gt;
===Equality===&lt;br /&gt;
&lt;br /&gt;
Note that many of the objects in PCGen have strange equality defined, and unfortunately, removing that equality causes bugs (so *something* is still depending on some best-practice violating equality methods).  To avoid false positives, many of the Facets use instance equality for comparison.  Some MUST do so in order to be able to properly process Equipment, MULT:YES items, etc.&lt;br /&gt;
&lt;br /&gt;
===Trailing PRExxx===&lt;br /&gt;
&lt;br /&gt;
Current/older granting tokens allow a trailing PRExxx token to appear on the grant.  This produces a number of challenges, including that any change to the PC results in a need to re-evaluate every trailing PRExxx to determine if it changed.  These items typically have an update(CharID) method, and you can see them called in the setDirty method of PlayerCharacter.  It is not the intent to support this type of behavior going forward, due to the significant difficulty and time required to process this form of logic.  (As clarity for those not involved in many of the parts of the formula rebuild: Yes, I get some things are conditional.  Yes, something needs to be able to conditionally grant.  No, you don't need a trailing PRExxx to accomplish those ends.  The full explanation of this is handled elsewhere).&lt;br /&gt;
&lt;br /&gt;
=New Storage/Granting=&lt;br /&gt;
&lt;br /&gt;
The Facet system in many cases is providing a simple item or list storage mechanism.  The new formula system inherently provides such storage as well, and can do so without separate classes required for each piece of storage.  Therefore, the strategic design is moving away from Facets and into storing items in the variable system.&lt;br /&gt;
&lt;br /&gt;
The system will effectively be able to grant certain variables.  This will start with Alignment.  For the moment, there will be a series of Facets that act as a transition, allowing a pull of certain variables from the new formula system and granting the contents of those variables to the PC.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Full_Load_Order_Detail&amp;diff=4256</id>
		<title>Full Load Order Detail</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Full_Load_Order_Detail&amp;diff=4256"/>
		<updated>2018-03-04T17:17:37Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is a more complete explanation of load processing beyond the simple literal Loader and Token processing.  This assumes that the GameModes have been loaded, and that a campaign is undergoing load.  That front-end process is described in the [[Rules Persistence System]] and the [[Load Commit Subsystem]].&lt;br /&gt;
&lt;br /&gt;
This deals with the full (and right now necessary) order of operations for loading that occurs after the persistence files are fully loaded from disk.  This describes what is happening in pcgen.persistence.SourceFileLoader.&lt;br /&gt;
# An internal Ability Object to handle the Bonus Languages is constructed.  This is used internally to help provide a foundation for the CHOOSE and other items necessary to support making the Bonus Language choices and granting those choices to the PC.&lt;br /&gt;
# Deferred Objects are constructed, if necessary.  These are items that are implied by the data, but where we have no specific construct in the data to force their construction (and forcing their construction at every reference would be hazardous).  Currently this is limited to CompanionList objects.&lt;br /&gt;
# Derived Objects are constructed.  This includes many of the skill and spell lists, which are implied by the existance of a PCClass, but for which no specific construct in the data forces their construction.  Note that we cannot do these &amp;quot;Live&amp;quot; with the Class construction, because a &amp;quot;KEY:&amp;quot; token which renamed the identifier of the PCClass would mean the identifier of the Derived Objects should be changed as well.  So it is currently only safe to derive these after load is complete (and it's actually easier this way).&lt;br /&gt;
# We ensure that all Ability Categories that are created are in some way used.&lt;br /&gt;
# Deferred Tokens are run.  Deferred Tokens are those that intend to process information on an object, but it needs to ensure that all items are loaded before the test or analysis is done.  Often this is some form of error checking, such as a FACT token that is REQUIRED:YES for a given FACT ensuring that all objects of a given Format have that FACT defined.  Deferred Tokens implement the DeferredToken interface.&lt;br /&gt;
# Any unresolved references are identified and UnconstrutedReference errors are thrown, if necessary.&lt;br /&gt;
# Any Post-Validation Tokens are run.  This includes items that implement PostValidationToken, and are items run across MULTIPLE OBJECTs.  These tokens are provided all objects of a given type.  This can validate things like &amp;quot;Is there only one SIZE with &amp;quot;DEFAULTSIZE:YES&amp;quot; which are impossible to answer looking one object at a time.&lt;br /&gt;
# Any Post-Deferred Tokens are run.  These tokens implement the PostDeferredToken interface, and require a fully validated dataset where CDOMReference objects are resolved before they are run.  This will do cross-token checks (such as MULT:YES and CHOOSE: travel together), but are only processing one object at a time.  As a note, if it is possible, the DeferredToken interface is preferable to the PostDeferredToken interface.&lt;br /&gt;
# We validate that the new formula system has a full set of defaults that can be resolved without external dependencies.  This has to be done post-resolution since a default (ALIGNMENT is None) might be an object, and we need that reference to have been filled before we test that the default can be properly processed without external dependencies.  (Meaning it needs to not have external dependencies AT RUNTIME, it is welcome to have a dependency on a part of the data which will be static at runtime).&lt;br /&gt;
# We validate that any reference where a choice was included (e.g. an Exotic Weapon Proficiency FEAT chooses a Weapon Proficiency)... this will detect if someone attempted to grant a CHOOSE including ability without a choice (or provided a choice to an Ability that didn't have a CHOOSE).&lt;br /&gt;
# Choices on EquipmentModifiers are processed to ensure they are correctly applied.&lt;br /&gt;
# We validate that all weapons have either TYPE:Melee or TYPE:Ranged&lt;br /&gt;
# We Auto Generate Equipment (if enabled)&lt;br /&gt;
# We initialize any Data Set Facets with required information about the loaded data.&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4255</id>
		<title>Index to Architecture Documents</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4255"/>
		<updated>2018-02-27T04:38:32Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: /* Loading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is effectively a &amp;quot;shorthand&amp;quot; list of documents (and a tiny bit of context around the links) for &amp;quot;A Day in the Life of PCGen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
&lt;br /&gt;
Before reading about the details of the PCGen architecture, it is likely helpful to understand our key [[Design Concepts for PCGen]] and [[Architecture Document Conventions]]&lt;br /&gt;
&lt;br /&gt;
=Loading=&lt;br /&gt;
&lt;br /&gt;
# The [[Startup System]] initializes PCGen and loads the initial user interface&lt;br /&gt;
# Files from Disk are loaded by the [[Rules Persistence System]]&lt;br /&gt;
# These files use [[CDOM References Concept Document|CDOM References]] to resolve order of operations conflicts during load and [[Referring to Groups in LST Data|Refer to Groups in LST Data]] to identify multiple possible objects (for say, a choice)&lt;br /&gt;
# The [[Load Commit Subsystem]] is used to commit information into the [[Rules Data Store]]&lt;br /&gt;
# Post Processing is completed as described in the [[Full Load Order Detail]]&lt;br /&gt;
&lt;br /&gt;
=Using Data=&lt;br /&gt;
&lt;br /&gt;
# When retrieving items from the Rules Data Store, it's important to [[Identifying Objects|Identify the right Object]]&lt;br /&gt;
&lt;br /&gt;
=Processing a PC=&lt;br /&gt;
&lt;br /&gt;
# After [[Adding items to the PC]], we begin [[Calculating Items on the PC]]&lt;br /&gt;
# This calculation heavily depends on the [[Formula Systems]]&lt;br /&gt;
# Some of the items on a PC can be conditional, so it's valuable to understand [[Prerequisites and Requirements]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
	<entry>
		<id>http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4254</id>
		<title>Index to Architecture Documents</title>
		<link rel="alternate" type="text/html" href="http://159.203.101.162/w/index.php?title=Index_to_Architecture_Documents&amp;diff=4254"/>
		<updated>2018-02-27T04:37:21Z</updated>

		<summary type="html">&lt;p&gt;Tom Parker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot;&lt;br /&gt;
  | __TOC__&lt;br /&gt;
  |}&lt;br /&gt;
&lt;br /&gt;
This is effectively a &amp;quot;shorthand&amp;quot; list of documents (and a tiny bit of context around the links) for &amp;quot;A Day in the Life of PCGen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=Resources=&lt;br /&gt;
&lt;br /&gt;
Before reading about the details of the PCGen architecture, it is likely helpful to understand our key [[Design Concepts for PCGen]] and [[Architecture Document Conventions]]&lt;br /&gt;
&lt;br /&gt;
=Loading=&lt;br /&gt;
&lt;br /&gt;
# The [[Startup System]] initializes PCGen and loads the initial user interface&lt;br /&gt;
# Files from Disk are loaded by the [[Rules Persistence System]]&lt;br /&gt;
# These files use [[CDOM References Concept Document|CDOM References]] to resolve order of operations conflicts during load&lt;br /&gt;
# The files also can [[Referring to Groups in LST Data|Refer to Groups in LST Data]] to identify multiple possible objects (for say, a choice)&lt;br /&gt;
# The [[Load Commit Subsystem]] is used to commit information into the [[Rules Data Store]]&lt;br /&gt;
# Post Processing is completed as described in the [[Full Load Order Detail]]&lt;br /&gt;
&lt;br /&gt;
=Using Data=&lt;br /&gt;
&lt;br /&gt;
# When retrieving items from the Rules Data Store, it's important to [[Identifying Objects|Identify the right Object]]&lt;br /&gt;
&lt;br /&gt;
=Processing a PC=&lt;br /&gt;
&lt;br /&gt;
# After [[Adding items to the PC]], we begin [[Calculating Items on the PC]]&lt;br /&gt;
# This calculation heavily depends on the [[Formula Systems]]&lt;br /&gt;
# Some of the items on a PC can be conditional, so it's valuable to understand [[Prerequisites and Requirements]]&lt;/div&gt;</summary>
		<author><name>Tom Parker</name></author>
		
	</entry>
</feed>