Hello, I have been working on updating my custom character sheets for quite some time.  I've had to skip doing several things because I don't really understand how to get them to work.  I was wondering if someone might be able to show me, and in two cases give me a bit of example code that I can pick apart and work on myself. My first issue is that I have several cases where a field is filled in by the user with a formula to deterimine certain aspects of the sheet.  MAX HP, MAX Skills and MAX Power Points.  Those all require a formula that may change from game to game.  I have seen on some character sheets that it does appear to be possible to have helper scripts "parse" the text in those fields to it gives the correct value.  Does anyone have the code for that that I could add to my sheets (and a bit of commenting that explains how it is working would help as well, if its possible. I would also be using this for my encounter npcs, because I have set some of the fields up to use both a fix number and an auto-calc formula to make scaling my monsters easier.  (@{fa-bab-#}, @{me-bab-#} and @{sl-bab-#} and similar for saves and spell range information. The second issue is even with examples I have seen out there I've had a hard time getting repeating section calculations to work.  Would anyone be able to help me but taking one of my repeating sections and writing the code for it, so I can pick it apart and hopefully learn to the rest of them myself.   I would be highly appreciative, and would compensate you for the time in some way we could work out privately, if you so desire.   I have several sets of repeating sections that this would be useful for, but I am most interested in having it done with my spell section. Third and finally, perhaps the easiest.  My games use a lot of dynamic adjustments to characters and tokens.  Therefore I've taken to using an attribute modifier api.  The problem is, when this is used in conjunction with helper scripts.  the field does not register a change on the character sheet when you use the api command to change character sheet attributes.  You have to open the character sheet and manaully start clicking around the changed attributed to get it to function.  Which obviously defeats the purpose of a one click mechanism to alter attributes.  Anything I can do to get this to work, so that the moment you click it, and the moment the values in the character sheet change, it automatically refreshes the worker script. var ModUtils = ModUtils || {}; ModUtils.setAttribute = function(char_id, attr_name, newVal) {     var attribute = findObjs({         _type: "attribute",     _characterid: char_id, _name: attr_name })[0]; //log(attribute); if (attribute == undefined) { createObj("attribute", { name: attr_name, current: newVal, characterid: char_id }); } else { attribute.set("current", newVal.toString()); } //log(attribute); } ModUtils.decrementAttribute = function(char_id, attr_name, curVal) { var attribute = findObjs({ _type: "attribute", _characterid: char_id, _name: attr_name })[0]; if (attribute == undefined) { ModUtils.setAttribute(char_id, attr_name, -1); return; } //log(attribute); attribute.set("current", (parseInt(curVal) - 1).toString()); //log(attribute); } ModUtils.incrementAttribute = function(char_id, attr_name, curVal) { var attribute = findObjs({ _type: "attribute", _characterid: char_id, _name: attr_name })[0]; if (attribute == undefined) { ModUtils.setAttribute(char_id, attr_name, 1); return; } //log(attribute); attribute.set("current", (parseInt(curVal) + 1).toString()); //log(attribute); } ModUtils.alterAttribute = function(char_id, attr_name, modVal) { var attribute = findObjs({ _type: "attribute", _characterid: char_id, _name: attr_name })[0]; if (attribute == undefined) { ModUtils.setAttribute(char_id, attr_name, modVal); return; } //log(attribute); attribute.set("current", (parseInt(attribute.get("current")) + modVal).toString()); //log(attribute); } ModUtils.alterBar = function(tokenID, barNum, modVal) { var token = getObj("graphic", tokenID); if (token == undefined || barNum < 1 && barNum > 3) return; var bar = "bar" + barNum; var barVal = parseInt(token.get(bar + "_value")); var barMax = parseInt(token.get(bar + "_max")); barVal += modVal; if (barVal > barMax) barVal = barMax; token.set(bar + "_value", barVal); }; on("chat:message", function (msg) { //log(msg.content); if (msg.type != "api") return; var args = msg.content.split(" "); var command = args.shift(); if (command === "!decattr") { var token = getObj("graphic", args[0]); var char_id = token.get("represents"); if (char_id != "") { var attr_name = args[1]; var curVal = getAttrByName(char_id, attr_name); //log(!char_id); //log(attr_name); //log(curVal); ModUtils.decrementAttribute(char_id, attr_name, curVal); } } else if (command === "!incattr") { var token = getObj("graphic", args[0]); var char_id = token.get("represents"); if (char_id != "") { var attr_name = args[1]; var curVal = getAttrByName(char_id, attr_name); //log(char_id); //log(attr_name); //log(curVal); ModUtils.incrementAttribute(char_id, attr_name, curVal); } } else if (command === "!alterattr") { var token = getObj("graphic", args[0]); var char_id = token.get("represents"); if (char_id != "") { var attr_name = args[1]; var modVal = args[2]; modVal = parseInt(modVal); //log(char_id); //og(attr_name); //log(modVal); ModUtils.alterAttribute(char_id, attr_name, modVal); } } else if (command === "!setattr") { var token = getObj("graphic", args[0]); var char_id = token.get("represents"); if (char_id != "") { var attr_name = args[1]; var newVal = args[2]; //log(char_id); //log(attr_name); //log(newVal); ModUtils.setAttribute(char_id, attr_name, newVal); } } else if(command === "!settint") { var token = getObj("graphic", args[0]); var color = args[1]; //log(color); token.set("tint_color", color); } else if (command === "!addtracker") {         var turnorder = JSON.parse(Campaign().get("turnorder"));              var token = getObj("graphic", args[0]);     var char_id = token.get("represents");         var rounds = args[1];         var condition = args[2];         var CUorCD = args[3];                  log(turnorder);         log(char_id);         log(rounds);         log(condition);         log(CUorCD);          if (char_id != "") {     turnorder.push({     id: "-1",     pr: rounds,     custom: token.get("name") + "\'s " + condition + "|" + CUorCD     });             Campaign().set("turnorder", JSON.stringify(turnorder)); }         log(turnorder); } else if (command === "!decattrforselected") { var attr_name = args[0]; _.each(msg.selected, function(selected) { //log(selected) var char_id = getObj("graphic", selected._id).get("represents"); if (char_id != "") { var curVal = getAttrByName(char_id, attr_name); //log(char_id); //log(attr_name); //log(curVal); ModUtils.decrementAttribute(char_id, attr_name, curVal); } }); } else if (command === "!incattrforselected") { var attr_name = args[0]; _.each(msg.selected, function(selected) { //log(selected) var char_id = getObj("graphic", selected._id).get("represents"); if (char_id != "") { var curVal = getAttrByName(char_id, attr_name); //log(char_id); //log(attr_name); //log(curVal); ModUtils.incrementAttribute(char_id, attr_name, curVal); } }); } }); I did not create this script, all credit and thank to our resident Scriptomancer Aaron for this script.