b90
* Miscellaneous
Altered a parsing routine to fall in line with how my parsing is intended to work these days. (Intention is: when matching containers, you can include a mis-matched paren or brace within quotes, or a mismatched paren inside braces, but can’t include any mismatched quotes anywhere. GCA’s older code is currently rather inconsistent as to when it’s honoring matching quotes, braces, parens, just two of those, or all three. I’m trying to fix that as I come across it.)
Added a new set of parsing routines that should simplify processing many of the keyword-clause based features.
Added Bonus Classes to Resynchronizing.
* Solver
Updated the GetItemVal routine, and the @ItemHasMod() function handling. Both should now support the ability to find a trait with various possible name extensions, using the base name and one of several special directives in place of a name extension: #any, #best, #worst. So, if you have several possible Flight advantages, but any one of them works just to say that you have Flight, you could use a reference like “SK:Flight (#any)” to find any of them.
The values work like this: #any will return the first valid non-zero trait with the given name; #best will return the best (highest non-zero); and #worst will return the worst (lowest non-zero). Note that #best and #worst can be tricky, and should be used cautiously, as results may not be as expected in all cases, depending on what tag or value you’re looking for.
Notes: The intention here is to allow for accepting variations of a trait via name extensions. Only numeric values can be judged.
Also updated the GetItemTextVal routine. Should be smarter about duplicate and inactive items now, and support #any, #best, #worst; although because it returns text, there’s no good way to determine best or worst, and it therefore treats all of them as #any, where any non-empty value satisfies the request.
* Bonuses
Reworked the routine in the Bonus object that converts the given bonus text into the proper bonus data. This uses the new parsing routines, which means we can now allow for any of the different clauses to be used in any order within the text; just the actual bonus part needs to be listed first, as before. For example, you could now use
gives(+2 to “SK:Acrobatics” when “on Earth” listas “native gravity bonus” upto 4 onlyif target::points > 0)
or you could use
gives(+2 to “SK:Acrobatics” onlyif target::points > 0 listas “native gravity bonus” upto 4 when “on Earth”)
and either should work correctly and without issue.
Note: spaces around the keywords aren’t required any more, except for the ” to ” and ” from ” keywords in the basic bonus block, but you must enclose other blocks in quotes or braces if they might include any of the other keywords: “onlyif”, “unless”, “listas”, “class”, “upto”, “when”. GCA will strip the containers after parsing. (Yes, parsing should now honor braces as well as quotes as containers for these clauses.)
* Bonus Classes
BonusClasses exist to provide rules for limiting bonuses from defined “classes” of bonuses. Bonuses include themselves in a BonusClass, and the rules for the classes are defined in the data files. Support is specific and limited at this time, but allows for limiting the total bonus levels applied from a class of bonuses to an item, or might prevent stacking, and so forth. At this time, Bonus Classes are applied only to addition/subtraction bonuses (whether variable or static) affecting only points or levels.
To include a bonus in a particular BonusClass, just use the “class” keyword and specify the name or names of the classes to which it should belong after that (in quotes/braces if needed) within the bonus text. It might look like this:
gives(+1 to “SK:Acrobatics” upto 4 class “Talents, Acrobatics”)
That would include the bonus as a member of the classes “Talents” and “Acrobatics”.
Here’s how you define BonusClasses in the data files:
[BonusClasses]
ClassName, [ { affects | appliesto } { levels | points }] [ stacks { yes | no } ][ upto X ][ downto Y ][ best A ][ worst B ]
X, Y, A, and B can be expressions, and they’ll be sent to the Solver, but you can’t use me:: references because Bonus Classes aren’t tagged items.
Affects and AppliesTo (one word!) are synonyms, use the one you’re comfortable with, but don’t use both. Affects Levels means the class applies to bonus levels only. Affects Points means the class applies to bonus points only. The default is Affects Levels, so that’s what will happen if the Affects clause isn’t specified.
Stacks specifies if multiple bonuses from the same class can apply. Stacks Yes is the default behavior in GCA for all bonuses. Stacks No means only 1 bonus from the class will be allowed (usually the best one, unless you also specify Worst 1).
Upto specifies an upper limit on the total bonus value that may be applied by all bonuses in the class. If exceeded, GCA will create an Adjustment to apply, which will correct for the excess value. If Affects Points, do *not* include “pts” in the value.
Downto specifies a lower limit on the total bonus value that may be applied by all bonuses in the class. If exceeded, GCA will create an Adjustment to apply, which will correct for the excess value. If Affects Points, do *not* include “pts” in the value.
Best specifies the maximum number of bonuses that may be applied, and that the highest values upto that number should be used.
Worst specifies the maximum number of bonuses that may be applied, and that the lowest values upto that number should be used.
For example:
[BonusClasses]
Talents, stacks yes upto 4 best 2
Acrobatics, stacks no worst 1
The Talents class allows stacking as usual, but limits the total bonus from Talents to 4, and only allows the best 2 bonuses (which, if totaling over 4, will have an adjustment created so that the net bonus is 4).
The Acrobatics class doesn’t allow bonuses to stack, and only wants the worst possible non-zero bonus to apply. Rough.
Notes: This can get conceptually confusing. Remember that any particular bonus will only be applied *once*, no matter the number of classes to which it belongs. If a bonus is excluded for any reason by any BonusClass rule, it will not be applied *at all* regardless of how many other classes it might belong to that didn’t exclude it.