I suggest trying to make the changes I suggested to that worker. It's possible it isn't probably being converted amd operated on. That would look like this: on("change:reduction change:reduction_max change:base_reduction change:add_reduction", function() { getAttrs(["reduction", "reduction_max", "base_reduction", "add_reduction"], function(values) { let output = {}; // Final reduction var b_reduction = values.base_reduction || 0; var t_reduction = b_reduction + (values.add_reduction || 0); output.reduction = t_reduction; var chk_reduction = t_reduction > (values.reduction_max || 0) ? (values.reduction_max || 0) : t_reduction; output. hide_reduction = chk_reduction; // Bonus by reduction value var red_effect = getreduction_effect(t_reduction); // what is this function? var add_dice = red_effect[0]; // plus dice var add_lv = red_effect[1]; // plus level // 1) Additional level output. effect_level = add_lv; // 2) Additional dice output. add_dice:add_dice; let max = values.reduction_max || 0; let now = t_reduction ; let pers = (now == 0 || max == 0) ? 0 : now/max*100; pers = Math.floor(pers); output. reduction_per = pers; setAttrs(output); }); }); There's something I'd want to check here: this line calls a function var red_effect = getreduction_effect(t_reduction); You'd need to include that, so we can check it is working properly. Luckily you included the address of the code earlier. That is function getreduction_effect(type) { var data = {0:0,1:0}; // 1 - 다이스 / 2 - 이펙트 레벨 if(type >= 60) { // 침식치 60 이상 data[0] = 1; } if(type >= 80) { // 침식치 80 이상 data[0] = 2; } if(type >= 100) { // 침식치 100 이상 data[0] = 3; data[1] = 1; } if(type >= 130) { // 침식치 130 이상 data[0] = 4; } if(type >= 160) { // 침식치 160 이상 data[1] = 2; } if(type >= 190) { // 침식치 190 이상 data[0] = 5; } if(type >= 220) { // 침식치 220 이상 data[1] = 3; } if(type >= 260) { // 침식치 260 이상 data[0] = 6; } if(type >= 300) { // 침식치 300 이상 data[0] = 7; } return data; } I cant tell if this is working properly, but it looks like that the first line creates a data variable, but the later lines are based on a different format. This create an initial variable: var data = {0:0,1:0}, this means data[0] = 0:0, and data[1] = 1:0, but the if statements later set a simple integer, 1, 2, 3, etc. Is this correct? Back to Your Specific Problem You said the problem wasthe reduction_per stat not being set correctly. Looking at your worker, tere is this code: let max = values.reduction_max; let now = values.reduction; let pers = (now == 0 || max == 0) ? 0 : now/max*100; pers = Math.floor(pers); setAttrs({reduction_per: pers}); It looks like reduction_per depends only on reduction and reduction_max, so I'd look at those stats and see if they are being calculated properly. It looks like reduction_per shows a percentage (hence the _per part of the name). In the sheet, both of these stats are readonly. How are they being set? Aha I think I see your issue. reduction is being set in this worker, so it looks like your issue is being caused by having separate setAttrs statements. Try the corrected worker above and see if this fixes the issue. The fact that you have change:reduction in a worker where reduction is also set could be a problem - this may create an infinite loop. It'll probably run just once extra, but if it does cause an infinite loop this is your issue.