Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Spell-Like Ability in Token Bar

So I have been poking around with the API and discovered a number of wonderful things I can and want to do with my Pathfinder game. I am using the Official Roll20 Pathfinder sheet and can make formulas and abilities do all kind of fancy things we need done. I am running into a situation I have yet to understand using either a macro or an ability or something with API work out. In short, I have a monk and he keeps track of his ki using "bar 2" of the token and a magus tracking his arcane pool the same way. We want to make it so it will automatically update from or to the sheet regardless of where he changes the value. So, if he changes the value in the token, I would want the spell-like ability we defined to handle and auto-adjust his ki (or pool for the magus) on his token bar 2, and vice verse (if he adjusts bar 2, the sheet gets updated). I can easily read the values from the sheet but I cannot wrap my brain around how to make it write back the value to sheet. I can certainly tie the bar to an attribute but then it won't update the sheet, like it would if you connect it to the character's HP or whatever. I hope I am making sense with this, but in short I want to create something to ensure accuracy so I don't need to open players sheets during the game and confirm the changes. While I have scolded my players many time to pick one, they aren't consistent and want to make it so I can trust the screen easier. Any suggestions or direction of help would be welcome. And yes, I can go into a lot more detail if this doesn't make sense into what I am directly seeking to do; I just didn't want this to get too much longer before anyone offer the help. Thanks!
1618803083
The Aaron
Roll20 Production Team
API Scripter
So, how is it failing when you link bar 2 to the attribute for ki?
Well, when I make an ability, I can setup a formula that points to the proper field on the proper spell-like ability, and it displays just fine. The problem is that when you change the bar value in-game, it wipes out the formula and replaces it with whatever number is entered for "current". If you update the spell-like ability, it does not destroy the formula but it also does not update the value in bar2. I swear I read somewhere there was a way to use the API to write back to the character sheet but now I cannot find anything and don't remember any details. I may be completely wrong but I assume - from what I know of javascript at least - that as long as I can reference the ID of the field, I should be able to set the value of the "tag". I get that the API interface my not work exactly as expected on a "normal" web page, I get it is close. So... after a lot of babbling... is there a way to write back to the "repeating_spell-like_$0_perday" attribute (or whatever the index may be) when you click on a token and update bar2? I can read the value from that attribute with getAttrByName(character.id, "repeating_spell-like_$0_perday") just fine, but how would I write back to that field? Thanks.
1618883233
The Aaron
Roll20 Production Team
API Scripter
getAttrByName() is a helper function that gets just the value or just the max value of an attribute.  It also handles autocalc fields, which are an old way of having formulas (pre-sheet worker days) and character sheet default values. To update the attribute, you need to get the attribute object, and in some cases create it.  It gets a little complicated when you're talking about repeating fields, as you need to know the actual name, not the offset. To start with, lets talk about regular attributes.  If you know the character ID and the attribute's name, you can get it with findObjs(): 1 2 3 4 let attr = findObjs ({ character_id : charid , name : "some_attr_name" })[ 0 ]; If an attribute for that character exists with that name, you'll have the attribute object.  Note that findObjs() returns an array of objects, which may be an empty array, so you need to test attr to make sure it isn't undefined. You can then set the value with a standard set function: 1 2 3 4 5 if ( attr ){ attr . set ({ current : someValue }); } In the case of repeating attributes, it can be quite a bit more difficult as finding the attribute based on the offset order is a bit tricky.  I have a function for that though, so maybe you can use it: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const attrLookup = ( character , name , caseSensitive ) => { let match = name . match ( /^(repeating_.*)_\$(\d+)_.*$/ ); if ( match ){ let index = match [ 2 ]; let attrMatcher = new RegExp ( ` ^ $ { name . replace ( /_\$\d+_/ , '_([-\\da-zA-Z]+)_' )} $ ` ,( caseSensitive ? 'i' : '' )); let createOrderKeys = []; let attrs = _ . chain ( findObjs ({ type : 'attribute' , characterid : character . id })) . map (( a ) => { return { attr : a , match : a . get ( 'name' ). match ( attrMatcher )}; }) . filter (( o ) => o . match ) . each (( o ) => createOrderKeys . push ( o . match [ 1 ])) . reduce (( m , o ) => { m [ o . match [ 1 ]] = o . attr ; return m ;},{}) . value (); let sortOrderKeys = _ . chain ( (( findObjs ({ type : 'attribute' , characterid : character . id , name : ` _reporder_$ { match [ 1 ]} ` })[ 0 ] || { get : _ . noop }). get ( 'current' ) || '' ). split ( /\s*,\s*/ )) . intersection ( createOrderKeys ) . union ( createOrderKeys ) . value (); if ( index < sortOrderKeys . length && _ . has ( attrs , sortOrderKeys [ index ])){ return attrs [ sortOrderKeys [ index ]]; } return ; } return findObjs ({ type : 'attribute' , characterid : character . id , name : name }, { caseInsensitive : ! caseSensitive })[ 0 ]; }; This function takes a character object and the name of an attribute.  If the attribute is a repeating attribute, it will find it based on the offset order. Hope that helps!
Huzzah! That did it! So... yes - that helped! And that is why we have forums... when you can't find the answer yourself, be assured someone else out there has at least tried and gotten farther! Thank you yet again.
On a side note, is there a way to make a "master" script file reference by other script files? Then functions like these could be in my "core code" and then easily references across multiple games. Or is that just not possible with how Roll20 works?
1619016761

Edited 1619016877
Oh and another thing... is there an "event" to trigger an update when someone was to update their character sheet? I haven't looked much but figured I would ask quick here as well. Looking to basically update "bar 2" when someone updates the sheet so it reflects back on the token display. Or should I setup an attribute to connect to bar 2 and then run script code to work off when that changes? Thanks