We use Cookies to help personalize and improve Roll20. For more information on our use of non-essential Cookies, visit our Privacy Policy here.
Accept
Advertisement Create a free account

Trying to figure out how to call an attribute value in an active number field

1584579536
Agent of Change
Pro
Sheet Author
Ok so short version i'm trying to figure out how to use an attribute as both the default value and max value for a number field. Here is the html for the value I'm calling:  <input type="number" class="field-edg transparent" name="attr_edg" title="@{edg}" value="1" min="1" max="6"> Here is the html for the section I'm trying to configure: <input type="number" class="field-edge-points font-name transparent" title="@{edge-points}" name="attr_edge-points" value="@{edg}" min="0" max="@{edg}" > Right now it defaults to a blank counter and minimums at 0 but has no effective maximum.  If I add disabled="true" to that string it sets it to the correct edg value but won't allow and incrementing anymore. Ideally the default state would be the value set for "@{edg}" and it would be the max value for the number field, the user should be able to increment it down to 0. Long term I'd like a button that resets it to the start value, and a function that send a message from the player to the chat log when incremented down.  I feel that the first of those is easier than the latter but i have no idea how to do either at this point so first things first.  Need to get the counter working correctly. Thanks
1584730802
Agent of Change
Pro
Sheet Author
I still haven't found a solution to this.  Anybody have any ides? Can a title pull only work as a static numerical value?
1584734987

Edited 1584837527
GiGs
Pro
Sheet Author
API Scripter
The best way to solve this issue is with a sheet worker. Change your second input to this <input type="number" class="field-edge-points font-name transparent" title="@{edge-points}" name="attr_edge-points" value="" min="0" /> The max doesnt matter since youre going to be handling that through a sheet worker. Step 2: if you dont have any sheet workers in your sheet, create a script block for them. This goes in your html page, usually at the bottom. <script type="text/worker">  </script> All sheet workers you create get put between those two script statements. Step 3, final part: Now for the sheet worker itself. Just copy this into the script block you just created. The lines that begin with // are explanations, you can delete them. // tell roll20 watch for changes in the values of edg and edge-points on('change:edg change:edge-points',  () => {     // when they change, start a function to grab their values and do some work     getAttrs(['edg', 'edge-points'], values => {                  // get the values of edge and edge-points in a form we can use         let edge = +values['edg'] ||0;         let points = +values['edge-points'] || 0;                  // create a variable based on egde-points, to work with                 let newpoints = points;         // check if edge-points are over edge; if so restrict to edge         if(newpoints > edge) newpoints = edge;         // check if edge-points are below 0, if so restrict to zero         else if (newpoints < 0) newpoints = 0;         // if the edge-points score has actually changed (either of the 2 if statements did anything) update the character sheet value.         if (newpoints !== points)             setAttrs({                 'edge-points': newpoints             });     }); }); Give this a try.
1584757107
Agent of Change
Pro
Sheet Author
THANK YOU VERY MUCH!!!!!!!!! GiGs you are a boss.  well this is my intro to sheet workers and I'm about to use this same general theory for about a dozen other things, the floodgates are open. Just FYI though, it didn't work at first (i do appreciate the explanation comments)  I needed to add a '(' before 'getattrs' but i figured that out.  Thanks again.
1584757355

Edited 1584757428
GiGs
Pro
Sheet Author
API Scripter
You're welcome, and congratulations on solving that deliberate puzzle I left you (or maybe I made a goof, who knows...) :) Thanks for mentioning it. I've fixed it in the original post, in case others find the thread and want to use the worker.
1584757930

Edited 1584758020
Agent of Change
Pro
Sheet Author
Quick question,  I have another group of values.  It's actually 12 values that all basically need the same sort of script to work properly.  In the interest of seeking elegant code is there a way to combine the script so that if any of the values are changed the script does it or is it better/more possible if I just do 12 more individual scripts. Basically I'm tracking armor and structure for a Battlemech and would like, exactly like the edge example above, the max value to be called from a defined value elsewhere. So i have following values that would need to refer to each other. Head armor, Head max/starting armor, Head structure,  Head max/starting Structure Torso armor,Torso max/starting armor, Torso structure,  Torso max/starting Structure Left Arm armor, Arms max/starting armor, Left Arm structure,  Arms max/starting Structure Right Arm armor, Arms max/starting armor, Right Arm,  Arms max/starting Structure Left Leg armor, Legs max/starting armor, Left Leg structure,  Legs max/starting Structure Right Leg armor, Legs max/starting armor, Right Leg structure,  Legs max/starting Structure
1584772867
GiGs
Pro
Sheet Author
API Scripter
Yes, this is possible. See this page for the approach I usually use:&nbsp; <a href="https://wiki.roll20.net/UniversalSheetWorkers" rel="nofollow">https://wiki.roll20.net/UniversalSheetWorkers</a> If you supply the attribute names for all the relative parts I'll show you how it works.
1584813278

Edited 1584813343
Agent of Change
Pro
Sheet Author
OK, so&nbsp; I plugged in a modified version of the edg script for the 12 fields last night and that is working.&nbsp; this is what I used: //script&nbsp; on('change:max change:ra-armor', () =&gt; { &nbsp; &nbsp; getAttrs(['arms-a-max', 'ra-armor'], values =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let max = +values['arms-a-max'] ||0; &nbsp; &nbsp; &nbsp; &nbsp; let current = +values['ra-armor'] || 0; &nbsp; &nbsp; &nbsp; &nbsp; let newcurrent = current; &nbsp; &nbsp; &nbsp; &nbsp; if(newcurrent &gt; max) newcurrent = max; &nbsp; &nbsp; &nbsp; &nbsp; else if (newcurrent &lt; 0) newcurrent = 0; &nbsp; &nbsp; &nbsp; &nbsp; if (newcurrent !== current)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'ra-armor': newcurrent &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); I am interested in efficiency&nbsp; so i would like to work out how to do more work with less code.&nbsp; That said the Attribute names are as follows: The source attributes: attr_head-a-max attr_head-s-max attr_torso-a-max attr_torso-s-max attr_arms-a-max&nbsp; (applies to both arms) attr_arms-s-max&nbsp; (applies to both arms) attr_legs-a-max&nbsp; (applies to both legs) attr_legs-s-max&nbsp; (applies to both legs) Destination attributes (the counters i want to be modified by the source) attr_head-armor attr_head-struc attr_torso-armor attr_torso-struc attr_ra-armor attr_ra-struc attr_la-armor attr_la-struc attr_rl-armor attr_rl-struc attr_ll-armor attr_ll-struc Additionally it would be awesome if I can script it so that when the reference attribute changes it automatically changes teh destination field to the new max value.&nbsp; I tried figuring that out last night to no avail before I crashed out. Thank you again for your help.
1584826825
GiGs
Pro
Sheet Author
API Scripter
There are two ways I;d approach this. The first is more complicated to write, the second is fairly easy to write but would require you rename your attributes. Note: attr_ in those names doesnt need to be there -&nbsp; it's not part of the attribute name, it's just an indicate to roll20 to that what follows is an attribute name. So, I would suggest changing the names as follows The max scores attr_head-armor-max attr_head-structure-max attr_torso-armor-max attr_torso-structure-max attr_arm-armor-max&nbsp;&nbsp; (applies to both arms) attr_arm-structure-max&nbsp; &nbsp;(applies to both arms) attr_leg-armor-max&nbsp; &nbsp;(applies to both legs) attr_leg-structure-max&nbsp; &nbsp;(applies to both legs) Destination attributes attr_head-armor attr_head-structure attr_torso-armor attr_torso-structure attr_rightarm-armor attr_rightarm-structure attr_leftarm-armor attr_leftarm-structure attr_rightleg-armor attr_rightleg-structure attr_leftleg-armor attr_leftleg-structure There are two reasons to do this: the first is for readability. There's no practical limit on attribute name lengths, so you should name them so they are easy ti read and understand. The second is for this process, you need to be able to match perfectly part of one attribute with another. So we can match "leg-armor" in the destination attribute&nbsp; rightleg-armor &nbsp;and&nbsp; leg-armor-max&nbsp; &nbsp;in the max set. Once we've done that we can approach the sheet worker. //&nbsp;first&nbsp;we&nbsp;create&nbsp;an&nbsp;array&nbsp;with&nbsp;the&nbsp;all&nbsp;common&nbsp;parts const&nbsp;bodyparts&nbsp;=&nbsp;['head-armor',&nbsp;'head-structure',&nbsp;'torso-armor',&nbsp;'torso-structure',&nbsp;'rightarm-armor',&nbsp;'rightarm-structure',&nbsp;'rightleg-armor',&nbsp;'rightleg-structure',&nbsp;'leftarm-armor',&nbsp;'leftarm-structure',&nbsp;'leftleg-armor',&nbsp;'leftleg-structure']; //&nbsp;now&nbsp;loop&nbsp;through&nbsp;each&nbsp;of&nbsp;those&nbsp;parts&nbsp;and&nbsp;create&nbsp;a&nbsp;worker&nbsp;for&nbsp;each bodyparts.forEach(part&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;in&nbsp;the&nbsp;next&nbsp;line,&nbsp;'part'&nbsp;is&nbsp;a&nbsp;placeholder&nbsp;for&nbsp;the&nbsp;currentbody&nbsp;part&nbsp;as&nbsp;you&nbsp;loop&nbsp;through&nbsp;the&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;on(`change:${part}&nbsp;change:${partmax}`,&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;create&nbsp;a&nbsp;reference&nbsp;we&nbsp;can&nbsp;use&nbsp;for&nbsp;the&nbsp;max&nbsp;attribute,&nbsp;by&nbsp;removing&nbsp;right&nbsp;and&nbsp;left&nbsp;if&nbsp;they&nbsp;exist&nbsp;in&nbsp;the&nbsp;part&nbsp;name. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;partmax&nbsp;=&nbsp;part.replace('right',&nbsp;''); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;partmax&nbsp;=&nbsp;part.replace('left',&nbsp;''); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;add&nbsp;max&nbsp;to&nbsp;the&nbsp;name,&nbsp;so&nbsp;the&nbsp;reference&nbsp;is&nbsp;now&nbsp;complete. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;partmax&nbsp;=&nbsp;partmax&nbsp;+&nbsp;"-max"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;now&nbsp;in&nbsp;the&nbsp;following,&nbsp;since&nbsp;we&nbsp;are&nbsp;using&nbsp;variables,&nbsp;they&nbsp;don't&nbsp;need&nbsp;to&nbsp;have&nbsp;quotes&nbsp;aroudn&nbsp;their&nbsp;names. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs([part,partmax],&nbsp;values&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;form&nbsp;here&nbsp;on&nbsp;its&nbsp;basically&nbsp;the&nbsp;same&nbsp;as&nbsp;before. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;max&nbsp;=&nbsp;+values[partmax]&nbsp;||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;current&nbsp;=&nbsp;+values[part]&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;newcurrent&nbsp;=&nbsp;current; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(newcurrent&nbsp;&gt;&nbsp;max)&nbsp;newcurrent&nbsp;=&nbsp;max; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(newcurrent&nbsp;&lt;&nbsp;0)&nbsp;newcurrent&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(newcurrent&nbsp;!==&nbsp;current)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[part]:&nbsp;newcurrent &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); That should do the trick. I dont understand what you mean here: what reference attribute are you referring to? Additionally it would be awesome if I can script it so that when the reference attribute changes it automatically changes teh destination field to the new max value.&nbsp; I tried figuring that out last night to no avail before I crashed out.
1584835067
Agent of Change
Pro
Sheet Author
I will try out that script here shortly because that's a lot less code than the 12 individual scripts and i have no worries changing attribute names. What i was saying and i apologize for being unclear is this:&nbsp; Using the original edge for an example. I have a stat on the page EDGE (edg) and we have Edge Points&nbsp; (edge-points).&nbsp; witht he earlier script we have set the maximum value for Edge points to the current value of Edge.&nbsp; I would like to know if there was a way that when the value of Edge changed if it would basically reset Edge points to that value.&nbsp; &nbsp;so like if someone upped their edge stat from 2 to 3 it would immediately assign a value of 3 to the edge points field regardless of the current value. Thats what i was working on but i couldn't make it work.&nbsp; &nbsp;I was calling Edge the reference value and the destination value being edge points.
1584838725
GiGs
Pro
Sheet Author
API Scripter
So the behaviour is as follows: When EDGE changes, edge-points get changed to that value, regardless of what they were before and when edge points change, they cant go above edge, or below zero. They are several different ways to do this. &nbsp;The easiest is to use two separate workers, the most efficient is to use a single worker (this requires a new property, eventInfo). So, as two workers, you would keep the original worker and add a new one. Though I just realised the original worker had a mistake in the first line (not a problem, just unnecessary part), so I'll post that here too // removed one of the change statements, not needed here on(' change:edge-points', &nbsp;() =&gt; { &nbsp; &nbsp; getAttrs(['edg', 'edge-points'], values =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let edge = +values['edg'] ||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let points = +values['edge-points'] || 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let newpoints = points; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; if(newpoints &gt; edge) newpoints = edge; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; else if (newpoints &lt; 0) newpoints = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; if (newpoints !== points) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 'edge-points': newpoints &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; }); &nbsp;&nbsp;&nbsp;&nbsp;}); }); Then the second worker monitors edg and changes edge-points, like so on(' change:edg', &nbsp;() =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;// only need to get edg this time, becuase it's going to overwite edge-points, &nbsp; &nbsp; getAttrs(['edg'], values =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let edge = +values['edg'] ||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'edge-points': edge &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, {silent:true}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); This is much shorter (and could be shorter still, but I want to make every step as easy to understand as possible). The addition to the setAttrs function is {silent:true}. This stops any changes made by this worker from triggering other workers. Without it, when you change edge-points, it would trigger the other worker (which has change:edge-points, &nbsp;so is watching for changes), and go through that function. But that function is irrelevant in this case, because edg and edge-points have just been set to the same value, so we stop it from triggering. Another approach is with a single sheet worker, where you monitor both attributes, and identify which one changed, and take action appropriately. // here we add a reference to eventInfo, so we can identify what triggered the change. on('change:edg change:edge-points', &nbsp;(eventInfo) =&gt; { &nbsp; &nbsp; getAttrs(['edg', 'edge-points'], values =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let edge = +values['edg'] ||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; let points = +values['edge-points'] || 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// we want a variable to hold the output (you'll see how this is used) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let output = {}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//check which attribute triggered this sheet worker &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let trigger = eventInfo.triggerName; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// the trigger must be either 'edg' or 'edge-points' so we can do an if/else statement &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// since the if statement contains more than a single line of instruction it has to be enclosed in {} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(trigger === 'edge-points') { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// do the edge-points function from before, but this time save the result in the output object. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let newpoints = points; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; if(newpoints &gt; edge) newpoints = edge; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; else if (newpoints &lt; 0) newpoints = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; if (newpoints !== points) output['edge-points'] = newpoints &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// if trigger is not edge-points, it must be edg, so we do the other worker &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output['edge-points'] = edge; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// now we have a a value to save, we update the sheet. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'edge-points': newpoints &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); });
1584838972

Edited 1584839311
Agent of Change
Pro
Sheet Author
Update, I changed all my attribute names and I tried to use the script above.&nbsp; It's not doing anything that I can tell, not messing anything up just not functioning as far as i can tell. further update tried the single worker solution above and I'm not sure what i'm doing wrong because that one is no acting like I have no worker at all.&nbsp; for reference this is my sheet-worker section at this point: &lt;script type="text/worker"&gt;&nbsp; //EdgePoints Scripts on('change:edg change:edge-points', (eventInfo) =&gt; { &nbsp; &nbsp; getAttrs(['edg', 'edge-points'], values =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let edge = +values['edg'] ||0; &nbsp; &nbsp; &nbsp; &nbsp; let points = +values['edge-points'] || 0; &nbsp; &nbsp; &nbsp; &nbsp; let output = {}; &nbsp; &nbsp; &nbsp; &nbsp; let trigger = eventInfo.triggerName; &nbsp; &nbsp; &nbsp; &nbsp; if(trigger === 'edge-points') { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let newpoints = points; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(newpoints &gt; edge) newpoints = edge; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (newpoints &lt; 0) newpoints = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (newpoints !== points) output['edge-points'] = newpoints &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output['edge-points'] = edge; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'edge-points': newpoints &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); //Armor Default Scripts const bodyparts = ['head-armor', 'head-structure', 'torso-armor', 'torso-structure', 'rightarm-armor', 'rightarm-structure', 'rightleg-armor', 'rightleg-structure', 'leftarm-armor', 'leftarm-structure', 'leftleg-armor', 'leftleg-structure']; bodyparts.forEach(part =&gt; { &nbsp; &nbsp; on(`change:${part} change:${partmax}`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs([part,partmax], values =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let max = +values[partmax] ||0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let current = +values[part] || 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let newcurrent = current; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(newcurrent &gt; max) newcurrent = max; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (newcurrent &lt; 0) newcurrent = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (newcurrent !== current)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [part]: newcurrent &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); &lt;/script&gt;
1584839799
GiGs
Pro
Sheet Author
API Scripter
Can you post your sheet code (both html and css files) to pastebin or gist, and link it here, so i can try it out and see what the issue is.
1584840187
Agent of Change
Pro
Sheet Author
Ok posted it in gist (a tool i didn't know existed) both HTML and CSS.&nbsp; This is the working copy I'm making edits in as use the sheet sandbox. Also i just started learning html/css a couple weeks ago so i apologize if my code does some strange things, I've been feeling my way through it. <a href="https://gist.github.com/AgentofChange/8d6d82086c6cae200098417fccb55289" rel="nofollow">https://gist.github.com/AgentofChange/8d6d82086c6cae200098417fccb55289</a>
1584843282
GiGs
Pro
Sheet Author
API Scripter
I should have noticed this in the code above - you changed the order of something and broke the worker. This const bodyparts = ['head-armor', 'head-structure', 'torso-armor', 'torso-structure', 'rightarm-armor', 'rightarm-structure', 'rightleg-armor', 'rightleg-structure', 'leftarm-armor', 'leftarm-structure', 'leftleg-armor', 'leftleg-structure']; bodyparts.forEach(part =&gt; { &nbsp; &nbsp; on(`change:${part} change:${partmax}`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs([part,partmax], values =&gt; { should be const bodyparts = ['head-armor', 'head-structure', 'torso-armor', 'torso-structure', 'rightarm-armor', 'rightarm-structure', 'rightleg-armor', 'rightleg-structure', 'leftarm-armor', 'leftarm-structure', 'leftleg-armor', 'leftleg-structure']; bodyparts.forEach(part =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; &nbsp; &nbsp; on(`change:${part} change:${partmax}`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; getAttrs([part,partmax], values =&gt; { Notice in your version that this on(`change:${part} change:${partmax}`, () =&gt; { comes before you define partmax, with&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; If you have a critical error like this, it stops all sheet workers from working.
1584846253
Agent of Change
Pro
Sheet Author
Thank you again,&nbsp; that appears to have fixed the Armor script (I thought I had copied it exactly) however the new edge script is still doing nothing at all as far as I can tell. I did throw in the two script solution for the Edge situation and it worked perfectly the first time.&nbsp; I was trying to reverse engineer the two script solution for the armor bits and It's not quite right.&nbsp; i'm probably missing a variable name: //So i didn't repeat the constant because that not being behind any closed it would be availabel to be called by any subsequent script and the first segment looked necessary for this to work bodyparts.forEach(part =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; //here I started changing variables, since the Max values are what i care about here i called that &nbsp;and only that on('change:${partmax}', () =&gt; { //following the pattern of the edge script I called part max in the get command &nbsp; &nbsp; getAttrs([partmax], values =&gt; { \\I left the the only let comment as the partmax defining it's value (at least i think thats whats happening&nbsp;there. &nbsp; &nbsp; &nbsp; &nbsp; let partmax = +values[partmax] ||0; //here i was trying to have the part overwrite as intended but I'm unsure if I changed the value correctly. &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [part]: partmax &nbsp; &nbsp; &nbsp; &nbsp; }, {silent:true}); &nbsp; &nbsp; }); }); In short the the fanciness of the bodyparts script has confused me as to how the redefined variables work.
1584846911
GiGs
Pro
Sheet Author
API Scripter
I havent been able to test the Edge function, because I cant find the attribute on the character sheet. I can find edge-points, but not edge. For the rest of your post, one thing that trips everyone up at first: when you have this syntax `change:${partmax}` noticee that the quotes used are not ' or " quotes, they are ` (backticks) found at the top left of most keyboards - to the left of the number 1. What the ${} is doing is letting you put a variable in that string, and it will be dynamically replaced by the value of partmax. But that doesmt work in a normal string (one using ' or "), you have to use backticks (`). Also when you use&nbsp; let &nbsp;it creates a new variable. It does not overwrite the original. To overwrite the original, you just reassign it with equals, as shown here: &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; In the 2nd and third lines, partmax is being overridden by whatever is on the right of the = sign.&nbsp; Regarding the rest of that script - I'm not following what you are trying to do. Why does the function I supplied not work? Doesnt it already grab the max valyues?
1584847957

Edited 1584847984
Agent of Change
Pro
Sheet Author
Yes teh armor script from before works, but what i'm trying to do is engineer a second script to do the same thing the second edge script does. So the ides is that when I change any of the max values it automatically sets the corresponding armor or structure value to match the max.
1584848524
GiGs
Pro
Sheet Author
API Scripter
ohhh right. So if you change the max, it sets any parts depending on that equal to the max?
1584850023
Agent of Change
Pro
Sheet Author
yup
1584860793
GiGs
Pro
Sheet Author
API Scripter
This should do the trick. Don't have much time to explain right now, but give it a try. const&nbsp;bodypartsmax&nbsp;=&nbsp;['head-armor',&nbsp;'head-structure',&nbsp;'torso-armor',&nbsp;'torso-structure',&nbsp;'arm-armor',&nbsp;'arm-structure',&nbsp;'leg-armor',&nbsp;'leg-structure']; bodyartsmax.forEach(max&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;on(`change:${max}`,&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs([`${max}-max`],&nbsp;values&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;score&nbsp;=&nbsp;+values[max]&nbsp;||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;output&nbsp;={}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(max.startsWith('arm')&nbsp;||&nbsp;max.startsWith('leg'))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`left${max}`]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`right${max}`]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[max]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output,&nbsp;{silent:true}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); });
1584913233

Edited 1584922204
Agent of Change
Pro
Sheet Author
Ok updates.&nbsp; The Edge scripts both still work normally and perfectly. So the first Bodyparts script, the current layout below works for every thing except the right arm and leg, the left side works great settign and enforcing a maximum of arm/leg-armor/structure as normal but the right side just allows any value above 0.&nbsp; Not sure what I broke on it. const bodyparts = ['head-armor', 'head-structure', 'torso-armor', 'torso-structure', 'rightarm-armor', 'rightarm-structure', 'rightleg-armor', 'rightleg-structure', 'leftarm-armor', 'leftarm-structure', 'leftleg-armor', 'leftleg-structure']; bodyparts.forEach(part =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; let partmax = part.replace('right', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = part.replace('left', ''); &nbsp; &nbsp; &nbsp; &nbsp; partmax = partmax + "-max"; &nbsp; &nbsp; on(`change:${part} change:${partmax}`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; getAttrs([part,partmax], values =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let max = +values[partmax] ||0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let current = +values[part] || 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let newcurrent = current; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(newcurrent &gt; max) newcurrent = max; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (newcurrent &lt; 0) newcurrent = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (newcurrent !== current)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [part]: newcurrent &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); Second the bodypartsmax script doesn't seem to be doing anything.&nbsp; I&nbsp;did notice a 'p' missing in " bodyartsmax.forEach" &nbsp;which i fixed but i'm still really unsure why the script isn't working.&nbsp; i'm tryign to understand it's functions and based on what worked on teh other scripts i'm not seeing anything glaring I can spot.&nbsp; Does the order of the scripts matter? here is what is the last text of the script i tried: const bodypartsmax = ['head-armor', 'head-structure', 'torso-armor', 'torso-structure', 'arm-armor', 'arm-structure', 'leg-armor', 'leg-structure']; bodypartsmax.forEach(max =&gt; { &nbsp; &nbsp; on(`change:${max}`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; getAttrs([`${max}-max`], values =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let score = +values[max] ||0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let output ={}; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(max.startsWith('arm') || max.startsWith('leg')) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output[`left${max}`] = score; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output[`right${max}`] = score; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output[max] = score; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs(output, {silent:true}); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); Also I can't figure out how to do a code block in post and I know that would make readability a bit better.
1584916566
GiGs
Pro
Sheet Author
API Scripter
I'll have a look at this later in the day, but for now, to get a code block: when youre writing a post, at the top of the text window, you have a bar across the top with buttons for B, I, U, and so on. The very left button on that bar hides a dropdown, which lets you apply some formatting to blocks of text. The Code option is in there.
1584930010
GiGs
Pro
Sheet Author
API Scripter
The issue in the first worker is this line (my mistake, sorry!) partmax = part.replace('left', ''); It should be partmax = partmax.replace('left', '');
1584934095
GiGs
Pro
Sheet Author
API Scripter
I had two errors in the second sheet worker. This is the fixed version, I;ll explain the errors below: const&nbsp;bodypartsmax&nbsp;=&nbsp;['head-armor',&nbsp;'head-structure',&nbsp;'torso-armor',&nbsp;'torso-structure',&nbsp;'arm-armor',&nbsp;'arm-structure',&nbsp;'leg-armor',&nbsp;'leg-structure']; bodypartsmax.forEach(max&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;on(`change:${max}-max`,&nbsp;()&nbsp;=&gt;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;// one error here &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs([`${max}-max`],&nbsp;values&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;score&nbsp;=&nbsp;+values[`${max}-max`]&nbsp;||0; // another error here &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;output&nbsp;={}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(max.startsWith('arm')&nbsp;||&nbsp;max.startsWith('leg'))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`left${max}`]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`right${max}`]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[max]&nbsp;=&nbsp;score; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output,&nbsp;{silent:true}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); So this worker loops through a collection of location names. Note that the names are not complete:&nbsp; arm-armor &nbsp;doesn;t quite match arm-armor-max, nor does it match rightarm-armor. But it is the part of the name that they both have in common. So when we go through the loop, the variable max becomes 'head-armor', then 'head-structure', then 'torso-armor', and so on until it has been all of them. We need to change whatever max is at present to perfectly match the attribute we are using it to access. Notice on the getAttrs line, I used&nbsp; `${max}-max` to turn that name into a proper attribute name. torso-armor would become torso-armor-max, which is what we need. But I forgot to do that on the on(change) line, and the let score line, As a result, they were trying to access attributes that didnt exist.
1584934234
GiGs
Pro
Sheet Author
API Scripter
Agent of Change said: Does the order of the scripts matter? In this case it doesn't. it can sometimes. If you create a variable outside of ascript (like i did with const bodyparts and bodypartsmax), those have to be defined before they are used.&nbsp;
1584977117
Agent of Change
Pro
Sheet Author
All scripts working like a charm! Thank you. Only gonna get more complicated.
1586458040
GiGs
Pro
Sheet Author
API Scripter
That;s the way it usually goes :) You're welcome.