Thank you so much for the tip that it was asynchronous, that was my biggest problem. I now have it working. The intention is to create and/or update treasure handouts. What I have so far: // THandout ////////////////////// // // !THandout --HandoutName --rTableName --comment // // initial offering by John Edsall 01 Jan 2022 // ////////////////////// // get the rTableItem // get the handout // update handout with rTableItem // ////////////////////// on('ready',function(){ "use strict"; on('chat:message',function(msg){ var player,handout, tableItemText, noteText; var version = "1.0"; if('api' === msg.type && msg.content.match(/^!THandout/) ){ if(msg.type == "api" && ((msg.content.indexOf('!THandout') == 0) )) { let args = msg.content.split(/\s+--/); log( args[0] + ' ver. ' + version); player=getObj('player',msg.playerid); if(player){ log("handout: " + args[1] + " table: " + args[2] + " gm comment: " + args[3]); handout=getHandout(args[1]); if(!handout) { return;} if(args[3] !== undefined) { handout.get('gmnotes', function(gmText) { if(!_.isNull(gmText)){ setTimeout(function(){ var newtext; // log('args[3]: ' + args[3]); if(gmText !== undefined && gmText !== 'null') { newtext = gmText + "<br>" + args[3]; } else { newtext = args[3]; } handout.set('gmnotes', newtext); // update the handout gmnotes },0); } setTimeout(function(){},0); }); } tableItemText=getTableItem(args[2]); if(!tableItemText) { return;} handout.get('notes', function(noteText) { if(!_.isNull(noteText)){ setTimeout(function(){ var newtext; if(tableItemText !== undefined) { // log('handout.get table Item: ' + tableItemText); if(noteText !== undefined && noteText !== 'null') { newtext = noteText + "<br>" + tableItemText; } else { newtext = tableItemText; } }; handout.set('notes', newtext); // update the handout notes },0); } setTimeout(function(){},0); }); }; sendChat('','/w "'+player.get('displayname')+'" Created a handout for you: <a href="<a href="http://journal.roll20.net/handout/'+handout.id+" rel="nofollow">http://journal.roll20.net/handout/'+handout.id+</a>'" style="color:blue;text-decoration:underline;">Handout for '+player.get('displayname')+'</a>'); } } }); }); //////////////// returns a new handout function createHandout(handoutName) { var handout = createObj('handout',{ name: handoutName }); log("Create " + handoutName); return handout; } //////////////// returns a handout obj function getHandout(handoutName) { var handout = filterObjs(function(o){ return ( 'handout' === o.get('type') && handoutName === o.get('name') && false === o.get('archived')); })[0]; if(handout) { log("Found " + handoutName); return handout; } return createHandout(handoutName); } //////////////// returns an item from a rollabletable function getTableItem(tableName) { var rTableItem, rTable; var table = findTable( tableName ); if( table.length < 1 ) { log('No such table exists. '); } else { return rollTableItem( table[0].id ); } } //////////////// returns a rollabletable obj function findTable( tableName ) { var rollTable = findObjs({ type: 'rollabletable', name: tableName }, { caseInsensitive: true }); return rollTable; } //////////////// returns a rollTableItem function rollTableItem( tableId ) { // Picks an item from the table var items = findObjs({ type: 'tableitem', rollabletableid: tableId }), weightedList = []; if( items.length > 0 ) { _.each( items, function( item ){ // Build a weighted list to draw from let weight = item.get( 'weight' ); _( weight ).times(function( x ){ weightedList.push( item.id ); }); }); var chosenItem = getObj( 'tableitem', weightedList[ randomInteger( weightedList.length ) - 1 ] ); return chosenItem.get( 'name' ) ; } else { log( 'No items on this table.' ); } } ///////////////