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

Generic Functions

1497659733

Edited 1497659741
Coal Powered Puppet
Pro
Sheet Author
I found a  thread talking about generic functions .  If I can figure this out, it would help me a lot.  Is there anyone who can explain this with colored markers and big poster boards?  I am making a sheet for the Cortex system, and it uses a lot of "steps", starting at d0, d2, d4 and going all the way to d12+d2, d12+d4, etc.  I was hoping to get one set of sheet workers to use when something is increased a few steps at a time. 
Thought I'd mention that if you'd prefer to use a macro (benefit is being able to use Roll Queries to modify step number), I've written a few macros for Earthdawn's step system. Assuming it works the same way, I'd just need a picture of the step table to write a macro for it
I actually want to set this up using sheet workers, and do it that way.  Right now, I can make a series of a hundred sheet workers to do what I want, and I am hoping for a across the board fix. Macros...macros have a tendency to drive me (more) bonkers.
1497667669
Lithl
Pro
Sheet Author
API Scripter
The problem that the code is trying to solve is having several blocks of code that are similar, and creating a function that will do those repeated actions with the small differences replaced by parameters. Exactly what that entails varies widely by the logic you're trying to achieve.
Renaming things to make the code works is doable.  Right, so this is what I have, and works; I would love to make an easy set of code everything can use, instead of 47 sheet workers with only name changes:      //Step Calc part 1 on("change:Agility_select change:Agility_mod sheet:opened", function() {         getAttrs(["Agility_select", "Agility_mod"], function(values) {             setAttrs({                 Agility_subtotal: +values.Agility_select + +values.Agility_mod             });         });     });     //Step Calc part 2 on("change:Agility_subtotal sheet:opened", function() {     getAttrs(["Agility_subtotal"], function(values) {         if (values.Agility_subtotal == 0) {             setAttrs({                  Agility: 'd0'             })         } else if (values.Agility_subtotal == 1) {             setAttrs({  Agility: 'd2'             })         } else if (values.Agility_subtotal == 2) {             setAttrs({  Agility: 'd4'             })         } else if (values.Agility_subtotal == 3) {             setAttrs({  Agility: 'd6'             })         } else if (values.Agility_subtotal == 4) {             setAttrs({  Agility: 'd8'             })         } else if (values.Agility_subtotal == 5) {             setAttrs({  Agility: 'd10'             })         } else if (values.Agility_subtotal == 6) {             setAttrs({  Agility: 'd12'             })         } else if (values.Agility_subtotal == 7) {             setAttrs({  Agility: 'd12+d2'             })         } else if (values.Agility_subtotal == 8) {             setAttrs({  Agility: 'd12+d4'             })         } else if (values.Agility_subtotal == 9) {             setAttrs({  Agility: 'd12+d6'             })         } else if (values.Agility_subtotal == 10) {             setAttrs({  Agility: 'd12+d8'             })         } else if (values.Agility_subtotal == 11) {             setAttrs({  Agility: 'd12+d10'             })         } else if (values.Agility_subtotal == 12) {             setAttrs({  Agility: 'd12+d12'             })         }     }); });
1497730831

Edited 1497731270
Jakob
Sheet Author
API Scripter
Like this? (Remark: I think you need to lowercase your attribute names in all events). var stats = ['Agility', 'Wits', 'Strength']; stats.forEach(stat => {   'use strict';   on(`change:${stat.toLowerCase()}_select change:${stat.toLowerCase()}_mod sheet:opened`, () => {     getAttrs([`${stat}_select`, `${stat}_mod`], function(values) {       let setting = {};       setting[`${stat}_subtotal`] = +values[`${stat}_select`] + +values[`${stat}_mod`];       setAttrs(setting);     });   });   on(`change:${stat.toLowerCase()}_subtotal sheet:opened`, function() {     let dieFromSubtotal = {       '0': 'd0',       '1': 'd2',       '2': 'd4',       '3': 'd6',       '4': 'd8',       '5': 'd10',       '6': 'd12',       '7': 'd12+d2',       '8': 'd12+d4',       '9': 'd12+d4',       '10': 'd12+d8',       '11': 'd12+d10',       '12': 'd12+d12'     };     getAttrs([`${stat}_subtotal`], function(values) {       let setting = {};       setting[stat] = dieFromSubtotal[values[`${stat}_subtotal`]]; // Might want to add some defaults here in case something is undefined       setAttrs(setting);     });   }); }); I don't if there's a whole lot to explain, basically, you need to replace every string with Agility in it by the templated version, which also requires you to write the objects a bit differently, because you cannot use a variable name as the key for an object if you write it as a literal (or at least I don't know how you could do it).
I will try it out.  Thank you
This works great.  Thank you very much. Another question: does this work at all with repeating fields?
1497881158
Jakob
Sheet Author
API Scripter
Coal Powered Puppet said: This works great.  Thank you very much. Another question: does this work at all with repeating fields? Yes, with the right alterations depending on what exactly you want to do :). If you have a bunch of repeating sections, with a bunch of attributes within each section, plus a bunch of non-repeating attributes whose changes you still care about to calculate stuff within the section, you will probably have to loop over several objects to do it.
So far, all I have done is use this code for the attributes and non-repeating skills.  This is amazing , Jakob.  Thank you.
Oh, Master Jacob, Wandering master of all things Sheet Workers...I got another issue you help me with. The idea is that when the player selects something from a drop down (foo_attrib) it will populate three fields (foo_AttName, foo_AttRating, and foo_EpicRating).  foo_AttName is suppose to be the name of an attribute, foo_AttRating is a number equal to the corresponding @{attribute}, and foo_EpicRating is equal to foo_box.   Here is what I got, and it is not working.  What did I do wrong? var stats = ['Appearance','Charisma','Dexterity','Intelligence','Manipulation','Perception', 'Strength', 'Stamina', 'Wits', 'Appearance_box','Charisma_box','Dexterity_box','Intelligence_box','Manipulation_box','Perception_box', 'Strength_box', 'Wits_box', 'Stamina_box',]; stats.forEach(stat => {   'use strict';   on(`change:${stat.toLowerCase()}_attrib change:${stat.toLowerCase()}_box sheet:opened`, () => {     getAttrs([`${stat}_attrib`, `${stat}_box`], function(values) {       let setting = {};       setting[`${stat}_AttRating`] = ${stat};       setAttrs(setting);     });   });   on(`change:${stat.toLowerCase()}_AttName sheet:opened`, function() {     let dieFromSubtotal = {       '0': 'None',       '1': 'Appearance',       '2': 'Charisma',       '3': 'Dexterity',       '4': 'Intelligence',       '5': 'Manipulation',       '6': 'Perception',       '7': 'Stamina',       '8': 'Strength',       '9': 'Wits'     };     getAttrs([`${stat}_box`], function(values) {       let setting = {};       setting[`${stat}_EpicRating`] = [values[`${stat}_box`];       setAttrs(setting);     });   }); });
1499518059
Jakob
Sheet Author
API Scripter
So, the code is all kinds of wrong, but I don't even completely understand what you want to do, and in some cases it conflicts with what you have actually written in the code. So, you have one select, or multiples (one for each attribute)? What is the name of the select/selects (as in name="attr_???")? What are the option values for the select(s)? Once we have that, maybe you can explain how exactly the value of the ${foo}_AttName, ${foo}_AttRating and ${foo}_EpicRating attributes are determined from the select/selects. Because from what I've reading here, you have one select for each attribute, and can select any of the attributes in each of them, and that seems to make no sense.
Jakob said: So, the code is all kinds of wrong... S it is worse than I thought.  Okay.  Here is what I want it to do, for a single drop-down: on("change:Academics_attrib change:Strength_box change:Dexterity_box change:Stamina_box change:Charisma_box change:Manipulation_box change:Appearance_box change:Intelligence_box change:Wits_box change:Perception_box change:Strength change:Dexterity change:Stamina change:Charisma change:Manipulation change:Appearance change:Intelligence change:Wits change:Perception sheet:opened", function() {     getAttrs(['Academics_attrib', 'Perception', 'Wits', 'Intelligence', 'Appearance', 'Manipulation', 'Charisma', 'Stamina', 'Dexterity', 'Strength', 'Perception_box', 'Wits_box', 'Intelligence_box', 'Appearance_box', 'Manipulation_box', 'Charisma_box', 'Stamina_box', 'Dexterity_box', 'Strength_box'], function(values) {             if (values.Academics_attrib == 1 ) {                 setAttrs({                     Academics_AttName: 'Appearance',                     Academics_AttRating: values.Appearance,                     Academics_EpicRating: values.Appearance_box                 })             }             else if (values.Academics_attrib == 2 ) {                 setAttrs({                     Academics_AttName: 'Charisma',                     Academics_AttRating: values.Charisma,                     Academics_EpicRating: values.Charisma_box                 })             }             else if (values.Academics_attrib == 3 ) {                 setAttrs({                     Academics_AttName: 'Dexterity',                     Academics_AttRating: values.Dexterity,                     Academics_EpicRating: values.Dexterity_box                 })             }             else if (values.Academics_attrib == 4 ) {                 setAttrs({                     Academics_AttName: 'Intelligence',                     Academics_AttRating: values.Intelligence,                     Academics_EpicRating: values.Intelligence_box                 })             }             else if (values.Academics_attrib == 5 ) {                 setAttrs({                     Academics_AttName: 'Manipulation',                     Academics_AttRating: values.Manipulation,                     Academics_EpicRating: values.Manipulation_box                 })             }             else if (values.Academics_attrib == 6 ) {                 setAttrs({                     Academics_AttName: 'Perception',                     Academics_AttRating: values.Perception,                     Academics_EpicRating: values.Perception_box                 })             }             else if (values.Academics_attrib == 7 ) {                 setAttrs({                     Academics_AttName: 'Stamina',                     Academics_AttRating: values.Stamina,                     Academics_EpicRating: values.Stamina_box                 })             }             else if (values.Academics_attrib == 8 ) {                 setAttrs({                     Academics_AttName: 'Strength',                     Academics_AttRating: values.Strength,                     Academics_EpicRating: values.Strength_box                 })             }             else if (values.Academics_attrib == 9 ) {                 setAttrs({                     Academics_AttName: 'Wits',                     Academics_AttRating: values.Wits,                     Academics_EpicRating: values.Wits_box                 })             }             else if (values.Academics_attrib == 0 ) {                 setAttrs({                     Academics_AttName: 'None',                     Academics_AttRating: 0,                     Academics_EpicRating: 'None'                 })             }         });     });  Let me see if I can explain this a little better.  I am going to break this very far down to make sure I'm saying it right.  You, by all evidence, understand a much higher level of coding than I knew existed. Player selects from a drop down menu (select) the last attribute (Wits, which is the option with a value "9").   Code installs the name Wits in the name="attr_Academics_AttName" input. Code installs the value of @{Wits} in the name="attr_Academics_AttRating" input.  This is a number Code installs the value of @{Wits_box} in the name="attr_Academics_EpicRating" input.  This is also a number, pulled from a series of radio inputs. Upon all of that, when the roll button is pressed, a roll template displays that Academics is added to Wits (rating whatever) and has an Epic Rating of (whatever).   
1499522970

Edited 1499523381
Jakob
Sheet Author
API Scripter
Ah, thank you! Sometimes it's VERY helpful to know what exactly is going on. Part of what programming is about is to break down problems to their essence until they end up trivial :). Part of what had me confused is that there are two lists of attributes going on, stats (Charisma) on the one hand and skils (Academics) on the other hand. So, the following does the same thing as what you are doing in the code above, except that the fixed 'Academics' is replaced by a loop over the skills array. I mention it in the code, but it would be simpler if the value of the dropdown was simply "Wits" and not "9", but if there is a good reason to keep the 9, then by all means, keep it. var stats = ['Appearance', 'Charisma', 'Dexterity', 'Intelligence', 'Manipulation', 'Perception', 'Strength', 'Stamina', 'Wits'],   skills = ['Academics', 'Underwater_Basketweaving']; skills.forEach(function (skill) {   'use strict'; // relevantAttrs is e.g. ['Apperance', 'Charisma', ... , 'Appearance_box', ... , 'Academics_attrib']   let relevantAttrs = [...stats, ...stats.map(stat => `${stat}_box`), `${skill}_attrib`];   on(relevantAttrs.map(x => `change:${x.toLowerCase()}`) + ' sheet:opened', function () {     getAttrs(relevantAttrs, function (values) {       // Note: you could get rid of this step if the skill_attrib select just stored the name       // of the attribute, and not some cryptic number.       let numToStat = {           '0': 'None',           '1': 'Appearance',           '2': 'Charisma',           '3': 'Dexterity',           '4': 'Intelligence',           '5': 'Manipulation',           '6': 'Perception',           '7': 'Stamina',           '8': 'Strength',           '9': 'Wits'         },         attributeName = numToStat[values[`${skill}_attrib`]] || 'None', // translate number to a stat name         setting = {}; // Set values according to known attributeName       setting[`${skill}_AttName`] = attributeName;       setting[`${skill}_AttRating`] = values[attributeName] || 0; // The "|| 0" is for the case of None.       setting[`${skill}_EpicRating`] = values[`${attributeName}_box`] || 0;       // Remark: EpicRating treats the case of None differently than your code, but I think 0 makes more sense here than None.       setAttrs(setting);     });   }); });
So everything works when I reload the page.  How do I get it to work when the @{skill_attrib} is changed? And what part- exactly- do I delete if I do as you suggested and change 0-9 to the actual names?  The story behind that is rather complicated.  Best describe as a series of scripting misadventures and confusion and not enough booze, which resulted in me going to the very, very basics.  Hence, numbers.  
1499530086
Jakob
Sheet Author
API Scripter
Oops, I messed up the event. Replace the corresponding line by this (changes in bold)   on(relevantAttrs.map(x => `change:${x.toLowerCase()}`) .join(' ') + ' sheet:opened', function () { Currently, the event string looks like ["change:appearance", ... "change:charisma", ... "change:academics_attrib"] sheet:opened, which of course does not work at all. With regard to the change, suppose the select looks like this instead: <select name="attr_academics_attrib"> <option value="None">None</option> <option value="Appearance">Appearance</option> .... </select> Then 1) you obviously don't need ${skill}_AttName anymore at all 2) you don't need the numToStat and attributeName variables in the above script 3) instead, the attributeName is just values[`${skill}_attrib`]. So the innermost function is something like this getAttrs(relevantAttrs, function (values) { let setting = {}; setting[`${skill}_AttRating`] = values[values[`${skill}_attrib`]] || 0; // The "|| 0" is for the case of None. setting[`${skill}_EpicRating`] = values[values[`${skill}_attrib`] + '_box'] || 0; setAttrs(setting); });
This works, very well.  Amazingly well.  You, good sir, are a valuable resource. Thank you once again.
1499626545
Jakob
Sheet Author
API Scripter
Happy to help.
New problem, one, and only one section of this code is not updating properly:     //REAPTING mod value setting var stats = ['Skill1','Skill2', 'Skill3', 'Skill4', 'Skill5', 'Skill6', 'Skill7', 'Skill8', 'Skill9', 'Skill10', 'Skill11', 'Skill12', 'Skill13', 'Skill14', 'Skill15', 'Skill19', 'Skill17', 'Skill18', 'Skill19', 'Skill20', 'Skill21', 'Skill22']; stats.forEach(stat => {   'use strict';   on(`change:repeating_${stat}:${stat.toLowerCase()}_Spec_select change:repeating_${stat}:${stat.toLowerCase()}_Spec_mod sheet:opened`, () => {     getAttrs([`repeating_${stat}_${stat}_Spec_select`, `repeating_${stat}_${stat}_Spec_mod`], function(values) {       let setting = {};       setting[`repeating_${stat}_${stat}_Spec_subtotal`] = +values[`repeating_${stat}_${stat}_Spec_select`] + +values[`repeating_${stat}_${stat}_Spec_mod`];       setAttrs(setting);     });   });   on(`change:repeating_${stat}:${stat.toLowerCase()}_Spec_subtotal sheet:opened`, function() {     let dieFromSubtotal = {       '0': 'd0',       '1': 'd2',       '2': 'd4',       '3': 'd6',       '4': 'd8',       '5': 'd10',       '6': 'd12',       '7': 'd12+d2',       '8': 'd12+d4',       '9': 'd12+d4',       '10': 'd12+d8',       '11': 'd12+d10',       '12': 'd12+d12',       '13': 'd12+d12+d2',       '14': 'd12+d12+d4',       '15': 'd12+d12+d6',       '16': 'd12+d12+d8',       '17': 'd12+d12+d10',       '18': 'd12+d12+d12'     };     getAttrs([`repeating_${stat}_${stat}_Spec_subtotal`], function(values) {       let setting = {};       setting[stat] = dieFromSubtotal[values[`repeating_${stat}_${stat}_Spec_subtotal`]]; // Might want to add some defaults here in case something is undefined       setAttrs(setting);     });   }); }); I think, at the very end, "setting[stat]" is suppose to refer to "repeating_${stat}_${stat}" but I don't know how to name it right.  Am I making sense?
Never mind, I figurd it out.  I is SMRT!
Ooooooookay.  Hopefully the last time on this subject: Right now, I am using  this code (plus what ya fixed for me).  Within his code sum that is compared to the following, and spits out "d#" on(`change:${stat.toLowerCase()}_subtotal sheet:opened`, function() {     let dieFromSubtotal = {       '0': 'd0',       '1': 'd2',       '2': 'd4',       '3': 'd6',       '4': 'd8',       '5': 'd10',       '6': 'd12',       '7': 'd12+d2',       '8': 'd12+d4',       '9': 'd12+d4',       '10': 'd12+d8',       '11': 'd12+d10',       '12': 'd12+d12'     }; Now, I would like a code that does the same thing, but with adding something first. I thought this would work, but it does not. var stats = ['Skill1']; stats.forEach(stat => {   'use strict';   on(`change:${stat.toLowerCase()}_select sheet:opened`, function() {     let dieFromSubskill = {       '0': 'd0',       '1': 'd2',       '2': 'd4',       '3': 'd6',       '4': 'd8',       '5': 'd10',       '6': 'd12',       '7': 'd12+d2',       '8': 'd12+d4',       '9': 'd12+d4',       '10': 'd12+d8',       '11': 'd12+d10',       '12': 'd12+d12'     };     getAttrs([`${stat}_select`], function(values) {       let setting = {};       setting[stat] = dieFromSubskill[values[`${stat}_ratiing`]]; // Might want to add some defaults here in case something is undefined       setAttrs(setting);     });   }); });
1500453120
Jakob
Sheet Author
API Scripter
You are trying to access values[`${stat}_ratiing`] (typo btw), but in the first argument for getAttrs, you are getting [`${stat}_select`]?
I want the sheet to get the values[`${stat}_select`],compare it to the list to find a die, and set values[`${stat}_rating`] to that die. Stupid typo.  I will check to see if this works it.
Holy crap, your advice fix it.  I think the code knew I was talking to you and got intimidated.  Thank you! This has caused me days of fustration.  Thank you again.
1500482475
Jakob
Sheet Author
API Scripter
Coal Powered Puppet said: Holy crap, your advice fix it.  I think the code knew I was talking to you and got intimidated.  Thank you! This has caused me days of fustration.  Thank you again. Ha!