Difference between revisions of "CHOOSE Token Proposal for 6.0"

From PCGen Wiki
Jump to: navigation, search
Line 135: Line 135:
 
CHOOSE:SKILLLIST|LIST --> CHOOSE:SKILL|ALL<br>
 
CHOOSE:SKILLLIST|LIST --> CHOOSE:SKILL|ALL<br>
 
CHOOSE:FEAT=Weapon Focus --> CHOOSE:WEAPONPROF|FEAT=WeaponFocus<br>
 
CHOOSE:FEAT=Weapon Focus --> CHOOSE:WEAPONPROF|FEAT=WeaponFocus<br>
CHOOSE:STAT|STR --> CHOOSE:PCSTAT|REMOVE[STR]
+
CHOOSE:STAT|STR --> CHOOSE:PCSTAT|INW|WIS|DEX|CON|CHA
  
 
==Non-PObject CHOOSERS==
 
==Non-PObject CHOOSERS==

Revision as of 23:14, 22 March 2009

Background

The current CHOOSE system has a few challenges that I would like to eliminate for PCGen 6.0. In particular:

  1. It is inconsistent. "PC" is occasionally used for what is granted to a PC, other items use "LIST" for the same meaning. This makes it impossible to share code and still be able to "unparse" the choose back to the LST format.
  2. It is incomplete. There are base objects that cannot be chosen (such as CHOOSE:DEITY, CHOOSE:CLASS)
  3. It is even more incomplete. There are combinations (ANY, Granted, Unique, Qualified) that are possible in some tokens, but not others
  4. It is not type safe (everything is stored as a String)

Thus, in order to head off a ton of additional CHOOSE function being required through coding, I would like to propose a complete rebuild of the CHOOSE system for PCGen 6.0 into a standardized format.

Here are the goals:

  1. Any primitive PObject must be able to be chosen
  2. Any type safe constants must be able to be chosen
  3. Any primitive PObject must be selectable if it (1) exists, (2) is granted to the PC (3) The PC is qualified for it OR (4) If the PC is qualified and doesn't already have it

Proposed format for CHOOSE in PCGen 6.0

CHOOSE will have two sets of syntax: One set will be for those items that do NOT require clarification to establish identity. For example, Classes. The second will be for those that DO require clarification to establish identify. For example, Ability (which requires CATEGORY). In all of the examples below, there will be a GROUPING item, but that is ONLY required for a small subset of CHOOSE items (to be explained later).

Note also in this syntax that <primitive> refers to a direct name, such as "Fighter" for a Class.

The general structure of CHOOSE will be:

CHOOSE:[NUMCHOICES=m|]SUBTOKEN|GROUPING|LIST

I'm going to leave out the NUMCHOICES to keep the syntax below simple, but they are legal on all PObject CHOOSERs

PObject CHOOSERS

These are valid calls for CHOOSE for all PObject CHOOSE SUBTOKENs (ABILITY, FEAT, DEITY, DOMAIN, EQUIPMENT, EQMOD, CLASS, RACE, SKILL, SPELL, TEMPLATE, STAT, WEAPONPROF, ARMORPROF, SHIELDPROF)

CHOOSE:SUBTOKEN|GROUPING|ALL
CHOOSE:SUBTOKEN|GROUPING|PC
CHOOSE:SUBTOKEN|GROUPING|QUALIFIED
CHOOSE:SUBTOKEN|GROUPING|UNIQUE
CHOOSE:SUBTOKEN|GROUPING|TYPE=x.x
CHOOSE:SUBTOKEN|GROUPING|<primitive>
CHOOSE:SUBTOKEN|GROUPING|POBJECT=<primitive>

Note: The last syntax POBJECT=<primitive> does not actually use "POBJECT", instead it is replaced by a POBJECT identifier, such as "FEAT".

These can be combined, given typical restrictions on not combining items with "ALL" (because that doesn't make sense)

In addition, each of these items can be additionally qualified (since it is beneficial to select items of TYPE=x that are granted to the PC). This is done by placing the restriction to the qualifier in brackets. !TYPE is legal, e.g.:

CHOOSE:SUBTOKEN|GROUPING|ALL[!TYPE=x.x]
CHOOSE:SUBTOKEN|GROUPING|PC[TYPE=x|<primitive>]
CHOOSE:SUBTOKEN|GROUPING|QUALIFIED[TYPE=x|<primitive>]
CHOOSE:SUBTOKEN|GROUPING|UNIQUE[TYPE=x|<primitive>]

In addition , is used as AND and | as or in the brackets, so

CHOOSE:SUBTOKEN|GROUPING|PC[TYPE=x,!TYPE=y]

Would choose from the items granted to the PC that ARE type x AND are NOT type y

By combining these, one can presumably create very flexible choosers, e.g.:

CHOOSE:SUBTOKEN|GROUPING|PC[TYPE=x|<primitive1>|<primitive2>|<primitive3>]|QUALIFIED[!TYPE=y,TYPE=z|<primitive4>]

(To the code monkeys, yes this sucks to parse because | can appear inside the brackets - I think the flexibility is worth it, though I'm open to other syntax... e.g. is ; useful at all??? )

GROUPING CHOOSEers

There is only one PObject tokens that requires a GROUPING: Ability. All other PObject choosers do not have a GROUPING (To clarify, if the GROUPING is not requried, then there is only one | that separates SUBTOKEN from the list items, see the examples below if you are confused)

For Ability, the GROUPING is [using regular expressions]:

CATEGORY=(ANY|x[,x]*)[;NATURE=y[,y]*]

This says:

  1. CATEGORY is requried, nature is optional.
  2. Nature muse be specific (NATURE=ALL is the default if NATURE is not specified).
  3. More than one CATEGORY or NATURE can be specified, comma separated.

Thus, the following are legal GROUPINGs for Abilities:

CATEGORY=ANY
CATEGORY=x,x
CATEGORY=ANY;NATURE=x,x
CATEGORY=x;NATURE=y

Presumably, we should to RANK<n, RANK<=n, RANK>n and RANK>=n (with the understanding that today's RANK=n actually means RANK>=n)

Additional LIST items

Some CHOOSE tokens demand additional list items to maintain current function. The following are valid LIST items

  • Domain: Allows DEITY=x ... as a primitive (like TYPE=x or y) [can be placed in [] after an a qualifier like PC or UNIQUE]
  • Deity: Allows PANTHEON=x ... as a primitive (like TYPE=x or y) [can be placed in [] after an a qualifier like PC or UNIQUE]
  • Deity: Allows ALIGNMENT=x ... as a primitive (like TYPE=x or y) [can be placed in [] after an a qualifier like PC or UNIQUE] (refers to the Deity's Alignment)
  • Spell: Allows CLASSLIST=x or DOMAINLIST=x

//DO NOT ASK ME TO SHORTEN THIS TO CLASS= or LIST=//. There is GOOD reason for this choice that echoes to other parts of CDOM/6.0

  • Stat: Allows REMOVE[x,x] as a qualifier (INSTEAD of PC, UNIQUE, QUALIFIED)

There is a small potential to make this global, BUT, it MUST be understood that CHOOSE is fundamentally ORDER INDEPENDENT and IS AN OR FUNCTION, thus the REMOVE could not be usefully used with other items in most cases. For more complex CHOOSE items, see the end of this proposal.

Additional LIST items for Skills:

There are few additional qualifiers here (these are items in addition to PC, QUALIFIED, etc):

CLASS
!CLASS
CROSSCLASS
!CROSSCLASS
EXCLUSIVE
!EXCLUSIVE
NORANK
RANK=n

Additional LIST items for Proficiecy items

This includes ARMORPROF, SHIELDPROF, WEAPONPROF

Allows EQUIPMENT as a qualifier in addition to PC, UNIQUE, etc. Allows WIELD=x as a primitive ONLY inside of the EQUIPMENT qualifier (in addition to TYPE=x or <primitive>, still valid inside of EQUIPMENT)

Examples

So here are a few examples of how CHOOSE changes:

CHOOSE:ARMORTYPE --> CHOOSE:ARMORPROF|PC
CHOOSE:CCSKILLLIST --> CHOOSE:SKILL|CROSSCLASS
CHOOSE:CCSKILLLIST|x,x --> CHOOSE:SKILL|CROSSCLASS[x,x]
CHOOSE:CSKILLS --> CHOOSE:SKILL|CLASS
CHOOSE:DOMAIN|DEITY=x --> CHOOSE:DOMAIN|DEITY=x
CHOOSE:EQUIPTYPE|x --> CHOOSE:EQUIPMENT|TYPE=x
CHOOSE:NONCLASSSKILLLIST|LIST --> CHOOSE:SKILL|!CLASS|PC
CHOOSE:PROFICIENCY|ARMOR|PC|x --> CHOOSE:ARMORPROF|PC[x]
CHOOSE:SKILLLIST|LIST --> CHOOSE:SKILL|ALL
CHOOSE:FEAT=Weapon Focus --> CHOOSE:WEAPONPROF|FEAT=WeaponFocus
CHOOSE:STAT|STR --> CHOOSE:PCSTAT|INW|WIS|DEX|CON|CHA

Non-PObject CHOOSERS

There are a few choosers (in particular CHOOSE:SCHOOLS) that are NOT PObject choosers. Therefore:

CHOOSE:NUMBER remains unchanged. CHOOSE:STRING (to be put into 5.14) remains unchanged. CHOOSE:USERINPUT remains unchanged

Many Type Safe constants can be chosen, using the syntax:

CHOOSE:SUBTOKEN CHOOSE:SUBTOKEN|REMOVE[x,x]

Examples

CHOOSE:SCHOOLS --> CHOOSE:SPELLSCHOOL

Examples of New Stuff:

CHOOSE:SPELLDESCRIPTOR
CHOOSE:REGION
CHOOSE:ABILITYCATEGORY
CHOOSE:ABILITYNATURE
CHOOSE:GENDER

Situations not handled

There are two situations that I know are not handled by this syntax change, both are in CHOOSE:WEAPONPROFS

These are Spellcaster.x and Size.x

While SPELLCASTER.x actually is present in our datasets, it refers to a WEAPONPROF that does not exist, and therefore is a Data bug and should be removed.

SIZE.x does not appear in our data.

I have a solution for these, but it is a bit complicated. I *can* convert from the 5.x syntax, so I am *not* dropping function, I just would prefer to wait for another day to explain the exact details of how it works (pretty complicated in an of itself)...

Actual Proposals

CHOOSE:PCSTAT

SUBTOKEN: PCSTAT (new)
SUBTOKEN: STAT (deprecated by this proposal)

Reason for deprecation: The Challenge with the existing CHOOSE:STAT is that it is negative. Meaning, CHOOSE:STAT|STR means to allow a choice of any STAT except STR. This seems a bit weird, and I would like to get away from this.

Syntax

CHOOSE:PCSTAT|x|x

x is a PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications.

In the case of PCStat objects, the only valid PRIMITIVES are the three global PRIMITIVES:

x = a Stat abbreviation (STR, INT, etc.)
x = TYPE.x (a TYPE identifier for a Stat) - note that none of our STATs actually use TYPE: but this works anyway :)
x = ALL (allow the choice of any STAT)

Since we can easily add other things later (at least a lot easier than the old CHOOSE system), I would like to start simple on this one. :)

Conversion

CHOOSE:STAT
becomes
CHOOSE:PCSTAT|ALL

CHOOSE:STAT|STR
becomes
CHOOSE:PCSTAT|INT|WIS|DEX|CON|CHA

Note that this latter replacement is "deterministic" as the Stats can only be defined in the Game Mode.

CHOOSE:ARMORPROFICIENCY

SUBTOKEN: ARMORPROFICIENCY (new)
SUBTOKEN: ARMORPROF (deprecated by this proposal)

Reason for deprecation: The Challenge with the existing CHOOSE:ARMORPROF is that it is based on equipment. Meaning, CHOOSE:ARMORPROF|TYPE=Foo means to allow a choice of any ArmorProf that is used in a PROFICIENCY:ARMOR|x token on a piece of Equipment of TYPE=Foo. This is counter to the long-term plan for CHOOSE tokens, and I would like to get away from this.

Syntax

CHOOSE:ARMORPROFICIENCY|x|x,y[z,z]|y[z,z],y[z,z]

x is an ArmorProf PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications. In the case of ArmorProf objects, the only valid PRIMITIVES are the three global PRIMITIVES:

x = an ArmorProf (specified by key)
x = TYPE.x (a TYPE identifier for an ArmorProf) - note that none of our ArmorProfs actually use TYPE: but this works anyway :)
x = ALL (allow the choice of any ArmorProf)

y is a QUALIFIER

A QUALIFIER is a special keyword that identifies a subset of objects that should be returned. Valid qualifiers for ArmorProf objects are the global qualifiers:

ANY: This means any item in the brackets should be returned (this is implied, so that CHOOSE:ARMORPROFICIENCY|Foo,TYPE=Bar is equivalent to CHOOSE:ARMORPROFICIENCY|ANY[Foo,TYPE=Bar]

PC: This means any ArmorProf which has been granted to the PC by AUTO:ARMORPROF. If the AUTO:ARMORPROF token has an ARMORTYPE= argument, then that *will* be resolved to include ArmorProf objects of that type. In other words if AND ONLY IF the PC has AUTO:ARMORPROF|ARMORTYPE=Foo ... then CHOOSE:ARMORPROFICIENCY|PC[ALL] is equivalent to CHOOSE:ARMORPROFICIENCY|EQUIPMENT[TYPE=Foo]

!PC: This means any ArmorProf which has NOT been granted to the PC by AUTO:ARMORPROF. If the AUTO:ARMORPROF token has an ARMORTYPE= argument, then that *will* be resolved to include ArmorProf objects of that type.

QUALIFIED: This means any ArmorProf for which the PC qualifies. (Generally since our ArmorProf objects don't have PRExxx associated with them, this is a useless qualifier)

in the above cases, z is an ArmorProf PRIMITIVE (see above)

An additional "local" QUALIFIER specific to ArmorProf objects is also available:

EQUIPMENT: If this is used then the parameters in z are evaluated. Once the equipment identified by the z parameters is summarized, the equipment is queried to determine the ArmorProf objects as identified by their PROFICIENCY:ARMOR tokens. These ArmorProf objects are then added to the items that can be selected.

In this case, z is an Equipment PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications. In the case of Equipment objects, there only valid PRIMITIVES are the three global primitives:

z = a piece of Equipment (specified by key)
z = TYPE.z (a TYPE identifier for Equipment)
z = ALL (use any Equipment)

Note that for a QUALIFIER, ALL is the implied PRIMITIVE, so:

CHOOSE:ARMORPROFICIENCY|EQUIPMENT[ALL]
is equivalent to
CHOOSE:ARMORPROFICIENCY|EQUIPMENT


A comma represents "AND", meaning multiple items are evaluated independently and then any item that appears in ALL of the items is added to the list.

CHOOSE:ARMORPROF|Chainmail,Field Plate
will result in NO choices because no ArmorProf is both Chainmail and Field Plate.

CHOOSE:ARMORPROF|TYPE=Foo,EQUIPMENT[TYPE=Bar]
would test for any ArmorProf that has the Foo type (as defined in the ArmorProf LST file) which is ALSO the proficiency for an Equipment that has the TYPE Bar (as defined in the Equipment LST file)

A pipe represents "OR", meaning multiple items are evaluated independently and then any item that appears in any of the items is added to the list:

CHOOSE:ARMORPROF|Chainmail|Field Plate

All commas (ANDs) are evaluated before pipes (ORs), so something like:

CHOOSE:ARMORPROF|Chainmail|TYPE=Foo,EQUIPMENT[TYPE=Bar]
would include Chainmail unconditionally, in addition to any ArmorProf that has the Foo type (as defined in the ArmorProf LST file) which is ALSO the proficiency for an Equipment that has the TYPE Bar (as defined in the Equipment LST file)

Conversion

CHOOSE:ARMORPROF|Chainmail
becomes
CHOOSE:ARMORPROFICIENCY|EQUIPMENT[Chainmail]

CHOOSE:ARMORPROF|ALL
becomes
CHOOSE:ARMORPROFICIENCY|EQUIPMENT[ALL]

CHOOSE:SHIELDPROFICIENCY

SUBTOKEN: SHIELDPROFICIENCY (new)
SUBTOKEN: SHIELDPROF (deprecated by this proposal)

Reason for deprecation: The Challenge with the existing CHOOSE:SHIELDPROF is that it is based on equipment. Meaning, CHOOSE:SHIELDPROF|TYPE=Foo means to allow a choice of any ShieldProf that is used in a PROFICIENCY:SHIELD|x token on a piece of Equipment of TYPE=Foo. This is counter to the long-term plan for CHOOSE tokens, and I would like to get away from this.

Syntax

CHOOSE:SHIELDPROFICIENCY|x,y[z,z]|y[z,z],y[z,z]

x is an ShieldProf PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications. In the case of ShieldProf objects, the only valid PRIMITIVES are the three global PRIMITIVES:

x = an ShieldProf (specified by key)
x = TYPE.x (a TYPE identifier for an ShieldProf) - note that none of our ShieldProfs actually use TYPE: but this works anyway :)
x = ALL (allow the choice of any ShieldProf)

y is a QUALIFIER

A QUALIFIER is a special keyword that identifies a subset of objects that should be returned. Valid qualifiers for ShieldProf objects are the global qualifiers:

ANY: This means any item in the brackets should be returned (this is implied, so that CHOOSE:SHIELDPROFICIENCY|Foo,TYPE=Bar is equivalent to CHOOSE:SHIELDPROFICIENCY|ANY[Foo,TYPE=Bar]

PC: This means any ShieldProf which has been granted to the PC by AUTO:SHIELDPROF. If the AUTO:SHIELDPROF token has an SHIELDTYPE= argument, then that *will* be resolved to include ShieldProf objects of that type. In other words if AND ONLY IF the PC has AUTO:SHIELDPROF|SHIELDTYPE=Foo ... then CHOOSE:SHIELDPROFICIENCY|PC[ALL] is equivalent to CHOOSE:SHIELDPROFICIENCY|EQUIPMENT[TYPE=Foo]

!PC: This means any ShieldProf which has NOT been granted to the PC by AUTO:SHIELDPROF. If the AUTO:SHIELDPROF token has an SHIELDTYPE= argument, then that *will* be resolved to include ShieldProf objects of that type.

QUALIFIED: This means any ShieldProf for which the PC qualifies. (Generally since our ShieldProf objects don't have PRExxx associated with them, this is a useless qualifier)

in the above cases, z is an ShieldProf PRIMITIVE (see above)

An additional "local" QUALIFIER specific to ShieldProf objects is also available:

EQUIPMENT: If this is used then the parameters in z are evaluated. Once the equipment identified by the z parameters is summarized, the equipment is queried to determine the ShieldProf objects as identified by their PROFICIENCY:SHIELD tokens. These ShieldProf objects are then added to the items that can be selected.

In this case, z is an Equipment PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications. In the case of Equipment objects, there only valid PRIMITIVES are the three global primitives:

z = a piece of Equipment (specified by key)
z = TYPE.z (a TYPE identifier for Equipment)
z = ALL (use any Equipment)

Note that for a QUALIFIER, ALL is the implied PRIMITIVE, so:

CHOOSE:SHIELDPROFICIENCY|EQUIPMENT[ALL]
is equivalent to
CHOOSE:SHIELDPROFICIENCY|EQUIPMENT


A comma represents "AND", meaning multiple items are evaluated independently and then any item that appears in ALL of the items is added to the list.

CHOOSE:SHIELDPROF|Chainmail,Field Plate
will result in NO choices because no ShieldProf is both Chainmail and Field Plate.

CHOOSE:SHIELDPROF|TYPE=Foo,EQUIPMENT[TYPE=Bar]
would test for any ShieldProf that has the Foo type (as defined in the ShieldProf LST file) which is ALSO the proficiency for an Equipment that has the TYPE Bar (as defined in the Equipment LST file)

A pipe represents "OR", meaning multiple items are evaluated independently and then any item that appears in any of the items is added to the list:

CHOOSE:SHIELDPROF|Chainmail|Field Plate

All commas (ANDs) are evaluated before pipes (ORs), so something like:

CHOOSE:SHIELDPROF|Chainmail|TYPE=Foo,EQUIPMENT[TYPE=Bar]
would include Chainmail unconditionally, in addition to any ShieldProf that has the Foo type (as defined in the ShieldProf LST file) which is ALSO the proficiency for an Equipment that has the TYPE Bar (as defined in the Equipment LST file)


Conversion

CHOOSE:SHIELDPROF|Chainmail
becomes
CHOOSE:SHIELDPROFICIENCY|EQUIPMENT[Chainmail]

CHOOSE:SHIELDPROF|ALL
becomes
CHOOSE:SHIELDPROFICIENCY|EQUIPMENT[ALL]

CHOOSE:DOMAIN

SUBTOKEN: DOMAIN (unchanged)

Syntax

CHOOSE:DOMAIN|x,y[z,z]

x is an Domain PRIMITIVE

A PRIMITIVE is an identifier of objects, and may include any number of specifications. In the case of Domain objects, there are are the three global PRIMITIVES:

x = an Domain (specified by key)
x = TYPE.x (a TYPE identifier for an Domain)
x = ALL (allow the choice of any Domain)

There is also one Domain specific PRIMITIVE:

DEITY = Domains allowed by the Deity

y is a QUALIFIER

A QUALIFIER is a special keyword that identifies a subset of objects that should be returned. Valid qualifiers for Domain objects are the global qualifiers:

ANY: This means any item in the brackets should be returned (this is implied, so that CHOOSE:DOMAIN|Foo,TYPE=Bar is equivalent to CHOOSE:DOMAIN|ANY[Foo,TYPE=Bar]

PC: This means any Domain which has already been taken by the PlayerCharacter.

!PC: This means any Domain which has NOT already been taken by the PlayerCharacter.

QUALIFIED: This means any Domain for which the PC qualifies (meets the PRExxx on the Domain or has QUALIFY:DOMAIN|x for that Domain)

Note that for a QUALIFIER, ALL is the implied PRIMITIVE, so:

CHOOSE:DOMAIN|PC[ALL]
is equivalent to
CHOOSE:DOMAIN|PC


A comma represents "AND", meaning multiple items are evaluated independently and then any item that appears in ALL of the items is added to the list.

CHOOSE:DOMAIN|Fire,War

will result in NO choices because no Domain is both Fire and War.

CHOOSE:DOMAIN|TYPE=Foo,PC
would test for any Domain that has the Foo type (as defined in the Domain LST file) which is ALSO already selected by the PlayerCharacter

This could also be written (probably more clearly):
CHOOSE:DOMAIN|PC[TYPE=Foo]


A pipe represents "OR", meaning multiple items are evaluated independently and then any item that appears in any of the items is added to the list:

CHOOSE:DOMAIN|Fire|War

All commas (ANDs) are evaluated before pipes (ORs), so something like:

CHOOSE:DOMAIN|War|TYPE=Foo,PC
would include War unconditionally, in addition to any Domain that has the Foo type (as defined in the Domain LST file) which is ALSO already selected by the PlayerCharacter

Specific Case

ARGUMENT: QUALIFY

This is the only situation where the existing syntax of CHOOSE:DOMAIN will change. QUALIFY currently is a compound behavior, which is performing two tests: - Is the PC qualified for the Domain (equivalent of the QUALIFIER QUALIFIED) - Has the PC taken this Domain (equivalent of the QUALIFIER !PC)

QUALIFY is therefore named in a way that may not be completely clear, and can easily be replaced by two qualifiers joined with a comma (AND):

QUALIFIED,!PC

Conversion

CHOOSE:DOMAIN|War,Fire
remains unchanged

CHOOSE:DOMAIN|QUALIFY (this currently provides any Domain which the PC is qualified for and hasn't yet taken)
becomes
CHOOSE:DOMAIN|QUALIFIED,!PC