Difference between revisions of "Formula Parser Conversion - Data"

From PCGen Wiki
Jump to: navigation, search
(Conversion Process Ideas)
Line 751: Line 751:
  
 
Tom has some ideas, but needs to discuss the ramifications with the development team.
 
Tom has some ideas, but needs to discuss the ramifications with the development team.
 +
 +
 +
 +
 +
=== Log Discussion for Non-Stacking modifiers interaction with SKILL / SKILLSIT ===
 +
 +
* Tom[Arch_SB]: Making up something new for the moment
 +
* DEFAULTVARIABLEVALUE:NONSTACKING|0
 +
* VARTYPEDEF:NONSTACKING|NONSTACKINGBONUS
 +
* LOCAL:ALL|NONSTACKINGBONUS|Trait
 +
* (and this is on the fly, so don't try to remember or quote me on this later as being set or coherent in any way)
 +
* @Andrew[Chair]: concepts and brainstorm sessions are like that... Nothing is set in stone.
 +
* Tom[Arch_SB]:
 +
* MyTrait <> MODIFYOTHER:SKILL|Foo|Trait|APPLY|1
 +
* MyTrait.MOD <> MODIFYOTHER:SKILLSIT|Foo (Bar)|Trait|APPLY|2
 +
* MODIFYOTHER:SKILLSIT|ALL|Trait|APPLY|parent()
 +
* the last in the global file
 +
* APPLY as a modifier knows Trait is a NONSTACKINGBONUS
 +
* APPLY then performing the stacking rules
 +
* in the case of NONSTACKINGBONUS that is the equivalent of MAX
 +
* in the semiequivalent case of STACKINGBONUS it's ADD
 +
* @Andrew[Chair]: Okay, you lost me...
 +
* Tom[Arch_SB]: so "Trait" starts its life with value zero
 +
* @Andrew[Chair]: A bunch of new concepts packed in tightly...
 +
* Okay Trait = 0
 +
* Tom[Arch_SB]: since the default value for any NONSTACKING is zero as per the default variable value line
 +
* @Andrew[Chair]: Correct
 +
* Tom[Arch_SB]: Trait is local to all objects that was caused by the
 +
* LOCAL:ALL|NONSTACKINGBONUS|Trait
 +
* so Foo as a skill has a local variable Trait then in MyTrait, we modified Trait on the skill to be 1
 +
* MODIFYOTHER:SKILL|Foo|Trait|APPLY|1
 +
* we also modified via the .MOD, the Trait on the Situation to be 2
 +
* MODIFYOTHER:SKILLSIT|Foo (Bar)|Trait|APPLY|2
 +
* globally we modified Trait on the situation to be equivalent to the parent
 +
* MODIFYOTHER:SKILLSIT|ALL|Trait|APPLY|parent()
 +
* thus if we didn't have the APPLY|2 it would be 1
 +
* since the parent (the skill foo)has Trait of 1
 +
* follow?
 +
* @Andrew[Chair]: Is APPLY a new Function? And is parent() a new function?
 +
* Tom[Arch_SB]: yes
 +
* things I'm creating on the fly
 +
* parent() is referring to the var on the skill (when used for a situation)
 +
* @Andrew[Chair]: Okay, then yes. Now I'm following. Takes a bit, I've been learning pseudo-code algorithms in class
 +
* Tom[Arch_SB]: APPLY is equivalent to MAX if the underlying object is non-stacking
 +
* would be equivalent to ADD if the underlying object is stacking
 +
* just trying to give you guys ONE way to spell it out, with the ability elsewhere to declare stacking vs non stacking
 +
* that way you don't have to be concerned about which one it is when you are writing the modify
 +
* like you don't have to worry about it today with BONUS
 +
* @Andrew[Chair]: Cool. But not set in stone ;) - Mark is available. You able to chat on GTalk?
 +
* Tom[Arch_SB]: that would take a bit
 +
* @Andrew[Chair]: okay.
 +
* Tom[Arch_SB]:
 +
* MODIFYOTHER:SKILL|ALL|Rank|Add|asnumber(Trait)
 +
* MODIFYOTHER:SKILLSIT|ALL|Rank|ADD|asnumber(Trait)
 +
* @Andrew[Chair]: Eh?
 +
* Tom[Arch_SB]: Trait is a NONSTACKINGBONUS
 +
* not a VAR
 +
* Rank is a (local) VAR
 +
* presumably
 +
* need to convert Trait to a VAR
 +
* which is actually a NUMBER
 +
* hence asnumber(Trait)
 +
* basically strips off the fact that it's non-stacking in this case
 +
* and just returns the value
 +
* @Andrew[Chair]: Gotcha.
 +
* Tom[Arch_SB]: ok, this authentication thing isn't going to happen tonight
 +
* haven't had to authenticate an app before and too much reading
 +
* @Andrew[Chair]: no worries, Mark hasn't popped online for me the big issues left for the conversion:
 +
* 1) Apply Luck bonus boost to ALL existing Luck bonuses
 +
* Tom[Arch_SB]: have you seen my latest note to _Exp?
 +
* @Andrew[Chair]: something you mentioned in your last email
 +
* Tom[Arch_SB]: ok, I THINK that answers it
 +
* What I'd like to know is how you guys are doing the bauble thing today
 +
* @Andrew[Chair]: And the AC discussion... Periods were mentioned as legal in the wiki, is that no longer the case?
 +
* Tom[Arch_SB]: if you can't get a bonus from a type of object more than once
 +
* @Andrew[Chair]: Bauble thing caught me off-guard. Today, if you put on three, you'd have a +3 bonus.
 +
* that's a tricky sneaky rule I wasn't aware of till today.
 +
* Tom[Arch_SB]: you are correct, period is legal as per the wiki
 +
* my bad
 +
* @Andrew[Chair]: Oh, Mark just popped on
 +
* Distant_Scholar: Typically, you can't get more than one of the same ability/feat/object anyway. How many objects would this apply to?
 +
* @Andrew[Chair]: Items
 +
* Tom[Arch_SB]: two identical rings for example would cause the issue
 +
* @Andrew[Chair]: Say an equipment without slots or two rings, yes
 +
* Tom[Arch_SB]: So today you'd probably just create a TYPE = localto that object?
 +
* TYPE=FooRingStuff
 +
* on the BONUS?
 +
* Distant_Scholar: Ah. To my eyes, the simplest "fix" would be to make up a new type. (Tom beat me to it.)
 +
* @Andrew[Chair]: pretty much
 +
* if I was made aware of it, I would have done something like that, yes
 +
* sounds like items will need those "types" to manage...
 +
* mjmeans: ok
 +
* hi
 +
* Tom[Arch_SB]: Hi Mark
 +
* @Andrew[Chair]: Yay!
 +
* Hi Mark
 +
* mjmeans: Dont worry about the fate's favored ability. It isn't possible with the current system either.
 +
* Tom[Arch_SB]: do you think my example work work though?
 +
* mjmeans: for fate's favores? no
 +
* Tom[Arch_SB]: why not?
 +
* mjmeans: consider a pc with one ability that gives a luck bonus to intimidate, one equipment that gives a luck bonus to AC and a eqmod that gives a luck bonus to shield.
 +
* There is no way a single modify would identify and add 1 luck to each and every one of those luck bonuses
 +
* Tom[Arch_SB]: oh, I get the question now
 +
* so it's actually based on the TYPE=
 +
* mjmeans: it's an array formuls that is required for that solution
 +
* Tom[Arch_SB]: that you are triggering off of
 +
* mjmeans: yeah. that's why the current JEP can't do it either
 +
* Tom[Arch_SB]: so one question
 +
* if you have a luck bonus to intimidate from item a and a luck bonus to intimidate from item b, each are 1. is the result 3 or 4?
 +
* mjmeans: i think there are more pressing concens than this one trait, so lets work on the regular issues with stacking.
 +
* Tom[Arch_SB]: well, I have a solution that may do both
 +
* so let's spend a few more moments on this
 +
* mjmeans: ok.. so i'll restate the issue with luck then
 +
* with expected results
 +
* PC has Ability_1 that gives a +2 luck bonus to intimidate.
 +
* PC has 1 equipment item that gives a +1 luck bonus to AC.
 +
* PC has a spell that grants +1 luck bonus to AC, Attacks and saves. Got it so far?
 +
* Tom[Arch_SB]: y
 +
* mjmeans: So at this point (without the fate's favored trait) the PC has a total +2 luck bonus to intimidate, +1 luck bonus to AC, attacks and damage. The equipment and the spell both provide a +1 luck bonus to AC but they don't stack. Okay so far?
 +
* Tom[Arch_SB]: y
 +
* mjmeans: So now fate's favor is applied. each of the various luck bonuses go up by 1, but the net effect is the PC has +3 luck bonus to intimidate, and +2 to AC, attacks and damage.
 +
* Tom[Arch_SB]: k
 +
* mjmeans: Now consider that a luck bonus could apply to any skill or conditional skill, of which there are are least 100.
 +
* Tom[Arch_SB]: understand
 +
* my question was an order of ops issue
 +
* but because it doesn't stack it's moot
 +
* because max (1,1)+1 is the same as max (1+1,1+1)
 +
* mjmeans: To make fate's favored work, one method is to .MOD each existing item or ability or spell that is known to have a luck bonus, to add an additional 1 if the PC has fate's favoreed.
 +
* Tom[Arch_SB]: I think that' s a mess
 +
* mjmeans: But that is prone to error.
 +
* Tom[Arch_SB]: we need better
 +
* so let's leave that aside for a moment
 +
* mjmeans: Another method might be is there is a way to query the AC total to "know" if a luck bonus was applied and then apply 1 more if fate's favored. A smaller list to be sure, but still hundreds. And each SKILLSIT would still have to be .MODed since they are never added into any total.
 +
* Tom[Arch_SB]: still bad
 +
* I have better
 +
* mjmeans: right
 +
* Tom[Arch_SB]: So let's talk about the variable system as it's proposed
 +
* right now, there are some default types built into the system
 +
* One of those is NUMBER
 +
* In the variable proposal
 +
* every game mode will have to provide a default value:
 +
* '''DEFAULTVARIABLEVALUE:NUMBER|0'''
 +
* We can then define different types of numbers
 +
* think of these as local scopes in a way
 +
* '''VARTYPEDEF:NUMBER|VAR'''
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: so any time we create a new VAR, it takes on the characteristics of NUMBER, including the default value of zero
 +
* '''GLOBAL:VAR|GlobalVariable'''
 +
* so GlobalVariable has a default value of zero
 +
* mjmeans: ok
 +
* next?
 +
* Tom[Arch_SB]: So NUMBER has the quirk, as you've pointed out, that with the operations we have, such as MAX and ADD, that if we use NUMBER for BONUSES (either as a VAR or as another type of NUMBER)
 +
* ...then we end up with a problem of locality of knowledge
 +
* meaning the BONUS type of Luck was defined in a book on page 2 for example
 +
* and was said to be non-stacking
 +
* mjmeans: right
 +
* Tom[Arch_SB]: then it was used on pages 25-30 in variables thingies
 +
* whatever they were
 +
* so as a thought exercise, let's define a new type, let's call it NONSTACKING
 +
* '''DEVAULTVARIABLEVALUE:NONSTACKING|0'''
 +
* '''VARTYPEDEF:NONSTACKING|NSBONUS'''
 +
* '''LOCAL:ALL|NSBONUS|Luck'''
 +
* every object is given a local variable (type is NSBONUS/NONSTACKING) called Luck'
 +
* mjmeans: So all items get a Local Luck variable?
 +
* Tom[Arch_SB]: yes
 +
* defaulting of course to zero
 +
* mjmeans: so we have armor and shield. each one has a local Luck variable. Got it.
 +
* @Andrew[Chair]: and skills and spells, etc.
 +
* mjmeans: Now let's consider a +1 luck bonus to armor and a +1 luck bonus to shield and the PC has fate's favored.
 +
* Tom[Arch_SB]: hold on
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: wait
 +
* let's not go there yet
 +
* By the way
 +
* This is a bit of brainstorming
 +
* so it may end up more verbose than necessary
 +
* and I may backtrack here and there
 +
* mjmeans: just remember that if the the luck bonus is 0 it gets no benefit from fate's favored.
 +
* "Whenever you are under the effect of a luck bonus of any kind, that bonus increases by 1."
 +
* Tom[Arch_SB]: that's the easy part :D
 +
* mjmeans: do go on
 +
* @Andrew[Chair]: All, I have to head off... be back in 30...
 +
* mjmeans: BCNU
 +
* Tom[Arch_SB]: (thinking)
 +
* this is likely to be too verbose, but it should function
 +
* '''GLOBAL:NSBONUS|LuckBonus'''
 +
* mjmeans: or LOCAL:ALL?
 +
* Tom[Arch_SB]: global
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: I need to summarize the local Lucks somewhere
 +
* mjmeans: Too bad there isn't a LOCAL:MODIFY|ALL|GLOBAL.Luck|ADD|Luck
 +
* a pseudo array forumula
 +
* Tom[Arch_SB]: There is: '''MODIFYOTHER:ALL|ALL|LuckBonus|ADD|Luck'''
 +
* mjmeans: Where the scope of the left argument is a global and the right argument is a local?
 +
* Tom[Arch_SB]: used once in the global file
 +
* local variables can't match the name of a global var
 +
* the data load would fail
 +
* mjmeans: that's bad
 +
* Tom[Arch_SB]: so the scope is directly known from the name
 +
* why is it bad
 +
* it's enormously confusing to have "Luck" in two places
 +
* these aren't programmers we're talking about that do the data
 +
* mjmeans: So then from a data standpoint, all global variables should follow an obvious naming scheme that will help keep them separate
 +
* Tom[Arch_SB]: That's a data team thing
 +
* I don't think that's necessary
 +
* mjmeans: Are variable type sensitive?
 +
* Tom[Arch_SB]: meaning what?
 +
* mjmeans: i.e. gFoo is a different variable than GFOO
 +
* like java or c++... case sensitive
 +
* Tom[Arch_SB]: not case sensitive
 +
* mjmeans: ick
 +
* Tom[Arch_SB]: it's a side effect of LST load
 +
* the files were always loaded in as all CAPS as part of the load process
 +
* that's the history we have
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: actually my MODIFYOTHER was wrong
 +
* because ADD would make them stack as it wer
 +
* *were
 +
* should be: '''MODIFYOTHER:ALL|ALL|LuckBonus|APPLY|Luck'''
 +
* '''APPLY''' is new for NONSTACKING and effectively acts as MAX
 +
* mjmeans: So let's get back to the LOCAL:ALL|NSBONUS|Luck... Luck to what? Some items will give Luck to AC, others will give Luck to a skill, others will give differing Luck to multiple skills or saves.
 +
* Tom[Arch_SB]: argh you're right
 +
* mjmeans: Consider AC only. So we use LOCAL:ALL|NSBONUS|LuckBonusToAC. Then on any item, ability or spell that gives a luck bonus to AC, it will SET it's local variable. SOmewhere else that is totaled back to a TotalACLuckBonus variable which is then totaled into the TotalAC variable reported on the OS.
 +
* So now we have NxN bonuses added to every item, spell or ability
 +
* Tom[Arch_SB]: except they are lazily instantiated, so they aren't really there if they aren't used
 +
* mjmeans: Well, N1 x N2... where N1 is the number of types, and N2 is the number of object because each object cannot stack with itself.
 +
* N2 is HUGE
 +
* Tom[Arch_SB]: let's ignore the bauble thing for the moment
 +
* mjmeans: ok
 +
* For the simple case of types, there are about 20 types in Pathfinder.
 +
* Tom[Arch_SB]: one clarification
 +
* you woudlnt' SET the LuckBonusToAC
 +
* you'd APPLY it
 +
* that way if there was a later .MOD that was a different value it would take the max
 +
* in the case of nonstacking
 +
* mjmeans: So at the very least we have LOCAL:ALL|NSBONUS|XBonusToY where X is the type of bonus and Y is AC, or STR, or a skill, etc.
 +
* As an exercise, let's start with a simpler case, but complex enough. The spell Divine Favor "you gain a +1 luck bonus on attack and weapon damage rolls for every three caster levels you have (at least +1, maximum +3)."
 +
* Tom[Arch_SB]: let's step back for a moment
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: I don't like X*Y even as you show it
 +
* If we were doing this in Java or C# or whatever
 +
* mjmeans: I dont like it either, but is there another way?
 +
* Tom[Arch_SB]: how would we accumulate it
 +
* we have some object that has a type and a value
 +
* call that class Bonus
 +
* mjmeans: If this was C# or Java, each spell, item or ability would be an Class in and of itself with shared and local variables
 +
* Tom[Arch_SB]: Luck:1, Luck:2 whatever
 +
* put on the constraint that each spell has no local or global variables
 +
* and design it that way :)
 +
* mjmeans: We'd use a singleton to handle the "not stacking with itself" behaviour
 +
* Tom[Arch_SB]: or assume you are using a visitor pattern to extract data from the list of objects
 +
* that's probably the better description of the scenario
 +
* mjmeans: I've never herd of a "visitor" pattern.
 +
* Tom[Arch_SB]: ok
 +
* let's do this then
 +
* mjmeans: but, ,yes, accessing data from a list of object, which each contain a list of bonuses
 +
* that;s back to an array formula
 +
* Tom[Arch_SB]: so we have a spell an an ability and a ring
 +
* to keep it simple
 +
* mjmeans: ok
 +
* Tom[Arch_SB]: each has a few bonuses
 +
* since we can .MOD items from different LST files
 +
* we have to assume the spell could have Luck for AC:1 and Luck for AC:2
 +
* so the order of ops has to be:
 +
* grab the list for object n
 +
* do a local consolidation (non stacking in this case)
 +
* then add that list to the global list
 +
* then do a global consolidation
 +
* right?
 +
* is the local one necessary?
 +
* mjmeans: yes
 +
* for luck's favor yes, but otherwise, maybe not
 +
* Tom[Arch_SB]: each bonus has 3 pieces of info
 +
* type, whereto apply and a value
 +
* mjmeans: if global consolidation is "per total", and you have the ability ti query "was there a non-0 luck bonus, then add 1" then global consolidation would work for fate's favored.
 +
* Tom[Arch_SB]: k
 +
* mjmeans: but back to the single spell, item and ability
 +
* assuming the bastard fate's favored is not the ability
 +
* Tom[Arch_SB]: '''MODIFY:ACBonus|APPLY|Luck: 1'''
 +
* mjmeans: So the item, spell and ability would simply APPLY to a GLOBAL variable that it should apply to.
 +
* Tom[Arch_SB]: ACBonus is a global NSBONUS
 +
* (I've changed NSBONUS a bit from what we were doing before)
 +
* mjmeans: I don't see "Luck:1" as a legal syntax in the current examples on the wiki
 +
* Tom[Arch_SB]: hehe
 +
* It's not
 +
* but the formula system can do some neat stuff :)
 +
* here's the key thing
 +
* when you have something like ''MODIFY:ACBonus|APPLY|Luck: 1'''
 +
* ACBonus is specific
 +
* mjmeans: AC is going to be totaled with each type of bonus separately because it gets reported on the OS as separate totals
 +
* Tom[Arch_SB]: it knows that is an NSBONUS
 +
* let's come back to that
 +
* and that NSBONUS is a NONSTACKINGBONUS
 +
* APPLY is made legal for the type of NONSTACKINGBONUS
 +
* and APPLY is taught to parse it's argument as expecting '''"TYPE:numeric VALUE"'''
 +
* mjmeans: once you finish your current train of through, let me know. I have a different question...
 +
* Tom[Arch_SB]: that way the type and value travel together
 +
* mjmeans: okay... good
 +
* Tom[Arch_SB]: and that way we can apply stacking
 +
* mjmeans: a vector number (or complex number)
 +
* Tom[Arch_SB]: effectively
 +
* mjmeans: That's one of my suggestions to Andrew
 +
* Tom[Arch_SB]: the framework for that is already in place
 +
* the system is actually fairly flexible
 +
* I can do (and have sample code that supports):
 +
* '''VARTYPEDEF:LIST|MyList'''
 +
* @Andrew[Chair]: Back
 +
* Tom[Arch_SB]:
 +
* '''MODIFY:MyList|ADD|4'''
 +
* MODIFY:MyList|ADD|5
 +
* and MyList is now [4, 5]
 +
* that isn't exposed right now
 +
* and I probably won't support that in the first release
 +
* but the power is there if we need it
 +
* (and there are places it will be useful)
 +
* so anyway, we create the type:value
 +
* and put it into AC
 +
* I think I've finished my thought, so what was your question
 +
* mjmeans: So MODIFY:MyList|ADD|Luck:4 MODIFY:MyList|ADD|Shield:5 becomes { [4,Luck], [5,Shield] } ?
 +
* Tom[Arch_SB]: give or take some complexities I've left out
 +
* MyList would need to have the underlying type predefined
 +
* so you can't mix and match a VAR with a NONSTACKING
 +
* for example
 +
* mjmeans: My different question is... why in the world did you decide to use key words for ADD MULTIPLY, whatever rather than just using arythmatic operators... "variable = {equation}"
 +
* Tom[Arch_SB]: speed
 +
* mjmeans: x+=1 for ADD
 +
* Tom[Arch_SB]: launching a formula system to interpret value()+4 is about 10,000 times more expensive than knowing I need to add 1
 +
* mjmeans: y = m*x+b normal formula
 +
* precompiling +=1 to static is simple and only needs to be done once
 +
* Tom[Arch_SB]: it is conceptually simple
 +
* it takes a lot of code to do that though
 +
* mjmeans: In fact the assembly language INC and DEC ops exist because they are in fact much faster than ADD x,1
 +
* But compilers will always identify statics and optimize them for you.
 +
* Tom[Arch_SB]: but these aren't in code
 +
* they are in files we load
 +
* mjmeans: So you can code ADD x,1 and the compiler will automatically replace that with INC x.
 +
* Tom[Arch_SB]: and we aren't doing a compile of them in the java sense
 +
* walk through the process
 +
* we have an LST file
 +
* mjmeans: So it's beyond the scope of the formula parser to PCode the formulas, then?
 +
* Tom[Arch_SB]: it has '''MODIFY:Foo|SOLVE|value()+1'''
 +
* When this project was started, I submitted code to the project that took a formula and *literally* compiled it into bytecode
 +
* that would have made this pretty moot as then the JIT compiler could do whatever it needed to do
 +
* that was deemed too complex and the decision was made to leave the formula in a tree format and solve from there for easier debugging and understanding by new developers
 +
* mjmeans: ok
 +
* well each formula is currently stored in a string somewhere. right?
 +
* Tom[Arch_SB]: no
 +
* when you have something like value()+1 it's turned into a parse tree
 +
* there is a + object with 2 children
 +
* value() and 1
 +
* value is actually a formula object with 2 children
 +
* sorry value() is a formula object with 2 children
 +
* value (a formula name) and an argument child that has zero children
 +
* Distant_Scholar: Sorry to interrupt, but I have to go for today. I'll want to get a transcript later; this is interesting stuff. G'night.
 +
* Tom[Arch_SB]: night
 +
* I have to quit in about 10 anyway
 +
* that make sense Mark?
 +
* @Andrew[Chair]: I will log it, minus the chit chat part.... ;)
 +
* mjmeans: what are the two children of value() nothing is specified in the aparens?
 +
* Tom[Arch_SB]: yes, the function is split into the function name and a node representing the parens that has the arguments (that would be in the parens in some cases) as children
 +
* that allows us to just look at the function name node to look up the code that runs that function
 +
* and hand it the array of children
 +
* in the case of if(a>4,5,b)
 +
* mjmeans: so parent node is "function" and two children are "function" and "parameterlist"?
 +
* Tom[Arch_SB]: the two children would be "if" and "()" and the children of "()" would be ">", "5", and "b", and the children of ">" would be "a" and "4"
 +
* mjmeans: sorry, lag.. .didn't mean you if example, your previous example where you said function() had two children
 +
* So function() becomes parent "Formula" with children "function" and "parameterlist" ?
 +
* Tom[Arch_SB]: so there is a node that represents the total "value()" [I forget what this node is actually called - function perhaps?]... it has children of "value" [the type is a string, but is interpreted as a function name since it's the child of the node type above that I can't remember] and "()" [an otherwise empty node that is interpreted as arguments since it's part of a function].
 +
* so yes, basically you are correct in your last statement
 +
* have you ever used lex or yacc?
 +
* mjmeans: So let me try to describe how I'm seeing this, if this is right... MODIFY:Foo|SOLVE|if(a>4,5,b) -> {Foo, SOLVE, {function {if, {a, >, b}, 5, b}}}
 +
* Tom[Arch_SB]: not quite
 +
* When modify is struck by the LST parser, it is decomposed
 +
* It knows Foo is to be modified, and it validates that Foo is legal in that context (if Foo is local to equipment and in a spell, expect an error)
 +
* it then looks at the second arg for the modification type in this case SOLVE
 +
* that is looked up against the type of Foo, in this case NUMBER
 +
* the SOLVE code in Java is then passed "if(a>4,5,b)" as a String
 +
* then the String passed into SOLVE is broken up into the tree as described
 +
* if you hit ADD instead of SOLVE, it knows the argument must only be a decimal number (can't be a formula) so it can just call Double.valueOf(inputString)
 +
* and store the double for direct addition later on
 +
* rather than needing a tree
 +
* that help?
 +
* mjmeans: So you would never MODIFY:Foo|ADD|if(a>b,4,5)
 +
* Tom[Arch_SB]: that would cause an LST load error
 +
* mjmeans: because rith righ operand is a formula
 +
* Tom[Arch_SB]: correct
 +
* and ADD requires something that is effectively interpret-able as a Double
 +
* mjmeans: And in the case MODIFY:Foo|SOLVE|Foo+5
 +
* Tom[Arch_SB]: "Foo+5" is passed to the parser, which generates a tree
 +
* mjmeans: the LST load does not see that as equivalent to ADD 5?
 +
* Tom[Arch_SB]: and the tree is interpreted at runtime to calculate
 +
* they are mathematically equivalent
 +
* but the SOLVE always triggers a tree
 +
* optimizing that call to detect equivalents is more code to write, maintain, test
 +
* mjmeans: Okay, so LST load hass areas where loading optimization can be applied behind the scenes, but that's not relevant at this early stage.
 +
* Tom[Arch_SB]: it could be improved, certainly, at the cost of time
 +
* I have not tried to do that optimization since I want to get the basics running to get out of the other issues we have
 +
* mjmeans: So back to nonstacking types... Do we have a xolution that is not X*Y variable names?
 +
* Tom[Arch_SB]: yes, remember the type:value setup
 +
* mjmeans: Using the concept Luck:1 (or whatever?
 +
* Tom[Arch_SB]: but I actually need to run
 +
* mjmeans: okay. greate chat
 +
* Tom[Arch_SB]: so we can pick this up later
 +
* mjmeans: yes
 +
* @Andrew[Chair]: Later Tom.
 +
* Tom[Arch_SB]: yes, thanks, I appreciate someone poking at this to make it better
 +
* mjmeans: BCNU
 +
* @Andrew[Chair]: Did you get all your major questions answered? I briefly skimmed the stuff I missed
 +
* mjmeans: it's still alittle foggy because the concept has talked about where we can use Luck:1 as a vector (or complex) number is not desribed in the docs yet.
 +
* @Andrew[Chair]: Yes, since he's brainstorming a lot of it.
 +
* mjmeans: It still doesn't address the issue of an item not stacking with other instances of itself. One question he has was, does the existing DATA support that. And I dont know. Should be easy ehough to test though
 +
* @Andrew[Chair]: No, Bauble +1 and Bauble +1 would give +2
 +
* mjmeans: That's a problem
 +
* @Andrew[Chair]: untyped bonuses stack, and the data/system doesn't equate the non-stack of same source.
 +
* mjmeans: But the current DATA *could* support it by always adding |TYPE:itemname
 +
* @Andrew[Chair]: The work around is to place a unique type on those items. yes

Revision as of 07:09, 9 December 2014


Proposed Changes

Based off of examples and discussion ideas from Formula_Parser_Equip_Vars_Proposal and Formula_Parser_Equip_Vars_Demo

  • NOTE: All syntax here is in planning stages, nothing is FINALIZED!
  • NOTATION:
  • X = Numerical Value appropriate for variable
  • N = Name as appropriate

New formula system MUST support PRExxx, the alternative is additional Ability objects with PRExxx tags to trigger the Formula. Performance would definitely take a hit.


Thought for attacks:

  • ATTACKS controls how many attacks are available.
  • We have a local 'ATTACKS' for equipment
  • We have a Global 'ATTACKS.Total'
  • MODIFYOTHER:ATTACKS|SOLVE|ATTACKS.Total
  • In our global file we have: MODIFY:ATTACKS.Total|SOLVE|1+min((BASEAB-1)/5,3)
  • This grants first attack, and then the pattern +1 at 6, +2 at 11, +3 at 16
  • Next, since we need fine control over attack bonuses, we set this up:
  • TOHIT.Base, TOHIT.2, TOHIT.3, TOHIT.4, TOHIT.5, etc. (Assume all base PCs should have 5 values - this accounts for 4 attacks from high BAB, and +1 for a speed/haste effect
  • MODIFYOTHER:TOHIT.Base|SOLVE|value()+TOHIT.Total
  • MODIFYOTHER:TOHIT.2|SOLVE|value()+TOHIT.Base|PREVARGTEQ:ATTACKS,2
  • MODIFYOTHER:TOHIT.3|SOLVE|value()+TOHIT.Base|PREVARGTEQ:ATTACKS,3
  • MODIFYOTHER:TOHIT.4|SOLVE|value()+TOHIT.Base|PREVARGTEQ:ATTACKS,4
  • MODIFYOTHER:TOHIT.2|SUBTRACT|5|PREVARGTEQ:ATTACKS,2
  • MODIFYOTHER:TOHIT.3|SUBTRACT|10|PREVARGTEQ:ATTACKS,3
  • MODIFYOTHER:TOHIT.4|SUBTRACT|15|PREVARGTEQ:ATTACKS,4


Now, that handles standard attacks.

For Flurry of Blows:

  • MODIFY:ATTACKS|SOLVE|MonkBAB-1/3 -> This sets us to have more attacks for the Flurry

Next we want to set up the Flurry Attack Values

  • MODIFY:FlurryAttackTotal|SOLVE|value()+TOHIT.Total-2
  • MODIFY:TOHIT.1|SOLVE|value()+FlurryAttackTotal
  • MODIFY:TOHIT.2|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,2
  • MODIFY:TOHIT.3|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,3
  • MODIFY:TOHIT.4|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,4
  • MODIFY:TOHIT.5|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,5
  • MODIFY:TOHIT.6|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,6
  • MODIFY:TOHIT.7|SOLVE|value()+TOHIT.1|PREVARGTEQ:ATTACKS,7

That gives us up to seven attacks, all set at the initial to hit value of attack #1. We can then designate each attack to have a decreased value from the initial value.

  • MODIFY:TOHIT.3|SUBTRACT|2

Attack value assumed 20, Number of attacks set to 5, display would be +20/+20/+18/+20/+20

With this thought process, we need to devise a method that can do such things as Haste or Speed

  • Items which typically add an additional attack at the highest value


Standard Tokens

HANDS:x

  • Defined as "HANDS"
  • Set by MODIFY:HANDS|SET|x

LEGS:x

  • Defined as "LEGS"
  • Set by MODIFY:LEGS|SET|x

FACE:x

  • Defined as "FACE"
  • Set by MODIFY:FACE|SET|x,x
  • NOTE: This is an AREA not a VAR, hence the syntax expression allowed is "x,x"; oddly enough, I am curious how this value will be altered. NOTE FOR TOM!

MOVE:x,y,x,y (x = being valid movement modes such as Walk, Fly, Burrow, Climb, Swim; y = value)

  • Defined as the movement mode name "WALK", "FLY", etc.
  • Set by MODIFY:MOVE.n|SET|x

CR:x

  • Defined as "CR"
  • Set by MODIFY:CR|SET|x
  • Special Consideration as CR has other system mechanic implications handled in the gamemode.

CL:x (CLASS ONLY Token)

  • Defined as "CL"
  • Set by MODIFY:CL|SOLVE|thisclass()

SR:x (Since this typically comes in two race flavors 5+Level, or 11+Level, we can set this up via ability)

  • Defined as "SR"
  • Set by MODIFY:SR|SOLVE|x

CT: (CASTINGTHRESHOLD)

  • Defined as "CT"
  • Set by MODIFY:CT|ADD|x

Special Considerations

FOLLOWERS:x|y - has BONUS:FOLLOWERS|x|y - conversion will require the "y" be a variable

  • Set as "FOLLOWER.n"

ABILITYCATEGORY - has POOL. This should be set "POOL.n"

HD:x - probably be altered to "HD.n" to allow the bonus replacement

HITDIE:x (Three variations - CLASS alters the HD it's located on - use "HD.n", Race/Template alters all granted HD)

MOVEBASE - this should be used exclusively on race or attached if the base.

  • Set "MOVEBASE.n" with n being a valid movement value

BONUS:KNOWN

mastervar() - this needs to be ported over as this function is crucial; we should also get one back 'companionvar()' if possible.

MAXLEVEL:x -

XTRAFEATS:x - DEPRECATE (Can be replicated by BONUS:ABILITYPOOL|FEAT|x, and MODIFY:POOL.FEAT|ADD|x)

MOVECLONE:x,x,y - DEPRECATE (Can be replicated better by MODIFY:MOVE.n2|SOLVE|max(MOVE.n1*2,30)

NONPP:x

  • Set with "NONPP" - Replace Gamemode tag for that.

STARTSKILLPTS:x - replace with local var?

TEMPBONUS??? - Very special consideration!!!

WT:x (Ties into a JIRA for robot armor)

  • Set with "WT"

WIELD:x - need to evaluate due to this going away:

  • EQSIZEPENALTY:35 Size Penalty
  • BONUS:WEAPON|TOHIT|(PC.SIZE.INT-EQUIP.SIZE.INT)*-2|PREVARGT:PC.SIZE.INT,EQUIP.SIZE.INT|!PRETYPE:2,Melee,Natural|!PRETYPE:1,NoAttackPenalty|TYPE=DifferentEQSizePenalty
  • BONUS:WEAPON|TOHIT|(EQUIP.SIZE.INT-PC.SIZE.INT)*-2|PREVARGT:EQUIP.SIZE.INT,PC.SIZE.INT|!PRETYPE:2,Melee,Natural|!PRETYPE:1,NoAttackPenalty|TYPE=DifferentEQSizePenalty * BONUS:WEAPON|TOHIT|SizeIncrease*2|PREVARGT:PC.SIZE.INT,EQUIP.SIZE.INT|!PRETYPE:2,Melee,Natural|PREVARGTEQ:SizeIncrease,1 * BONUS:WEAPON|TOHIT|SizeDecrease*2|PREVARGT:EQUIP.SIZE.INT,PC.SIZE.INT|!PRETYPE:2,Melee,Natural|PREVARGTEQ:SizeDecrease,1 * BONUS:WEAPON|TOHIT|2|PREVARGT:EQUIP.SIZE.INT,PC.SIZE.INT|!PRETYPE:2,Melee,Natural|PREABILITY:1,CATEGORY=Special Ability,Oversized Weapon
  • BONUS:WEAPON|TOHIT|min(OversizeWeaponToHitBonus,((EQUIP.SIZE.INT-PC.SIZE.INT)*2))|PREVARGT:EQUIP.SIZE.INT,PC.SIZE.INT|!PRETYPE:2,Melee,Natural

And this:

WIELDCATEGORY:Light HANDS:1 FINESSABLE:Yes SIZEDIFF:-1 DAMAGEMULT:1=1,2=1 WIELDCATEGORY:OneHanded HANDS:1 SIZEDIFF:0 DAMAGEMULT:1=1,2=1.5 WIELDCATEGORY:TwoHanded HANDS:2 SIZEDIFF:1 DAMAGEMULT:2=1.5 WIELDCATEGORY:TooSmall HANDS:999 WIELDCATEGORY:TooLarge HANDS:999 WIELDCATEGORY:Unusable HANDS:999 WIELDCATEGORY:None HANDS:0

  • Light weapon vs PC size changes

WIELDCATEGORY:Light PREVARLTEQ:EQUIP.SIZE.INT,PC.SIZE.INT-1 SWITCH:TooSmall WIELDCATEGORY:Light PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT+1 SWITCH:OneHanded WIELDCATEGORY:Light PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT+2 SWITCH:TwoHanded WIELDCATEGORY:Light PREVARGTEQ:EQUIP.SIZE.INT,PC.SIZE.INT+3 SWITCH:TooLarge

  • OneHanded weapon vs PC size changes

WIELDCATEGORY:OneHanded PREVARLTEQ:EQUIP.SIZE.INT,PC.SIZE.INT-2 SWITCH:TooSmall WIELDCATEGORY:OneHanded PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT-1 SWITCH:Light WIELDCATEGORY:OneHanded PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT+1 SWITCH:TwoHanded WIELDCATEGORY:OneHanded PREVARGTEQ:EQUIP.SIZE.INT,PC.SIZE.INT+2 SWITCH:TooLarge

  • TwoHanded weapon vs PC size changes

WIELDCATEGORY:TwoHanded PREVARLTEQ:EQUIP.SIZE.INT,PC.SIZE.INT-3 SWITCH:TooSmall WIELDCATEGORY:TwoHanded PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT-2 SWITCH:Light WIELDCATEGORY:TwoHanded PREVAREQ:EQUIP.SIZE.INT,PC.SIZE.INT-1 SWITCH:OneHanded WIELDCATEGORY:TwoHanded PREVARGTEQ:EQUIP.SIZE.INT,PC.SIZE.INT+1 SWITCH:TooLarge

  1. Wield Category Steps
  2. This is used when figuring bonuses that allow you to wield Larger or Smaller size weapons

WCSTEPSFORMULA:EQUIP.SIZE.INT-PC.SIZE.INT

WIELDCATEGORY:TooSmall UP:Light|OneHanded|TwoHanded ZERO:Light WIELDCATEGORY:Light UP:OneHanded|TwoHanded WIELDCATEGORY:OneHanded UP:TwoHanded DOWN:Light WIELDCATEGORY:TwoHanded DOWN:OneHanded|Light WIELDCATEGORY:TooLarge DOWN:TwoHanded|OneHanded|Light ZERO:TwoHanded </nowiki>


Variables

These have special value that needs to be handled

  • STR & STRSCORE
  • DEX & DEXSCORE
  • CON & CONSCORE
  • INT & INTSCORE
  • WIS & WISSCORE
  • CHA & CHASCORE

=> All should be rather simple to whip up

  • TL => Global 'MODIFY:TL|SOLVE|???' - need a method to grab all levels.
  • CL => Local 'MODIFY:CL|SOLVE|thisclass()'
  • BASECR => Was set by CR on the race, 'MODIFY:BASECR|SET|x' on race
  • CR => MODIFY:CR|SOLVE|value()+BASECR

CASTERLEVEL - gonna need some thought

BASEHD -

  • MODIFY:BASEHD|SOLVE|CLASS.Monster
  • NOTE: All classes designated as "Monster" need "MODIFY:BASEHD|SOLVE|thisclass()"

RACIALHDSIZE

  • MODIFY:RACIALHDSIZE|SET|x - placed in all Class TYPE "Monster"

WEIGHT.CARRIED

WEIGHT.EQUIPPED

WEIGHT.PC

WEIGHT.TOTAL


SKILLTOTAL=name

  • "MODIFY:SKILLTOTAL.n|SOLVE|SKILLRANK.n+SKILL.n+SKILLSTAT.n
  • Debating how we handle bonuses to skills with types "BONUS:SKILL|n|x|TYPE=Competence"
  • MODIFY:SKILL.n|SOLVE|Competence+Profane+Holy+Morale+Misc

TYPEs

We will set up each "TYPE" assigned as a local variable. We will need to establish "Non-Stacking" rules

Common TYPE's

  • Deflection (AC)
  • Dodge (AC, Stacks)
  • Profane (AC)
  • Holy (AC)
  • NaturalArmor (AC)
  • Enhancement (Armor/Weapon/tool)
  • Morale (Attack/Save)
  • Competence (Skill)

AC Types: (Most systems)

  • Base
  • Touch
  • TouchMisc
  • Flatfooted
  • Ability
  • Size
  • Armor
  • ArmorEnhancement
  • Shield
  • ShieldEnhancement
  • NaturalArmor
  • NaturalArmorEnhancement
  • Dodge
  • Deflection
  • Misc
  • Circumstance
  • Insight
  • Morale
  • Profane
  • Sacred/Holy
  • CMD
  • ClassDefense

Stats & Checks

  • FORMULATERM:STR
  • FORMULATERM:DEX
  • FORMULATERM:CON
  • FORMULATERM:INT
  • FORMULATERM:WIS
  • FORMULATERM:CHA

SAVE will be a special case involving FORMULATERM:x

BONUS:SAVE becomes

  • Defined as "SAVE.n"
  • MODIFY:SAVE.n|SOLVE|value()+STATVAR

Equipment Tokens - using Local Formula System

ACCHECK

  • Becomes three Defined values 'ACCHECK' is the total value; 'ACCHECK.Armor' will be used for Armor; 'ACCHECK.Shield' will be used for Shields
  • Conversion will need to realize if ACCHECK is TYPE "Armor" or "Shield" to convert to proper variable.
  • Set by MODIFY:ACCHECK.n|SET|x
  • Example: MODIFY:ACCHECK.Armor|SET|-6

ALTCRITMULT (See also CRITMULT)

  • Defined as "CritMult"
  • Set by 'PART:2|MODIFY:CritMult|SET|x' with x being the value

ALTCRITRANGE (See also CRITRANGE)

  • Defined as "CritRange"
  • Set by 'PART:2|MODIFY:CritRange|SET|x' with x being the value

ALTDAMAGE (Conversion ?)

COST

  • Needs to be considered. We have a lot of issues factoring costs, so using the new system may be beneficial.

CRITMULT (See also ALTCRITMULT)

  • Defined as "CritMult"
  • Set by 'PART:1|MODIFY:CritMult|SET|x'

CRITRANGE

  • Define as "CritRange"
  • Set by 'PART:1|MODIFY:CritRange|SET|x'


DAMAGE (Conversion ?) Would make sense in some aspects, but make things harder in another. Need to contemplate and deliberate with Code and Arch.

EDR

  • Defined as "EDR"
  • Set by 'MODIFY:EDR|SET|x"

FUMBLERANGE

  • Defined as "FUMBLERANGE"
  • Set by 'MODIFY:FUMBLERANGE|SET|x'
  • May use PART:x|MODIFY:FUMBLERANGE|SET|x if double weapon

MAXDEX

  • Defined as "MAXDEX"
  • Set by 'MODIFY:MAXDEX|SET|x'
  • NOTE: This will be presented to "MODIFY:MAXDEX.TOTAL|SOLVE|thisvalue()+MAXDEX" which will set the global Max Dex to work with the d20 systems.

NUMPAGES (?)

PAGEUSAGE (?)

RANGE

  • Defined as "RANGE"
  • Set by 'MODIFY:RANGE|SET|x'

RATEOFFIRE

  • Defined as "RATEOFFIRE"
  • Set by 'MODIFY:RATEOFFIRE|SET|x'

REACH

  • Defined as "REACH"
  • Set by 'MODIFY:REACH|SET|x'

REACHMULT

  • Defined as "REACH" - REACHMULT becomes part of the Formula system.
  • Set by 'MODIFYOTHER:EQUIPMENT.PART|ALL|REACH|SOLVE|value()*x'

SLOTS (EQMHANDS interfaces with this value)

  • Defined as "SLOTS"
  • Set by 'MODIFY:SLOTS|SET|x'

SPELLFAILURE

  • Defined as "SPELLFAILURE"
  • Set by 'MODIFY:SPELLFAILURE|SET|x'
  • NOTE: This will be presented to "MODIFY:SPELLFAILURE.TOTAL|SOLVE|thisvalue()+SPELLFAILURE" which will set the global SPELLFAILURE to work with the d20 systems and OS.
  • NOTE TO TOM: Need to make sure we can grab multiple values to get correct values - such as SPELLFAILURE from equipped Shield and Armor.

WT

  • Defined as "WT"
  • Set by 'MODIFY:WT|SET|x'

BONUS TAGS PROPOSED

ABILITYPOOL => Simple conversion, we implement the POOL:n tag in all the ABILITYCATEGORIES, then use MODIFY for the POOLNAME. Example: MODIFY:POOL.n|ADD|x then ABILITYCATEGORY:Pool <> POOL:POOL.x

BONUS:ACVALUE - Gamemode tag, skipping for now.

BONUS:CASTERLEVEL - This would become MODIFY:CASTERLEVEL.n|SOLVE|thisclass()+CasterLevelBonus.n

  • x = Class Name, we will continue to use 'CASTERLEVEL' as the first portion in all CAPS.


BONUS:CONCENTRATION - Becomes "MODIFY:CONCENTRATION.n|SOLVE|ConcentrationBase+ConcentrationClassBonus.n

  • x = Class Name, we will use CONCENTRATIONBASE to set the base line level across all classes. (Pathfinder only)

BONUS:DC - becomes MODIFY:DC.n|SOLVE|STATBONUS.x


Master Bonus Tag List

  • BONUS:COMBAT (Global BONUS - this applied to all things)
    • Encompasses:
    • "AC",
      • Set as 'AC.n' - due to multiple types, needs extra consideration


    • "ATTACKS", Global is defined as "COMBAT.ATTACKS", local for weapons is "ATTACKS"
      • Set as 'MODIFY:COMBAT.ATTACKS|ADD|x'
    • "BASEAB",
      • Set as 'MODIFY:BASEAB|SOLVE|thisclass("APPLIEDAS=NONEPIC")'
      • "DAMAGE.Weapon or TYPE",
      • "DAMAGEMULT - special values",
      • "DAMAGESIZE",
      • "DAMAGE-SHORTRANGE",
    • "EPICAB",
      • Set as 'MODIFY:BASEAB|SOLVE|thisclass("APPLIEDAS=EPIC")'
    • "INITIATIVE",
      • Set as 'MODIFY:INITIATIVE|ADD|x'
    • "REACH",
      • Global is "REACH.Race", Local is REACH for individual weapons
      • Set as 'MODIFY:REACH.Race|ADD|x'
      • "RANGEPENALTY",
      • "SECONDARYATTACKS",
      • "SECONDARYDAMAGE",
    • "TOHIT",
      • Set as 'MODIFY:COMBAT.TOHIT|ADD|x'
      • "TOHIT.Weapon Type",
      • "TOHIT-PRIMARY",
      • "TOHIT-SECONDARY",
      • "TOHIT-SHORTRANGE"



  • BONUS:DR (Global BONUS) - Special Consideration, may need to keep DR unless Tom has something in mind for the "DR:cold iron/5"


  • BONUS:DOMAIN|NUMBER (Special Consideration - UI ramifications, along with class ramifications)
  • Defined as
  • Modified by 'MODIFYOTHER:||x'


BONUS:EQM|HANDS (Equipment Modifier)

  • Defined as "SLOTS"
  • 'MODIFYOTHER:SLOTS|Z|x'

These following are all handled with the same tag:

  • BONUS:EQM|WEIGHTADD
  • BONUS:EQM|WEIGHTDIV
  • BONUS:EQM|WEIGHTMULT
  • Defined as "WT"
  • Modified by MODIFYOTHER:WT|Z|X
  • Z = ADD, DIVIDE, or MULTIPLY
  • X = Number

BONUS:EQMARMOR|ACCHECK (Equipment Modifier)

  • Defined as 'ACCHECK.Armor'
  • Modified by 'MODIFYOTHER:ACCHECK.Armor|ADD|x'

BONUS:EQMARMOR|EDR (Equipment Modifier)

  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:EQMARMOR|MAXDEX (Equipment Modifier)
  • Defined as 'MAXDEX'
  • Modified by 'MODIFYOTHER:MAXDEX|ADD|x'
  • BONUS:EQMARMOR|SPELLFAILURE (Equipment Modifier)
  • Defined as 'SPELLFAILURE'
  • Modified by 'MODIFYOTHER:SPELLFAILURE|SUBTRACT|x'
  • BONUS:EQMWEAPON|CRITRANGEADD (Equipment Modifier)
  • Defined as 'CRITRANGE'
  • Modified by 'MODIFYOTHER:CRITRANGE|ADD|x'
  • BONUS:EQMWEAPON|CRITRANGEDOUBLE (Equipment Modifier)
  • Defined as 'CRITRANGE'
  • Modified by 'MODIFYOTHER:CRITRANGE|MULTIPLY|2'
  • BONUS:EQMWEAPON|DAMAGESIZE (Equipment Modifier) ???
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:EQMWEAPON|RANGEADD (Equipment Modifier)
  • Defined as 'RANGE'
  • Modified by 'MODIFYOTHER:RANGE|ADD|x'
  • BONUS:EQMWEAPON|RANGEMULT (Equipment Modifier)
  • Defined as 'RANGE'
  • Modified by 'MODIFYOTHER:RANGE|MULT|x'
  • BONUS:FEAT|POOL (Global BONUS)
  • Defined as 'POOL.Feat'
  • Modified by 'MODIFY:POOL.Feat|ADD|x'
  • BONUS:FOLLOWERS (Global BONUS) - Exception tag, needs consideration?
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:HD (CLASS ONLY TAG - increases HD size)
  • Defined as 'HD.N'
  • Modified by 'MODIFYOTHER:HD.N|ADD|x'
  • BONUS:HP
  • Defined as 'HP.CURRENTMAX' or 'HP.ALTHP'
  • Modified by 'MODIFY:n|ADD|x'
  • BONUS:ITEMCAPACITY (Size Adjustment) - Special tag using TYPE - needs evaluation
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:ITEMCOST - Special tag using TYPE - needs evaluation
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:ITEMCOST|TYPE (Global BONUS) - Special tag using TYPE - needs evaluation
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:ITEMCOST (Size Adjustment) - Special tag using TYPE - needs evaluation
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:ITEMWEIGHT (Size Adjustment) - Special tag using TYPE - needs evaluation
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:LANG (Stats & Checks) (In STATNAME Line)
  • Defined as 'LANGUAGE.INTBASED'
  • Modified by 'OTHER:LANGUAGE.INTBASED|ADD|INT'
  • BONUS:LOADMULT (Size Adjustment) - Gamemode - needs consideration
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:LANGUAGES|NUMBER (Global BONUS)
  • Defined as 'LANGUAGE.TOTAL'
  • Modified by 'MODIFY:LANGUAGE.TOTAL|ADD|x'
  • BONUS:LOCKEDSTAT (Global BONUS) - Special tag / review
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:MISC (Global BONUS)
  • Covers these:
    • ACCHECK,
    • CR,
    • MAXDEX,
    • SPELLFAILURE,
    • SR
  • Defined as 'ACCHECK', 'CR', 'MAXDEX', 'SPELLFAILURE', 'SR'
  • Modified by 'MODIFY:n|ADD|x'
  • BONUS:MODSKILLPOINTS (Stats & Checks)
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:MONSKILLPTS|LOCKNUMBER (Template)
  • Defined as
  • Modified by 'MODIFYOTHER:||x'

BONUS:MOVEADD|TYPE & BONUS:MOVEMULT|TYPE

  • Valid normal values are any defined movement - Walk, Fly, Swim, Climb, Burrow
  • Defined as 'MOVE.n'
  • Modified by 'MODIFY:MOVE|ADD|x'
  • Modified by 'MODIFY:MOVE|MULTIPLY|x'
  • BONUS:PCLEVEL (Global BONUS)
  • Defined as 'PCLEVEL.n'
  • Modified by 'MODIFYOTHER:PCLEVEL.n|ADD|x'
  • BONUS:POSTMOVEADD|TYPE (Global BONUS)
  • Valid normal values are any defined movement - Walk, Fly, Swim, Climb, Burrow
  • Defined as 'MOVE.n'
  • Modified by 'MODIFY:MOVE|ADD|x|PRIORITY=1000'
  • BONUS:POSTRANGEADD (Global BONUS)
  • Defined as 'RANGE'
  • Modified by 'MODIFYOTHER:RANGE|ADD|x|PRIORITY=1000'
  • BONUS:PPCOST (Spell)
  • Defined as 'PPCOST'
  • Modified by 'MODIFYOTHER:PPCOST|ADD|x'
  • BONUS:RANGEADD (Global BONUS)
  • Defined as 'RANGE'
  • Modified by 'MODIFYOTHER:RANGE|ADD|x'
  • BONUS:RANGEMULT (Global BONUS)
  • Defined as 'RANGE'
  • Modified by 'MODIFYOTHER:RANGE|MULTIPLY|x'
  • BONUS:SAVE (Global BONUS) - will this convert?
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SITUATION (Global BONUS)
  • Defined as 'SITUATION.n'
  • Modified by 'MODIFYOTHER:SITUATION.n|ADD|x'
  • BONUS:SIZEMOD|NUMBER (Global BONUS)
  • Defined as 'SIZEMOD'
  • Modified by 'MODIFY:SIZEMOD|ADD/SUBTRACT|x'
  • BONUS:SKILL (Global BONUS)
  • Defined as 'SKILL.n'
  • Modified by 'MODIFYOTHER:SKILL.n|ADD/SUBTRACT|x'
  • BONUS:SKILLRANK (Global BONUS)
  • Defined as 'SKILLRANK.n'
  • Modified by 'MODIFYOTHER:SKILLRANK.n|ADD|x'
  • BONUS:SKILLPOINTS (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SKILLPOOL - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SLOTS (Global BONUS)
  • Defined as 'SLOT.n'
  • Modified by 'MODIFY:SLOT.n|ADD/SUBTRACT|x'
  • BONUS:SPECIALTYSPELLKNOWN (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SPELLCAST (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SPELLCASTMULT (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SPELLKNOWN (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:SPELLKNOWNMULT (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:STAT (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:STAT|BASESPELLKNOWNSTAT (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:STAT|BASESPELLKNOWNSTAT:CLASS (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:STAT|BASESPELLSTAT (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:STAT|BASESPELLSTAT;CLASS (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:UDAM (Global BONUS) - Special considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:VAR (Global BONUS) - DEPRECATED!
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:VISION (Global BONUS)
  • Defined as 'VISION.n'
  • Modified by 'MODIFY:VISION.n|ADD|x'
  • BONUS:WEAPON (Global BONUS) - REVIEW
  • Values
      • 'ATTACKS',
      • 'ATTACKSPROGRESS',
      • 'DAMAGE',
      • 'DAMAGEMULT',
      • 'DAMAGE-SHORTRANGE',
      • 'TOHIT',
      • 'TOHIT-SHORTRANGE',
      • 'WEAPONBAB',
      • 'WIELDCATEGORY'.
  • Defined as 'ATTACKS', 'ATTACKSPROGRESS', 'DAMAGE', 'DAMAGEMULT', 'DAMAGE-SHORTRANGE', 'TOHIT', 'TOHIT-SHORTRANGE', 'WEAPONBAB', 'WIELDCATEGORY'
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:WEAPONPROF (Global BONUS) - Special Considerations
  • Defined as
  • Modified by 'MODIFYOTHER:||x'
  • BONUS:WIELDCATEGORY (Global BONUS) - this needs to consider single item and all items.
  • Defined as 'WIELDCATEGORY'
  • Modified by 'MODIFYOTHER:WIELDCATEGORY|ADD/SUBTRACT|x'

NEW DEFINES

Any Class/Object name with a SPACE in it's name will use an UNDERSCORE '_' to replace the space, as I don't believe that the System can handle SPACES. (Check with Tom)

  • POOL.n > Used for ABILITYCATEGORY on the POOL: token "POOL:POOL.n" to easily designate Pools we can alter.
  • CASTERLEVEL.n = Used for all classes that CAST spells. n = Class Name. Example CASTERLEVEL.Wizard, CASTERLEVEL.Mage_Blade
  • AC.n = Used for designating the AC Type. Example, AC.NATURAL.

DEPRECATION

  • JEP Formula Parser which includes:
    • DEFINE:x
    • BONUS:VAR
  • All Bonus Tags are planned on being replaced by the Formula Parser system in the future and any base tag that they affect is a potential candidate for Formula Parser replacement, such as:
  • HANDS
  • LEGS
  • CR
  • SLOTS
  • CRITMULT
  • ACCHECK,
  • MAXDEX,
  • SPELLFAILURE,
  • SR
  • DR (BONUS:DR is an odd duck)


Homebrew Conversion Start

Here is a basic list of conversion - should be universal.

NOTE: This is still in the planning phase, this is not official yet.

Tag Name Converted to Reviewable? Comments
CRITMULT:x PART:1|MODIFY:CritMult|SET|x No No concerns
CRITRANGE:x PART:1|MODIFY:CritRange|SET|x No No concerns
ALTCRITMULT:x PART:2|MODIFY:CritMult|SET|x No No concerns
ALTCRITRANGE:x PART:2|MODIFY:CritRange|SET|x No No concerns
PLACEHOLDER


Conversion Process Ideas

Keeping homebrews caught up with changes in pcgen is a daunting task. We strive to make it easier for those who maintain their own data to keep up with production cycle changes. This Formula Parser is going to be a tough conversion process, since this will not be an apples to apples process. Many issues hinder a one-to-one or apples-to-apples conversion approach:

  1. TERMS are not allowed
  2. Some magical back up parser would kick in if JEP failed
  3. JEP and FORMULA parser will not interact at all
  4. The vars and replacement tokens are Data Scope and Driven by Data Decisions
  5. TYPE=x is not supported in the new system, making BONUS:VAR|MyVar|5|TYPE=Competence much harder to convert.

A suggestion I made was a PER gamemode system migration file to help with conversions. This would house all the OLDTAGS and give them the "NEWTAG". However, this does not address the TYPE=x issue.

Tom has some ideas, but needs to discuss the ramifications with the development team.



Log Discussion for Non-Stacking modifiers interaction with SKILL / SKILLSIT

  • Tom[Arch_SB]: Making up something new for the moment
  • DEFAULTVARIABLEVALUE:NONSTACKING|0
  • VARTYPEDEF:NONSTACKING|NONSTACKINGBONUS
  • LOCAL:ALL|NONSTACKINGBONUS|Trait
  • (and this is on the fly, so don't try to remember or quote me on this later as being set or coherent in any way)
  • @Andrew[Chair]: concepts and brainstorm sessions are like that... Nothing is set in stone.
  • Tom[Arch_SB]:
  • MyTrait <> MODIFYOTHER:SKILL|Foo|Trait|APPLY|1
  • MyTrait.MOD <> MODIFYOTHER:SKILLSIT|Foo (Bar)|Trait|APPLY|2
  • MODIFYOTHER:SKILLSIT|ALL|Trait|APPLY|parent()
  • the last in the global file
  • APPLY as a modifier knows Trait is a NONSTACKINGBONUS
  • APPLY then performing the stacking rules
  • in the case of NONSTACKINGBONUS that is the equivalent of MAX
  • in the semiequivalent case of STACKINGBONUS it's ADD
  • @Andrew[Chair]: Okay, you lost me...
  • Tom[Arch_SB]: so "Trait" starts its life with value zero
  • @Andrew[Chair]: A bunch of new concepts packed in tightly...
  • Okay Trait = 0
  • Tom[Arch_SB]: since the default value for any NONSTACKING is zero as per the default variable value line
  • @Andrew[Chair]: Correct
  • Tom[Arch_SB]: Trait is local to all objects that was caused by the
  • LOCAL:ALL|NONSTACKINGBONUS|Trait
  • so Foo as a skill has a local variable Trait then in MyTrait, we modified Trait on the skill to be 1
  • MODIFYOTHER:SKILL|Foo|Trait|APPLY|1
  • we also modified via the .MOD, the Trait on the Situation to be 2
  • MODIFYOTHER:SKILLSIT|Foo (Bar)|Trait|APPLY|2
  • globally we modified Trait on the situation to be equivalent to the parent
  • MODIFYOTHER:SKILLSIT|ALL|Trait|APPLY|parent()
  • thus if we didn't have the APPLY|2 it would be 1
  • since the parent (the skill foo)has Trait of 1
  • follow?
  • @Andrew[Chair]: Is APPLY a new Function? And is parent() a new function?
  • Tom[Arch_SB]: yes
  • things I'm creating on the fly
  • parent() is referring to the var on the skill (when used for a situation)
  • @Andrew[Chair]: Okay, then yes. Now I'm following. Takes a bit, I've been learning pseudo-code algorithms in class
  • Tom[Arch_SB]: APPLY is equivalent to MAX if the underlying object is non-stacking
  • would be equivalent to ADD if the underlying object is stacking
  • just trying to give you guys ONE way to spell it out, with the ability elsewhere to declare stacking vs non stacking
  • that way you don't have to be concerned about which one it is when you are writing the modify
  • like you don't have to worry about it today with BONUS
  • @Andrew[Chair]: Cool. But not set in stone ;) - Mark is available. You able to chat on GTalk?
  • Tom[Arch_SB]: that would take a bit
  • @Andrew[Chair]: okay.
  • Tom[Arch_SB]:
  • MODIFYOTHER:SKILL|ALL|Rank|Add|asnumber(Trait)
  • MODIFYOTHER:SKILLSIT|ALL|Rank|ADD|asnumber(Trait)
  • @Andrew[Chair]: Eh?
  • Tom[Arch_SB]: Trait is a NONSTACKINGBONUS
  • not a VAR
  • Rank is a (local) VAR
  • presumably
  • need to convert Trait to a VAR
  • which is actually a NUMBER
  • hence asnumber(Trait)
  • basically strips off the fact that it's non-stacking in this case
  • and just returns the value
  • @Andrew[Chair]: Gotcha.
  • Tom[Arch_SB]: ok, this authentication thing isn't going to happen tonight
  • haven't had to authenticate an app before and too much reading
  • @Andrew[Chair]: no worries, Mark hasn't popped online for me the big issues left for the conversion:
  • 1) Apply Luck bonus boost to ALL existing Luck bonuses
  • Tom[Arch_SB]: have you seen my latest note to _Exp?
  • @Andrew[Chair]: something you mentioned in your last email
  • Tom[Arch_SB]: ok, I THINK that answers it
  • What I'd like to know is how you guys are doing the bauble thing today
  • @Andrew[Chair]: And the AC discussion... Periods were mentioned as legal in the wiki, is that no longer the case?
  • Tom[Arch_SB]: if you can't get a bonus from a type of object more than once
  • @Andrew[Chair]: Bauble thing caught me off-guard. Today, if you put on three, you'd have a +3 bonus.
  • that's a tricky sneaky rule I wasn't aware of till today.
  • Tom[Arch_SB]: you are correct, period is legal as per the wiki
  • my bad
  • @Andrew[Chair]: Oh, Mark just popped on
  • Distant_Scholar: Typically, you can't get more than one of the same ability/feat/object anyway. How many objects would this apply to?
  • @Andrew[Chair]: Items
  • Tom[Arch_SB]: two identical rings for example would cause the issue
  • @Andrew[Chair]: Say an equipment without slots or two rings, yes
  • Tom[Arch_SB]: So today you'd probably just create a TYPE = localto that object?
  • TYPE=FooRingStuff
  • on the BONUS?
  • Distant_Scholar: Ah. To my eyes, the simplest "fix" would be to make up a new type. (Tom beat me to it.)
  • @Andrew[Chair]: pretty much
  • if I was made aware of it, I would have done something like that, yes
  • sounds like items will need those "types" to manage...
  • mjmeans: ok
  • hi
  • Tom[Arch_SB]: Hi Mark
  • @Andrew[Chair]: Yay!
  • Hi Mark
  • mjmeans: Dont worry about the fate's favored ability. It isn't possible with the current system either.
  • Tom[Arch_SB]: do you think my example work work though?
  • mjmeans: for fate's favores? no
  • Tom[Arch_SB]: why not?
  • mjmeans: consider a pc with one ability that gives a luck bonus to intimidate, one equipment that gives a luck bonus to AC and a eqmod that gives a luck bonus to shield.
  • There is no way a single modify would identify and add 1 luck to each and every one of those luck bonuses
  • Tom[Arch_SB]: oh, I get the question now
  • so it's actually based on the TYPE=
  • mjmeans: it's an array formuls that is required for that solution
  • Tom[Arch_SB]: that you are triggering off of
  • mjmeans: yeah. that's why the current JEP can't do it either
  • Tom[Arch_SB]: so one question
  • if you have a luck bonus to intimidate from item a and a luck bonus to intimidate from item b, each are 1. is the result 3 or 4?
  • mjmeans: i think there are more pressing concens than this one trait, so lets work on the regular issues with stacking.
  • Tom[Arch_SB]: well, I have a solution that may do both
  • so let's spend a few more moments on this
  • mjmeans: ok.. so i'll restate the issue with luck then
  • with expected results
  • PC has Ability_1 that gives a +2 luck bonus to intimidate.
  • PC has 1 equipment item that gives a +1 luck bonus to AC.
  • PC has a spell that grants +1 luck bonus to AC, Attacks and saves. Got it so far?
  • Tom[Arch_SB]: y
  • mjmeans: So at this point (without the fate's favored trait) the PC has a total +2 luck bonus to intimidate, +1 luck bonus to AC, attacks and damage. The equipment and the spell both provide a +1 luck bonus to AC but they don't stack. Okay so far?
  • Tom[Arch_SB]: y
  • mjmeans: So now fate's favor is applied. each of the various luck bonuses go up by 1, but the net effect is the PC has +3 luck bonus to intimidate, and +2 to AC, attacks and damage.
  • Tom[Arch_SB]: k
  • mjmeans: Now consider that a luck bonus could apply to any skill or conditional skill, of which there are are least 100.
  • Tom[Arch_SB]: understand
  • my question was an order of ops issue
  • but because it doesn't stack it's moot
  • because max (1,1)+1 is the same as max (1+1,1+1)
  • mjmeans: To make fate's favored work, one method is to .MOD each existing item or ability or spell that is known to have a luck bonus, to add an additional 1 if the PC has fate's favoreed.
  • Tom[Arch_SB]: I think that' s a mess
  • mjmeans: But that is prone to error.
  • Tom[Arch_SB]: we need better
  • so let's leave that aside for a moment
  • mjmeans: Another method might be is there is a way to query the AC total to "know" if a luck bonus was applied and then apply 1 more if fate's favored. A smaller list to be sure, but still hundreds. And each SKILLSIT would still have to be .MODed since they are never added into any total.
  • Tom[Arch_SB]: still bad
  • I have better
  • mjmeans: right
  • Tom[Arch_SB]: So let's talk about the variable system as it's proposed
  • right now, there are some default types built into the system
  • One of those is NUMBER
  • In the variable proposal
  • every game mode will have to provide a default value:
  • DEFAULTVARIABLEVALUE:NUMBER|0
  • We can then define different types of numbers
  • think of these as local scopes in a way
  • VARTYPEDEF:NUMBER|VAR
  • mjmeans: ok
  • Tom[Arch_SB]: so any time we create a new VAR, it takes on the characteristics of NUMBER, including the default value of zero
  • GLOBAL:VAR|GlobalVariable
  • so GlobalVariable has a default value of zero
  • mjmeans: ok
  • next?
  • Tom[Arch_SB]: So NUMBER has the quirk, as you've pointed out, that with the operations we have, such as MAX and ADD, that if we use NUMBER for BONUSES (either as a VAR or as another type of NUMBER)
  • ...then we end up with a problem of locality of knowledge
  • meaning the BONUS type of Luck was defined in a book on page 2 for example
  • and was said to be non-stacking
  • mjmeans: right
  • Tom[Arch_SB]: then it was used on pages 25-30 in variables thingies
  • whatever they were
  • so as a thought exercise, let's define a new type, let's call it NONSTACKING
  • DEVAULTVARIABLEVALUE:NONSTACKING|0
  • VARTYPEDEF:NONSTACKING|NSBONUS
  • LOCAL:ALL|NSBONUS|Luck
  • every object is given a local variable (type is NSBONUS/NONSTACKING) called Luck'
  • mjmeans: So all items get a Local Luck variable?
  • Tom[Arch_SB]: yes
  • defaulting of course to zero
  • mjmeans: so we have armor and shield. each one has a local Luck variable. Got it.
  • @Andrew[Chair]: and skills and spells, etc.
  • mjmeans: Now let's consider a +1 luck bonus to armor and a +1 luck bonus to shield and the PC has fate's favored.
  • Tom[Arch_SB]: hold on
  • mjmeans: ok
  • Tom[Arch_SB]: wait
  • let's not go there yet
  • By the way
  • This is a bit of brainstorming
  • so it may end up more verbose than necessary
  • and I may backtrack here and there
  • mjmeans: just remember that if the the luck bonus is 0 it gets no benefit from fate's favored.
  • "Whenever you are under the effect of a luck bonus of any kind, that bonus increases by 1."
  • Tom[Arch_SB]: that's the easy part :D
  • mjmeans: do go on
  • @Andrew[Chair]: All, I have to head off... be back in 30...
  • mjmeans: BCNU
  • Tom[Arch_SB]: (thinking)
  • this is likely to be too verbose, but it should function
  • GLOBAL:NSBONUS|LuckBonus
  • mjmeans: or LOCAL:ALL?
  • Tom[Arch_SB]: global
  • mjmeans: ok
  • Tom[Arch_SB]: I need to summarize the local Lucks somewhere
  • mjmeans: Too bad there isn't a LOCAL:MODIFY|ALL|GLOBAL.Luck|ADD|Luck
  • a pseudo array forumula
  • Tom[Arch_SB]: There is: MODIFYOTHER:ALL|ALL|LuckBonus|ADD|Luck
  • mjmeans: Where the scope of the left argument is a global and the right argument is a local?
  • Tom[Arch_SB]: used once in the global file
  • local variables can't match the name of a global var
  • the data load would fail
  • mjmeans: that's bad
  • Tom[Arch_SB]: so the scope is directly known from the name
  • why is it bad
  • it's enormously confusing to have "Luck" in two places
  • these aren't programmers we're talking about that do the data
  • mjmeans: So then from a data standpoint, all global variables should follow an obvious naming scheme that will help keep them separate
  • Tom[Arch_SB]: That's a data team thing
  • I don't think that's necessary
  • mjmeans: Are variable type sensitive?
  • Tom[Arch_SB]: meaning what?
  • mjmeans: i.e. gFoo is a different variable than GFOO
  • like java or c++... case sensitive
  • Tom[Arch_SB]: not case sensitive
  • mjmeans: ick
  • Tom[Arch_SB]: it's a side effect of LST load
  • the files were always loaded in as all CAPS as part of the load process
  • that's the history we have
  • mjmeans: ok
  • Tom[Arch_SB]: actually my MODIFYOTHER was wrong
  • because ADD would make them stack as it wer
  • *were
  • should be: MODIFYOTHER:ALL|ALL|LuckBonus|APPLY|Luck
  • APPLY is new for NONSTACKING and effectively acts as MAX
  • mjmeans: So let's get back to the LOCAL:ALL|NSBONUS|Luck... Luck to what? Some items will give Luck to AC, others will give Luck to a skill, others will give differing Luck to multiple skills or saves.
  • Tom[Arch_SB]: argh you're right
  • mjmeans: Consider AC only. So we use LOCAL:ALL|NSBONUS|LuckBonusToAC. Then on any item, ability or spell that gives a luck bonus to AC, it will SET it's local variable. SOmewhere else that is totaled back to a TotalACLuckBonus variable which is then totaled into the TotalAC variable reported on the OS.
  • So now we have NxN bonuses added to every item, spell or ability
  • Tom[Arch_SB]: except they are lazily instantiated, so they aren't really there if they aren't used
  • mjmeans: Well, N1 x N2... where N1 is the number of types, and N2 is the number of object because each object cannot stack with itself.
  • N2 is HUGE
  • Tom[Arch_SB]: let's ignore the bauble thing for the moment
  • mjmeans: ok
  • For the simple case of types, there are about 20 types in Pathfinder.
  • Tom[Arch_SB]: one clarification
  • you woudlnt' SET the LuckBonusToAC
  • you'd APPLY it
  • that way if there was a later .MOD that was a different value it would take the max
  • in the case of nonstacking
  • mjmeans: So at the very least we have LOCAL:ALL|NSBONUS|XBonusToY where X is the type of bonus and Y is AC, or STR, or a skill, etc.
  • As an exercise, let's start with a simpler case, but complex enough. The spell Divine Favor "you gain a +1 luck bonus on attack and weapon damage rolls for every three caster levels you have (at least +1, maximum +3)."
  • Tom[Arch_SB]: let's step back for a moment
  • mjmeans: ok
  • Tom[Arch_SB]: I don't like X*Y even as you show it
  • If we were doing this in Java or C# or whatever
  • mjmeans: I dont like it either, but is there another way?
  • Tom[Arch_SB]: how would we accumulate it
  • we have some object that has a type and a value
  • call that class Bonus
  • mjmeans: If this was C# or Java, each spell, item or ability would be an Class in and of itself with shared and local variables
  • Tom[Arch_SB]: Luck:1, Luck:2 whatever
  • put on the constraint that each spell has no local or global variables
  • and design it that way :)
  • mjmeans: We'd use a singleton to handle the "not stacking with itself" behaviour
  • Tom[Arch_SB]: or assume you are using a visitor pattern to extract data from the list of objects
  • that's probably the better description of the scenario
  • mjmeans: I've never herd of a "visitor" pattern.
  • Tom[Arch_SB]: ok
  • let's do this then
  • mjmeans: but, ,yes, accessing data from a list of object, which each contain a list of bonuses
  • that;s back to an array formula
  • Tom[Arch_SB]: so we have a spell an an ability and a ring
  • to keep it simple
  • mjmeans: ok
  • Tom[Arch_SB]: each has a few bonuses
  • since we can .MOD items from different LST files
  • we have to assume the spell could have Luck for AC:1 and Luck for AC:2
  • so the order of ops has to be:
  • grab the list for object n
  • do a local consolidation (non stacking in this case)
  • then add that list to the global list
  • then do a global consolidation
  • right?
  • is the local one necessary?
  • mjmeans: yes
  • for luck's favor yes, but otherwise, maybe not
  • Tom[Arch_SB]: each bonus has 3 pieces of info
  • type, whereto apply and a value
  • mjmeans: if global consolidation is "per total", and you have the ability ti query "was there a non-0 luck bonus, then add 1" then global consolidation would work for fate's favored.
  • Tom[Arch_SB]: k
  • mjmeans: but back to the single spell, item and ability
  • assuming the bastard fate's favored is not the ability
  • Tom[Arch_SB]: MODIFY:ACBonus|APPLY|Luck: 1
  • mjmeans: So the item, spell and ability would simply APPLY to a GLOBAL variable that it should apply to.
  • Tom[Arch_SB]: ACBonus is a global NSBONUS
  • (I've changed NSBONUS a bit from what we were doing before)
  • mjmeans: I don't see "Luck:1" as a legal syntax in the current examples on the wiki
  • Tom[Arch_SB]: hehe
  • It's not
  • but the formula system can do some neat stuff :)
  • here's the key thing
  • when you have something like MODIFY:ACBonus|APPLY|Luck: 1'
  • ACBonus is specific
  • mjmeans: AC is going to be totaled with each type of bonus separately because it gets reported on the OS as separate totals
  • Tom[Arch_SB]: it knows that is an NSBONUS
  • let's come back to that
  • and that NSBONUS is a NONSTACKINGBONUS
  • APPLY is made legal for the type of NONSTACKINGBONUS
  • and APPLY is taught to parse it's argument as expecting "TYPE:numeric VALUE"
  • mjmeans: once you finish your current train of through, let me know. I have a different question...
  • Tom[Arch_SB]: that way the type and value travel together
  • mjmeans: okay... good
  • Tom[Arch_SB]: and that way we can apply stacking
  • mjmeans: a vector number (or complex number)
  • Tom[Arch_SB]: effectively
  • mjmeans: That's one of my suggestions to Andrew
  • Tom[Arch_SB]: the framework for that is already in place
  • the system is actually fairly flexible
  • I can do (and have sample code that supports):
  • VARTYPEDEF:LIST|MyList
  • @Andrew[Chair]: Back
  • Tom[Arch_SB]:
  • MODIFY:MyList|ADD|4
  • MODIFY:MyList|ADD|5
  • and MyList is now [4, 5]
  • that isn't exposed right now
  • and I probably won't support that in the first release
  • but the power is there if we need it
  • (and there are places it will be useful)
  • so anyway, we create the type:value
  • and put it into AC
  • I think I've finished my thought, so what was your question
  • mjmeans: So MODIFY:MyList|ADD|Luck:4 MODIFY:MyList|ADD|Shield:5 becomes { [4,Luck], [5,Shield] } ?
  • Tom[Arch_SB]: give or take some complexities I've left out
  • MyList would need to have the underlying type predefined
  • so you can't mix and match a VAR with a NONSTACKING
  • for example
  • mjmeans: My different question is... why in the world did you decide to use key words for ADD MULTIPLY, whatever rather than just using arythmatic operators... "variable = {equation}"
  • Tom[Arch_SB]: speed
  • mjmeans: x+=1 for ADD
  • Tom[Arch_SB]: launching a formula system to interpret value()+4 is about 10,000 times more expensive than knowing I need to add 1
  • mjmeans: y = m*x+b normal formula
  • precompiling +=1 to static is simple and only needs to be done once
  • Tom[Arch_SB]: it is conceptually simple
  • it takes a lot of code to do that though
  • mjmeans: In fact the assembly language INC and DEC ops exist because they are in fact much faster than ADD x,1
  • But compilers will always identify statics and optimize them for you.
  • Tom[Arch_SB]: but these aren't in code
  • they are in files we load
  • mjmeans: So you can code ADD x,1 and the compiler will automatically replace that with INC x.
  • Tom[Arch_SB]: and we aren't doing a compile of them in the java sense
  • walk through the process
  • we have an LST file
  • mjmeans: So it's beyond the scope of the formula parser to PCode the formulas, then?
  • Tom[Arch_SB]: it has MODIFY:Foo|SOLVE|value()+1
  • When this project was started, I submitted code to the project that took a formula and *literally* compiled it into bytecode
  • that would have made this pretty moot as then the JIT compiler could do whatever it needed to do
  • that was deemed too complex and the decision was made to leave the formula in a tree format and solve from there for easier debugging and understanding by new developers
  • mjmeans: ok
  • well each formula is currently stored in a string somewhere. right?
  • Tom[Arch_SB]: no
  • when you have something like value()+1 it's turned into a parse tree
  • there is a + object with 2 children
  • value() and 1
  • value is actually a formula object with 2 children
  • sorry value() is a formula object with 2 children
  • value (a formula name) and an argument child that has zero children
  • Distant_Scholar: Sorry to interrupt, but I have to go for today. I'll want to get a transcript later; this is interesting stuff. G'night.
  • Tom[Arch_SB]: night
  • I have to quit in about 10 anyway
  • that make sense Mark?
  • @Andrew[Chair]: I will log it, minus the chit chat part.... ;)
  • mjmeans: what are the two children of value() nothing is specified in the aparens?
  • Tom[Arch_SB]: yes, the function is split into the function name and a node representing the parens that has the arguments (that would be in the parens in some cases) as children
  • that allows us to just look at the function name node to look up the code that runs that function
  • and hand it the array of children
  • in the case of if(a>4,5,b)
  • mjmeans: so parent node is "function" and two children are "function" and "parameterlist"?
  • Tom[Arch_SB]: the two children would be "if" and "()" and the children of "()" would be ">", "5", and "b", and the children of ">" would be "a" and "4"
  • mjmeans: sorry, lag.. .didn't mean you if example, your previous example where you said function() had two children
  • So function() becomes parent "Formula" with children "function" and "parameterlist" ?
  • Tom[Arch_SB]: so there is a node that represents the total "value()" [I forget what this node is actually called - function perhaps?]... it has children of "value" [the type is a string, but is interpreted as a function name since it's the child of the node type above that I can't remember] and "()" [an otherwise empty node that is interpreted as arguments since it's part of a function].
  • so yes, basically you are correct in your last statement
  • have you ever used lex or yacc?
  • mjmeans: So let me try to describe how I'm seeing this, if this is right... MODIFY:Foo|SOLVE|if(a>4,5,b) -> {Foo, SOLVE, {function {if, {a, >, b}, 5, b}}}
  • Tom[Arch_SB]: not quite
  • When modify is struck by the LST parser, it is decomposed
  • It knows Foo is to be modified, and it validates that Foo is legal in that context (if Foo is local to equipment and in a spell, expect an error)
  • it then looks at the second arg for the modification type in this case SOLVE
  • that is looked up against the type of Foo, in this case NUMBER
  • the SOLVE code in Java is then passed "if(a>4,5,b)" as a String
  • then the String passed into SOLVE is broken up into the tree as described
  • if you hit ADD instead of SOLVE, it knows the argument must only be a decimal number (can't be a formula) so it can just call Double.valueOf(inputString)
  • and store the double for direct addition later on
  • rather than needing a tree
  • that help?
  • mjmeans: So you would never MODIFY:Foo|ADD|if(a>b,4,5)
  • Tom[Arch_SB]: that would cause an LST load error
  • mjmeans: because rith righ operand is a formula
  • Tom[Arch_SB]: correct
  • and ADD requires something that is effectively interpret-able as a Double
  • mjmeans: And in the case MODIFY:Foo|SOLVE|Foo+5
  • Tom[Arch_SB]: "Foo+5" is passed to the parser, which generates a tree
  • mjmeans: the LST load does not see that as equivalent to ADD 5?
  • Tom[Arch_SB]: and the tree is interpreted at runtime to calculate
  • they are mathematically equivalent
  • but the SOLVE always triggers a tree
  • optimizing that call to detect equivalents is more code to write, maintain, test
  • mjmeans: Okay, so LST load hass areas where loading optimization can be applied behind the scenes, but that's not relevant at this early stage.
  • Tom[Arch_SB]: it could be improved, certainly, at the cost of time
  • I have not tried to do that optimization since I want to get the basics running to get out of the other issues we have
  • mjmeans: So back to nonstacking types... Do we have a xolution that is not X*Y variable names?
  • Tom[Arch_SB]: yes, remember the type:value setup
  • mjmeans: Using the concept Luck:1 (or whatever?
  • Tom[Arch_SB]: but I actually need to run
  • mjmeans: okay. greate chat
  • Tom[Arch_SB]: so we can pick this up later
  • mjmeans: yes
  • @Andrew[Chair]: Later Tom.
  • Tom[Arch_SB]: yes, thanks, I appreciate someone poking at this to make it better
  • mjmeans: BCNU
  • @Andrew[Chair]: Did you get all your major questions answered? I briefly skimmed the stuff I missed
  • mjmeans: it's still alittle foggy because the concept has talked about where we can use Luck:1 as a vector (or complex) number is not desribed in the docs yet.
  • @Andrew[Chair]: Yes, since he's brainstorming a lot of it.
  • mjmeans: It still doesn't address the issue of an item not stacking with other instances of itself. One question he has was, does the existing DATA support that. And I dont know. Should be easy ehough to test though
  • @Andrew[Chair]: No, Bauble +1 and Bauble +1 would give +2
  • mjmeans: That's a problem
  • @Andrew[Chair]: untyped bonuses stack, and the data/system doesn't equate the non-stack of same source.
  • mjmeans: But the current DATA *could* support it by always adding |TYPE:itemname
  • @Andrew[Chair]: The work around is to place a unique type on those items. yes