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

[Attribute 3.5] can't modify the spell used without somme random error

Hello, I'm trying to increment the spell used for all spell level (for my sorcerer). For reading the caract no problem I can used getAttrByName function and works like a charm. But to editing I first thought of getting the attribute with findObj and the attribute name repeating_spells02_$0_spellused02 but return no result. After some digging I extract all attribute and see the $0 are in fact the ID attribute. So I modify my script so first get the ID of the attribute and after that search it. It works... partially. Meaning sometimes I'm able to read 5 spells, sometimes just 2 before getting the error   TypeError: Cannot read property 'get' of undefined Anyone know why it succed sometimes and failed other ? and how I can fix it ? Code :  function getUsedSpell(character, spellName){     debug("getting usedspell for : " + spellName + "...");          // get the name attribute first, need to do it cause of the id     var attributeName = findObjs({         type: 'attribute',         characterid: character.get("id"),         current: spellName     });          if (attributeName === undefined){         debug("No attribute name for : " + spellName);         return undefined;     }     attributeName = attributeName[0].get("name");          /* we want the spellused */     attributeName = attributeName.replace("_spellname","_spellused");          var attribute = findObjs({         type: 'attribute',         characterid: character.get("id"),         name : attributeName     });     if (attribute === undefined){         debug("No attribute for : " + attributeName);         return undefined;     }     debug("successfully get usedspell !");     return attribute[0]; } for (var spellNum = 0; spellNum < 50; spellNum++) {   var spellName = getAttrByName(character.get("id"), "repeating_spells" + spellLevel + spellClass +"_$" + spellNum + "_spellname" + spellLevel + spellClass); var attribute = getUsedSpell(character, spellName); log(attribute); if (attribute === undefined){ break; } log(spellName + " : " + attribute.get("current")); } Log (run1): "API SD ##########################################" "API SD    command received : !spellbook -decrementLevel 2 -METd8D9XpHC1o4S4q0E 0" "API SD ==> decrementing all spell level 0..." "API SD ==> getting usedspell for : Message..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyE7Rr40fr0tKRkJP_spellused02","current":"0","max":"","_id":"-M3b7cjqkw_-BQIIv2X3","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "Message : 0" "API SD ==> getting usedspell for : detection du poison..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyGE2I5srAFB9Tjxz_spellused02","current":"0","max":"","_id":"-M3b7dIp3t8Icwab2EdK","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "detection du poison : 0" "API SD ==> getting usedspell for : lumiere..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyI8fZ7ycxJCBMmUl_spellused02","current":"0","max":"","_id":"-M3b7do3EyWQ22NKBhLp","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "lumiere : 0" "API SD ==> getting usedspell for : destruction des morts vivants..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3Nyx9LTkk5MgMB8dAL_spellused02","current":"0","max":"","_id":"-M3b7eI4EPM_JYiF0kE3","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "destruction des morts vivants : 0" TypeError: Cannot read property 'get' of undefined     at getUsedSpell (apiscript.js:7962:38)     at decrementAll (apiscript.js:7788:25)     at apiscript.js:8070:17     at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:65:16)     at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:70:8)     at /home/node/d20-api-server/api.js:1661:12     at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560     at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147)     at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546)     at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) Log (run2)  "API SD ##########################################" "API SD    command received : !spellbook -decrementLevel 2 -METd8D9XpHC1o4S4q0E 0" "API SD ==> decrementing all spell level 0..." "API SD ==> getting usedspell for : Message..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyE7Rr40fr0tKRkJP_spellused02","current":"0","max":"","_id":"-M3b7cjqkw_-BQIIv2X3","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "Message : 0" "API SD ==> getting usedspell for : detection du poison..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyGE2I5srAFB9Tjxz_spellused02","current":"0","max":"","_id":"-M3b7dIp3t8Icwab2EdK","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "detection du poison : 0" "API SD ==> getting usedspell for : lumiere..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3MyI8fZ7ycxJCBMmUl_spellused02","current":"0","max":"","_id":"-M3b7do3EyWQ22NKBhLp","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "lumiere : 0" "API SD ==> getting usedspell for : destruction des morts vivants..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M3Nyx9LTkk5MgMB8dAL_spellused02","current":"0","max":"","_id":"-M3b7eI4EPM_JYiF0kE3","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "destruction des morts vivants : 0" "API SD ==> getting usedspell for : lecture de la magie..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-M4ABNuxBSh9Y-ogJvoL_spellused02","current":"0","max":"","_id":"-M4ABSXy4bHJTTOMkgnL","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "lecture de la magie : 0" "API SD ==> getting usedspell for : aspersion d'acide..." "API SD *** successfully get usedspell !" {"name":"repeating_spells02_-MFzCsPrxQpW335fb8lJ_spellused02","current":"0","max":"","_id":"-MFzCxJ4tzBE59b2RESM","_type":"attribute","_characterid":"-M36h3LmD8XmgUrwqHj3"} "aspersion d'acide : 0" "API SD ==> getting usedspell for : rayon de givre..." TypeError: Cannot read property 'get' of undefined TypeError: Cannot read property 'get' of undefined     at getUsedSpell (apiscript.js:7962:38)     at decrementAll (apiscript.js:7788:25)     at apiscript.js:8070:17     at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:65:16)     at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:70:8)     at /home/node/d20-api-server/api.js:1661:12     at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560     at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147)     at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546)     at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489)
1598902974
timmaugh
Forum Champion
API Scripter
Part of the issue is that findObjs will always return an array, even if it is an empty array... meaning this test will never come back positive:     if (attributeName === undefined){         debug("No attribute name for : " + spellName);         return undefined;     } If you want to test if the array is empty, you'll have to test the length property...     if (!attributeName.length){         debug("No attribute name for : " + spellName);         return undefined;     } Another thing to think about is that not every entry in a repeating section has every sub-attribute. I would suggest my XRay script to walk the character sheet and inspect the repeating section in chat. Maybe you will see a difference between one spell to the next. Also... one last thing to think about is that I sometimes see this sort of strange behavior if I am using a regular expression and not resetting its lastIndex property between uses... eventually it just walks itself to the end of whatever string it is looking at and it returns no match even though it should. I don't see one in your code, but I would log the spellName argument you are getting at the start of the function and see if it is what you would expect it to be.
Thanks timmaugh ! With your correction about the testing it's ok. I forgot findobjs return an array (can be empty but still an array). I still don't understand why the log were different but it's working so it can wait some knowledge improvement ;) I keep in mind your XRay script for which I would have kill to have it someday ago ^^
1598923072
GiGs
Pro
Sheet Author
API Scripter
Another thing - when working in the API (or sheet workers) it's better to work with the real row ids, not the $0, $1 form of the id. You can use findObs to get all the attributes in a repeating section on a character, and then extract the unique row ids from that. Then you can use them to eitehr cycle through the section, or access specific attributes.
Hi Gigs i'm using the id in the name like  repeating_spells02_-M3MyGE2I5srAFB9Tjxz_spellused02  because I don't know how I can get all the line through findObjs. Are you telling me it's possible to filter on a partial name like  repeating_spells02%spellused02  ?
1598969065
GiGs
Pro
Sheet Author
API Scripter
Yes, you can filter on partial attribute names. You can do a filterObjs to get the filtered list directly (though the wiki discourages this due to performance), or findObjs to get all attributes in the repeating section, then filter that to the subset you actually want using the partial names. I hadnt looked closely at your code-  now I see what it's doing, and yes, you can replace that for loop and get the attributes more efficiently. There's more than one way to do it, but here's one example: function getSpellAttributes(character, spellLevel, spellClass, whichStat) { // assuming whichStat = 'spellused'     const section = findObjs({         type: 'attribute',         characterid: character.get("id")     }) // this returns an array of ALL attributes from this character. Then we filter to the ones we want.     .filter(att => att.name.startsWith(`repeating_spells${spellLevel}${spellClass}_`) && att.name.endsWith(`_${whichStat}${spellLevel}${spellClass}`));     return section; } Assuming you call this function with whichStat = 'spellused', it will return an array of all 'spellused' attributes from the desired section. (Assuming I'm not messing up the code due to being half asleep, haha.)
1598969684

Edited 1598969832
GiGs
Pro
Sheet Author
API Scripter
Also, Jakob posted a function a couple of years ago you can use to get all the IDs of a repeating section, in the order the rows are listed on the sheet, here: <a href="https://app.roll20.net/forum/permalink/5782857/" rel="nofollow">https://app.roll20.net/forum/permalink/5782857/</a> You could then loop through the ids and build any attribute name you wanted for the section.
Thanks ! Yes I avoided the filter function due to the warning on the API page. This way will solve the warning message&nbsp;"ERROR: You tried to use the repeating section row at index 5 for repeating_spells22, but there doesn't seem to be a row at that index." in the log. I will rework this functionnality of my scripts with your code.
Thanks again your code is exactly what I need (just a little error to getting the name) ! In case of anyone reading this post in the future : function getSpellAttributes(character, spellLevel, spellClass, whichStat) { // assuming whichStat = 'spellused' &nbsp; &nbsp; const section = findObjs({ &nbsp; &nbsp; &nbsp; &nbsp; type: 'attribute', &nbsp; &nbsp; &nbsp; &nbsp; characterid: character.get("id") &nbsp; &nbsp; }) // this returns an array of ALL attributes from this character. Then we filter to the ones we want. &nbsp; &nbsp; .filter(att =&gt; att.get("name").startsWith(`repeating_spells${spellLevel}${spellClass}_`) &amp;&amp; att.get("name").endsWith(`_${whichStat}${spellLevel}${spellClass}`)); &nbsp; &nbsp; return section; } Hope you will have a restful night
1599004704
GiGs
Pro
Sheet Author
API Scripter
regarding the error: ah yes of course. This always happens when I post code just before going to bed, lol. I'm glad you got it sorted :)