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

[Sheet Workers] The Aaron Sheet / TAS + Sheet worker question

1452855742
Natha
KS Backer
Sheet Author
API Scripter
This topic is aimed at the Mighty Aaron and his wonderfull TAS script, but perhaps others could help or be interested by this. I've got an API script that help create characters (no copyright infrigement, it's for a free french retroclone, and I'm working with game's author on this). As repeating sections can't be handled through the API (unless I'm mistaken) and following a suggestion by Aaron, my API script puts a JSON string in an hidden attribute, containing the base equipments/inventory. This string is then processed by a sheet worker on the sheet:opened event, and it creates the inventory lines. Then it empties the JSON string Then it calls TAS.repeatingSimpleSum to tally the encumbrance  Then it calls another function of mine to use the total encumbrance to calculate and sets movement rates (and this doesn't work). Basically it's doing this : on('sheet:opened',function(){   getAttrs(["todoequip"], function(values) {     if(values.todoequip.length > 0){ // there is an equipment JSON string list to process // Do stuff with the JSON string to add repeating_equipement (equipment items) // use setAttrs to empty the todoequip attribute TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement'); // THIS WORKS : tally the encumbrance in the 'encombrement' attribute PMT.majEncombrement(); //DOESN'T WORK : my function that sets movement rates based on the total encumbrance ('encombrement' attribute) } }); }); Then, I've got other events that use the same function / logic, but it works : on("change:repeating_equipement:equipqte change:repeating_equipement:equippoids", function() {         getAttrs(["repeating_equipement_equipqte", "repeating_equipement_equippoids"], function(values) { //DO STUFF WITH ITEM                 });                 TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement'); //tally the encumbrance in the 'encombrement' attribute             });     });      on('remove:repeating_equipement',function(){         TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement'); tally the encumbrance in the 'encombrement' attribute     });     on("change:encombrement", function() { // the total encumbrance has changed         PMT.majEncombrement(); //THIS WORKS : my function that sets movement rates based on the total encumbrance ('encombrement' attribute)     }); I don't get why the encumbrance total is correctly calculated on the sheet:opened event, but my function PMT.majEncombrement() doesn't appear to anything, while it's working on the change:encombrement event. Any idea ?
1452882327

Edited 1452882379
The Aaron
Pro
API Scripter
I know precisely why it happens. =D  It's because internally, TAS.rerpeatingSimpleSum() must use asynchronous functions, so the actual order of evaluation ends up being: on('sheet:opened',function(){ getAttrs(["todoequip"], function(values) { if(values.todoequip.length > 0){ // there is an equipment JSON string list to process // Do stuff with the JSON string to add repeating_equipement (equipment items) // use setAttrs to empty the todoequip attribute /* REQUEST */ TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement'); // THIS WORKS : tally the encumbrance in the 'encombrement' attribute PMT.majEncombrement(); //DOESN'T WORK : my function that sets movement rates based on the total encumbrance ('encombrement' attribute) /* ACTUAL EVALUATION */ TAS.repeatingSimpleSum(...); } }); }); The best way to handle this would be to use the non-simple repeating functions: on('sheet:opened',function(){   getAttrs(["todoequip"], function(values) {     if(values.todoequip.length > 0){          TAS.repeating('equipement')   /* declares the repeating set to work on */             .fields('equippoidstot') /* declares the fields to be available for each row */             .attrs('encombrement')   /* declares the attributes to be available */             .reduce(function(m,r){   /* the reduce function executed for each row, */                                      /*   m is the memo returned from each iteration */                 m.total += r.F.equippoidstot;   /* adds the floating point value to the memo's total */                 return m;             /* returns the memo for the next iteration */             },             { total: 0},             /* the initial value of the memo, an object with total= 0 */             function(m,r,a){         /* the final function called with the results of the reduce */                 a.D[2].encombrement = m.total;   /* set the total encombrement with 2 decimal places */                 PMT.majEncombrement();   /* call the other function */             })             .execute();   /* causes all of the above to be run. */     }   }); }); The .F, .D, .I, .S properties on r and a cause the value of the attribute or field to be cast to those types, since the types are all string by default.  let me know if you have any questions!
1452886782
Natha
KS Backer
Sheet Author
API Scripter
Ok! I suspected some kind of asynchronous shenanigan ;) Thanks a lot, I'll try and let you know.
1452888757
Natha
KS Backer
Sheet Author
API Scripter
Sorry to say it didn't work. Does my PMT.* functions have to be in scope for TAS ? (my javascript scope knowledge is not great). My script section is like this :  <script type="text/worker">     var PMT = PMT || (function(){         // my stuff      }());     var TAS = TAS || (function(){         // TAS     }());     on('sheet:opened',function(){         //stuff explained before      });     on("change:repeating_equipement:equipqte change:repeating_equipement:equippoids", function() {         getAttrs(["repeating_equipement_equipqte", "repeating_equipement_equippoids"], function(values) {                 //stuff                 TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement');             });     });     on("change:encombrement", function() {         PMT.majEncombrement();     });      on('remove:repeating_equipement',function(){         TAS.repeatingSimpleSum('equipement','equippoidstot','encombrement');     });     // Other events handling </script>
1453057129
The Aaron
Pro
API Scripter
Ideally, you need to have all your scripts in the same <script type="text/worker"> block.  I'm not sure what Roll20 does in the backend when it loads these, but basically if you have something like this it should work fine: <script type="text/worker"> /* Modules */ var TAS = /* ... */; var PMT = /* ... */; /* event handlers */ on('some:event some:other_event',function(){ /* ... */ }); on('some:event some:other_event',function(){ /* ... */ }); </script> Let me know if that's still now working and I'll escalate my support!  =D
1453108522
Natha
KS Backer
Sheet Author
API Scripter
I tried various solutions but I'm sorry to say it didn't work as intended. So, I ended up not using TAS on the sheet:opened event, tallying the encumbrance myself as I was adding the inventory lines, and keeping TAS use for change:xxx events.
1453143331
The Aaron
Pro
API Scripter
Ok.  If you want to PM me a gist link for your script with TAS on the open that wasn't working, I'd be happy to try and track down what's happening.  =D
1453145877

Edited 1453145928
Natha
KS Backer
Sheet Author
API Scripter
Thanks for your time and customer service ;) Gist :&nbsp; <a href="https://gist.github.com/NathaTerrien/2f825727a0a52" rel="nofollow">https://gist.github.com/NathaTerrien/2f825727a0a52</a>... Source of the current version of the sheet (the script shoud be replaced with the gist to try what didn't worked) : <a href="https://github.com/NathaTerrien/roll20-character-s" rel="nofollow">https://github.com/NathaTerrien/roll20-character-s</a>... The "todoequip" string attribute contains something like this :&nbsp; '{"nom":"Sac à dos (20 kg)","qte":"1","poids":"1"}|{"nom":"Silex et amorce","qte":"1","poids":"0"}|{"nom":"Gourde","qte":"1","poids":"0.5"}|{"nom":"Jour de rations de voyage","qte":"4","poids":"0.5"}|{"nom":"Corde en chanvre de 15 m de long","qte":"1","poids":"5"}|{"nom":"Torches","qte":"4","poids":"0.5"}
1453149634
The Aaron
Pro
API Scripter
Cool. &nbsp;I'll take a look tonight. =D
1453574335
The Aaron
Pro
API Scripter
Ok, finally remembered to look at this. &nbsp;I can't be certain, but my guess is this is another case of an asynchronous issue. &nbsp;The way TAS works with attributes is by keeping a dirty list when things are changed and doing the save in one go after execution. &nbsp;Since PMT.majEncombrement() gets and attribute to deal with, the get is probably occurring before TAS has saved the changes. &nbsp;To deal with this, I'll add a way to defer operations until after TAS is done with writing it's changes.