Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Scripting Help] setAttrs() or .set?

Yep, it's me again. I have a question as to which one is more appropriate for what I'm trying to do.  I have 2 arrays of skills that I am combining that came from table rolls by converting them to strings and then splitting them to form a final array. So: ["Insight 4,Perception 4,Technology 4"] and ["Expertise 4,Perception 4,Vehicles 4"] becomes rollArray = [Insight 4,Perception 4,Technology 4,Expertise 4,Perception 4,Vehicles 4] As I'm setting these skills into the character sheet, since Perception appears twice, I want to end up with Perception 8 total.  Here is what I have so far: for (i = 0; i < rollArray.length; i++) { skillEntry = skillArrayEntry.split(" ") skillName = skillEntry[0].toLowerCase() + "_rank" skillRank = skillEntry[1] var existingSkillRank = getAttrByName(character.id, skillName); if (existingSkillRank != 0) {     createAttribute(skillName, skillRank) } else {     skillRank = parseInt(existingSkillRank) + parseInt(skillRank)     skill = findObjs({ type: 'attribute', characterid: character.id, name: skillName })[0];     skill.set('current', skillRank) } }; However, it doesn't seem to be seeing the first skill creation by the time the second one comes up. The API throws an error that says that it cannot .set an undefined property. And I've tried to use setAttrs, but I don't think I'm using it correctly } else {     skillRank = parseInt(existingSkillRank) + parseInt(skillRank)     setAttrs(character.id, { skillName: skillRank }) } Any advice would be appreciated. 
1638077199
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I think your problem is that you've inverted your existing skillRank detection. You create a fresh attribute if the value found for the attribute isn't 0. There's a few issues with this. If getAttrByName doesn't find an attribute of the given name, it returns either the default value specified in the character sheet, or (i believe) undefined. Because of this, your script is going to the else condition for everything except for the perception value most likely and then doesn't have an attribute value to work with for that attribute. Additionally, when working with the values of attributes, it is best practice to assume that they have been returned as strings and force them into numbers. I'd also probably avoid the for loop and do this slightly differently using a reduce. The below will require a change to createAttribute so that it returns the created attribute object. rollArray.reduce((created,string)=>{ let [skillName,skillRank] = string.split(' ');//destructuring assignment to quickly extract things from the split skillName = `${skillName}_rank`; if(created[skillName]){//If we already have an object for the skill, use that let origValue = created[skillName].get('current'); created[skillName].set({current:+origValue + (+skillRank)}); }else{//other wise, create a new attribute object and store it in the created object. created[skillName] = createAttribute(skillName,skillRank); } return created;//return the created object for use in further operations of the reduce. },{});
I'll take a look at this. Thanks, Scott!