Hi everyone,
I wrote a quick script this morning to utilize the Roll20AM script's global variable and generate an inline-link chat menu macro for the 5e OGL Character Sheet. I wanted the chat menu to list all of my playlists along with each track I have imported for traps and spells. This handles that and can be customized to build any other type of Roll20AM menu. Additionally, with a bit more customization, you can build any type of chat menu you wanted. I know other API scripts exist out there that can do this, but I needed a bit of customization and it was a nice morning challenge. Hope someone finds it useful!
var roll20AMMenuGenerator = roll20AMMenuGenerator || { menuStr: '/w gm&{template:npcaction} {{rname=Roll20AM Menu}} {{description=', trackDetails: state.Roll20AM.trackDetails, playlistDetails: state.Roll20AM.playLists, r20AMStopCommand: '!roll20AM --audio,stop', makeBold: (str) => { return '**'+str+'**' }, makeChatCommand: (title, command) => { return '['+title+']('+command+')' }, r20AMPlayCommand: (objName) => { return '!roll20AM --audio,play|'+ encodeURIComponent(objName) }, inputHandler: function(msg_original) { if(msg_original.content.indexOf('!r20AMMenuGenerator') !== 0){ return; } else { this.generateMenu(msg_original.playerid); } }, generatePlaylistStr: function(playlistNameArr) { var playListStr = this.makeBold('Playlists')+'\n'; let playListNames = playlistNameArr.filter( name => !name.toLowerCase().match(/tag[0-9]/) ).sort(); _.each(playListNames, (plName) => playListStr += this.makeChatCommand(plName, this.r20AMPlayCommand(plName))+'\n'); return playListStr; }, generateTrapTracks: function(tracksNameArr) { var trapTrackStr = this.makeBold('Trap Sounds')+'\n'; let trapTrackNames = tracksNameArr.filter( name => name.toLowerCase().includes('trap') ).sort(); _.each(trapTrackNames, (ttName) => trapTrackStr += this.makeChatCommand(ttName.split(' by')[0].replace('Trap',''), this.r20AMPlayCommand(ttName))+' | '); return trapTrackStr; }, generateSpellSoundEffects: function(tracksNameArr) { var spellTrackStr = this.makeBold('Spell Sounds')+'\n'; let spellTrackNames = _.filter(tracksNameArr, name => name.toLowerCase().includes('spell') ).sort(); _.each(spellTrackNames, (stName) => spellTrackStr += this.makeChatCommand(stName.split(' by')[0].replace('Spell',''), this.r20AMPlayCommand(stName))+' | '); return spellTrackStr }, generateMenu: function(playerId){ let playListStr = this.generatePlaylistStr(Object.keys(this.playlistDetails)); let trackNames = _.map(this.trackDetails, (track) => track['title']); let trapTrackStr = this.generateTrapTracks(trackNames); let spellTrackStr = this.generateSpellSoundEffects(trackNames); let stopAudioButton = this.makeChatCommand('STOP ALL AUDIO', this.r20AMStopCommand); // Finalize menu string this.menuStr += playListStr + '\n' + trapTrackStr + '\n\n' + spellTrackStr + '\n' + '\n\n' + stopAudioButton + '}}'; // send chat for test // sendChat('yaBoi', this.menuStr); createObj('macro', { name: 'roll20AM-Audio-Menu', action: this.menuStr, playerid: playerId }); } }; on('chat:message', function(msg){ 'use strict'; roll20AMMenuGenerator.inputHandler(msg); });