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

Sheet worker help

1610824190

Edited 1610824314
I have a series of checkboxes to represent wounds. Whenever a box from the trivial wounds section is checked, it applies a -1 modifier, when a box from the light wounds is checked, it applies a -2 modifier, etc. It then takes the highest value of all the sections (i.e. if two trivial wounds are checked, and 1 light wound is checked, it would display "-2"). I got this to display the way I want using an autocalc field, but when I pass that to a button macro, it crashes. I; sure there is a way to update the field with a sheet worker instead, but I have no clue how to accomplish this. What I have right now is: HTML             <div class="health-bar">                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health1_flag" value="1" />                   <button type="action" name="act_health1" class="health left-cap">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health2_flag" value="1"/>                   <button type="action" name="act_health2" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health3_flag" value="1" />                   <button type="action" name="act_health3" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health4_flag" value="1" />                   <button type="action" name="act_health4" class="health bar-divider">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health5_flag" value="7" />                   <button type="action" name="act_health5" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health6_flag" value="2" />                   <button type="action" name="act_health6" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health7_flag" value="2" />                   <button type="action" name="act_health7" class="health bar-divider">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health8_flag" value="3" />                   <button type="action" name="act_health8" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health9_flag" value="3" />                   <button type="action" name="act_health9" class="health bar-divider">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health10_flag" value="4" />                   <button type="action" name="act_health10" class="health">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health11_flag" value="4" />                   <button type="action" name="act_health11" class="health bar-divider">k                     <span class="chequed">k</span>                   </button>                 </div>                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health12_flag" value="5" />                   <button type="action" name="act_health12" class="health right-cap">k                     <span class="chequed">k</span>                   </button>                 </div>                 <input type="hidden" name="attr_w1" value="(((@{health1_flag} + @{health2_flag}) + abs(@{health1_flag} - @{health2_flag})) / 2)"/>                 <input type="hidden" name="attr_w2" value="(((@{health3_flag} + @{health4_flag}) + abs(@{health3_flag} - @{health4_flag})) / 2)"/>                 <input type="hidden" name="attr_trivial" value="(((@{w1} + @{w2}) + abs(@{w1} - @{w2})) / 2)"/>                 <input type="hidden" name="attr_w3" value="(((@{health5_flag}*2 + @{health6_flag}*2) + abs(@{health5_flag}*2 - @{health6_flag}*2)) / 2)"/>                 <input type="hidden" name="attr_light" value="(((@{w3} + @{health7_flag}*2) + abs(@{w3} - @{health7_flag}*2)) / 2)"/>                 <input type="hidden" name="attr_minor" value="(((@{trivial} + @{light}) + abs(@{trivial} - @{light})) / 2)"/>                 <input type="hidden" name="attr_moderate" value="(((@{health8_flag}*3 + @{health9_flag}*3) + abs(@{health8_flag}*3 - @{health9_flag}*3)) / 2)"/>                 <input type="hidden" name="attr_severe" value="(((@{health10_flag}*4 + @{health11_flag}*4) + abs(@{health10_flag}*4 - @{health11_flag}*4)) / 2)"/>                 <input type="hidden" name="attr_major" value="(((@{moderate} + @{severe}) + abs(@{moderate} - @{severe})) / 2)"/>                 <input type="hidden" name="attr_nonfatal" value="(((@{minor} + @{major}) + abs(@{minor} - @{major})) / 2)"/>                 <input disabled type="number" class="wound-mod" name="attr_wounded-mod" value="-1*(((@{nonfatal} + @{health12_flag}*5) + abs(@{nonfatal} - @{health12_flag}*5)) / 2)"/>             </div>             <div class="health-bar">                 <label style="width:96px;text-align:center;padding:0px;font-weight:normal;font-size:10px;border-right: solid 1px;">Trivial</label>                 <label style="width:72px;text-align:center;padding:0px;font-weight:normal;font-size:10px;border-right: solid 1px;">Light</label>                 <label style="width:48px;text-align:center;padding:0px;font-weight:normal;font-size:10px;border-right: solid 1px;">Moderate</label>                 <label style="width:48px;text-align:center;padding:0px;font-weight:normal;font-size:10px;border-right: solid 1px;">Severe</label>                 <label style="width:32px;text-align:center;padding:0px;font-weight:normal;font-size:10px;">Fatal</label>             </div>             </div> Sheet worker: <script type="text/worker">   // Register the click handler to all specified buttons.   const healthList = ["health1","health2","health3","health4","health5","health6","health7","health8","health9","health10","health11","health12"];   healthList.forEach(function(button) {     on(`clicked:${button}`, function() {       const flag = `${button}_flag`;       // Check the current value of the hidden flag.       getAttrs([flag], function(v) {         // Update the value of the hidden flag to "1" for checked or "0" for unchecked.         setAttrs({           [flag]: v[flag] !== "1" ? "1" : "0"         });       });     });   }); </script> CSS .sheet-wound-mod{     font-size:24px;     font-weight:bold;     color:red;     text-align:center;     border:none;     background-color:transparent; } .sheet-bar-divider{     border-right: solid 1px #FFF !important; } .sheet-left-cap{     border-radius:50% 0% 0% 50%;     border-right:none !important; } .sheet-right-cap{     border-radius:0% 50% 50% 0%; } .sheet-health-bar{     display:flex;     margin-top:-8px; } /* Configure a container for the health */ .sheet-health-container {   display: inline-flex;   align-items: center; } button.sheet-health:focus{     outline:0 !important; } /* Configure the button styling. This example makes it look like a checkbox. */ button.sheet-health {   padding: 0;   border: solid 1px #000;   border-left:none;   border-right:none;   cursor: pointer;   background-color:#BDBDBD;   width: 24px;   height: 24px;   display: flex;   justify-content: center;   align-items: center;   font-family:pictos;   font-size: 18px;   color:#FFF; } .sheet-chequed{     position:absolute;     font-family:pictos;     color:#FF3300; } /* Hide the "checked" section of the health if the attribute value is not "1". */ input.sheet-health:not([value="1"]) ~ button.sheet-health > span.sheet-chequed {   display: none; }
1610853502
GiGs
Pro
Sheet Author
API Scripter
It's likely your penalty calculation attributes arent working properly. They need to be disabled to work as autocalcs. So this: <input type="hidden" name="attr_w1" value="(((@{health1_flag} + @{health2_flag}) + abs(@{health1_flag} - @{health2_flag})) / 2)"/> should be <input type="hidden" name="attr_w1" value="(((@{health1_flag} + @{health2_flag}) + abs(@{health1_flag} - @{health2_flag})) / 2)" disabled="true"> The fact they are hidden is hiding this. If you use @{selected|w1} to test their values you'll likely see they aren't working properly.
1610853699
GiGs
Pro
Sheet Author
API Scripter
Another problem I notice: <input type="hidden" class="health" name="attr_health5_flag" value="7" />                   <button type="action" name="act_health5" class="health">k                     <span class="chequed">k</span>                   </button> Your sheet worker button only checks for values of 1, but this has a value of 7. Changing to a sheet worker to calculate all the modifiers would be a better approach.
I wasn't sure how it was working, so I changed that value to 7 to see if it changed anything. It didn't.
Changing them to disabled fixed the problem. Thank you! That was driving me nuts.
1610883678

Edited 1610883708
GiGs
Pro
Sheet Author
API Scripter
I just picked that 7 as an example - you have several values that are different from 1, multiple 2s, 3,s, 4s, and a 5. Edit: You're welcome
The question is, can I replace those disabled autocalc inputs for a sheetworker? I'm having trouble getting that autocalc into my overly complex macro. If I had a field that just contained the result as a number without a formula, it would make things infinitely easier.
I got it to work this way, but the macro now freezes up the browser for 20 seconds while it calculates the whole formula.
1610891730
GiGs
Pro
Sheet Author
API Scripter
Thats pretty slow! Yes, you can replace those disabled inputs with a sheet worker, and it wont lag the sheet like that.  You can also simplify the calculations. It looks like your w1, w2, and w3 attributes are just there to help construct some of the other stats. So they wont be needed in the sheet worker version. Before I post a sample worker, which attributes do you actually need calculated? A single sheet worker will calculate them all. Which of trivial, light, minor, moderate, etc., are actually needed? Imagine you only need to calculate the ones you actually use in the game.
Trivial wounds are worth -1, Light wounds -2, moderate wounds -3, severe wounds -4, and fatal wounds -5. When a player has one or more wounds checked, I need it to calculate the worst modifier. So if a character has 2 trivial wounds, it would be a net -1. If they then take a moderate wound, that would change the value to a -3. If they took a second moderate wound, it would still be a -3, and son on. The modifier is determined by the worst category of wound the character has.
1610940408
GiGs
Pro
Sheet Author
API Scripter
So you count only the single largest modifier? Does the sheet record the number of wounds you catually take? That is, can players mark down they have taken 2 trivial wounds? It would be possible for a sheet worker to calculate this appropriately, but I need to know how the sheet records it.
So, with the boxes each having a value of 1 or zero (which makes the checkboxes work right), I need a single attr_wounded-mod that has a value of -1 * MAX(health1_flag, health2_flag, haelth3_flag, health4_flag, health5_flag*2, health6_flag*2, health7_flag*2, health8_flag*3, health9_flag*3, health10_flag*4, health11_flag*4, health12_flag*5)
1610947832

Edited 1610947912
GiGs
Pro
Sheet Author
API Scripter
Is there are a reson you are using action buttons to change attributes, like this:                 <div class="health-container">                   <input type="hidden" class="health" name="attr_health1_flag" value="1" />                   <button type="action" name="act_health1" class="health left-cap">k                     <span class="chequed">k</span>                   </button>                 </div> instead of just using an actual checkbox like               <input type="checkbox" class="health health-container" name="attr_health1_flag" value="1" /> You can probably style the checkbox to look like a button, and dont need a sheet worker to do the change, and you dont need to embed it in a div. Obviously you'd need a label to identify which wound its for. I'm not saying you should  do it this way, I'm just curious about the reason for the button method.
1610950871

Edited 1610965515
GiGs
Pro
Sheet Author
API Scripter
Here's a sheet worker with explanatory comments. It replaces your existing one. So delete this current code: // Register the click handler to all specified buttons.   const healthList = ["health1","health2","health3","health4","health5","health6","health7","health8","health9","health10","health11","health12"];   healthList.forEach(function(button) {     on(`clicked:${button}`, function() {       const flag = `${button}_flag`;       // Check the current value of the hidden flag.       getAttrs([flag], function(v) {         // Update the value of the hidden flag to "1" for checked or "0" for unchecked.         setAttrs({           [flag]: v[flag] !== "1" ? "1" : "0"         });       });     });   }); and replace with this (it handles the button clicks as well as the wound-mod calculation). It is untested, but the principle works. (It has been tested now.) // create a function to create an array of numbers (like from 1 to 12) const   buildRange  = ( start , end )  =>  [... Array ( end )]. map (( _ ,  index )  =>   index  +  start ); // use that function to get an array of numbers from 1 to 12. const   buttonIndices  =  buildRange ( 1 , 12 );                 // the map function lets us build an array, and join turns it into a string, so we can create the  // code for the 'changed' part without having to type out all 12 click event strings. on ( buttonIndices . map ( f   =>   `clicked:health ${ f } ` ). join ( ' ' ),  eventInfo   =>  {      // get which button was just clicked (need to update its value); eventInfo gives is the name of the clicked button      // then need to extract the actual button number, and convert from a string to a number.      const   whichButton  = + eventInfo . triggerName . replace ( 'clicked:health' ,  '' ) ||  0 ;                                      // again map lets use build an array of the 12 attribute names      getAttrs ( buttonIndices . map ( f   =>   `health ${ f } _flag` ),  values   =>  {          // create a variable to hold the values to save to the sheet          const   output   = {};                                          // update attribute that was actually clicked, both in current values, and to update on the sheet           // use the clicked button number to construct the attribute name.                 const   clickedFlag  =  `health ${ whichButton } _flag` ;          // toggle the value between 0 and 1          const   clickedValue  =  1  - (+ values [ clickedFlag ] ||  0 );          // update the values (as well be using it later), and save to output          // remember the button has been clicked, but the attribute hasnt been updated yet.          values [ clickedFlag ] =  clickedValue ;          output [ clickedFlag ] =  clickedValue ;                                          // get the largest clicked value          // first create an array of the correct size, showing the wound multiples at each index (1-12)          const   multiples  = [ 0 ,  1 ,  1 ,  1 ,  1 ,  2 ,  2 ,  2 ,  3 ,  3 ,  4 ,  4 ,  5 ];          // then create an array of all the actual wound modifiers, by multiplying each button value by its multiple.          // the first item is 0 because that element doesnt get used, only array[1] to array[12] are used.          const   wounds  =  buttonIndices . map ( i   =>  (+ values [ `health ${ i } _flag` ] ||  0 ) *  multiples [ i ]);          // then use Math.max to find the largesat modifier, and make it negative          const   largestWound  = - Math . max (... wounds );          // finally update the output variable to be saved to the sheet          output [ 'wounded-mod' ] =  largestWound ;                                          //update the clicked button value and the wound modifier          setAttrs ( output );     }); }); You also need to change your woonded-mod attribute to readonly, not disabled: sheet workers cant update disabled attributes. So that would be <input type="number" class="wound-mod" name="attr_wounded-mod" value="0" readonly> The code in the sheet worker could be shortened, but I wanted to spell out the steps.
1610964108

Edited 1610965273
GiGs
Pro
Sheet Author
API Scripter
The code in the above post had a small syntax error which I've corrected. Also you'll want to set the values of all you health1_flag attributes to 0 not 1, to start with, otherwise new characters will start with them all checked. For example:                  < div   class = "health-container" >                      < input   type = "hidden"   class = "health"   name = "attr_health1_flag"   value = "0"   />                      < button   type = "action"   name = "act_health1"   class = "health left-cap" > k                          < span   class = "chequed" > k </ span >                      </ button >                  </ div >                  make sure all 1-12 flags have a value="0", and the wound mod attribute is readonly, like so: < input   type = "number"   class = "wound-mod"   name = "attr_wounded-mod"   value = "0"   readonly   /> Having tested it now, I see why you are using the button method. I like the design a lot. It's cool. Thank you for supplying enough code, including CSS, for me to build a proper test.
Thank you! This works perfectly! And it now passes the value to the macro without a huge delay.
And thank you for indulging me on so many dumb questions. I have no real knowledge of css or javascript, and I have just been stealing snippets and tweaking them. Having someone who knows what they are doing is a huge help.
1610988818
GiGs
Pro
Sheet Author
API Scripter
You're welcome :) You're doing a pretty good job of tweaking the stuff you find - that's how most of us start.