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

[L5R] A Second Two Variables, One Dropdown Issue

I have a new take on the old two variable, one dropdown issue that we had such fun with on the old L5R sheet. My players have requested a feature on the new beta sheet for the skill to output the approach they used (the ring they selected) as well as the result of the roll. So basically, they select a ring, Air, Earth, Fire, etc. The sheet immediately put the value of the ring into the <skillname>_approach variable. They want the output to tell the friendly name of that ring as well. Now I could make a sheet worker that detects when you set that ring and sets a variable for emote to output telling them what ring they used, but the skills have all sorts of different names martial, social, courtesy, etc. Some are repeating variables for adding custom skills. I'm trying to tackle the general logic. Do I need to make a sheet worker for each skill and each repeater? Can Most of the skills be lumped into one big one and each of the reapeaters be their own, etc. Help me see how big a problem this is, in general.
1509995573
Lithl
Pro
Sheet Author
API Scripter
So when you select from the ring dropdown, you want to set the value of <skillname>_approach, for each <skillname> that exists, including a repeating section? And you also want the output to be able to include the name of the ring selected? If all the <skillname>_approach values are the same, why do you need separate attributes for them? Why not just "approach" or "skill_approach" or something?
No, there are, say thirty different skills with different approaches that can all be set differently. When a player sets the one for Composition, it needs to put the value of the ring that they selected into the variable for the composition_approach variable. It does this currently. It also needs to store, somewhere in a new variable, the name of the ring that they just selected, to output in an emote when they roll the skill. Since there are, say thirty different skills, there can be thirty different variables we're tracking (I pulled that number out of thin air, I haven't counted) and some of them are repeating. I'm figuring I could easily make thirty sheet workers, one for each skill, that sets the new variable whenever the dropdown changed for any one of them (since the sheetworker can see the variable name stored in that composition_approach variable, not just the value). I'm figuring that there's a better way to do this than writing 30 sheet workers, by using some form of string concatenation, maybe to change the variable name on the fly, maybe reducing it to just a few sheet workers one for the main skills and maybe one for each major repeating section, depending on what the variables look like.
1509997840
Jakob
Sheet Author
API Scripter
It sounds like you already know what you need to do? It will be some kind of loop over all the skills in an array, and probably a separate loop over repeating sections.
Yeah. Basically, I wrote these two sheet workers as a test case: <script type="text/worker"> on('sheet:opened change:aesthetics_approach', () => { getAttrs(['aesthetics_approach'], (values) => { const val = parseInt(values['aesthetics_approach']); var aesthetics_approach_selected = 'Air'; switch (values.aesthetics_approach) { case '@{air}': aesthetics_approach_selected = 'Air'; break; case '@{earth}': aesthetics_approach_selected = 'Earth'; break; case '@{fire}': aesthetics_approach_selected = 'Fire'; break; case '@{water}': aesthetics_approach_selected = 'Water'; break; case '@{void}': aesthetics_approach_selected = 'Void'; break; } setAttrs({aesthetics_approach_selected}); }); }); </script> <script type="text/worker"> on('sheet:opened change:composition_approach', () => { getAttrs(['composition_approach'], (values) => { const val = parseInt(values['composition_approach']); var composition_approach_selected = 'Air'; switch (values.composition_approach) { case '@{air}': composition_approach_selected = 'Air'; break; case '@{earth}': composition_approach_selected = 'Earth'; break; case '@{fire}': composition_approach_selected = 'Fire'; break; case '@{water}': composition_approach_selected = 'Water'; break; case '@{void}': composition_approach_selected = 'Void'; break; } setAttrs({composition_approach_selected}); }); }); </script> I need to reformat them and all the other set skills into a loop that goes through and replaces "composition" and "aesthetics" with a string so I only have one worker. (Other skills are "design", "smithing", "martial_arts_melee", etc). I've looked at the code you helped me write for the other sheet and it's doing SO many things that I can't pluck just that part out of the weave, so I'll likely to find an example on someone else's sheet where they wrote a simple sheet worker for a repeating section so I can find JUST that bit of logic. I suspect I'll do the repeaters as a separate worker, just to keep myself sane. The variables are just a bit too different.
1510009653

Edited 1510010071
Lithl
Pro
Sheet Author
API Scripter
So first, you don't need separate <script> tags. You can have multiple calls to on  within a single sheet worker script. If I'm understanding the problem space correctly, this should get you close to what you want (code untested): const skills = [ 'aethestics', 'composition', 'martial_arts_melee', 'social', 'courtesy', 'design', 'smithing', // etc. ]; const repeatingSkillNames = []; const repeatingSkillApproaches = []; const ringMap = { '@{air}': 'Air', '@{earth}': 'Earth', '@{fire}': 'Fire', '@{water}': 'Water', '@{void}': 'Void', }; on('sheet:opened remove:repeating_skills', () => { // collect skills in repeating section repeatingSkillNames.splice(0, repeatingSkillNames.length); repeatingSkillApproaches.splice(0, repeatingSkillApproaches.length); TAS.repeating('skills') .each((row) => { repeatingSkillNames.push(`repeating_skills_${row.id}_name`); repeatingSkillApproaches.push(`repeating_skills_${row.id}_approach`); }) .execute(); }); on(`sheet:opened ${skills.map((s) => `change:${s}_approach`).join(' ')} change:repeating_skills:approach change:repeating_skills:name`, (e) => { if (e.sourceAttribute && /repeating_skills_.*/.test(e.sourceAttribute)) { // make sure the repeating item is tracked if it's new const source = e.sourceAttribute.substring(source.indexOf('_') + 1); const sourceId = source.substring(source.indexOf('_') + 1, source.lastIndexOf('_')); // sourceId is all lower-case, we need to find the correctly-cased value let trueSourceId; TAS.repeating('skills') .each((row) => { if (row.id.toLowerCase() === sourceId) { trueSourceId = row.id; } }) .execute(); const sourceName = `repeating_skills_${trueSourceId}_name`; const sourceApproach = `repeating_skills_${trueSourceId}_approach`; // if the changed repeating name/approach value isn't in the list, it's new if (repeatingSkillNames.indexOf(sourceName) < 0) { repeatingSkillNames.push(sourceName); } if (repeatingSkillApproaches.indexOf(sourceApproach) < 0) { repeatingSkillApproaches.push(sourceApproach); } } getAttrs(skills.map((s) => `${s}_approach`).concat(repeatingSkills, repeatingSkillApproaches), (values) => { const attrs = {}; _.each(skills, (skillName) { // <skill>_approach_selected for non-repeating skills attrs[`${skillName}_approach_selected`] = ringMap[values[`${skillName}_approach`]] || 'Air'; }); _.each(repeatingSkills, (skillAttrName) { const skillName = values[skillAttrName]; // name of repeating skill const rowId = skillAttrName.substring( // row of repeating skill skillAttrName.indexOf('_', skillAttrName.indexOf('_') + 1) + 1, skillAttrName.lastIndexOf('_')); const skillAttrApproach = repeatingSkillApproached.find( // approach attribute in the same row (a) => a.substring(a.indexOf('_', a.indexOf('_') + 1) + 1, a.lastIndexOf('_')) === rowId); attrs[`${skillName}_approach_selected`] = ringMap[values[skillAttrApproach]] || 'Air'; }); }); }); The above code will leave orphaned attributes when you change a repeating skill's name. For example, if you create skill "Piracy" the script will create @{Piracy_approach_selected} (with the value "Air" or whatever). If you later change the name of the attribute to "Sailing", the script will create @{Sailing_approach_selected}, but won't delete @{Piracy_approach_selected}. It will also create @{_approach_selected} if you change the approach selection before setting the repeating skill's name.
It's sorta working. The compiler has a problem with this part of the code. _.each(skills, (skillName) { // <skill>_approach_selected for non-repeating skills attrs[`${skillName}_approach_selected`] = ringMap[values[`${skillName}_approach`]] || 'Air'; }); _.each(repeatingSkills, (skillAttrName) { const skillName = values[skillAttrName]; // name of repeating skill const rowId = skillAttrName.substring( // row of repeating skill skillAttrName.indexOf('_', skillAttrName.indexOf('_') + 1) + 1, skillAttrName.lastIndexOf('_')); const skillAttrApproach = repeatingSkillApproached.find( // approach attribute in the same row (a) => a.substring(a.indexOf('_', a.indexOf('_') + 1) + 1, a.lastIndexOf('_')) === rowId); attrs[`${skillName}_approach_selected`] = ringMap[values[skillAttrApproach]] || 'Air'; }); }); }); It's expecting a coma after that first (skillname). whatever the problem, it's breaking the chat window. :)
I was wrong. *I* broke chat. Fixed it. This works with variables already created by my sheet workers. It doesn't work with ones that don't already exist.
1510080063
Lithl
Pro
Sheet Author
API Scripter
Robert D. said: It's sorta working. The compiler has a problem with this part of the code. _.each(skills, (skillName) { // <skill>_approach_selected for non-repeating skills attrs[`${skillName}_approach_selected`] = ringMap[values[`${skillName}_approach`]] || 'Air'; }); _.each(repeatingSkills, (skillAttrName) { const skillName = values[skillAttrName]; // name of repeating skill const rowId = skillAttrName.substring( // row of repeating skill skillAttrName.indexOf('_', skillAttrName.indexOf('_') + 1) + 1, skillAttrName.lastIndexOf('_')); const skillAttrApproach = repeatingSkillApproached.find( // approach attribute in the same row (a) => a.substring(a.indexOf('_', a.indexOf('_') + 1) + 1, a.lastIndexOf('_')) === rowId); attrs[`${skillName}_approach_selected`] = ringMap[values[skillAttrApproach]] || 'Air'; }); }); }); It's expecting a coma after that first (skillname). whatever the problem, it's breaking the chat window. :) Whoops, those should be (skillName) => { and (skillAttrName) => { Also I forgot to add setAttrs(attrs);  at the bottom of the getAttrs  function.
Not sure where to add that first one and it would require a close bracket somewhere. I don't suppose you'd mind posting the fixed code. :)
Just bumping this.
1510343212
Jakob
Sheet Author
API Scripter
What he means is _.each(skills, (skillName) => { // <skill>_approach_selected for non-repeating skills attrs[`${skillName}_approach_selected`] = ringMap[values[`${skillName}_approach`]] || 'Air'; }); _.each(repeatingSkills, (skillAttrName) => { const skillName = values[skillAttrName]; // name of repeating skill const rowId = skillAttrName.substring( // row of repeating skill skillAttrName.indexOf('_', skillAttrName.indexOf('_') + 1) + 1, skillAttrName.lastIndexOf('_')); const skillAttrApproach = repeatingSkillApproached.find( // approach attribute in the same row (a) => a.substring(a.indexOf('_', a.indexOf('_') + 1) + 1, a.lastIndexOf('_')) === rowId); attrs[`${skillName}_approach_selected`] = ringMap[values[skillAttrApproach]] || 'Air'; }); setAttrs(attrs); }); });
Now when I compile, I get the error: JSC_REFERENCE_BEFORE_DECLARE_ERROR: Illegal variable reference before declaration: source at line 42 character 47 const source = e.sourceAttribute.substring(source.indexOf('_') + 1); It appears to be this line: const source = e.sourceAttribute.substring(source.indexOf('_') + 1);
This still isn't working, and I feel like I'm imposing too much with this one. How about a simpler one. I'm trying to teach myself how to do a basic case inside a repeating section, then I can just do one for each. It sets the value to the default, but it doesn't seem to be passing in the initial value. Can you tell what I'm doing wrong getting the initial reartisan_${id}_approach value? on("sheet:opened change:repeating_reartisan", function() { getSectionIDs('repeating_reartisan', function (idArray) { getAttrs(idArray.map(id => `reartisan_${id}_approach`), function (values) { console.log(values); // Logging all the approach key:value pairs console.log(idArray); // logging all row ids. Those missing from the values object above don't have an approach   // attribute set, so they should default to air   let setting = {}; idArray.forEach(function (id) { switch (values[`reartisan_${id}_approach`]) { case '@{void}': setting[`reartisan_${id}_approach_selected`] = 'Void'; break; case '@{water}': setting[`reartisan_${id}_approach_selected`] = 'Water'; break; case '@{fire}': setting[`reartisan_${id}_approach_selected`] = 'Fire'; break; case '@{earth}': setting[`reartisan_${id}_approach_selected`] = 'Earth'; break; default: setting[`reartisan_${id}_approach_selected`] = 'Air'; // defaulting to air in case the select was never changed } }); console.log(setting); // Logging the attributes we are about to set. setAttrs(setting); }); }); });
1510827344
Jakob
Sheet Author
API Scripter
One thing that occurs to me: the attribute name is `repeating_reartisan_${id}_...`, not `reartisan_${id}_...`.
That was it. I also discovered that if you also have reartisan in the variable name, it breaks everything. So that will be a breaking change in the next update of my character sheet.