My API is quite large now so I hope I can encapsulate all relevant information here. /** * Sets the `current` and `max` values of the sheet's HP as per the configuration, either with averages or randomly. * @param {Character} sheet */ function setHp(sheet) { const hp = getOrCreateAttrObject(sheet.id, "hp"); const form = getAttrByName(sheet.id, "npc_hpformula"); if (AWS_rollHp) { if (form && rollHp()) return; if (setAvgHp()) return toChat( `Could not roll for HP! Did the beast have a valid entry in the npc_hpformula attribute?<br>**Average beast HP has been used instead.**`, { code: 60 } ); } else { if (setAvgHp()) return; if (form && calcAvgHp()) return; } setHpToOne(); return toChat( `Could not find any HP attributes! **HP is set to 1 instead.**<br>To fix this, set max hp or npc_hpformula on the beast sheet.`, { code: 61 } ); function setAvgHp() { const hpMax = hp.get("max") || ""; if (!hpMax) return false; hp.setWithWorker("current", hp.get("max")); return true; } function calcAvgHp() { const count = /[0-9]+(?=d)/.exec(form)[0]; const die = /(?<=d)[0-9]+/.exec(form)[0]; const avg = +die / 2 + 0.5; const tot = Math.ceil(+count * avg); const resolve = form.replace(`${count}d${die}`, tot); return setHpToResolve(resolve); } function rollHp() { return setHpToResolve(form); } function setHpToOne() { hp.setWithWorker({ current: "1", max: "1" }); return true; } function setHpToResolve(formula) { sendChat(AWS_name, `/r ${formula}`, (r) => { const resolved = r[0] && r[0].content && JSON.parse(r[0].content).total; hp.setWithWorker({ current: resolved, max: resolved }); }); return true; } } In the above code, when a creature has an empty hp.get("max") value and the user has set AWS_rollHp to false , the setHpToOne() function is called. I am sure it is running and that the hp attribute is correct. The issue is that after the first time setHpToOne() is called, the .setWithWorker function calls are doing nothing. I am sure they are being called. Is there a solution to this? It seems ridiculous. I'll be editing this post with more information if it is requested. Referenced functions are here, but I'm almost certain they're not relevant: /** * Attempts to find the attribute by name, else returns a new attribute. * @param {string} _characterid * @param {string} name Name of the attribute. * @returns {Attribute} */ function getOrCreateAttrObject(_characterid, name) { try { return getAttrObject(_characterid, name); } catch (err1) { if (err1.name === "RangeError") throw err1; try { return createObj("attribute", { _characterid, name, }); } catch (err2) { throw new Error( `Failed to create Attribute Object with errors "${err2.message}" and "${err1.message}".` ); } } } /** * Returns an attribute object found by character id and attribute name. * @param {string} _characterid * @param {string} name * @returns {Attribute} */ function getAttrObject(_characterid, name) { const attrs = findObjs({ _type: "attribute", _characterid, name, }); if (attrs.length < 1) throw new Error(`Attribute by name "${name}" could not be found.`); if (attrs.length > 1) throw new RangeError(`Multiple attributes found with name "${name}".`); return attrs[0]; }
/** * Output the supplied message to chat, optionally as a whisper and/or as an error which will also log to the console. * @param {string} message * @param {{code:number, player:string, logMsg:string}} options */ function toChat( message, { code = undefined, player = undefined, logMsg = undefined } = {} ) { const isError = code !== undefined; const playerName = player && player.concat(" ").split(" ", 1)[0]; if (message) sendChat( isError ? AWS_error : AWS_name, `${playerName ? "/w " + playerName + " " : ""}${"<br>" + message}` ); if (isError) log(AWS_log + (logMsg || message) + " Error code " + code + "."); }