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

How do I remove the current row from a repeating section?

Correction - it works most of the time. It randomly fails.
1614022768
GiGs
Pro
Sheet Author
API Scripter
My solution would be to remove chatSetAttrs and just rely on manual entry, since that always works. It might not look as good, but the roll20 platform has limits and its best to work within them. Plus if you ever drop down from Pro, you'll be able to keep using the sheet -relying on chatSetAttrs binds you to pro forever.
An I will likely have to do as you suggest, but it will eliminate almost all of the automation in the sheet. If there was another way to make die rolls inside the sheet and another way to generate popup input windows, that would do the trick, but this is the only way I can find to do these things.
1614025149
GiGs
Pro
Sheet Author
API Scripter
Yeah, one common approach is to build the sheet as best you can within roll20's limits. And then have a Companion Script that has the features you want that the sheet itself cant do. You can also integrate them by having a configuration setting on the sheet to show buttons or other elements designed for the companion script only when the setting is checked, and then hide the stuff that those elements replace.
Here's an example of one of the things I'm trying to do: At the beginning of a combat, each character rolls a die for initiative. When playing face to face, this die is placed on the table next to the character sheet. Each turn, the player selects a maneuver, and the speed of that maneuver is added to the initiative die to determine the order of play. I can do this with ChatSetAttr by using a macro that rolls the initiative die and then sets an attribute on the sheet which causes it to display on the sheet and leaves it available to use in any macro. If I take out ChatSetAttr, the initiative cannot be stored on the sheet. Macros on the sheet then cannot call that value automatically.
1614027903
GiGs
Pro
Sheet Author
API Scripter
Since the initiative die if rolled only one once per combat, you could easily have a place (attribute) on the character sheet for people to manually enter the value. Then just have the necessary macros incorporate that attribute value.
That's what I'm rewriting it to do. I just hate having to click on the character sheet to roll, then look at the chat to see the value, then go back to the character to manually enter the value. And I'm going to have a dozen other buttons that work the same way. Unfortunately, that's the only thing that seems to work reliably. 
1614197023

Edited 1614200692
Ken
Pro
After reading your thread (and not understanding almost any of the sheet coding), your last message brought something to mind that might help you. What if you set up macros to run most of it through a 'chat menu'? If I am understanding what is going on correctly, with a chat menu you would be able to do everything without opening up the character sheet *except* entering the information on the sheet (so would only have to open it once to add your maneuver speed for the action taken) Chat Menus Edit: This kept going through my head. Question - does each maneuver have the same speed each time? (like maneuver A = 5, manenuver B = 8, maneuver c = 13)? If so, you could do that through the chat menu i linked before (with a series of choices that would automatically display the maneuver with the maneuver speed) and output a result of the two combined. The only downside of this is that the maneuver speed would not be input into the character sheet. You could also use the tokens, and set your bars to "Initiative Roll", "Maneuver Speed", and leave one open (or use for hp or whatever else you want to display on the token) Using the token, when first rolling initiative, physically put that roll to the bubble for bar1. That bubble would stay as is for the whole combat. When picking the maneuver, the speed for that maneuver could be placed into the bubble for bar2, and be changed each round. That way you could see the Initiative Roll and the chosen Maneuver Speed just by clicking on the token. You could even reference those through a macro.
So the awesome script works great. I have three different health bars, one for physical wounds, one for mental stressors, and one for psychic wounds. I thought I could get away with copying the script and changing "wounds" to "stressors" and changing "health" to "mid" to reflect the appropriate HTMl controls. It did not work. What am I missing? Here's what I changed the copy to: on('change:repeating_stressors:severity remove:repeating_stressors', function(eventInfo) {     const output = {};     let severities = Array(6).fill(0);     const sevmins = [0, 1, 5, 8, 10, 12];     getSectionIDs('repeating_stressors', idarray => {         const fields = [];         idarray.forEach(id => fields.push(`repeating_stressors_${id}_severity`));         getAttrs(fields, values => {             idarray.forEach(id => {                 const sev = parseInt(values[`repeating_stressors_${id}_severity`]) || 0;                 if(sev==0){                     removeRepeatingRow('repeating_stressors_' + id);                 } else {                     if ([1, 2, 3, 4, 5].includes(sev)) {                         severities[sev] = severities[sev] +1;                     } else {                         severities[0] = severities[0] +1;                     }                 }             });             const findNextEmptyStressor = (arr, start) => arr.indexOf('0', start);             const healthtrack = severities.reduce((arr, size, index) => {                 if (index === 0) return arr;                 for(let i = 0; i < size; i++) {                     const nextEmpty = findNextEmptyStressor(arr, sevmins[index]);                     if(nextEmpty > 0) arr[nextEmpty] = '1';                 }                 return arr;             }, Array(13).fill('0'));             healthtrack.forEach((check, index) => {                 if(index > 0) {                     output[`mind${index}`] = check;                 }             });             const getStressorMod = (stressors, stressorBands) => {                 const biggestStressor = stressors.lastIndexOf('1') === -1 ? 0 : stressors.lastIndexOf('1');                 const whichBand = 5-stressorBands.reverse().findIndex(index => biggestStressor >= index);                 return -whichBand;             };             output['mind-mod'] = getStressorMod(healthtrack, sevmins);             setAttrs(output);         });     }); });
I tried changing the names of the repeating sections and modifying the sheet worker so one script would modify all three sections, but it does not work. Here is what I tried: HTML Sheet worker
1615230029
GiGs
Pro
Sheet Author
API Scripter
This thread has a lot of back and forth. Can you post the sheet worker that worked for one section , and that you're happy with, and I'll figure out how to convert it to work for the three sections.
This was the sheet worker that works for the one section: on('change:repeating_body:severity remove:repeating_body', function(eventInfo) {     // create a holding object to save attributes     const output = {};          // initialise an array to track the severity values. This assumes severities have values of 1-5     let severities = Array(6).fill(0);     // an array for the minumum pont on the wound track each wound size must mark.     const sevmins = [0, 1, 5, 8, 10, 12];     getSectionIDs('repeating_body', idarray => {         const fields = [];         idarray.forEach(id => fields.push(`repeating_body_${id}_severity`));         getAttrs(fields, values => {             idarray.forEach(id => {                 const sev = parseInt(values[`repeating_body_${id}_severity`]) || 0;                 if(sev==0){                     removeRepeatingRow('repeating_body_' + id);                 } else {                     if ([1, 2, 3, 4, 5].includes(sev)) {                         severities[sev] = severities[sev] +1;                     } else {                         // if a severity is outside the valid range of 1-5, add it to                          severities[0] = severities[0] +1;                     }                 }             });                          // a function to find the first eligible 0 value in the body track             const findNextEmptyWound = (arr, start) => arr.indexOf('0', start);             // a complex function to build a bodytrack of 0-12 with values 0 or 1.             // I would normally explain how this function works, but lets just say its magic.             // reduce is an extremely powerful function, but not easy to explain.             const bodytrack = severities.reduce((arr, size, index) => {                 if (index === 0) return arr;                 for(let i = 0; i < size; i++) {                     const nextEmpty = findNextEmptyWound(arr, sevmins[index]);                     if(nextEmpty > 0) arr[nextEmpty] = '1';                 }                 return arr;             }, Array(13).fill('0'));             // now that we know which points on bodytrack are 1 and which 0, save them to output.             bodytrack.forEach((check, index) => {                 if(index > 0) {                     // set the body track value to 0 or 1.                     output[`body${index}`] = check;                 }             });             const getWoundMod = (wounds, woundBands) => {                 // this will give the largest entry that has a marked wound, and 0 if no wounds.                 const biggestWound = wounds.lastIndexOf('1') === -1 ? 0 : wounds.lastIndexOf('1');                 // this will find which wound band that wound falls into                 const whichBand = 5-woundBands.reverse().findIndex(index => biggestWound >= index);                 return -whichBand;             };             output['body-mod'] = getWoundMod(bodytrack, sevmins);             setAttrs(output);         });     }); }); I had thought that if I changed the "health1" "health2", etc fields to "body1", "body2", etc., and changed the "repeating_wounds" section to "repeating_body" I could then have a "repeating_mind" section with "mind1", "mind2" etc., and a "repeating_psyche" with "psyche1" and so on and then be able to run it all through a single script, but all I did was get it to stop working altogether.
1615239290
GiGs
Pro
Sheet Author
API Scripter
If this one stopped working, because you made changes to other workers, that means there was a syntax error somewhere - a missing or extra bracket, comma, and so on; easy to do when making this kind of tweak. In principle, what you were trying to do should work - but a better way is to turn the above worker inot a more universal function that serves all three sections. I'll look over the code later and see what needs to be changed. What are the three repeating sections caused (you referred to wounds earlier, but this one is called body), and what are the relevant attributes inside each section. In the above section there are body1 , body2 , up to 5? body-mod severity Knowing the equivalent names in each section will be necessary.
1615240839

Edited 1615241090
GiGs
Pro
Sheet Author
API Scripter
Looking over the swrker you linked above, there is a line with a big error in it. This:         getSectionIDs([repeatingWoundType], idarray => { should be          getSectionIDs (` repeating_${woundType}` ,  idarray   =>  { getSectionIDs isnt the same as getAttrs. It doesnt want an array, it just wants a string, the name of the repeating section. Technically this should work         getSectionIDs(woundType, idarray => { (supplying just 'body' instead of 'repeating_body', and leaving off the repeating_ part), but in practice there are situations where this doesnt work properly so its always best to supply the 'repeating_' part.
body1 to body5, body-mod, and severity for the first section mind1 to mid5, mind-mod, and severity for the second, and psyche1 to psyche5, psyche-mod, and severity for the third section. with the sections being, repeating_body, repeating_mind, and repeating_psyche
1616020429

Edited 1616020479
GiGs
Pro
Sheet Author
API Scripter
Hi, sorry RL caught up with me in a big way. I think I'm missing some information, can you post the full sheet code, html and css, in an external link? Now time to start catching up on hundreds of roll20 notifications. If only it gave you only one notification per thread...
Yeah, this last week seems to have been crazy for everyone. I'm just grateful for the help. html css