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

question on returning value from die roll in API function

Below is a sample of the code I am currently building, and I am currently stumped on how to return the dieResult# out of the send chat function so I am not nesting multiple commands together.  I will if I have to, but hope I don't need to.  What I have below is how I would like to use this, if possible. on('ready', function() { on('chat:message', function(msg) { var args = msg.content.split(' ') if('!cncAttack' === args.shift() ) { // Usage: !cncAttack <attacker token id> <BtH> <Damage Roll> <Advantage> <target token id> // BtH - Character Base to Hit bonus # // Damage Roll - Die formula for damage roll // Advantage - S:Standard, A:Advantage, D:Disadvantage // Example: // !cncAttack @{selected|token_id} 3 1d8+3 S @{target|token_id} var attackerTokenID = args[0] var attackerTokenObj = getObj('graphic', attackerTokenID) var attackerBtH = args[1] var attackerDamageRoll = args[2] var attackerAdvantage = args[3] var targetTokenID = args[4] var targetTokenObj = getObj('graphic', targetTokenID) var targetHP = parseInt(targetTokenObj.get('bar1_value')) var toHitRoll = 0 sendChat(msg.who, '/roll 1d20', function(ops1) { var rollResult = JSON.parse(ops[0].content) var dieResult1 = rollResult.total }) sendChat(msg.who, '/roll 1d20', function(ops2) { var rollResult = JSON.parse(ops[0].content) var dieResult2 = rollResult.total }) switch(attackerAdvantage) { case 'S': toHitRoll = dieResult1 break; case 'A': if (dieResult1 >= dieResult2) { toHitRoll = dieResult1 } else { toHitRoll = dieResult2 } break; case 'D': if (dieResult1 <= dieResult2) { toHitRoll = dieResult1 } else { toHitRoll = dieResult2 } break; } if (toHitRoll >= parseInt(targetTokenObj.get('bar2_value'))) { sendChat(msg.who, '/roll ' + attackerDamageRoll, function(ops) { var rollResult = JSON.parse(ops[0].content) var damageResult = rollResult.total targetTokenObj.set('bar1_value', targetHP - damageResult) } } }) })
1597887247
timmaugh
Pro
API Scripter
Doing it this way you are sending the chat asynchronously, so all of your references to the values in your callback don't actually resolve until your synchronous code finishes. You basically have 2 options: put everything that you imagine running *after the sendChat inside the callback function (so your synchronous code ends and this async stuff can take over), or split everything downstream of the async swndChat into its own function and then call it from the callback. Sometimes this second option can help you visualize what is happening better (seeing it as synchronous... Even if it is displaced to be synchronous only to what is running asynchronously)... Plus, it can sometimes let you reuse code (making the downstream stuff able to be called from elsewhere).
1597893973

Edited 1597894114
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
A third option is to use the async/await functionality and Promises of modern javascript to write asynchronous code as if it were synchronous. Here's how I'd adjust your code to do this (I believe this code is doing what you are looking for): on('ready',()=>{ on('chat:message', async function(msg) {//the async keyword denotes this function as an asynchronous function. This is necessary to use the await keyword later var args = msg.content.split(' '); if('!cncAttack' !== args.shift() ) { return; } // Usage: !cncAttack <attacker token id> <BtH> <Damage Roll> <Advantage> <target token id> // BtH - Character Base to Hit bonus # // Damage Roll - Die formula for damage roll // Advantage - S:Standard, A:Advantage, D:Disadvantage // Example: // !cncAttack @{selected|token_id} 3 1d8+3 S @{target|token_id} let attackerTokenID = args[0]; let attackerTokenObj = getObj('graphic', attackerTokenID); let attackerBtH = args[1]; let attackerDamageRoll = args[2]; let attackerAdvantage = args[3]; let targetTokenID = args[4]; let targetTokenObj = getObj('graphic', targetTokenID); let targetHP = parseInt(targetTokenObj.get('bar1_value')); let toHitRoll = 0; let dieResult1 = await new Promise((resolve,reject)=>{//the await keyword tells the system to pause and wait for the asynchronous event. In this case, it's a promise that will be resolved once the sendChat responds with the die result sendChat(msg.who, '/roll 1d20', function(ops) { let rollResult = JSON.parse(ops[0].content); resolve(rollResult.total);//We resolve the promise to the roll result }); }); let dieResult2 = await new Promise((resolve,reject)=>{//same thing as in dieResult1 sendChat(msg.who, '/roll 1d20', function(ops) { let rollResult = JSON.parse(ops[0].content); resolve(rollResult.total); }); }); //At this point, dieResult1 and dieResult2 have both been resolved to their correct results. And now you can write your code as normal. switch(attackerAdvantage) { case 'S': toHitRoll = dieResult1 break; case 'A': if (dieResult1 >= dieResult2) { toHitRoll = dieResult1 } else { toHitRoll = dieResult2 } break; case 'D': if (dieResult1 <= dieResult2) { toHitRoll = dieResult1 } else { toHitRoll = dieResult2 } break; } if (toHitRoll >= parseInt(targetTokenObj.get('bar2_value'))) { sendChat(msg.who, '/roll ' + attackerDamageRoll, function(ops) { var rollResult = JSON.parse(ops[0].content) var damageResult = rollResult.total targetTokenObj.set('bar1_value', targetHP - damageResult) }); } }); });
Thanks everyone, I think I got this.  Being a bit of a hack, ok, not that back, a novice/hobbyist with programming having you guys out here for help is amazing!  I am going to post another thread, seeing a strange issue with a switch command.