I'm trying to figure out why this script keeps failing but the error messages are soooo fucking unhelpful and obtuse. It's god damned frustrating. TypeError: Cannot call method 'set' of undefined at Sandbox.<anonymous> (evalmachine.<anonymous>:76:29) at eval ( What the fuck does this even mean and why do the line numbers 76:29 not point to anything at all related to set? // The D&D Next Health Monitor script prevents tokens from having more // hit points points than their maximum hp. It also prevents tokens from // being in negative hit points since D&D Next does not track negative hp. // -- SETTINGS -- // HealthBarID - Sets which bar you use for hit points or health (1, 2, or 3) var HealthBarID = 3; on("change:token", function(obj, prev) { // Exit the script if the token is flagged as a drawing if(obj.get("subtype") != "token") return; // Get the tokens previous, current, and max hit points var iPreviousHP = parseInt(prev["bar" + HealthBarID + "_value"]); var iCurrentHP = parseInt(obj.get("bar" + HealthBarID + "_value")); var iMaxHP = parseInt(obj.get("bar" + HealthBarID + "_max")); log(obj.get("represents")); log(obj.get("controlledby")); if (obj.get("represents") == "" || obj.get ("controlledby") == "") { // Token is not linked to a journal entry if(obj.id in state) { var iTempHP = parseInt(state[obj.id]["TempHP"]); } else { var iTempHP = 0; } } else { // Token is linked to a journal entry var oCharacter = getObj("character", obj.get("represents")); var oTempHP = findObjs({_type: "attribute", name: "TempHP", _characterid: oCharacter.id})[0]; if (oTempHP == undefined ) { createObj("attribute", { name: "TempHP", current: 0, characterid: oCharacter.id }) var iTempHP = 0; } else { var iTempHP = parseInt(oTempHP.get("current")); } } // Set iTempHP to 0 if NaN if(iTempHP == NaN) { iTempHP = 0; } // Adjust current hit points if the token has temporary hit points and its // previous hit points are greater than its current hit points. if (iTempHP > 0) { if (iPreviousHP > iCurrentHP) { var iHPChange = iPreviousHP - iCurrentHP; if (iHPChange >= iTempHP) { // Add temphp to currenthp, remove all temp hp. obj.set("bar" + HealthBarID + "_value", iCurrentHP + iTempHP); iCurrentHP += iTempHP; if (obj.get("represents") == "" || obj.get("controlledby")) { if(obj.get("id") in state) { state[obj.id] = {"TempHP": 0}; } } else { oTempHP.set("current", 0); } } else { // Damage is less than current TempHP, so remove hpchange from // temphp, add hpchange to currenthp, and set new temphp value obj.set("bar" + HealthBarID + "_value", iCurrentHP + iHPChange); iCurrentHP += iHPChange; if (obj.get("represents") == "" || obj.get("controlledby")) { if(obj.it in state) { state[obj.id] = {"TempHP": iTempHP - iHPChange}; } } else { oTempHP.set("current", iTempHP - iHPChange); } } } } // Determine how much damage the token took. This will be used to // figure out if the target will die instantly from Massive Damage. if (iCurrentHP < iPreviousHP) { var iDamage = iPreviousHP - iCurrentHP; } else { var iDamage = 0; } // If the tokens current hit points are less than zero, apply the red // X to the token to signifiy that it is dead or dying and set hit points // to zero. D&D Next does not track negative hit points. if (iCurrentHP <= 0) { obj.set("status_dead", true); obj.set("bar" + HealthBarID + "_value", 0); } else { obj.set("status_dead", false); } // Set current hp to maximum hp if current is greater than maximum hp if (iCurrentHP > iMaxHP) { obj.set("bar" + HealthBarID + "_value", iMaxHP); } });