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

TAS Replacing an Auto-calc with a sheetworker.

1560795992
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
Calling on the Aaron.... I need your expertise. I am trying to replace an auto-calc with a sheetworker using the TAS. The auto-calc <div class="sheet-cell sheet-col2"> <input type="text" name="attr_level" disabled="disabled" value="[[@{difficulty}*1]]" /> </div> <div class="sheet-cell sheet-col2"> <select name="attr_base"> <option value="@{current_strength}">ST</option> <option value="@{current_dexterity}">DX</option> <option value="@{current_intelligence}">IQ</option> <option value="@{current_health}">HT</option> <option value="@{willpower}">Will</option> <option value="@{perception}">Per</option> <option value="10">10</option> </select> </div> <div class="sheet-cell sheet-col2"> <select name="attr_difficulty"> <option value="-1 + @{base} + @{bonus} + @{enc} + (floor((@{points} * 0.25) + 2) * ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) + @{points} * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ))"> E</option> <option value="-2 + @{base} + @{bonus} + @{enc} + (floor((@{points} * 0.25) + 2) * ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) + @{points} * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ))"> A</option> <option value="-3 + @{base} + @{bonus} + @{enc} + (floor((@{points} * 0.25) + 2) * ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) + @{points} * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ))"> H</option> <option value="-4 + @{base} + @{bonus} + @{enc} + (floor((@{points} * 0.25) + 2) * ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) + @{points} * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ))"> VH</option> <option value="-4 + @{base} + @{bonus} + @{enc} + (floor( (floor( @{points} / 3) * 0.25) + 2) * ceil( ( ( floor( @{points} / 3) - 2 ) + abs( floor( @{points} / 3) - 2) ) / 256 ) + floor( @{points} / 3) * abs( ceil( ( ( floor( @{points} / 3) - 2 ) + abs( floor( @{points} / 3) - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( floor( @{points} / 3) - 2 ) + abs( floor( @{points} / 3) - 2) ) / 256 ) - 1 ))"> WC</option> <!-- rebuild as sheetworker --> </select> </div> <div class="sheet-cell sheet-col2"> <input type="number" name="attr_bonus" value="0" placeholder="0" /> </div> <div class="sheet-cell sheet-col2"> <input type="number" name="attr_points" value="0" placeholder="0" /> </div> The new code: // Update Lines on Skills on("change:repeating_skills remove:repeating_skills change:current_strength change:current_dexterity change:current_intelligence change:current_health change:willpower change:perception change:current_conditions change:skillRoll_mod change:encumbrance_level", function () { TAS.repeating("skills") .attrs("current_strength", "current_dexterity", "current_intelligence", "current_health", "willpower", "perception", "skillRoll_mod", "encumbrance_level", "skillRoll_mod" ) .fields("difficulty", "bonus", "points", "level", "enc_penalty", "enc", "baseattr" ) .each(function (r, a) { r.D[0].enc_penalty = r.F.enc * a.F.encumbrance_level; if (r.S.baseattr === "ST") { r.D[0].base = a.F.current_strength; } else if (r.S.baseattr === "DX") { r.D[0].base = a.F.current_dexterity; } else if (r.S.baseattr === "IQ") { r.D[0].base = a.F.current_intelligence; } else if (r.S.baseattr === "HT") { r.D[0].base = a.F.current_health; } else if (r.S.baseattr === "Will") { r.D[0].base = a.F.willpower; } else if (r.S.baseattr === "Per") { r.D[0].base = a.F.perception; } else if (r.S.baseattr === "Ten") { r.D[0].base = 10; } if (r.S.difficulty === "E") { r.D[0].level = a.F.skillRoll_mod + -1 + r.F.base + r.F.bonus + r.F.enc + (Math.floor((r.F.points * 0.25) + 2) * Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) + r.F.points * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 ) * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 )); } else if (r.S.difficulty === "A") { r.D[0].level = a.F.skillRoll_mod + -2 + r.F.base + r.F.bonus + r.F.enc + (Math.floor((r.F.points * 0.25) + 2) * Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) + r.F.points * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 ) * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 )); } else if (r.S.difficulty === "H") { r.D[0].level = a.F.skillRoll_mod + -3 + r.F.base + r.F.bonus + r.F.enc + (Math.floor((r.F.points * 0.25) + 2) * Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) + r.F.points * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 ) * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 )); } else if (r.S.difficulty === "V") { r.D[0].level = a.F.skillRoll_mod + -4 + r.F.base + r.F.bonus + r.F.enc + (Math.floor((r.F.points * 0.25) + 2) * Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) + r.F.points * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 ) * Math.abs( Math.ceil( ( ( r.F.points - 2 ) + Math.abs( r.F.points - 2) ) / 256 ) - 1 )); } else if (r.S.difficulty === "W") { r.D[0].level = a.F.skillRoll_mod + -4 + r.F.base + r.F.bonus + r.F.enc + (Math.floor( (Math.floor( r.F.points / 3) * 0.25) + 2) * Math.ceil( ( ( Math.floor( r.F.points / 3) - 2 ) + Math.abs( Math.floor( r.F.points / 3) - 2) ) / 256 ) + Math.floor( r.F.points / 3) * Math.abs( Math.ceil( ( ( Math.floor( r.F.points / 3) - 2 ) + Math.abs( Math.floor( r.F.points / 3) - 2) ) / 256 ) - 1 ) * Math.abs( Math.ceil( ( ( Math.floor( r.F.points / 3) - 2 ) + Math.abs( Math.floor( r.F.points / 3) - 2) ) / 256 ) - 1 )); } }) .execute(); });
1560799742

Edited 1560799814
GiGs
Pro
Sheet Author
API Scripter
I'll leave the TAS advice to Aaron,  but i can see one thing you can massively simplify: What is this calculation for?  (floor((@{points} * 0.25) + 2) * ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) + @{points} * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( @{points} - 2 ) + abs( @{points} - 2) ) / 256 ) - 1 )) I have difficulty believing it needs to be as complicated as this. But since the only input value here is the points attribute, you can turn it into a function, so you don't need to repeat it at several places in your code. It would be simple as function pointscalc(points) { return  (floor((points * 0.25) + 2) * ceil( ( ( points - 2 ) + abs( points - 2) ) / 256 ) + points * abs( ceil( ( ( points - 2 ) + abs( points - 2) ) / 256 ) - 1 ) * abs( ceil( ( ( points - 2 ) + abs( points - 2) ) / 256 ) - 1 )); } Then everywhere in your code you have the calculation, you can instead use pointscalc(r.F.points) .
1560804276

Edited 1560804373
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
Except for the last repetition. In which the points expenditure is tripled I wasn't sure about the "floor", "ceil", "abs" but I will try your suggestion.
1560807459
GiGs
Pro
Sheet Author
API Scripter
Oh yes, i didnt notice that was different. I dont want to derail the thread, but I'd love to discuss that formula (I'm cuious about what its for) and see if we can come up with a simpler version. If you're interested, open another thread to discuss it.
1560814965

Edited 1560815158
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
OK The last one is for Wildcard skills. I managed to figure, mostly, how the formula works... At the wildcard level, point cost is triple very hard skill cost. The formula is to replicate this table
1560821246

Edited 1560821459
GiGs
Pro
Sheet Author
API Scripter
Thanks for that, it's much clearer. I can see a simpler way to do your calculation, but I need a couple of questions answered first: Is all the html above within the repeating_skills section? Is the levels attribute where the final skill score gets sent? It looks to me like players enter the points and their skill is calculated. Wouldnt it be better to do it the other way: enter the skill level, and have the points be calculated? 
1560821475
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
level, points, bonus is in the rows, 
1560824824

Edited 1560846238
GiGs
Pro
Sheet Author
API Scripter
Edit: I overlooked some things in the first post, this is updated. Here's how to do it, calculating level from points. I'll post code for the opposite way later. First, change the html as follows: <fieldset class="repeating_skills"> <input type="hidden" name="attr_situation_mods" value="0" readonly /> <div class="sheet-cell sheet-col2"> <input type="number" name="attr_level" value="10" readonly /> </div> <div class="sheet-cell sheet-col2"> <select name="attr_base"> <option value="current_strength">ST</option> <option value="current_dexterity">DX</option> <option value="current_intelligence">IQ</option> <option value="current_health">HT</option> <option value="willpower">Will</option> <option value="perception">Per</option> <option value="10">10</option> </select> <input type="hidden" name="attr_base_value" value="10" readonly/> </div> <div class="sheet-cell sheet-col2"> <select name="attr_difficulty"> <option value="1"> E</option> <option value="2"> A</option> <option value="3"> H</option> <option value="4"> VH</option> <option value="WC"> WC</option> </select> </div> <div class="sheet-cell sheet-col2"> <input type="number" name="attr_bonus" value="0" placeholder="0" /> </div> <div class="sheet-cell sheet-col2"> <input type="number" name="attr_points" value="0" placeholder="0" /> </div> <hr/> </fieldset> Description of changes: Changed the base value section - adding a hidden score, that will be calculated by sheet workers to simplify final process. Changed difficulty to make the sheet worker easier - no need for any forumla or calculation in there. Added a hidden attribute situation_mods, which will hold the sum of current_conditions, encumbrance, and rollMod. Four Sheet Workers on("change:repeating_skills:base", function () { getAttrs(['repeating_skills_base','current_strength','current_dexterity', 'current_intelligence', 'current_health','willpower','perception'],function(values) { const stat = values.repeating_skills_base; console.log('========= stat: ' + stat); const score = ('10' === stat) ? 10 : (+values[stat] || 10); console.log('========= score: ' + score); setAttrs({ repeating_skills_base_value: score }); }); }); ['current_strength','current_dexterity', 'current_intelligence', 'current_health','willpower','perception'].forEach(stat => { on(`change:${stat} sheet:opened`, function () { getSectionIDs("repeating_skills", function(idArray) { const fieldNames = idArray.map(id => `repeating_skills_${id}_base`); getAttrs(fieldNames.concat(stat), function(values) { const score = values[stat] || 0; console.log('========= score: ' + score); const settings = {}; fieldNames.forEach(field => { if(values[field] === stat) settings[field + '_value'] = score; }) setAttrs(settings); }); }); }); }); on('change:encumbrance_level change:skillRoll_mod change:current_conditions sheet:opened', function () { getSectionIDs("repeating_skills", function(idArray) { const fieldNames = idArray.map(id => `repeating_skills_${id}_situation_mods`); getAttrs(fieldNames.concat(['encumbrance_level', 'skillRoll_mod', 'current_conditions']), function(values) { const enc = +values.encumbrance_level || 0; const rollmod = +values.skillRoll_mod || 0; const conditions = +values.current_conditions || 0; const totalmods = enc + rollmod + conditions; console.log('========= mods: ' + totalmods); const settings = {}; fieldNames.forEach(field => { settings[field] = totalmods; }) setAttrs(settings); }); }); }); on("change:repeating_skills:base_value change:repeating_skills:points change:repeating_skills:difficulty change:repeating_skills:bonus change:repeating_skills:situation_mods", function () { getAttrs(['repeating_skills_situation_mods','repeating_skills_base_value','repeating_skills_points','repeating_skills_difficulty','repeating_skills_bonus'],function(values) { let points = +values.repeating_skills_points ||0; const base = +values.repeating_skills_base_value || 10; const difficulty = +values.repeating_skills_difficulty || 'wc'; const bonus = +values.repeating_skills_bonus ||0; const mods = +values.repeating_skills_situation_mods ||0; const totalmod = base + bonus + mods + 1 - (+difficulty || 4); if(difficulty === 'wc') points = points /3; let level = '-'; if(points >= 4) level = Math.floor(points/4) + 1 + totalmod; else if (points >= 1) level = Math.floor(points/2) + totalmod; setAttrs({ repeating_skills_level: level }); }); }); Description The first two sheet workers calculate the base score from the chosen stat. The first calculates the value when you change the base stat dropdown. The second calculates the value when you change the stat outside the repeating section. The third sheetworker calculates the hidden situation_mods attribute value, whenever the encumbrance, conditions, and and rollmod attribute change. The final sheet worker will use that value, instead of looking up the individual enc/rollmod/condition mods. The final sheet worker calculates the skill level, taking the points spent and all the other modifiers into account. This turned out to be pretty complex. The actual table was easy to implement but how all the various attributes fitted together made it complex. I hope I grasped your sheet setup properly. It outputs level 0, if points spent are too low to buy a stat (which whill only happen on WC difficulty). This approach is still a bit weird to me, as players visible skill score will drop when they suffer penalties, and calculating based off points makes it a bit more convoluted than if we did it the other way around. So I'll give a tweaked version for calculating points from level in another post. 
1560846171

Edited 1560848121
GiGs
Pro
Sheet Author
API Scripter
I noticed a couple of oversights in my last post - i have updated it, and tested it. If you want to calculate Points from level, replace the 4th sheet worker above with this one: n("change:repeating_skills:base_value change:repeating_skills:level change:repeating_skills:difficulty change:repeating_skills:bonus", function () { getAttrs(['repeating_skills_base_value','repeating_skills_level','repeating_skills_difficulty','repeating_skills_bonus'],function(values) { let level = +values.repeating_skills_level ||0; const base = +values.repeating_skills_base_value || 10; const difficulty = values.repeating_skills_difficulty ; const bonus = +values.repeating_skills_bonus ||0; const totalbase = base + bonus + 1 - (+difficulty || 4) ; console.log('==========diff: ' + difficulty); const difference = level - totalbase; let points = 0; if (difference < 0) points = 0; else if (difference < 3) points = Math.pow(2, difference); else if (difference >= 3) points = (difference -1) *4; if(difficulty === 'WC') points = points * 3; setAttrs({ repeating_skills_points: points }); }); }); Also in the html section, remove the readonly tag from attr_level and add it to attr_points instead. With this version, the level does not include the enc/condition/rollmod modifiers. They are in the hidden situational mods attribute. Two ways to handle this: One way would be to show a second Level attribute ("Current level"), so players can see how their score is reduced.  A second way (better IMO) is to change the button roll you use: add in @{situation_mods} as a modifier.
1560872327

Edited 1560872522
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
However, looking at how you have worked on this...I am thinking that I could have an RSL column. Like the GCS character sheet which is my ultimate goal. (see below). The unfortunate part is that I must have the other entries of difficulty and bonus
1560872742
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
GiGs said: A second way (better IMO) is to change the button roll you use: add in @{situation_mods} as a modifier. While a great idea...a lot of players make their decisions on how likely they would be successful. Thus must see the ESL.
1560885836
GiGs
Pro
Sheet Author
API Scripter
They'll know what their penalties are. You can also either (a) include a total penalty box above the skill section), or (b) include an effective skill level next to the real skill level. Players will want to know their actual  skill level too.
1560885923
GiGs
Pro
Sheet Author
API Scripter
SᵃᵛᵃǤᵉ said: However, looking at how you have worked on this...I am thinking that I could have an RSL column. Like the GCS character sheet which is my ultimate goal. (see below). The unfortunate part is that I must have the other entries of difficulty and bonus I am not familiar with the GCS sheet. What would the RSL column be showing?
1560887159
SᵃᵛᵃǤᵉ
Sheet Author
API Scripter
RSL is relative skill level or how well trained. For instance a character has a DX of 16 in the pic above. He is leveling up in a hard skill. For a DX + 0 RSL (Relative Skill Level) in that skill he has to spend 4 points. If it were an "Easy" skill and spent 4 points his "RSL" for that skill would be DX + 2, referencing the chart posted even further above. The reason RSL is important is when breaking ties in opposed rolls where the better trained usually gets the advantage as opposed to raw ability from the base attribute. It's very nuanced once you get into the weeds.