Nice work! I'm not 100% sold on the color scheme, but it's impressive work. Since you asked for suggestions, i had a look at the sheet workers, and want to make some observations and suggestions for one of them. The one that starts on("change:might", function () { getAttrs(["might", "recupes_max", "recupes", "needs_max", "gear_max"], function (values) { setAttrs({ "recupes_max": 2 + (Math.floor(values.might / 2)), "recupes": 2 + (Math.floor(values.might / 2)) }); The first observation: your script sets the values of recupes, needs_max, etc. But it never actually reads them from the sheet. So you dont need them in the getAtrrs line. That should be getAttrs ([ "might" ], function ( values ) { You only need to "get" the "attrs" that you actually read from the sheet. This one's more important: its best practice to only have one getAttrs and one setAttrs per sheet worker. Each time you call one of these introduces a little slow down, and enough of them can add up. There's another problem with it - that isn't relevant to this sheet, but it can become one if you get comfortable writing scripts this way you can easily fall afoul of it by habit. So its best avoided: and that is setAttrs commands are asynchronous, which means they dont necessarily happen in the order they are written. This can be an issue if you arent careful - sometimes you can get the wrong value if you do things in a different order. So if you're in a situation were you want to setAttrs more than once, its better to learn the technique of saving the attribute changes you want to make to a variable, that you then later save all in one go. For that, instead of this: setAttrs({ "recupes_max": 2 + (Math.floor(values.might / 2)), "recupes": 2 + (Math.floor(values.might / 2)) }); do this const output = {}; output.recupes_max = 2 + (Math.floor(values.might / 2)); output.recupes = 2 + (Math.floor(values.might / 2)); I'd also add that since you are using values.might multiple times, it is better to save that into a variable first. You can then do some error checking on it. So the above would become const output = {};
const might = Math.floor( (+values.might||0) /2); output.recupes_max = 2 + might; output.recupes = 2 + might; Notice in the might declaration i did this: (+values.might||0) This is to coerce it into a number, and if its not recognised as a number, set its value to 0. That way the worker doesnt crash when a non-numeric value is entered. Okay, with your attributes in this form, how do you do setAttrs? That's simple: instead of setAttrs({ "recupes_max": 2 + (Math.floor(values.might / 2)), "recupes": 2 + (Math.floor(values.might / 2)) }); just do setAttrs(output); The output variable replaces the contents if the above setAttrs, and furthermore, if you add other stuff to output first, it works without changes. On to the rest of your worker. You have a bunch of if statements like this: if (values.might == -2) { setAttrs({ "needs_max": 1, "gear_max": 4 }); } if (values.might == -1) { setAttrs({ "needs_max": 2, "gear_max": 5 }); } Since we want to avoid multiple setAttrs statements, we can change that to if (might === -2) { output.needs_max: 1; output.gear_max": 4; } else if (might === -1) { output.needs_max: 2; output.gear_max: 5; } And so on. Note how setting might as a variable earlier is saving typing now. Also I changed the == to ===. This is an equals that only works if the data is the same type - but we have already set might as an integer earlier, so we know it always will be. Its better practice to use === when you can, it helps avoid certain subtle errors and can expose others. Notice also that I added an else statement after each if. This is for efficiency purposes. In javascript, the code stops at the first matched element, and skips the rest of the linked code. Without the else, those are separate, independent statements, and javascript will always check them all. Even when its not necessary. With the else statement, it skips the rest once it has matched one. Another thing I noticed: at the start of your function, you have if (values.might == -2) { setAttrs({ "needs_max": 1, "gear_max": 4 }); } And at the end you have if (values.might == -2) { setAttrs({ "needs_max": 7, "gear_max": 13 }); } You are checking for might of -2 both times, and setting different values. I have no way of knowing which is correct but you code will set them both, and because of asynchronicity, there's no way of predicting which one will happen last. Putting that all together, the worker (with only the first 3 parts of the if statement) would look like this: on("change:might", function () { getAttrs(["might"], function (values) { const output = {}; const might = Math.floor( (+values.might||0) /2); output.recupes_max = 2 + might; output.recupes = 2 + might; if (might === -2) { output.needs_max = 1; output.gear_max = 4; } else if (might === -1) { output.needs_max = 2; output.gear_max = 5; } else if (might === 0) { output.needs_max = 3; output.gear_max = 6; } setAttrs(output); }); }); Hope that helps!