Wow. Thanks for all the feedback everyone. First, I agree that async operations should be embraced lovingly, but sometimes they make simple tasks more difficult than they should be. Usually I find myself writing synchronous functions that have an asynchronous wrapper for use as often as plausible. Basically, I'm writing a bunch of scripts to help me DM my DnD5e games. When writing the script below, all I wanted to do was roll initiative for every character in the turn order, and then sort the order. I didn't want to do the work of sorting and setting the turn order until after every character had rolled. I found it inconvenient to deal with the sendChat async to parse a roll, so I just did it manually. The next API I wrote was to roll up random loot. Obviously, there were many more roll definitions in my tables, and instead of keeping a value of "1d6" I had to keep a diceCount: 1, and diceSize: 6 to roll up my own dice. Basically, I wrote my own getDiceRoll() routine...it just doesn't handle all of the fanciness of Roll20's roll parser, so I thought it would be a nice API call to be able to make, but if it can't be done...it can't be done. --- var chatCommands = { dnd5e_autoinitiative: function(args, msg) { if ( ! playerIsGM(msg.playerid) ) return; var npcOnly = (args !== undefined) && (args.length > 0) && (args[0] === 'npconly'); var turnorder = Campaign().get('turnorder'); if (turnorder === undefined) return; turnorder = JSON.parse(turnorder); _.each(turnorder, function(to) { var token = getObj('graphic', to.id); if(token === undefined) return; var represents = token.get('represents'); if(represents === '') return; var isNpc = getAttrByName(represents, 'is_npc'); isNpc = ( (isNpc !== undefined) && (isNpc === '1') ); var dex = 10; var ini = 0; if(isNpc) { dex = parseInt(getAttrByName(represents, 'npc_dexterity')); ini = parseInt(getAttrByName(represents, 'npc_initiative')); } else if(npcOnly) { return; } else { dex = parseInt(getAttrByName(represents, 'dexterity')); ini = parseInt(getAttrByName(represents, 'initiative')); } var mod = Math.floor((dex-10)/2); var rollValue = randomInteger(20) + mod + ini; var tieBreaker = randomInteger(99); to.pr = parseFloat(rollValue + '.' + mod + (tieBreaker < 10 ? '0' : '') + tieBreaker); }); turnorder.sort(compareTurnOrders); Campaign().set('turnorder', JSON.stringify(turnorder)); }
}; Thanks again, Andrew