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

API Scripting Help

I am having an issue with how the weaponName is being passed and interpreted by my javascript command when there is a space in the name. Specifically, when weaponName contains a space, it’s being split into multiple arguments, which causes unexpected behavior. I can not wrap weaponName in double quotes in my button, because for some reason that doesn't work. Any suggestions?
You'll need to post the code you are using to get any help. :) 
1731773953

Edited 1731868722
The Aaron
Roll20 Production Team
API Scripter
Agree with Jarren, you need to post your code so we can give specific guidance. Some possible suggestions: If you control the creation of the button you can use encodeURIComponent() to generate a version you can pass, and use decodeURIComponent() on it to get it back. sendChat('',`<a href="!myCommand $(encodeURIComponent(weaponName))">Click Me</a>`); let args = msg.content.split(/\s+/); let weaponName = decodeURIComponent(args[1]); If you only control the parsing (say, the weapon name is coming from an @{...} reference), you could use some sort of marker in the command syntax like -- and then split into arguments using that with .split(/\s+--/); sendChat('',`<a href="!myCommand --@{selected|weaponName}">Click Me</a>`); let args = msg.content.split(/\s+--/); let weaponName = args[1];
html: <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_hitattack" value="!hitattack @{character_name} @{weaponname} @{Weaptype} @{ThAC0} @{strengthhit} @{attackadj} @{skilladj} @{meleePenalty}"></button></td> Javascript that matters (rest of code is really long and is just if statements for fumble and critcals.): on('chat:message', function(msg) {     if (msg.type === 'api' && msg.content.startsWith('!hitattack')) {         let args = msg.content.match(/!hitattack\s+([^|]+)\s+([^|]+)\s+([^|]+)\s+([^|]+)\s+([^|]+)\s+([^|]+)\s+([^|]+)\s+([^|]+)/);         if (!args || args.length < 8) {             sendChat('System', '/w gm Incorrect number of arguments provided for !hitattack command.');             return;         }         let characterName = args[1].trim();         let weaponName = args[2].trim();          let weaponType = args[3].trim();         let thac0Value = parseInt(args[4].trim());         let strBonus = parseInt(args[5].trim());         let attackAdj = parseInt(args[6].trim());         let skillAdj = parseInt(args[7].trim());         let encumPen = parseInt(args[8].trim());                  if (isNaN(thac0Value) || isNaN(strBonus) || isNaN(attackAdj) || isNaN(skillAdj) || isNaN(encumPen)) {             sendChat('System', '/w gm Invalid numeric value provided. Ensure all numbers are valid.');             return;         }         let attackRoll = randomInteger(20);         let acHit = thac0Value - (attackRoll + strBonus + attackAdj + skillAdj - encumPen);         // Combat Math Debugging Output         sendChat(`${characterName} Attacking`, `<br /><div style="color: white; background-color: #2a0000; padding: 5px;"><span style="color: gray; font-style: italic;">THAC0: ${thac0Value} - (Atk Roll: ${attackRoll} + Str. Bonus: ${strBonus} + Atk Adj: ${attackAdj} + Skill Adj: ${skillAdj} - Encum. Pen.: ${encumPen})</span><br />${characterName} hits an AC of [[${acHit}]] or worse with ${weaponName}!</div>`);
1731776955

Edited 1731778026
As you can see in the results screen shot it is splitting up the argument or something weird if there is a space. Also I have tried using  encodeURIComponent but it doesn't like it in the button.
1731804643
The Aaron
Roll20 Production Team
API Scripter
What is generating that HTML? Can you change it to have each argument prefaced with --? <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_hitattack" value="!hitattack --@{character_name} --@{weaponname} --@{Weaptype} --@{ThAC0} --@{strengthhit} --@{attackadj} --@{skilladj} --@{meleePenalty}"></button></td>
The html is from the character sheet. This is a button that calls the script !hitattack which I shared in my last post. If I do what you suggest, then this is triggered:                  if (isNaN(thac0Value) || isNaN(strBonus) || isNaN(attackAdj) || isNaN(skillAdj) || isNaN(encumPen)) {             sendChat('System', '/w gm Invalid numeric value provided. Ensure all numbers are valid.');             return;         }
1731864296

Edited 1731869115
The Aaron
Roll20 Production Team
API Scripter
Did you also switch your split to .split(/\s+--/) ? Like this: let args = msg.content.split(/\s+--/); Side note, this should be <9 since arrays in JavaScript are zero-biased:         if (!args || args.length < 9) {             sendChat('System', '/w gm Incorrect number of arguments provided for !hitattack command.');             return;         } With String.match(), the 0th index will hold the full matched string, so there are 9 values in the array.  Using split above to just break at each of the "whitespace followed by --" points will still yield an array of 9, with the 0th element being "!hitattack".
No i did not. I am an amateur at this. I've only been at it for about a month. I used to do MUDs back in the 90s and that was in C/C++ and I haven't written any code until now and I am learning. Thanks for the help this worked!
While I have you here. Is it possible to index my list of ammo and give each row a sequential numeric order so that I can tap that with the my ranged weapons using a drop down menu? I want my ranged weapons to show what ammo they have loaded so when they attack it will automatically remove the appropriate ammo from the ammo list?         <b>Ammunition</b><br />         <table style='border-collapse: collapse; border-spacing: 0; width: 765px;'>         <tr>             <td style='border: 1px solid black; width: 220px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Ammo Name</td>             <td style='border: 1px solid black; width: 100px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Location</td>             <td style='border: 1px solid black; width: 55px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Wt.<br />Each</td>             <td style='border: 1px solid black; width: 55px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Amount</td>             <td style='border: 1px solid black; width: 45px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Weap<br />Adj.</td>             <td style='border: 1px solid black; width: 45px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Skill<br />Adj.</td>             <td style='border: 1px solid black; width: 45px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Dam<br />Adj.</td>             <td style='border: 1px solid black; width: 65px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Dam<br />Sml</td>             <td style='border: 1px solid black; width: 25px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Roll</td>             <td style='border: 1px solid black; width: 65px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Dam<br />Lrg</td>             <td style='border: 1px solid black; width: 25px; background-color: #000000; color: #bba53d; text-align: center; font-weight: bold;'>Roll</td>         </tr>         </table>         <table style='border-collapse: collapse; border-spacing: 0; width: 765px;'>         <tr>             <td style='width: 220px;'><input type="text" style="width: 100%;" name="attr_ammoname" class="medium"></td>             <td style='width: 100px;'><input type="text" style="width: 100%;" name="attr_ammoloc" class="medium"></td>             <td style='width: 55px;'><input type="number" style="width: 100%;" name="attr_static_rweapweight" class="sheet-short" value="0"></td>             <td style='width: 55px;'><input type="number" style="width: 100%;" name="attr_ammo" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_attackadj" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_skilladj" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_damadj" class="sheet-short" value="+0"></td>             <td style='width: 65px;'><input type="text" style="width: 100%;" name="attr_damsm" class="sheet-short"></td>             <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_test1" value="/em rolls [[@{damsm}+(@{attackadj})+(@{skilladj})+(@{damadj})+(?{Misc. bonus (please include + or -)|+0})]] damage using his/her @{ammoname}!"></button></td>             <td style='width: 65px;'><input type="text" style="width: 100%;" name="attr_daml" class="sheet-short"></td>             <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_test2" value="/em rolls [[@{daml}+(@{attackadj})+(@{skilladj})+(@{damadj})+(?{Misc. bonus (please include + or -)|+0})]] damage using his/her @{ammoname}!"></button></td>         </tr>         </table>         <fieldset name="repeating_ammo" class="repeating_ammo" style="width: 765px;">         <table style='border-collapse: collapse; border-spacing: 0; width: 765px;'>         <tr>             <td style='width: 220px;'><input type="text" style="width: 100%;" name="attr_ammoname" class="medium"></td>             <td style='width: 100px;'><input type="text" style="width: 100%;" name="attr_ammoloc" class="medium"></td>             <td style='width: 55px;'><input type="number" style="width: 100%;" name="attr_static_rweapweight" class="sheet-short" value="0"></td>             <td style='width: 55px;'><input type="number" style="width: 100%;" name="attr_ammo" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_attackadj" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_skilladj" class="sheet-short" value="0"></td>             <td style='width: 45px;'><input type="text" style="width: 100%;" name="attr_damadj" class="sheet-short" value="+0"></td>             <td style='width: 65px;'><input type="text" style="width: 100%;" name="attr_damsm" class="sheet-short"></td>             <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_test1" value="/em rolls [[@{damsm}+(@{attackadj})+(@{skilladj})+(@{damadj})+(?{Misc. bonus (please include + or -)|+0})]] damage using his/her @{ammoname}!"></button></td>             <td style='width: 65px;'><input type="text" style="width: 100%;" name="attr_daml" class="sheet-short"></td>             <td style='width: 25px;'><button type="roll" style="width: 20px; height: 20px; padding: 0; margin: 0;" name="roll_test2" value="/em rolls [[@{daml}+(@{attackadj})+(@{skilladj})+(@{damadj})+(?{Misc. bonus (please include + or -)|+0})]] damage using his/her @{ammoname}!"></button></td>         </tr>         </table>         </fieldset>
1731892989

Edited 1731893600
The Aaron
Roll20 Production Team
API Scripter
Yes, but it's complicated. If you look at the Ammo script, there is a function in there for resolving the order of repeating attrs. If you don't care if they are in the same order as the sheet (or you want them in alphabetical order) it's much easier.  const attrLookup = (character,name,caseSensitive) => { let match=name.match(/^(repeating_.*)_\$(\d+)_.*$/); if(match){ let index=match[2]; let attrMatcher=new RegExp(`^${name.replace(/_\$\d+_/,'_([-\\da-zA-Z]+)_')}$`,(caseSensitive?'i':'')); let createOrderKeys=[]; let attrs=_.chain(findObjs({type:'attribute', characterid:character.id})) .map((a)=>{ return {attr:a,match:a.get('name').match(attrMatcher)}; }) .filter((o)=>o.match) .each((o)=>createOrderKeys.push(o.match[1])) .reduce((m,o)=>{ m[o.match[1]]=o.attr; return m;},{}) .value() ; let sortOrderKeys = _.chain( ((findObjs({ type:'attribute', characterid:character.id, name: `_reporder_${match[1]}` })[0]||{get:_.noop}).get('current') || '' ).split(/\s*,\s*/)) .intersection(createOrderKeys) .union(createOrderKeys) .value() ; if(index<sortOrderKeys.length && _.has(attrs,sortOrderKeys[index])){ return attrs[sortOrderKeys[index]]; } return; } return findObjs({ type:'attribute', characterid:character.id, name: name}, {caseInsensitive: !caseSensitive})[0]; }; You can use that with something like: let character = getObj('character',someCharID); let name1 = attrLookup(character,'repeating_ammo_$1_ammoname');