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

[Help] Changing linked token bar values based on character sheet radio button changes

Hello all! I am, at best, a novice coder. Recently with the covid lockdown my friends and I have moved our games to roll20. One of those games is a Zweihander RPG game. We have loaded the character sheet and it has two condition tracks, peril and damage. They essentially go from 0 to 5, perfect for bars on a token. However, because of the way the game works, each of the steps on the tracks have their own variable name and a corresponding value, so there is no one value you can set these token bar values to. I tried to create a custom sheet based on the code and adding some on (change:variable) code in it but it didn't work. The values on the sheet are: "Damage_Track_1", "Damage_Track_2", "Damage_Track_3", "Damage_Track_4", "Damage_Track_5", "Damage_Track_6" for the Damage track and "peril_unhindered","peril_imperiled","peril_ignore_one","peril_ignore_two","peril_ignore_three","peril_incapcitated" for the peril track. I tried to add the following code to the character sheet. Keep in mind that the values for the peril track are as follows when the radio button is selected: peril_imperiled = 1, peril_ignore_one = -10, peril_ignore_two = -10, peril_ignore_three = -10 and peril_incapcitated = 1.  // Peril Token Change on("change:peril_imperiled change:peril_ignore_one change:peril_ignore_two change:peril_ignore_three change:peril_incapcitated", function(obj) { getAttrs(["peril_imperiled","peril_ignore_one","peril_ignore_two","peril_ignore_three","peril_incapcitated"], function(values) { obj.set({ bar1_value: parseInt(values.peril_imperiled,10) + parseInt(values.peril_incapcitated,10) + (parseInt(values.peril_ignore_one,10) / -10) + (parseInt(values.peril_ignore_two,10) / -10) + (parseInt(values.peril_ignore_three,10) / -10) }); }); }); I am clearly doing something wrong because this did nothing. However, I would rather not customize the sheet. I would rather add a separate API for this in addition to the official character sheet. Can someone lend me a hand, please? I would like it so that every radio button checked beyond the first (i.e. zero value) of each track, adds 1 to one of the three bars on a token. Ideally the blue one would be peril and the red one would be damage and when you remove a radio button the value drops from the token. Thus creating a 0-5 value for both red and blue token bars. Thank you, Ben G
Anyone?
1590417695
GiGs
Pro
Sheet Author
API Scripter
Character sheets cannot change tokens - they can only change attrubute values on the actual sheet. The way to solve this problem would be to have the sheet worker set a new attribute, and then you can select this attribute for tokens. So create a hidden input somewhere on the character sheet <input type="hidden" name="attr_peril_total" value="0"> Then in your sheet worker, set the attribute peril_total on("change:peril_imperiled change:peril_ignore_one change:peril_ignore_two change:peril_ignore_three change:peril_incapcitated", function(obj) { getAttrs(["peril_imperiled","peril_ignore_one","peril_ignore_two","peril_ignore_three","peril_incapcitated"], function(values) { obj.set({ peril_total: parseInt(values.peril_imperiled,10) + parseInt(values.peril_incapcitated,10) + (parseInt(values.peril_ignore_one,10) / -10) + (parseInt(values.peril_ignore_two,10) / -10) + (parseInt(values.peril_ignore_three,10) / -10) }); }); }); Note: i havent checked the rest of the sheet worker works. I suspect you'll want to manipulate it a bit, but that#s what you need to get it working. The question is what happens when players inevitably modify the token bar value?
1590417837
GiGs
Pro
Sheet Author
API Scripter
Ben G. said: Can someone lend me a hand, please? I would like it so that every radio button checked beyond the first (i.e. zero value) of each track, adds 1 to one of the three bars on a token. Ideally the blue one would be peril and the red one would be damage and when you remove a radio button the value drops from the token. Thus creating a 0-5 value for both red and blue token bars. To clarify: you want two attributes, one set by the damage boxes, and the other set by the peril boxes? Is there any relationship between the peril and damage tracks?
GiGs said: The question is what happens when players inevitably modify the token bar value? It would over write what we did, which should be ok because when someone next hits the radio button it will fix it.
GiGs said: To clarify: you want two attributes, one set by the damage boxes, and the other set by the peril boxes? Is there any relationship between the peril and damage tracks? Yes, two separate values for two separate token bars. No, there is no relationship between the two,
1590521963

Edited 1590522052
GiGs
Pro
Sheet Author
API Scripter
I finally found the time to look at your sheet worker properly and noticed a significant error in the body. obj.set needs too be setAttrs when running from a sheet worker. on("change:peril_imperiled change:peril_ignore_one change:peril_ignore_two change:peril_ignore_three change:peril_incapcitated", function(obj) { getAttrs(["peril_imperiled","peril_ignore_one","peril_ignore_two","peril_ignore_three","peril_incapcitated"], function(values) { setAttrs({ peril_total: (parseInt(values.peril_imperiled)||0) + (parseInt(values.peril_incapcitated)||0) + ((parseInt(values.peril_ignore_one)||0) / -10) + ((parseInt(values.peril_ignore_two)||0) / -10) + ((parseInt(values.peril_ignore_three)||0) / -10) }); }); }); I would rewrite it a bit more. on("change:peril_imperiled change:peril_ignore_one change:peril_ignore_two change:peril_ignore_three change:peril_incapcitated", function(obj) { getAttrs(["peril_imperiled","peril_ignore_one","peril_ignore_two","peril_ignore_three","peril_incapcitated"], function(values) {             const imperil = parseInt(values.peril_imperiled)||0;             const incap = parseInt(values. peril_incapcitated )||0;             const ignoreone = parseInt(values.peril_ignore_one)||0 ;             const ignoretwo = parseInt(values.peril_ignore_two)||0 ;             const ignorethree = parseInt(values.peril_ignore_three)||0 ; setAttrs({ peril_total: imperil + incap + ((ignoreone + ignoretwo + ignorethree)/ -10) }); }); }); From this you should be able to see how to do the damage one. Note I rewrote the parseInt function to include a default (|| 0), and to remove theb unneccesary radix (the ,10) inside the brackets. By the way, I'd check the spelling for the  peril_incapcitated  attribute. Should it be  peril_incapacitated?
Thanks for the help, I will try and mess with it this weekend. Good eye on the spelling but no, that is correct. I suspect the writer of the sheet made the mistake and decided just to run with it.
Forget waiting. Tested it just now. I had to assign Peril_Total to the bar on the token but it worked perfectly. Now the big ask. Do you know if there is any way to do this without modifying the sheet directly? Can it be done as an Script API maybe?
1590789520
GiGs
Pro
Sheet Author
API Scripter
This could be done as a script yes, but its not as straightforward. You have to set a change:attribute  event, then check if the attribute name is one of the relevant ones. Then identify which character that attribute changed on, since the api registers changes for all characters Then search every token (possibly on every map), and identify which if any belong to that character (looking in the token's represents property) Then update the relevant tokenbar of every token that belongs to that character
1590793909

Edited 1590797024
GiGs
Pro
Sheet Author
API Scripter
There's also an extra complication - adding the values to the token in the first place, without having to change every character's attributes. Here's a stab at an API script to do this. Just change the numbers in lines 3 and 4 to the bars you actually want to use. on('ready', () => { const bars = { peril: 1, damage: 2 }; const damages = ['Damage_Track_1', 'Damage_Track_2', 'Damage_Track_3', 'Damage_Track_4', 'Damage_Track_5', 'Damage_Track_6']; const perils = [ 'peril_unhindered','peril_imperiled','peril_ignore_one','peril_ignore_two','peril_ignore_three','peril_incapcitated']; const calcScore = (charid, peril = false) => { const stats = peril ? perils : damages; return stats.reduce((total, name) => total += (parseInt(getAttrByName(charid, name))||0) === 0 ? 0 : 1, 0); }; on('change:attribute:current', function(obj) { const att = obj.get('name'); if(perils.includes(att) || damages.includes(att)) { const char = getObj('character', obj.get('characterid')); // do a search of all matching tokens const tokens = findObjs({ _type: 'graphic', represents: char.id }); const score = calcScore (char.id, perils.includes(att)); tokens.forEach(token => { token.set({[`bar${perils.includes(att) ? bars.peril : bars.damage}_value`]: score}); }); } }); on('add:graphic', function(obj) { if(obj.get('represents') != '') { const token_id = obj.id; _.delay(()=>{ const token=getObj('graphic',token_id); if(token){ const char = getObj('character', obj.get('represents')); obj.set({ [`bar${bars.peril}_value`]: calcScore(char.id, true), [`bar${bars.damage}_value`]: calcScore(char.id, false) }); } }, 300); } }); });
OK! That 100% worked. I changed which bars it modified in the beginning as I wanted green aka 1 for peril as you put it and red aka 3 for damage. Simple enough. However, both Damage_Track_1 and peril_unhindered are both the zero values for their respective tracks. They are the "unharmed" states. Right now, this script does 1 to 6 and I need it to do 0 to 5 and I cannot understand the script enough to figure out where you are calculating that. I will work on it a bit and see if I cannot figure it out. If you read this before I reply than feel free to highlight what I need to change. If I didn't say it before,GiGs, thanks a TON for your help on this!!!!
I got it working by appending a - 1 to the end of const score = calcScore (char.id, perils.includes(att)) However, could I just remove the first value in each of const damages and const perils respectively?
That 100% worked. I took out that clunky -1 and removed the starting values and voila. It ran perfectly! You are awesome! Is there any way to give you credit for this and/or to publish it for the Zweihander community to use?
1591366064
GiGs
Pro
Sheet Author
API Scripter
I meant to ask about that 0 point stat, as i thought that might be the case. Glad you got it working. And Thank you! If the zweihander sheet has a page on the wiki, you could add to it a link to this thread and a description. I dont know how else to give visibility for it. Feel free to mention it in any zweihander forums you frequent.
on('ready', () => {     const bars = {         // 1 is green top bar, 2 is blue middle bar and 3 is bottom red bar. Set them below as you see fit.         peril: 1,         damage: 2     };     const damages = ['Damage_Track_2', 'Damage_Track_3', 'Damage_Track_4', 'Damage_Track_5', 'Damage_Track_6'];     const perils = [ 'peril_imperiled','peril_ignore_one','peril_ignore_two','peril_ignore_three','peril_incapcitated'];          const calcScore = (charid, peril = false) => {         const stats = peril ? perils : damages;         return stats.reduce((total, name) => total += (parseInt(getAttrByName(charid, name))||0) === 0 ? 0 : 1, 0);     };     on('change:attribute:current', function(obj) {         const att = obj.get('name');         if(perils.includes(att) || damages.includes(att)) {             const char = getObj('character', obj.get('characterid'));             // do a search of all matching tokens             const tokens = findObjs({                 _type: 'graphic',                    represents: char.id             });                          const score = calcScore (char.id, perils.includes(att));                          tokens.forEach(token => {                 token.set({[`bar${perils.includes(att) ? bars.peril : bars.damage}_value`]: score});             });         }     });     on('add:graphic', function(obj) {         if(obj.get('represents') != '') {             const token_id = obj.id;             _.delay(()=>{                 const token=getObj('graphic',token_id);                 if(token){                     const char = getObj('character', obj.get('represents'));                     obj.set({                         [`bar${bars.peril}_value`]: calcScore(char.id, true),                         [`bar${bars.damage}_value`]: calcScore(char.id, false)                     });                 }             }, 300);         }     }); });
Reposted with the changes.