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 .
×
May your rolls be chill this holiday season!
Create a free account

A Syntatical Conumdrum

1600744335

Edited 1600744391
Ah, the classic developer's problem.  What the heck does this other developer's code do?  This however, is a variation on that theme, as I know what the code does.  How the heck does it do it? I have this function that I believe GiGs wrote for me.  It adds up sets of enabled values from a repeating section.  It works great, but I want to expand its functionality.  The problem is that it is fairly dense and full of syntax I'm not yet familiar with.  I've been studying it and googling heavily, but I could use some clarification. I realize there's a bit of a learning curve for me here.  If someone could just describe the data structures that are being used and how they are being loaded, that would be great.  I understand concepts well.  If this were C++ I could juggle data structures with the best of them, but this javascript syntax is still a bit foreign to me.  It looks like arrays are being loaded with custom data structures. The purpose of this post is just to learn to read the worker as it is currently written.  However, I thought it might be helpful if I describe what it is I'm trying to do.  I'm not asking for this function to be rewritten for me, but if you did, I couldn't really object.  What I really want though, is to learn what it does, so I can rewrite it myself.  I mean, I know what it does.  I just don't know how it does it. So repeating_effects is loaded with "effects".  Each "effect" has a name, a checkbox called "toggle" that records whether the "effect" is enabled, and a set of 45 key value pairs, called "modifiers".  Each "modifier" has a label and a numerical value. The 45 "modifier" labels are the same for each "effect", but their numerical values can be different. What I'd like to do is: Add another checkbox to each "effect" called "hidden" that records whether the "effect" is shown or hidden. Then I'd like to is go through all the "effects" and make a list of only those "effects" where the "toggle" checkbox is enabled, and the "hidden" checkbox is disabled, meaning that these effects are both enabled, and shown.  Let's call these selected effects. Then I want to create an array of 45 empty arrays of strings, one for each "modifier" in an "effect". Then I want to go through each selected "effect", one "modifier" at a time.  If a selected "effect" has a modifier value other than 0, I want to add the name of that "effect" in string form, to the array of strings associated with that "modifier".  So say that the first of the 45 arrays of strings is the array associated with the "physicalstrength" modifier.  Once this step is complete, that array would contain the names of each selected "effect" that has a non-zero value for the "physicalstrength" modifier.  And all 45 would be filled in this way for their associated "modifiers". Now, inside the set of 45 modifiers, there are some modifiers that ultimately stand alone, and some that are grouped together.  The next step would be to combine the arrays for those modifiers which are grouped together.  This will take the number of arrays from 45 to 31. Then I want to remove any duplicates in an individual array, that were created by combining arrays. Then I'll take each of the remaining arrays, and concatenate it into a single space separated string.  This way I'll go from 31 arrays of strings, to 31 strings. Then I'll run through the remaining array and store each of those 31 strings in its own attribute.  This way, when each of the 31 rolls are made, I can include a list of all the "effects" that modified that roll. You know what?  If someone could just go through the function line by line and write out what it is doing, like I did with the 8 steps I just listed, that might be all I need to learn to read this function. Also, I've spent months working on this character sheet, and I've asked a lot of questions.  I've had a lot of help, but I keep wondering what if anything is expected from me in return for this help.  Are there people who are paid by Roll20 to answer questions on these forums?  Is that what I'm contributing, a monthly subscription fee?  Do my documented questions and their answers help others?  Or is there some social contract I'm unaware of and failing to fulfill? // add up effects modifiers const modifiers = [ 'physicalstrength', 'mentalstrength', 'mystictalent', 'meleedamage', 'rangeddamage', 'initiative', 'air', 'entropy', 'mental', 'physicalendurance', 'mentalendurance', 'mysticpower', 'meleeresistancepenalty', 'rangedresistancepenalty', 'mysticresistancepenalty', 'earth', 'bludgeoning', 'divine', 'agility', 'personality', 'defense', 'melee', 'ranged', 'mystic', 'fire', 'piercing', 'infernal', 'observation', 'abilitymagicpoints', 'defensemagicpoints', 'meleemagicpoints', 'rangedmagicpoints', 'spellmagicpoints', 'water', 'slashing', 'checks', 'actionpoint', 'abilityactionpoints', 'defenseactionpoints', 'meleeactionpoints', 'rangedactionpoints', 'spellactionpoints', 'animus', 'biological', 'skillrolls' ]; const section_field = (section, field, id = ':') => `repeating_${section}${id === ':' ? id : `_${id}_`}${field}`; const buildChanges = modifiers.reduce((total,item) => `${total} change:${section_field('effects', item)}_modifier`,''); on(`${buildChanges} change:repeating_effects:effect_checkbox remove:repeating_effects sheet:opened`, () => { getSectionIDs('repeating_effects', idarray => { const fieldnames = []; idarray.forEach(id => { modifiers.forEach(mod => fieldnames.push(section_field('effects', `${mod}_modifier`, id))); fieldnames.push(section_field('effects', 'effect_checkbox', id)); }); getAttrs(fieldnames, v => { const output = {}; modifiers.forEach(mod => output[`${mod}_modifier_total`] = 0); idarray.forEach(id => { const toggle = int(v[section_field('effects', 'effect_checkbox', id)]); if(toggle) { modifiers.forEach(mod => { output[`${mod}_modifier_total`] = output[`${mod}_modifier_total`] + int(v[section_field('effects', `${mod}_modifier`, id)]); }); } }); setAttrs(output); }); }); });
1600751003

Edited 1600751241
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I'm obviously not GiGs, but here's my understanding of the code: // add up effects modifiers const modifiers = [//An array of various modifiers you need to react to 'physicalstrength', 'mentalstrength', 'mystictalent', 'meleedamage', 'rangeddamage', 'initiative', 'air', 'entropy', 'mental', 'physicalendurance', 'mentalendurance', 'mysticpower', 'meleeresistancepenalty', 'rangedresistancepenalty', 'mysticresistancepenalty', 'earth', 'bludgeoning', 'divine', 'agility', 'personality', 'defense', 'melee', 'ranged', 'mystic', 'fire', 'piercing', 'infernal', 'observation', 'abilitymagicpoints', 'defensemagicpoints', 'meleemagicpoints', 'rangedmagicpoints', 'spellmagicpoints', 'water', 'slashing', 'checks', 'actionpoint', 'abilityactionpoints', 'defenseactionpoints', 'meleeactionpoints', 'rangedactionpoints', 'spellactionpoints', 'animus', 'biological', 'skillrolls' ]; //section_field assembles the repeating section call so it is correct for us in the listener const section_field = (section, field, id = ':') => `repeating_${section}${id === ':' ? id : `_${id}_`}${field}`; //buildChanges assembles a listener string for use in the on() out of all the modifiers const buildChanges = modifiers.reduce((total,item) => `${total} change:${section_field('effects', item)}_modifier`,''); //listen to each of those things on(`${buildChanges} change:repeating_effects:effect_checkbox remove:repeating_effects sheet:opened`, () => { //get the sectionIDs getSectionIDs('repeating_effects', idarray => { const fieldnames = []; //fieldnames will hold the names of all the repeating fields we need to get. we iterate over the idarray and for each id, push an assembled repeating attribute name to fieldnames idarray.forEach(id => { modifiers.forEach(mod => fieldnames.push(section_field('effects', `${mod}_modifier`, id))); fieldnames.push(section_field('effects', 'effect_checkbox', id)); }); //get the current attribute values of all of the fields getAttrs(fieldnames, v => { const output = {};//An object that will store our key:value pairs of attribute_name:attribute_value modifiers.forEach(mod => output[`${mod}_modifier_total`] = 0);//initialize them to 0 for each total idarray.forEach(id => { const toggle = int(v[section_field('effects', 'effect_checkbox', id)]);//toggle is either 0 (checkbox unchecked) or some number(checked) if(toggle) {//if toggle is truthy (in this case, not 0 and not NaN, undefined, or null) then do add the modifiers from it to the value stored in output modifiers.forEach(mod => { output[`${mod}_modifier_total`] = output[`${mod}_modifier_total`] + int(v[section_field('effects', `${mod}_modifier`, id)]); //add the modifier from this effect to the total for that modifier }); } }); //and finally set output setAttrs(output); }); }); }); Now, for what you want to do. I think that you could do what you want much more easily depending on how you have your roll buttons set up. I'd need to see the relevant html to be sure though before I send you off on a wild goose chase. EDIT  Actually, all I really need to know is this; what does your roll button look like for one of these? and are you displaying the total somewhere on the sheet? As for your questions and the answers you've gotten. No, there's no strings attached. We're just a bunch of people that enjoy sharing our knowledge, and (at least in my case) are paying the help we received forward. As for the social contract, your questions help others that are looking for answers to similar issues. Ideally, you'll pay the help forward as well and we'll wind up with another knowledgeable person on the forums who might have great ideas once they know the tech behind the scenes.
1600788662

Edited 1600798030
GiGs
Pro
Sheet Author
API Scripter
Agreed totally with Scott's last paragraph. I'll add a little extra explanation to go along with his comments. section_field is a function that return strings. If it's easier to understand, another way to write that would be something like function section_field(section, field, id = ':') {     let output = section + '_';     if(id === ':') {         output += ":" + field;     } else {         output += id + "_" + field;     }     return output; } The purpose of this function is to give you a string you can use either in the on(change) line, or the getAttrs([]) line. I often use different versions of this function, but the one here is designed to be used with functions using getSectionIDs, where you either need a string in the form suitable for the on(change) line, or one suitable for use in the getAttrs line. So if you call it like this: let name  = section_field('section', 'attribute'); it'll gave you a name in this format: 'repeating_section:attribute' which is perfect for use on on('change') lines. And if you call it in this format: let name  = section_field('section', 'attribute', 'id'); it'll gave you a name in this format: 'repeating_section_id_attribute' which is perfect for use in the getAttrs array. so wherever you see section_field, it is creating an repeating section attribute name in one of those two formats. buildChanges is a self-building variable. When you have a lot of attributes to watch for changes, it can be tiresome to list them all out. buildChanges lets you streamline that, especially if you already have your attributes in an array for some reason. I use various forms of buildChanges across my sheets, some as more universal functions. This one is specifically built to create a variable that includes the change events for all the attributes with _modifier added to the end of their names. So it'll return a string like 'change:repeating_effects:defense_modifier change:repeating_effects:melee_modifier change:repeating_effects:ranged_modifier change:repeating_effects:mystic_modifier etc' which you can just plug into the on('change') line. It's a lot more concise than writing all those out! It's possible to build this variable-creating function to accept different inputs, the way section_changes can, but for this sheet worker that wasn't necessary.  The structure of the sheet worker after that is a fairly standard repeating section worker. Broken down to its essentials its this: on('attributes to watch', () => { getSectionIDs('repeating_effects', idarray => { const fieldnames = 'build an array of attribute names suitable for use later in the function, like in getAttrs'; getAttrs(fieldnames, v => { // the actual work of the sheet worker, which Scott's comments describe }); }); }); Most sheet workers targeting repeating sections will have this basic structure.
1600793931

Edited 1600812920
I haven't had a chance to read GiGs post yet.  It was posted as I was writing this. I think the rollercoaster that is this thread just got to its highest point.  See my interpretation and questions below. //section_field assembles the repeating section call so it is correct for us in the listener const section_field = (section, field, id = ':') => `repeating_${section}${id === ':' ? id : `_${id}_`}${field}`; What does the repeating section call do?  It looks like this creates a function that serves as a data structure that builds and then stores the label for an individual "modifier" in a specific "effect". //buildChanges assembles a listener string for use in the on() out of all the modifiers const buildChanges = modifiers.reduce((total,item) => `${total} change:${section_field('effects', item)}_modifier`,''); It looks like this creates a string that lists all of the "modifiers" for each individual "effect", to be used to call a function if any of these values change. //listen to each of those things on(`${buildChanges} change:repeating_effects:effect_checkbox remove:repeating_effects sheet:opened`, () => { I think this uses buildChanges and 3 other relavent triggers to call this worker. //get the sectionIDs getSectionIDs('repeating_effects', idarray => { I think this pulls the IDs for all the "effects" and places them into an array. //fieldnames will hold the names of all the repeating fields we need to get. we iterate over the idarray and for each id, push an assembled repeating attribute name to fieldnames const fieldnames = []; idarray.forEach(id => { modifiers.forEach(mod => fieldnames.push(section_field('effects', `${mod}_modifier`, id))); fieldnames.push(section_field('effects', 'effect_checkbox', id)); }); I think this section loads up a new array with the names of each "modifier" in each "effect" along with the name of each "effect's" checkbox.  I don't think their values are stored here though. //get the current attribute values of all of the fields getAttrs(fieldnames, v => { This appears to retrieve a value for each fieldname, one at a time.  I don't understand where these values are stored though.  What do these data structures look like?  What logging statements can I put in this worker to show the data structures being built, so I can follow along in the log and see their structure? //An object that will store our key:value pairs of attribute_name:attribute_value const output = {}; This appears to create an undefined data structure. //initialize them to 0 for each total modifiers.forEach(mod => output[`${mod}_modifier_total`] = 0); idarray.forEach(id => { This appears to initialize the previously undefined data structure with an array of zero values, one for each of the "modifiers" in the modifiers array.  Then it begins to iterate through idarray. //toggle is either 0 (checkbox unchecked) or some number(checked) const toggle = int(v[section_field('effects', 'effect_checkbox', id)]); This stores the value for a checkbox in toggle.  "v" appears to be the name of an array, but I don't understand the structure of the data structure that v refers to. //if toggle is truthy (in this case, not 0 and not NaN, undefined, or null) then do add the modifiers from it to the value stored in output if(toggle) { modifiers.forEach(mod => { Let me just say that I love the use of the word "truthy" here.  That is hilarious = ). This checks the checkbox values for each effect. //add the modifier from this effect to the total for that modifier output[`${mod}_modifier_total`] = output[`${mod}_modifier_total`] + int(v[section_field('effects', `${mod}_modifier`, id)]); This adds the value of each "modifier" in each effect to it's associated "modifier" total value. //and finally set output setAttrs(output); Yup. I don't know of a simpler way to do this, but if you do I'm interested.  Here are the examples you asked for.  Please not that the value='' strings are broken up into multiple lines to be easier to read.  I don't believe they function when not all on the same line: <button class="buttonStyle abilityCheck" name="roll_observation_check" type='roll' value='&{template:default} {{name=Observation}} {{Check=[[@{observation_total}-1d100cf0cs0]]}} {{Half Check=[[round((@{observation_total})/2)-1d100cf0cs0]]}} {{Opposed Check=[[1d100cf0cs0+@{observation_total}]]}}' style="float:right;">OB</button> I'm not sure what you mean by "are you displaying the total somewhere on the sheet?"  Do you mean am I displaying on the sheet, the total including the roll?  My understanding is that this is not possible as the roll can't be saved.  Or do you mean am I displaying the total modifier that is being added to the roll?  I am doing this.  Here's an example of a check where I do: <button class="buttonStyleBottom roll" name="roll_melee_attack" type="roll" value='&{template:default} {{name=@{melee_attack_name}}} {{Attack Roll=[[1d100cf5cs0+@{melee_attack_total_attack_bonus}]]}} {{Properties=@{melee_attack_properties}}} {{Resistance Penalty=[[@{melee_attack_resistance_penalty}]]}} {{@{melee_attack_damage_type_1} =[[@{melee_attack_number_of_damage_dice_1}d@{melee_attack_damage_dice_facet_number_1}cf0cs0+@{melee_attack_damage_bonus_1}]]}}' style="float:right;">Attack</button> <input class="field derived24 section" name="attr_melee_attack_total_attack_bonus" value="@{melee_attack_basic_combat_bonus}+@{melee_attack_weapon_skill_attack_bonus}" disabled="true">
1600797707

Edited 1600808430
GiGs
Pro
Sheet Author
API Scripter
My previous post answers the first couple of questions. getSectionIDs is a basic roll20 sheet worker function described in the wiki. It returns an array of all the row ids in a repeating section. You can use this to then loop through all the rows of an entire repeating section. const fieldnames = [] creates an empty array. In the same way, this const output = {}; creates an empty javascript object variable. It's not undefined, it's an object containing no items, in the same way that [] is an array containing no items. //fieldnames will hold the names of all the repeating fields we need to get. we iterate over the idarray and for each id, push an assembled repeating attribute name to fieldnames const fieldnames = []; idarray.forEach(id => { modifiers.forEach(mod => fieldnames.push(section_field('effects', `${mod}_modifier`, id))); fieldnames.push(section_field('effects', 'effect_checkbox', id)); }); I think this section loads up a new array with the names of each "modifier" in each "effect" along with the name of each "effect's" checkbox.  I don't think their values are stored here though. Yes, this builds an array of their names. You can then use that array in getAttrs later, to get their values. It's important to do it this way. If you try to build a loop and put getAttrs inside that loop, you create a massive inefficiency in your code. Each getAtrrs call (and also each setAttrs call) introduces lag - very small if its just one, but if you have a loop, it'll become very noticeable and lag the sheet. //get the current attribute values of all of the fields getAttrs(fieldnames, v => { This appears to retrieve a value for each fieldname, one at a time.  I don't understand where these values are stored though.  What do these data structures look like?  What logging statements can I put in this worker to show the data structures being built, so I can follow along in the log and see their structure? getAttrs is a basic roll20 function, described (somewhat) in the wiki. like getSectionIDs and setAttrs, it relies on some understanding of some javascript - particularly javascriptr object variables, and the concept of callbacks (the latter of which I wont go into, you only need to know how this functions are structured). We cant hope to cover these concepts in detail on the forms - its the soprt of thing you need to research through javascript articles and tutorials to get full understanding. But in brief, a javascript data object has a structure like {         strength: '10',     dexterity: '12',     level: '3'     name: 'Bilbo Baggins',     class: 'rogue' } It is a way of storing multiple related variables in a single object. The roll20 getAttrs function takes an array of attribute names, and checks against the roll20 database for that character, and creates an object variable containing their names (called keys) and values. For instance, this line getAttrs(['strength', 'dexterity', 'level', 'name', 'class'], values => { would scan the current character, retrieve the values of the attributes listed in that array, and store them in a javascript object which would oook exactly like the one I posted above. Notice the object is given a name - here it is called values . If I instead had written getAttrs(['strength', 'dexterity', 'level', 'name', 'class'], v => { that object would be called v. I could just as easily have written getAttrs(['strength', 'dexterity', 'level', 'name', 'class'], spaghetti => { and the object would be called spaghetti . You can get values out of an object variable using this syntax: let str = spaghetti.strength; Notice though that the example object has everything encoded as a string. strength has a value of '12', not 12. Objects can contain any data type, but roll20 attributes are all stored as strings, so you often need to convert those values to numbers, like let str = parseInt(spaghetti.strength) || 0; Now usually you set the object name to be something more sensible than spaghetti, like values or v, then it would look like let str = parseInt(values.strength) || 0; You can also use this syntax (and this will be important later): let str = parseInt(values['strength']) || 0; Remember values was set in the getAttrs function. If I had set it to v (as I usually do), that would look like let str = parseInt(v['strength']) || 0; This syntax is extremely important for dynamic functions. You can use variables inside the [ ] that contain an attribute name. As you'll soon see. Now, as noted above, output = {} doesnt set an undefined variable. It creates an empty  object. So this: //initialize them to 0 for each total modifiers.forEach(mod => output[`${mod}_modifier_total`] = 0); idarray.forEach(id => { This appears to initialize the previously undefined data structure with an array of zero values, one for each of the "modifiers" in the modifiers array.  Then it begins to iterate through idarray. It creates entries (key and value pairs) within the object, initialised to a value of 0.  idarray here remember is a complete array of all the row ids within the repeating section. It was defined earlier with getSectionIDs. So what is actually happening here, is it is looping through each row of the repeating section. It does this because the output object is intended to hold the list of all attributes you'll be setting in setAttrs later. You want to make sure all checkboxes are set to 0 if they havent been changed. It's a very common oversight in loops to forget to handle the "isnt changed" situation, leading to situations where once a value is set it cant be restored to its default. This handles that - honestly there's a better way to do this, but it's the method In used at the time this function was written. //toggle is either 0 (checkbox unchecked) or some number(checked) const toggle = int(v[section_field('effects', 'effect_checkbox', id)]); This stores the value for a checkbox in toggle.  "v" appears to be the name of an array, but I don't understand the structure of the data structure that v refers to. So, v here refers to an object , specifically the one defined with getAttrs, which is an object containing the names and values of all attributes retrieved from the character sheet in this worker. Using getSectionIDs and the fieldname variable, the relevant attribute in every row in the repeating section was stored in the v object.  the section_field part builds the attribute name we need for the current row in the loop, so v[ ] can retrieve its value. //if toggle is truthy (in this case, not 0 and not NaN, undefined, or null) then do add the modifiers from it to the value stored in output if(toggle) { modifiers.forEach(mod => { Let me just say that I love the use of the word "truthy" here.  That is hilarious = ). This checks the checkbox values for each effect. truthy and falsy are actually javascript terms, with specific meanings in the language. because of them we can use if(toggle) instead of something like if(toggle==="1") So toggle is the value of the checkbox in that row. So this is saying, if that checkbox is checked, do the stuff in this if block. If its not checked, skip it (we dont need an else statement, thanks to the earlier line initialising all values to 0.) Hopefully that helps explain some things - but many of your questions are relating to javascript concepts, so you can also find additional explanations on these matters on general javascript help sites.
1600797922

Edited 1600798623
GiGs
Pro
Sheet Author
API Scripter
Note that since you using sheetworkers, this section is likely to give you serious problems at some point: <input class="field derived24 section" name="attr_melee_attack_total_attack_bonus" value="@{melee_attack_basic_combat_bonus}+@{melee_attack_weapon_skill_attack_bonus}" disabled="true"> Sheet workers do not work with disabled inputs. They cant change their values, and when they get the value, they get the full string: "@{melee_attack_basic_combat_bonus}+@{melee_attack_weapon_skill_attack_bonus}" NOT the sum of those two attributes. This is useless in a sheet worker. Sheet workers have no access to a character sheet beyond what you give them with getAttrs, so this: @{melee_attack_basic_combat_bonus} is just a string of letters and symbols, and has no link to the attribute: melee_attack_basic_combat_bonus So if you plan to use this value in another sheet worker, your best bet is to change this from disabled to readonly, and create a sheet worker that sets the value.
Well thank you both very much for answering my questions.&nbsp; This goes a long way toward developing my understanding, and it will go even further in the future when I am studying your words and hopefully a bit less sleep deprived. That is one of the challenges I face in learning this stuff.&nbsp; I don't know how fully Role20 supports Javascript.&nbsp; Taking a closer look at pages like this should help with that question: <a href="https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts#adding-a-sheet-worker-script-0-0" rel="nofollow">https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts#adding-a-sheet-worker-script-0-0</a> I am very excited to learn that both Role20 and Javascript support objects and functions which can be called by other functions.&nbsp; It seems like I might have realized that was the case, but learning curves can be tricky.&nbsp; I wonder whether they also supports default parameters. Objects, for a long time, have been my favorite data structure!&nbsp; No I'm not joking, and I'd thank you to stop looking at me like that.&nbsp; In other languages they offer shiny benefits like modularity, inheritance, polymorphism, structure, and encapsulation.&nbsp; I'm very interested to learn which benefits they offer to Javascript.&nbsp; Perhaps I'll learn more about it by perusing pages like W3's&nbsp; <a href="https://www.w3schools.com/js/js_objects.asp" rel="nofollow">https://www.w3schools.com/js/js_objects.asp</a> . I feel like everything from this function has been explained now, and I have all the information I need.&nbsp; I'll know for sure after I'm rested and I come back to attempt to accomplish my goal.
1600817941
GiGs
Pro
Sheet Author
API Scripter
roll20 supports most of javascript - except for anything which manipulates the DOM. Also, Sheet workers dont support async functions - you have to use callbacks if you want such functions. But the API does support async functions. Javascript objects arent the same as the kind of objects you'd encounter in object-oriented programming languages, so we have to be careful about terminology.&nbsp;
1600845762

Edited 1600846912
So does this mean that: I can create an all encompassing character object? I can give it properties, that are themselves objects, which store subsets of the character data in property form? I can give the character object, and its object properties, methods to be used to manipulate the objects' properties? I can trust these objects to be available for as long as the character sheet is open? I think I know the answers to the first three are yes.&nbsp; The last one is important though, because this would mean weeks of rewriting workers.&nbsp; I ask because I don't want to go to all the trouble if it's not a good strategy.&nbsp; I say trouble, but I'm hoping it's a good idea because I'm looking forward to it. Incidentally, according to my research, Javascript objects don't support inheritance or polymorphism, and they don't offer private / public property or method designation.
1600867188

Edited 1600869235
GiGs
Pro
Sheet Author
API Scripter
I already mentioned that javascript objects are not "Objects" in the OOP sense. It's best not to try to force a language of one type to try to behave in ways appropriate to other types of languages. It's better to think of what specific things you want to achieve, and figure out the best way to achieve it in this language. If you describe specifically what you want to do, we can tell you how to do it. The answer to all four of your questions is, I think, yes (I''ve never done the 4th, because it has never been necessary for me, but I think it's possible). The question is: are there better ways to achieve what you want, in the javascript paradigm (and, especially, within the constraints set by roll20)? I think the answer to that is also yes, but I can't be sure without knowing exactly what you need these things for. Note: I only dabbled in OOP, and never gained a deep understanding of it. But Javascript does have inheritance, and I believe you can do polymorphism, but its a fairly unique language, so neither appear in traditional OOP ways. If you want to ask advanced coding questions about javascript specifically, it's best googling for answers or asking in the API forum where, for instance, Jakob or Aaron or any of the more professional coders that frequent the boards are more likely to see them. And make sure your subject title isnt vague, and specifically says you're looking for advanced coding help.&nbsp;
1600871656
Andreas J.
Forum Champion
Sheet Author
Translator
Tim Z said: Well thank you both very much for answering my questions.&nbsp; This goes a long way toward developing my understanding, and it will go even further in the future when I am studying your words and hopefully a bit less sleep deprived. That is one of the challenges I face in learning this stuff.&nbsp; I don't know how fully Role20 supports Javascript.&nbsp; Taking a closer look at pages like this should help with that question: <a href="https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts#adding-a-sheet-worker-script-0-0" rel="nofollow">https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts#adding-a-sheet-worker-script-0-0</a> Please, consult the wiki first for anything related to Character Sheet Documentation, as there are much more info there and it's updated by the community constantly, while the HelpCenter documentation is just a pale copy of the wiki from like, 6 months ago. <a href="https://wiki.roll20.net/Sheet_Worker_Scripts" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts</a>
I'm confused Andreas. <a href="https://wiki.roll20.net/Sheet_Worker_Scripts" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts</a> &nbsp;shows this warning Attention: &nbsp; Roll20 is no longer maintaining this document on the community wiki. For the official version of this page, please visit Roll20's Help Center page:&nbsp; Here Which includes a link that takes you to: <a href="https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts" rel="nofollow">https://roll20.zendesk.com/hc/en-us/articles/360037773513-Sheet-Worker-Scripts</a> If you are correct, shouldn't that warning be taken down?
1600879338
GiGs
Pro
Sheet Author
API Scripter
That warning is inserted by roll20 devs. If we take it down (or if we can even take it down), they'll just replace it. But it's accurate: the wiki is no longer maintained by the roll20 staff (it never was, really!) - it's maintained by the community. Paradoxically, this means the wiki will always be more complete and more accurate than the official roll20 help centre.
1600879386

Edited 1600886873
Kraynic
Pro
Sheet Author
That notice was put up when Roll20 created the Help Center (which is relatively recent).&nbsp; The Help Center is not community editable, so doesn't contain all the info the wiki does. This applies to articles on character sheet building and articles on community created sheets (which don't exist on the Help Center at all).&nbsp; Unless they start intentionally keeping the Help Center up to date with various edits to the character sheet building related wiki articles, the wiki will always be where to go for that type of information.
1600883608

Edited 1600883817
Andreas J.
Forum Champion
Sheet Author
Translator
GiGs said: But it's accurate: the wiki is no longer maintained by the roll20 staff (it never was, really!) - it's maintained by the community. Paradoxically, this means the wiki will always be more complete and more accurate than the official roll20 help centre. I'd want to remove the disclaimer from the Character Sheet Dev pages, but compromised to edit the description to be more accurate for these page. The original message used to be this, which is absolutely not true: Considering they don't update documentation related to this, it should be fine to remove this inaccurate "warnings" from these pages. As a case in point, the Help Center article on Building Character Sheets credits me for contributing a massive amount to it, which kinda becmes funny as the Help Center pages are now just pale copies of the wiki pages, and missing ton of stuff.
Thank you GiGs, This thread is really informative for me. I was an early C and C++ programmer and now can see that I have a long steep learning curve ahead of me.&nbsp;
1600886532
GiGs
Pro
Sheet Author
API Scripter
I'm happy to hear that, KoS :)