John is right :) But John, you have seperate sheet workers for each attribute - it would be more efficient to use a single sheet worker with change events for each attribute built in. It looks like your formula is correct, so maybe there's something wrong with one of your initial attributes. Try putting each @{wpn_attk_totala} inside inline roll brackets [[ @{wpn_attk_totala} ]] and see if there's a change. Are any of the inital attributes themselves autocalcs? If any of these stats 'wpn_attk_value',
'manipulation_mod',
'gift_attk_value',
'magic_attk_value',
'fatigue_modgen_modn',
'gen_modp',
'negative_mod_value' are also autocalcs, try putting inline roll brackets around them to see if the behaviour changes. For a sheet worker, you can get rid of the first attribute, and just have a single attribute that takes the minimum of 5 into account: input type="hidden" name="attr_wpn_attk_total" value="5"> If you have never used sheet workers before, you need to create a space in your html for them. That's simple: just
create these two lines at the very bottom of your HTML: < script type = "text/worker" > </ script > All your sheet workers go between those two script lines. Here's an introductory version of your sheet worker would look something like: // with a sheet worker, you have to first list which attributes will be watched for changes. on ( 'change:wpn_attk_value change:manipulation_mod change:gift_attk_value change:magic_attk_value change:fatigue_modgen_modn change:gen_modp change:negative_mod_value sheet:opened' , () => { // then when a change happens on any of them, you have to tell roll20 which attributes to grab getAttrs ([ 'wpn_attk_value' , 'manipulation_mod' , 'gift_attk_value' , 'magic_attk_value' , 'fatigue_modgen_modn' , 'gen_modp' , 'negative_mod_value' ], values => { // then convert each attribute to a variable, so you can use it in arithmetic. const wpn_attk_value = parseInt ( values . wpn_attk_value ) || 0 ; const manipulation_mod = parseInt ( values . manipulation_mod ) || 0 ; const gift_attk_value = parseInt ( values . gift_attk_value ) || 0 ; const magic_attk_value = parseInt ( values . magic_attk_value ) || 0 ; const fatigue_modgen_modn = parseInt ( values . fatigue_modgen_modn ) || 0 ; const gen_modp = parseInt ( values . gen_modp ) || 0 ; const negative_mod_value = parseInt ( values . negative_mod_value ) || 0 ; // then add all the attributes together const total = wpn_attk_value + manipulation_mod + gift_attk_value + magic_attk_value + fatigue_modgen_modn + gen_modp + negative_mod_value ; //now that you have a sum, you want to make sure it isnt below 5. const final_total = Math . max ( 5 , total ); // finally you save the calculated value to the character sheet attribute. setAttrs ({ wpn_attk_total: final_total }); }); }); The green lines are comments describing what is happening in the next bit. They can be deleted. As you can see Sheet Workers are much more complex initially than using autocalcs, but there are advantages to using them - they are more efficient, and the attributes you create with them can be used for token bubble values, among other things. If you want anything explained in that sheet worker, ask away. It's
handy to understand how these work so you can make your own. Though it
looks complicated, almost all of your sheet workers will use the same
structure so it's very easy to create more once you know how one works. The big drawback is they cant be combined with autocalc attributes - if you have any autocalc attributes, they need to be changed to sheet worker calculations before those stats can be used. For John, since you know how to use reduce, here's another version of that sheet worker, taking advantage of functions and automation. I wouldnt recommend this to novices - there's way too much to explain here. The above worker has exactly the same result! const int = ( score , fallback = 0 ) => parseInt ( score ) || fallback ; const sum = scores => scores . reduce (( a , b ) => a + int ( b ), 0 ); const changes = ( stats , sheet_open = false ) => stats . reduce (( all , stat ) => ` ${ all } change: ${ stat . toLowerCase () } ` , sheet_open ? 'sheet:opened' : '' ); const weapon_attack_stats = [ 'wpn_attk_value' , 'manipulation_mod' , 'gift_attk_value' , 'magic_attk_value' , 'fatigue_modgen_modn' , 'gen_modp' , 'negative_mod_value' ]; on ( changes ( weapon_attack_stats , true ), () => { getAttrs ( weapon_attack_stats , values => { const output = {}; const total = sum ( Object . values ( values )); output . wpn_attk_total = Math . max ( 5 , total ); setAttrs ( output ); }); });