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

[Sheetworker] shorten a repetitive code / raccourcir un code répétitif

1519565605

Edited 1519574560
Bonjour j'ai dans ma feuille de personnage un système (basique) d'expérience pour chaque compétence. je les donc répéter pour chacune d'entre elle. Serait-t'il possible d'avoir une petite portion de code qui s'appliquerait pour tout les compétence? Voici mon code actuelle: Merci a vous! Hello I have in my character sheet a system (basic) of experience for each skill. I repeat them for each of them. Would it be possible to have a small portion of code that would apply for all skill? Here is my code: Thank you! EDIT: Thanks for this G G work perfectly     <script type="text/worker"> on("change:xpl_maniementépée", function() { getAttrs(["xpl_maniementépée","xpl_maniementépée_max","lv_maniementépée"], function(values) { const xpl = parseInt(values.xpl_maniementépée); const xplmax = parseInt(values.xpl_maniementépée_max); const lv = parseInt(values.lv_maniementépée); if (xpl >= xplmax) { setAttrs({ xpl_Maniementépée: xpl - xplmax, lv_Maniementépée: lv + 1, xpl_Maniementépée_max: (lv*200) + 100 // lv is still the old level }); }; }); }); on("change:xpl_constitution", function() {                 getAttrs(["xpl_constitution","xpl_constitution_max","lv_constitution"], function(values) {                     const xpl = parseInt(values.xpl_constitution);                     const xplmax = parseInt(values.xpl_constitution_max);                     const lv = parseInt(values.lv_constitution);                     if(xpl >= xplmax){                         setAttrs({                             xpl_constitution: xpl - xplmax,                             lv_constitution: lv + 1,                             xpl_constitution_max: (lv*200) + 100                         });                     };                 });              });             on("change:xpl_diplomatie", function() {                 getAttrs(["xpl_diplomatie","xpl_diplomatie_max","lv_diplomatie"], function(values) {                     const xpl = parseInt(values.xpl_diplomatie);                     const xplmax = parseInt(values.xpl_diplomatie_max);                     const lv = parseInt(values.lv_diplomatie);                     if(xpl >= xplmax){                         setAttrs({                                            xpl_diplomatie: xpl - xplmax,                             lv_diplomatie: lv + 1,                             xpl_diplomatie_max: (lv*200) + 100                         });                     };                 });              });     on("change:xpl_acrobatie", function() {                 getAttrs(["xpl_acrobatie","xpl_acrobatie_max","lv_acrobatie"], function(values) { const xpl = parseInt(values.xpl_acrobatie); const xplmax = parseInt(values.xpl_acrobatie_max); const lv = parseInt(values.lv_acrobatie); if(xpl >= xplmax){ setAttrs({ xpl_acrobatie: xpl - xplmax, lv_acrobatie:lv + 1, xpl_acrobatie_max:(lv*100) + 100 }); };     });     });            on("change:xpl_force", function() { getAttrs (["xpl_force","xpl_force_max","lv_force"], function(values){ const xpl = parseInt(values.xpl_force); const xplmax = parseInt(values.xpl_force_max); const lv = parseInt(values.lv_force); if(xpl >= xplmax){ setAttrs({ xpl_force: xpl - xplmax, lv_force:lv + 1, xpl_force_max:(lv*100) + 100 }); }; }); });    on("change:xpl_sensaiguise", function() { getAttrs (["xpl_sensaiguise","xpl_sensaiguise_max","lv_sensaiguise"], function(values){ const xpl = parseInt(values.xpl_sensaiguise); const xplmax = parseInt(values.xpl_sensaiguise_max); const lv = parseInt(values.lv_sensaiguise); if(xpl >= xplmax){ setAttrs({ xpl_sensaiguise: xpl - xplmax, lv_sensaiguise:lv + 1, xpl_sensaiguise_max:(lv*100) + 100 }); }; }); });    on("change:xpl_apprentissagetechnologie", function() { getAttrs (["xpl_apprentissagetechnologie","xpl_apprentissagetechnologie_max","lv_apprentissagetechnologie"], function(values){ const xpl = parseInt(values.xpl_apprentissagetechnologie); const xplmax = parseInt(values.xpl_apprentissagetechnologie_max); const lv = parseInt(values.lv_apprentissagetechnologie); if(xpl >= xplmax){ setAttrs({ xpl_apprentissagetechnologie: xpl - xplmax, lv_apprentissagetechnologie:lv + 1, xpl_apprentissagetechnologie_max:(lv*100) + 100 }); }; }); }); on("change:xpl_forgearmure",function() { getAttrs (["xpl_forgearmure","xpl_forgearmure_max","lv_forgearmure"], function(values){ const xpl = parseInt(values.xpl_forgearmure); const xplmax = parseInt(values.xpl_forgearmure_max); const lv = parseInt(values.lv_forgearmure); if(xpl >= xplmax){ setAttrs({ xpl_forgearmure: xpl - xplmax, lv_forgearmure:lv + 1, xpl_forgearmure_max:(lv*100) + 100 }); }; }); }); on("change:xpl_estimation", function() { getAttrs (["xpl_estimation","xpl_estimation_max","lv_estimation"], function(values){ const xpl = parseInt(values.xpl_estimation); const xplmax = parseInt(values.xpl_estimation_max); const lv = parseInt(values.lv_estimation); if(xpl >= xplmax){ setAttrs({ xpl_estimation: xpl - xplmax, lv_estimation:lv + 1, xpl_estimation_max:(lv*100) + 100 }); };   }); }); on("change:xpl_connaissancecode", function() { getAttrs (["xpl_connaissancecode","xpl_connaissancecode_max","lv_connaissancecode"], function(values){ const xpl = parseInt(values.xpl_connaissancecode); const xplmax = parseInt(values.xpl_connaissancecode_max); const lv = parseInt(values.lv_connaissancecode); if(xpl >= xplmax){ setAttrs({ xpl_connaissancecode: xpl - xplmax, lv_connaissancecode:lv + 1, xpl_connaissancecode_max:(lv*100) + 100 }); }; }); }); on("change:xpl_dex", function() { getAttrs (["xpl_dex","xpl_dex_max","lv_dex"], function(values){ const xpl = parseInt(values.xpl_dex); const xplmax = parseInt(values.xpl_dex_max); const lv = parseInt(values.lv_dex); if(xpl >= xplmax){ setAttrs({ xpl_dex: xpl - xplmax, lv_dex:lv + 1, xpl_dex_max:(lv*100) + 100 }); }; }); }); on("change:xpl_multitache", function() { getAttrs (["xpl_multitache","xpl_multitache_max","lv_multitache"], function(values){ const xpl = parseInt(values.xpl_multitache); const xplmax = parseInt(values.xpl_multitache_max); const lv = parseInt(values.lv_multitache); if(xpl >= xplmax){ setAttrs({ xpl_multitache: xpl - xplmax, lv_multitache:lv + 1, xpl_multitache_max:(lv*100) + 100 }); }; }); }); </script>  
1519572664
GiGs
Pro
Sheet Author
API Scripter
Yes, you can do this. This should work, barring any typos I may inadvertently include. ['multitache', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here     on("change:xpl_" + stat.toLowerCase() , function () {         getAttrs(["xpl_"+ stat, "xpl_" + stat + "_max","lv_" + stat], function(values) { const xpl = parseInt(values["xpl_" + stat]); const xplmax = parseInt(values["xpl_" + stat + "_max"]); const lv = parseInt(values["lv_" + stat]); if(xpl >= xplmax){ setAttrs({ ["xpl_" + stat]: xpl - xplmax, ["lv_" + stat]:lv + 1, ["xpl_" + stat + "_max"]:(lv*100) + 100 }); };         });     }); });
Thank you gg! I tried to adopt your code to another part of mine and I probably made a mistake. Can you help me? Merci gg! J'ai essayer d'adopter ton code a une autre partie du mien et j'ai surement fait une erreur. Peut tu m'aider? Here is the part of my code that I'm trying to shorten: / Voici la partie de mon code que j'essaye de raccourcir: on("change:classe", function() {getAttrs(["classe","b_forgea","lv_forgea"], function(values) { const C = values.classe; const bforgearmure = parseInt(values.b_forgea); const lvforge = parseInt(values.lv_forgea) setAttrs({ b_forgea: lvforge }) if(C == "Armurier"){ setAttrs({ b_forgea: lvforge + 4 }) }; }); }); on("change:lv_forgea", function() { getAttrs(["classe","b_forgea","lv_forgea"], function(values) { const C = values.classe; const bforgearmure = parseInt(values.b_forgea); const lvforge = parseInt(values.lv_forgea) setAttrs({ b_forgea: lvforge }) if(C == "Armurier"){ setAttrs({ b_forgea: lvforge + 100 }) }; }); }); And here the code i have for now: ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here on("change:classe", function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat]); const C = values.classe; const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C == Armurier){ ["b_" + stat]: lv + 4 }; }; if(stat == "estimation"){ if(C == roublard){ ["b_"+ stat]: lv + 5 } //ect... } }); }); }); ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here on("change:lv_" + stat.toLowerCase(), function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat]); const C = values.classe; const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C == Armurier){ ["b_" + stat]: lv + 4 }; }; }); }); });
1519604712

Edited 1519689204
GiGs
Pro
Sheet Author
API Scripter
You'd forgotten the setAttrs statement in both of those, and you need to put quotes around the value you are comparing C to, like so: if(C == roublard){ ["b_"+ stat]: lv + 5 } Should be if(C == "roublard"){ setAttrs({ ["b_"+ stat]: lv + 5 }); }; Late Edit: corrected syntax
thanks i think i have correct all fault occurence you said but its do not work again :/ ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here on("change:classe", function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const C = values.classe; const bonus = parseInt(values["b_" + stat]); const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C == "Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }; }; }; if(stat == "mé"){ if(C == "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }; }; }; }); }); }); ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here on("change:lv_" + stat.toLowerCase(), function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat]); const C = values.classe; const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C =="Armurier"){ ["b_" + stat]: lv + 4 }; }; if(stat == "mé"){ if(C == "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }; }; }; }); }); });
1519688342
GiGs
Pro
Sheet Author
API Scripter
Your second function is missing a setAttrs under if C == "Armurier" Also, each of the setattr statements are missing closing brackets. Looks like I posted the wrong syntax earlier! ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie', 'constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { on("change:classe", function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const C = values.classe; const bonus = parseInt(values["b_" + stat]); const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C == "Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }); }; }; if(stat == "mé"){ if(C == "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }); }; }; }); }); }); ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie', 'constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { on("change:lv_" + stat.toLowerCase(), function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat]); const C = values.classe; const lv = parseInt(values["lv_" + stat]); if(stat == "forgea"){ if(C =="Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }); }; }; if(stat == "mé"){ if(C == "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }); }; }; }); }); });
1519688791
GiGs
Pro
Sheet Author
API Scripter
By the way, the functions make me wonder. If you're having nested if statements to filter out which bonuses to apply, there's probably a better way to build these functions, but I cant suggest a solution without knowing what all the bonuses are and how they apply.  One thing: if classes can change, you should add them to the change event, like so: on("change:classe change:lv_" + stat.toLowerCase(), function () {
1519688936

Edited 1519689284
GiGs
Pro
Sheet Author
API Scripter
Never mind, i see you have two events there. You should replace both those functions with this single one: ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie', 'constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { on("change:classe change:lv_" + stat.toLowerCase(), function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat])||0; const C = values.classe; const lv = parseInt(values["lv_" + stat])||0; if(stat === "forgea"){ if(C === "Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }); }; }; if(stat === "mé"){ if(C === "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }); }; }; }); }); }); PS: i made some slight tweaks to the code. I changed each == to ===. It avoids some obscure errors, you should never use the ==. I added ||0 to each ParseInt(), so they became parseInt()||0. This sets a default of 0 (whatever is after the "||" is the default). This avoids some errors - if the cell is empty, or not a number, this code will usually fail without setting a default.
1519692247

Edited 1519694346
nice to know thanks.. but did not do nothing :) Do you have a tip for debug  (like alert(); in javascript) Edit:  3 way for add bonus, 1: if the class give a bonus 2 if the race .... 3: the lv of the skill (1lv for +1) The bonuses for race and skill are decided when I create them with the player. It is not yet all defined because I still miss a player who has not finished his character
1519701158

Edited 1519701172
GiGs
Pro
Sheet Author
API Scripter
You can debug in two ways log("stuff"); sends data to the script log, and sendChat("label","stuff") sends data to the chat window in game. Neither work if the script fails with an error. But if the script doesnt crash, but just isnt working, you can get information from them. So, you can add lots of log statements to test values. ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie', 'constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) { on("change:classe change:lv_" + stat.toLowerCase(), function () { getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) { const bonus = parseInt(values["b_" + stat])||0; const C = values.classe; const lv = parseInt(values["lv_" + stat])||0; log('stat = ' + stat + '. bonus = ' + bonus + '. C = ' + C + '. lv = ' + lv); if(stat === "forgea"){ if(C === "Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }); } } if(stat === "mé"){ if(C === "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }); } } }); }); }); I can't see why the code itself shouldnt work, but maybe I'm missing something. It seems more likely that the there's something up with the input data, or the logic is faulty. Personally, I'd remove this function temporarily, and go back to the version that doesnt use [stats].forEach, and test each individual version to see if its working.
1519701849

Edited 1519701867
GiGs
Pro
Sheet Author
API Scripter
Maximilien B. said: Edit:  3 way for add bonus, 1: if the class give a bonus 2 if the race .... 3: the lv of the skill (1lv for +1) The bonuses for race and skill are decided when I create them with the player. It is not yet all defined because I still miss a player who has not finished his character I am wondering if the logic of the script is faulty. For instance, you set up a bonus variable: const bonus = parseInt(values["b_" + stat])||0; But its never actually used after that. And this section: if(stat === "forgea"){ if(C === "Armurier"){ setAttrs({ ["b_" + stat]: lv + 4 }); } } It says that the forgeaa stat only gets a bonus if the class is Armurier. People not in the Armurier class will never get a forgea bonus. Is that intended? I suspect the script should look something more like this (but I'm guessing, since i dont know how the system works): const C = values.classe; const lv = parseInt(values["lv_" + stat])||0; let bonus = lv; if(stat === "forgea" && C === "Armurier"){ bonus = bonus +4; } if(stat === "mé" && C === "Guerrier"){ bonus = bonus +6; } setAttrs({ ["b_" + stat]: bonus });
yeah this is a better idea if(stat === "forgea" && C === "Armurier"){ bonus = bonus +4; } I did not find before go to job :/ if give you the part of my html who is affect by the script if can help :/     <div class="competenceSecondaire" style="float:right;">         <div class="cs1"> <input type="text" name="name_maniementépée" value="Maniement de l'épée"> Niveaux:<span name="attr_lv_mé"></span> Xp:<input type="number" name="attr_xpl_mé">/<span name="attr_xpl_mé_max"></span> Bonus: <span name="attr_b_mé" ></span> </div> <div class="cs2"> <input type="text" name="name_constitution" value="Constitution"> Niveaux:<span type="number" name="attr_lv_constitution"></span> Xp:<input type="number" name="attr_xpl_constitution">/<span name="attr_xpl_constitution_max"></span> Bonus: <span name="attr_b_constitution"></span>          </div>          <div class="cs3"> <input type="text"  value="Diplomatie" name="name_diplomatie"> Niveaux:<span type="number" name="attr_lv_diplomatie"></span> Xp:<input type="number" name="attr_xpl_diplomatie">/<span name="attr_xpl_diplomatie_max"></span>  Bonus: <span name="attr_b_diplomatie"></span>          </div>          <div class="cs4"> <input type="text" value="Acrobatie" name="name_acrobatie"> Niveaux:<span  name="attr_lv_acrobatie"></span> Xp:<input type="number" name="attr_xpl_acrobatie">/<span name="attr_xpl_acrobatie_max"></span>  Bonus: <span name="attr_b_acrobatie"></span>          </div>          <div class="cs5"> <input type="text" value="Force" name="name_force"> Niveaux:<span name="attr_lv_force"></span> Xp:<input type="number" name="attr_xpl_force">/<span type="number" name="attr_xpl_force_max"></span> Bonus: <span name="attr_b_force"></span>          </div>          <div class="cs6"> <input type="text" value="Sens aiguisé" name="name_sensaiguise"> Niveaux:<span name="attr_lv_sensaiguise"></span> Xp:<input type="number" name="attr_xpl_sensaiguise">/<span name="attr_xpl_sensaiguise_max"></span> Bonus: <span name="attr_b_sensaiguise"></span>          </div>          <div class="cs7"> <input type="text" value="Aprentissage des technologie" name="name_apprentissagetechnologie"> Niveaux:<span name="attr_lv_Apprentissagetechnologie"></span> Xp:<input type="number" name="attr_xpl_apprentissagetechnologie">/<span type="number" name="attr_xpl_apprentissagetechnologie_max"></span> Bonus: <span name="attr_b_apprentissagetechnologie"></span>          </div>          <div class="cs8"> <input type="text" value="Forge d'armure" name="name_forgearmure"> Niveaux:<span name="attr_lv_forgea"></span> Xp:<input type="number" name="attr_xpl_forgea">/<span type="number" name="attr_xpl_forgea_max"></span> Bonus: <span name="attr_b_forgea"></span>          </div>          <div class="cs9"> <input type="text" value="Estimation" name="name_estimation"> Niveaux:<span name="attr_lv_estimation"></span> Xp:<input type="number" name="attr_xpl_estimation">/<span type="number" name="attr_xpl_estimation_max"></span> Bonus: <span name="attr_b_estimation"></span>          </div>          <div class="cs10"> <input type="text" value="Connaissance code informatique" name="name_connaissancecode"> Niveaux:<span name="attr_lv_connaissancecode"></span> Xp:<input type="number" name="attr_xpl_connaissancecode">/<span type="number" name="attr_xpl_connaissancecode_max"></span> Bonus: <span name="attr_b_connaissancecode"></span>          </div>          <div class="cs11"> <input type="text" value="Dextériter" name="name_Dexteriter"> Niveaux:<span name="attr_lv_dex"></span> Xp:<input type="number" name="attr_xpl_dex">/<span type="number" name="attr_xpl_dex_max"></span> Bonus: <span name="attr_b_dex"></span> </div>          <div class="cs11"> <input type="text" value="Multi-tache" name="name_multitache"> Niveaux:<span name="attr_lv_multitache"></span> Xp:<input type="number" name="attr_xpl_multitache">/<span type="number" name="attr_xpl_multitache_max"></span> Bonus: <span name="attr_b_mu"></span> </div> <script type="textworker"> ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','multitache', 'dex', 'connaissancecode'].forEach(function (stat) {       on("change:classe change:lv_" +  stat.toLowerCase(), function () {         getAttrs(["classe", "b_" + stat, "lv_" + stat], function(values) {             const bonus = parseInt(values["b_" + stat])||0;             const C = values.classe;             const lv = parseInt(values["lv_" + stat])||0;         sendChat('Léane','stat = ' + stat + '. bonus = ' + bonus + '. C = ' + C + '. lv = ' + lv);             if(stat === "forgea"){                 if(C === "Armurier"){                      setAttrs({                     ["b_" + stat]: lv + 4 });                 };                };             if(stat === "mé"){                 if(C === "Guerrier"){                      setAttrs({                         ["b_" + stat]: lv + 6                     });                 };             };         });     }); }); </script>  
and yes other player can have a bonus if not in Armurier class on change lv sould work whit this if the code work a day ... xD <script type="textworker"> //Script for bonuse of race & classe ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) {   on("change:classe change:lv_" +  stat.toLowerCase(), function () { getAttrs(["classe","race", "b_" + stat, "lv_" + stat], function(values) { const bonus = 0; const C = values.classe; const R = value.race; const lv = parseInt(values["lv_" + stat])||0; sendChat('Léane','stat = ' + stat + '. bonus = ' + bonus + '. C = ' + C + '. lv = ' + lv);          ["b_" + stat]: lv if(stat === "forgea" && C === "Armurier"){                                 setAttrs({ ["b_" + stat]: lv + 4                                 }); }; if(stat === "mé" && C === "Guerrier"){ setAttrs({ ["b_" + stat]: lv + 6 }); }; if(R === "Homme-araignée" && stat === "dex"){ setAttrs({ ["b_"+ stat]: lv + 2 }); }; }); }); }); </script
1519787140

Edited 1519787317
GiGs
Pro
Sheet Author
API Scripter
First, I notice this function has a script wrapper around it. Just to check: do you have more than one of these in your sheet: <script type="textworker"> //Script for bonuse of race & classe // race and class functions </script> <script type="textworker"> // experience functions </script> <script type="textworker"> // other functions </script> If so, that may be where your issue lies. You should just have one script block. Change to  <script type="textworker"> //All scripts go here // race and class functions // experience functions // ALL other functions </script> Everything should be in a single script block. To your script: you're missing the first setAttrs call. Also, you should switch to the bonus method I suggested earlier. Now that you are having multiple setAttrs changing the value of the same stat in the same function, you will run into timing issues. Because of the way server-based software works, there's no guarantee these will run in the order you want. The "set stat to lvl+4" command may run before the "set stat to lv" command and you end up with the wrong value.  here's an adjusted version of your code: ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) {   on("change:classe change:race change:lv_" +  stat.toLowerCase(), function () { getAttrs(["classe","race", "lv_" + stat], function(values) { const C = values.classe; const R = value.race; let bonus = parseInt(values["lv_" + stat])||0; sendChat('Léane','stat = ' + stat + '. lv = ' + bonus + '. C = ' + C ); if(stat === "forgea" && C === "Armurier"){                     bonus += 4; } if(stat === "mé" && C === "Guerrier"){ bonus += 6; } if(R === "Homme-araignée" && stat === "dex"){ bonus +=2; } setAttrs({ ["b_"+ stat]: bonus }); }); }); }); I added a change:race statement to the second line, so the function will run when race, class, and stat changes. I removed [ "b_" + stat ] from the getAttrs line since you dont actually need it there. You only need to use getAttrs on stats you are reading in. You are setting the bonus, but you dont need to know what the bonus was before you set it. Hope this helps.  Also setting variables: you use const for variables that are fixed in value - once you create them, they won't change. Use let  or var  for variables that will change - like bonus above.
1519821008

Edited 1519822855
ok so i test to add log in the function and this is what the console give me... (not the result of the log) the function is to the end Triggering for change:race sheetsandboxworker.js?20170926:67 Triggering for change:race_max sheetsandboxworker.js?20170926:67 Triggering for change:race sheetsandboxworker.js?20170926:67 Triggering for change:race_max sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.4294962693536506] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.4294962693536506] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.6635648936856817] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.6635648936856817] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.08563075807027976] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.08563075807027976] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.735738733168201] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.735738733168201] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.7039901048622002] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.7039901048622002] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.4736217865049195] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.4736217865049195] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.5163047623033385] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.5163047623033385] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.7650923384177115] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.7650923384177115] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.033898327831756614] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.033898327831756614] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.8677942265808691] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.8677942265808691] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.21700519760309178] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.21700519760309178] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:302 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.04547415142874178] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) sheetsandboxworker.js?20170926:303 ReferenceError: value is not defined     at Object.eval [as -L5XPRYK2GQ30mMXVkVF//false//0.04547415142874178] (eval at messageHandler (sheetsandboxworker.js?20170926:276), <anonymous>:6:15)     at _fullfillAttrReq (sheetsandboxworker.js?20170926:251)     at messageHandler (sheetsandboxworker.js?20170926:283) EDIT: The function whit the log ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) {   on("change:classe change:race change:lv_" +  stat.toLowerCase(), function () { getAttrs(["classe","race", "lv_" + stat], function(values) { const C = values.classe; const R = value.race; let bonus = parseInt(values["lv_" + stat])||0; log("classe: "+ C + "Bonus " + bonus); if(stat === "forgea" && C === "Armurier"){                     bonus += 4;                     log("Forgea & Armurier "+ C + "Bonus " + bonus); }; if(stat === "mé" && C === "Guerrier"){ bonus += 6; log("mé & Guerrier "+ C + "Bonus " + bonus); }; if(R === "Homme-araignée" && stat === "dex"){ bonus +=2; log("Ha & dex "+ C + "Bonus " + bonus); }; }); }); });
1519830231

Edited 1519830243
GiGs
Pro
Sheet Author
API Scripter
The line const R = value.race should be const R= values.race
1519830272

Edited 1519830396
ok i rewrite the script one by one and for now this work:             ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) {  // fill in the rest of the stats here on("change:classe change:race change:lv_" + stat.toLowerCase() , function () { getAttrs(["classe", "lv_"+ stat, "b_"+ stat], function(values) {     const Cl= values.classe  const lv= parseInt(values["lv_" + stat]); let bonus= parseInt(values["b_" + stat]); if( lv != bonus){     setAttrs({         ["b_" + stat]:lv     }); }; }); }); });
1519833209

Edited 1519834387
Ok this work to but not if i add the line in comment EDIT: work now, i have correct the line             ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) {  // fill in the rest of the stats here on("change:classe change:race change:lv_" + stat.toLowerCase() , function () { getAttrs(["classe", "lv_"+ stat, "b_"+ stat], function(values) {     const Cl = values.classe; let bonus = parseInt(values["lv_" + stat])||0; if(Cl === "Armurier" && stat === "forgea"){    log("DEBUG: " + stat);   bonus += 4 }; setAttrs({         ["b_" + stat]:bonus     }); }); }); });
1519835033

Edited 1519835258
So this code all work :  Youpi!  And thanks alot xD ['estimation','forgea','apprentissagetechnologie','sensaiguise','force','acrobatie','diplomatie','constitution','mé','mu', 'dex', 'connaissancecode'].forEach(function (stat) { // fill in the rest of the stats here on("change:classe change:race change:lv_" + stat.toLowerCase() , function () { getAttrs(["race", "classe", "lv_"+ stat, "b_"+ stat], function(values) { const Cl = values.classe; const Rl = values.race; let bonus = parseInt(values["lv_" + stat])||0; if(Cl === "Armurier" && stat === "forgea"){ bonus += 4; }; if( Cl === "Guerrier" && stat === "mé"){ bonus += 6; }; if(Rl === "Homme-araignée" && stat === "dex"){ bonus += 2; }; setAttrs({ ["b_" + stat]:bonus }); }); }); });
1519836711
GiGs
Pro
Sheet Author
API Scripter
Well done, glad we got there in the end!