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

[Script] Triggered SFX -- In Progress

1443254112

Edited 1476729703
Lithl
Pro
Sheet Author
API Scripter
This script was spurred by the comments around the forum desiring a means to automatically trigger sound effects, but the direction I've taken it kind of results in being able to create small API scripts on-the-fly. <a href="https://github.com/Lithl/roll20-api-scripts/tree/t" rel="nofollow">https://github.com/Lithl/roll20-api-scripts/tree/t</a>... Depends on: &nbsp; splitArgs This is only version 0.2 right now, and it is still very much a work in progress. The primary features are: Create alias names for tracks or playlists in your jukebox. Aliases not only map a single word to a track or playlist, but also store a play duration and play mode (inorder/random/all-at-once) for playlists. The play mode of the alias does not need to match the one on the actual playlist. Dynamically bind expressions to Roll20 events (ready, chat:message, add:object, change:object[:property], and destroy:object) Use !play &nbsp;to play an alias directly Expressions also have access to a play(alias) function, which will play the named alias sound(s) So, here's an example of the script in use. First, we get a sound: Then, we create an alias for it: And bind an expression to an event: !triggersfx change:graphic play('crit') Moving a token will now play the first 2 seconds of the "Crit 2 by neijer" track. This example is very simple, of course, but most code you could put into an API script could be used in your expression. You also have access to "msg" (for chat:message events), and both "obj" and "prev" (for add/change/destroy events): !triggersfx change:graphic (obj.get('top') === prev.top && Math.abs(obj.get('left') - prev.left) &gt; 225) ? play('crit') : 0 You can always view your existing aliases and triggers: The API buttons let you view the alias/trigger in full detail, or delete them: I'll admit that in its current state, the script isn't the most user-friendly, as it not only requires you to write JavaScript for your triggers, it requires you to write "functional" code, the paradigm of lambda calculus, which is not the standard for JavaScript. (You'll notice my example above uses a ternary operator rather than an if condition -- this is because the ternary operator is functional programming and if is not.) I still have more work to do, but I figure I would share, since it works as-is if you understand what you're doing. If nothing else, it showcases dynamic event binding in Roll20. (Speaking of which, because we have no means to un bind events in the API, if you delete a trigger you'll have to restart the sandbox before it actually stops applying.)
Its a start, and I love the idea. I wouldn't know what else to have triggers for tbh. Fireballs or something maybe?&nbsp;
This sounds awesome and exactly what I need to enhance an upcoming game I'm putting together! I do have a small, totally novice inquiry -&nbsp; Okay, I've played around with the script and managed to link a track to an alias. However, I am having trouble linking the alias to a trigger event. I'd like to link to a chat:message event, but as I said before, I'm unsure how API syntax is organized (I am further confused by the mention of lambda expressions being necessary). Is there any way to provide me a small example of how to properly write the code to bind an alias to a chat:message event? I understand you're all busy, and I appreciate the hard work that goes into maintain and enhancing this awesome system, but any help or advice would be welcomed and revered.
1443747892
Lithl
Pro
Sheet Author
API Scripter
Joshua R. said: Is there any way to provide me a small example of how to properly write the code to bind an alias to a chat:message event?&nbsp; This will create a trigger that fires the alias when you type the API command "!example" in the chat: !triggersfx chat:message (msg.content === '!example' ? play('crit') : 0) Joshua R. said: I am further confused by the mention of lambda expressions being necessary It basically means that the trigger can only be a single "expression" as opposed to several. "if (msg.content === '!example') play('crit')" would be an example of something that doesn't &nbsp;work with this script. However, "(msg.content === '!example' ? play('crit') : 0)" (which is the same logic as the "if" line above) does work. This is the programming equivalent to&nbsp; lambda calculus At the moment, attempting to create a trigger binding with bad syntax will crash the script, but attempting to execute &nbsp;a trigger binding that has bad logic will send the GM an error message.
Oh my god, thank you! You just enhanced my game to the nth degree!&nbsp; I am in your debt, sir. Well done!&nbsp;
1443798832

Edited 1443798946
Scaby79
Sheet Author
API Scripter
There is something I'm missing here. I did as described by Brian in the first post:&nbsp; 1. Crit 2 by neijer is in my Jukebox 2. wrote the identical line in the chat !aliassfx crit -track crit -time 2 Then I get the following error message in the API Output Console: /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Object !aliassfx crit -track crit -time 2 has no method 'splitArgs' at handleInput (evalmachine.:4364:39) at eval ( I figured that I need the splitArgs script, but when I install the splitArgsSpec.js and the splitargs.js I just get another error: require is not defined If I just install the splitargs.js without the splitArgsSpec.js I get module is not defined If I just install the&nbsp;splitArgsSpec.js&nbsp;I get require is not defined again. Does anyone has an idea what I'm doing wrong here?
1443800731
The Aaron
Roll20 Production Team
API Scripter
It sounds like you're trying to use a node.js module. &nbsp;You probably need to grab Brian's splitArgs out of the Roll20 repo:&nbsp; <a href="https://github.com/Roll20/roll20-api-scripts/blob/" rel="nofollow">https://github.com/Roll20/roll20-api-scripts/blob/</a>...
1443800922

Edited 1443800965
Lithl
Pro
Sheet Author
API Scripter
I forgot to mention it in my opening post, but this script does rely on splitArgs, a function I appropriated from another GitHub project and created a Roll20 API script for, which is in the API repo:&nbsp; <a href="https://github.com/Roll20/roll20-api-scripts/tree/" rel="nofollow">https://github.com/Roll20/roll20-api-scripts/tree/</a>... splitArgsSpec.js is the filename from the original project which the function comes from which contains unit tests for the splitArgs function. It is not intended for production, it is intended for development. It also makes use of a number of functions which are defined in a JavaScript unit testing library, such as require, which shows up as an error when you install it as an API script, because the requisite library is not available. Similarly, module throws up an error when you try to use the original version of splitArgs, because it is an object from the original codebase which is not defined in the splitArgs.js file. Finally, even if you removed the unit testing and defined a module object to get rid of the errors, the original splitArgs wouldn't work, because my code depends on splitArgs being added as a prototype to the String object, which the original code does not do. You'll need to use my version of splitArgs (linked above, I'll add it to the original post shortly).
Wow. &nbsp;I'm following this topic, but I don't think I'm quite smart enough to use this script yet.
1443811134
Scaby79
Sheet Author
API Scripter
Nevermind!&nbsp; Apparently I was had some other splitArgs script installed. I found the right one&nbsp; here . Now it works!&nbsp; But somehow I'm just able to create triggered sound effects by chat messages with single tracks. I can create aliases for playlists and triggers for that aliases without any error messages, but when I try to trigger them f.e. with the line !fight I get the following error message in chat: (From System): An error occurred! A triggered event failed. Error message: TypeError: Cannot call method 'set' of undefined Event: function anonymous(msg) { return ((msg.content === '!fight' ? this.play('fight') : 0)) }
1443811277
Scaby79
Sheet Author
API Scripter
Oooops! I just saw that you postet the the link to the right script above. ;)
1443812956
Scaby79
Sheet Author
API Scripter
I just discovered another issue: Everytime I restart the sandbox, f.e. after deleting an alias, the triggers stop working, even the ones for the aliases I left untouched. I get a similar error message like the one before (issue with the playlists) in the chat: (From System): An error occurred! A triggered event failed. Error message: TypeError: Cannot call method 'play' of undefined Event: function anonymous(msg) { return ((msg.content === '!tix' ? this.this.play('tix') : 0)) } It is fixable by renewing the trigger, so the aliases remain working but the triggers seem to break by restarting the sandbox, does anybody else observe that?
1443814631
Scaby79
Sheet Author
API Scripter
Is there any way to play the alias directly like !play aliasname without using the trigger?
1443857049
Lithl
Pro
Sheet Author
API Scripter
Scaby79 said: Is there any way to play the alias directly like !play aliasname without using the trigger? Not at the moment, but it wouldn't be hard to add.
Its me again... Sooooo....turns out my celebration of finally getting the script working was a bit premature. Every time I try to run it, not only do I get the very same error message in the chat that Scaby was getting - (From System): An error occurred! A triggered event failed. Error message: TypeError: Cannot call method 'set' of undefined Event: function anonymous(msg) { return ((msg.content === '!fight' ? this.play('fight') : 0)) } - but it sends the error message ad infinitum until my game (and sometimes browser) crashes (this is why I copy/pasted the error message from Scaby's last post, as the error sends so rapidly that I cannot get a proper copy of it). I installed the splitARGS script posted here and still get the same thing.&nbsp; For clarity, my sequence in setting up the script is as follows;&nbsp; I start up my campaign and set up the track's alias per Brian's instruction in the OP. Then, I review the alias via !listsfx, just to make sure (maybe unnecessary, but better safe than sorry). Then, I set up the trigger via Brian's instruction in his reply to me: !triggersfx chat:message (msg.content === '!example' ? play('crit') : 0) Then, I try to execute the trigger - !example - and get nothing in return. Okay, maybe it didn't take. So, then I try to review the sfx again via the !listsfx command. That's when the error message I pasted above from Scaby returns in chat and keeps returning until I have to completely close the browser. Sometimes, if I try to log back into the campaign, the message will still be sending... Suggestions? (I'm going to attempt a screengrab of the issue here in a bit. Hopefully that'll give enough information to attempt some troubleshooting) Sorry if I'm being a bother. Like I said before, I know you authors are incredibly busy making our gaming experience the best it can be. This script is just exactly what I've been hoping for for my games, and I'd really like to get it working. Thanks in advance for all your hard work. :)
1444014561
Lithl
Pro
Sheet Author
API Scripter
Joshua, is your alias pointing at a playlist or single track? One of the errors Scaby posted seems to be coming from that, and it's one of the things on my plate for looking into.
1444015149

Edited 1444015183
Yep, single track. Haven't tried it with a playlist yet. Let me know if I can give you any more information that'll help you.&nbsp;
1444067650
Scaby79
Sheet Author
API Scripter
Joshua R. said: ... Then, I try to execute the trigger - !example - and get nothing in return. Okay, maybe it didn't take. So, then I try to review the sfx again via the !listsfx command. That's when the error message I pasted above from Scaby returns in chat and keeps returning until I have to completely close the browser. Sometimes, if I try to log back into the campaign, the message will still be sending... Suggestions? (I'm going to attempt a screengrab of the issue here in a bit. Hopefully that'll give enough information to attempt some troubleshooting) ... I experienced something similar, see&nbsp; here . Try this command in the chat: !deletetriggersfx chat-message that deletes all triggers you already set up and stops the infinite loop. But you have to set up all triggers again.
1444067761

Edited 1444067788
Scaby79
Sheet Author
API Scripter
Brian said: Scaby79 said: Is there any way to play the alias directly like !play aliasname without using the trigger? Not at the moment, but it wouldn't be hard to add. I would love that! ;)
1444071995

Edited 1444072336
Thanks for the suggestion, Scaby! Also, I'd like to second your request for the ability to play sfx without necessitating a trigger. That'd be pretty neat. But I'd be just as happy with the script as is if I can get it working.
1444190178

Edited 1444190792
Hey, Roll20 community,&nbsp; I didn't know where else to post this since this thread mentioned the desire for a script that calls jukebox tracks with an API command (!example) without a trigger attached, and since I didn't technically write this myself - instead, I kinda Frankensteined a bunch of scripts together that seemed to make sense to me and it ended up working. If this post belongs elsewhere, please move it to its more appropriate designation.&nbsp; So, without further ado, here is the script I stitched together that allowed me to call jukebox tracks with API commands: on("ready", function() { &nbsp; &nbsp; on("chat:message", function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api" && msg.content === "!hit") &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PlaySound('Doctor13', 9000); &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api" && msg.content === "!dark") &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PlaySound('FlowerCrown', 9000); &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; }); }); function PlaySound(trackname, time) { &nbsp; &nbsp; var track = findObjs({type: 'jukeboxtrack', title: trackname})[0]; &nbsp; &nbsp; track.set('playing',false); &nbsp; &nbsp; track.set('softstop',false); &nbsp; &nbsp; track.set('volume', 100); &nbsp; &nbsp; log(track); &nbsp; &nbsp; if(track) { &nbsp; &nbsp; &nbsp; &nbsp; track.set('playing',true); &nbsp; &nbsp; &nbsp; &nbsp; log('playing'); &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(function() {track.set('playing',false);log('stopping sound');}, time); &nbsp; &nbsp; &nbsp; &nbsp; log(track); &nbsp; &nbsp; } &nbsp; &nbsp; else { &nbsp; &nbsp; &nbsp; &nbsp; log("No track found"); &nbsp; &nbsp; } } "!hit" and "!dark" are the commands I chose to call the tracks "Doctor13" and "FlowerCrown" in my jukebox. So far, the script is working great for me, as I have tested it in both the chat window and within macros. I'm very, very, very API illiterate so if there are any scripts that this is incompatible with, I do not know. Also, if for some reason it doesn't work for you, I'll try to help but - like I said - this is really just a patchwork script taken from samples of other scripts already out there (and a bit from the API wiki docs).&nbsp; Hope this helps you guys!&nbsp; (ps Some of my players have a hard time hearing my SFX, thus I set the volume in the script to max [100]. Be aware of this lest you blow out your eardrums playing your sounds. :) ) &nbsp;OH! One more thing; as far as I know, you can add as many tracks to this script as you wish with the&nbsp; if (msg.type === "api" && msg.content === "!hit") { PlaySound('Doctor13', 9000); }; &nbsp;line. Just replace "!hit" with your own API chat command and "Doctor13" with your desired track's name. Update: The bulk of this script is borrowed from the script posted in&nbsp; DXWarlock's post .
Hmm...seems after moving a token, I have to restart the sandbox to get the scripts working again. Anyone got an idea of how to prevent that?&nbsp;
1444221533
The Aaron
Pro
API Scripter
Update your Blood and Honor Script.&nbsp;
I just updated the Blood and Honor script per your advice, and nothing's changed. Interesting.... Luckily, I'm off work today and my wife's out of town. So I've got plenty of time today to mess around with this. Haha.&nbsp;
1444243915
The Aaron
Pro
API Scripter
Probably best to start another thread then.
1444254705

Edited 1444255602
Scaby79
Sheet Author
API Scripter
If you add the code play: function(args, msg) { var alias; if (args.length === 0) { sendError(msg.playerid, 'Please supply an alias to play.'); return; } alias = (args[0] === '[null]' && !_.has(state.bshields.sfx.aliases, '[null]') ? '' : args[0]); if (!_.has(state.bshields.sfx.aliases, alias)) { sendError(msg.playerid, 'Alias "' + alias + '" not found. Please check the name and try again.'); return; } play(alias); }, in the section where the commands are located, for example in line 150 then you can play the aliases directly by&nbsp; !play aliasname ;)
1444256099
Scaby79
Sheet Author
API Scripter
playlists are still not working though I get the same error message as before by using the triggers. Maybe the problem isn't the triggers but somewhere in the "play(alias)"-function starting in line 279. Could it possibly be necessary to specify there if you wish to play a playlist instead of a track?
1444258618
Scaby79
Sheet Author
API Scripter
Something interesting: If&nbsp;you create an alias for a track with a playtime greater than the duration of the track itself, the alias is not playing (neither by direct play nor by trigger) without any error messages. If you go and delete the alias and create a new one with a minor playtime the new alias is not working either. BUT: If you delete the track out of the jukebox and add it again via soundcloud you can create a new fully functional alias. This issue was reproducible every time I tried that. Maybe thats something worth for debugging ;)
1444276811
Lithl
Pro
Sheet Author
API Scripter
Scaby79 said: Something interesting: If&nbsp;you create an alias for a track with a playtime greater than the duration of the track itself, the alias is not playing (neither by direct play nor by trigger) without any error messages. If you go and delete the alias and create a new one with a minor playtime the new alias is not working either. BUT: If you delete the track out of the jukebox and add it again via soundcloud you can create a new fully functional alias. This issue was reproducible every time I tried that. Maybe thats something worth for debugging ;) I'm not sure if there's a solution for that; the API doesn't know how long a track actually is . I can look into it, but I'm not hopeful on that front.
1444282933

Edited 1444283228
Lithl
Pro
Sheet Author
API Scripter
Version 0.2 has been committed to my repo. It's available from the same location ( <a href="https://github.com/Lithl/roll20-api-scripts/tree/t" rel="nofollow">https://github.com/Lithl/roll20-api-scripts/tree/t</a>... ). Changes: "Mode" (inorder/random/all) has been removed from alias display for single tracks, since it's only applicable to playlists The error causing calls to play() in your triggers migrating to this.play() and then this.this.play() has been fixed. From the user end, you should always only see play() Playlists should work properly as aliases now. The issue was that I was trying to iterate over playlist.n (the name of the playlist) instead of playlist.i (the array of ids of tracks in the playlist): obviously a problem. If the system throws an error at you as a whisper, it should include the full stack trace, instead of just the error message. This should help to make the script easier to debug in the future. Triggers on chat:message should no longer be capable of causing infinite loops when you use !listtriggerssfx or !reviewtriggersfx (the command called by clicking a trigger listed from !listtriggersfx). All chat:message triggers should do nothing if the message was sent by "System", so a trigger using logic like msg.content.match(/boom/) shouldn't cause problems. This does mean if you change your displayname to "System" and speak out of character, or speak as a character named "System" chat:message triggers won't work for you, but that seems like a pretty small price to pay. Restricted the functions available to use in triggers; you can still use Roll20 functions such as sendChat(), and you can still use standard library functions like Math.abs(), but it is no longer possible to use this script's checkInstall() or registerEventHandlers() functions. A trigger calling registerEventHandlers would have played havok with a lot of stuff, for example. The custom functions usable by this script are all in the availableFuncs &nbsp;property starting on line 427 in version 0.2, currently only play(). Added a !play alias &nbsp;command. It will simply play the indicated alias. As with all of the other API commands created in this script, !play can only be used by GMs. If you wish to create an API command similar to !play which is usable by non-GM players, you'll have to make a chat:message trigger for it. For example: !triggersfx chat:message msg.content.match(/^!playfx .*$/) ? play(msg.content.split(' ')[1]) : 0 Would create a !playfx command usable by non-GMs with near-identical functionality to the !play command available as a part of the script. NOTE: &nbsp;Any time you upgrade the version of this script, the checkInstall function will wipe out your current aliases and triggers. This is intended functionality, to prevent old aliases/triggers from causing bugs in new versions of the script.
1444304330

Edited 1444304516
Scaby79
Sheet Author
API Scripter
Great job! Thanks Brian! I'd like to suggest to add a possibility to stop a playing track by the command !stop alias which could be done by adding&nbsp;the code stop: function(args, msg) { if (args.length == 0) { sendError(msg.playerid, 'Please supply an alias to stop.'); return; } stop(args[0]); }, between lines 278 und 279 (counting in the original script)&nbsp; and the code function stop(alias) { var data = state.bshields.sfx.aliases[alias], track, playlist; if (!data) { sendChat('System', '/w gm Tried to stop "' + alias + '", but alias does not exist.'); return; } if (data.trackName) { track = getObj('jukeboxtrack', data.id); if (!track) { sendChat('System', '/w gm Tried to stop "' + data.trackName + '", but track no longer exists!'); return; } track.set('playing', false); setTimeout(function(trackObj) { trackObj.set('playing', false); }, data.duration * 1000, track); } else { playlist = _.find(JSON.parse(Campaign().get('jukeboxfolder')), function(folderObj) { return _.isObject(folderObj) && folderObj.id === data.id; }); if (!playlist) { sendChat('System', '/w gm Tried to stop "' + data.playlistName + '", but playlist no longer exists!'); return; } if (data.playAll) { _.each(playlist.i, function(trackId) { track = getObj('jukeboxtrack', trackId); track.set({ playing: false, softstop: false }); setTimeout(function(trackObj) { trackObj.set('playing', false); }, data.duration * 1000, track); }); } else if (data.playRandom) { track = getObj('jukeboxtrack', _.sample(playlist.i)); track.set('playing', false); setTimeout(function(trackObj) { trackObj.set('playing', false); }, data.duration * 1000, track); } else { if (data.nextIdx &gt;= playlist.i.length) { data.nextIdx = 0; } track = getObj('jukeboxtrack', playlist.i[data.nextIdx]); data.nextIdx = data.nextIdx + 1; track.set('playing', false); setTimeout(function(trackObj) { trackObj.set('playing', false); }, data.duration * 1000, track); } } } between lines 332 und 333 (counting in the original script) I'm pretty sure there are some redundant fragments in there but this suggestions are my first steps in playing with the scripts at all. ;) Is it possible to get somehow, which tracks or playlists are currently playing and stopping them by a command like !stop all or !stop -all ??
1444315122

Edited 1444315588
Scaby79
Sheet Author
API Scripter
For some reason, I have still trouble getting the triggers to work :( If I set a trigger for the existing alias "danger" (which is working fine with direct play) by the chat command !triggersfx chat:message (msg.content === '!example' ? play('danger') : 0) &nbsp;I get the following error message in the API Output Console: /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Object msg -&gt; (msg.content === '!example' ? play('danger') : 0) has no method 'replace' at triggerCodeToLambdaCode (evalmachine.:4481:21) at Object.bshields.sfx.commands.triggersfx (evalmachine.:4153:65) at handleInput (evalmachine.:4447:38) at eval ( Did I miss something?
1444322555
Lithl
Pro
Sheet Author
API Scripter
Scaby79 said: For some reason, I have still trouble getting the triggers to work :( If I set a trigger for the existing alias "danger" (which is working fine with direct play) by the chat command !triggersfx chat:message (msg.content === '!example' ? play('danger') : 0) &nbsp;I get the following error message in the API Output Console: /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Object msg -&gt; (msg.content === '!example' ? play('danger') : 0) has no method 'replace' at triggerCodeToLambdaCode (evalmachine.:4481:21) at Object.bshields.sfx.commands.triggersfx (evalmachine.:4153:65) at handleInput (evalmachine.:4447:38) at eval ( Did I miss something? No, I did. I'll get it fixed.
1444419246
Scaby79
Sheet Author
API Scripter
I just had another idea:&nbsp; How about a [play/stop] next to the [aliasname] and [DEL] button you get in the chat by !listsfx as a try I modified the listsfx command in the script slightly: listsfx: function(args, msg) { var who = getObj('player', msg.playerid).get('displayname'), message = '/w "' + who + '" '; _.chain(state.bshields.sfx.aliases) .map(function(data, alias) { var result = _.extend({ alias: alias }, data); if (alias.length === 0) result.alias = '&lt;em&gt;[null]&lt;/em&gt;'; return result; }) .sortBy(function(data) { return data.alias; }) .each(function(data) { message += '&lt;br&gt;&lt;a href="!reviewsfx ' + data.alias + '" style="width:50%"&gt;' + data.alias + '&lt;/a&gt;' + '&lt;a href="!play ' + data.alias + '" style="float:left"&gt;P&lt;/a&gt;' + '&lt;a href="!stop ' + data.alias + '" style="float:left"&gt;S&lt;/a&gt;' + '&lt;a href="!deletesfx ' + data.alias + '" style="float:right"&gt;DEL&lt;/a&gt;'; }); if (_.size(state.bshields.sfx.aliases) === 0) { message += '**No aliases registered.**'; } sendChat('System', message); }, Probably a toggle would be a better solution, but I have no idea how that can be done :(
1446007310

Edited 1446010795
Kiyomi N.
Sheet Author
Love this script and all the work you've put in Brian. Still trying to figure something out. I've done everything correct AFAIK but I don't hear any sounds when I try to use !play. My sound alias shows up in !listsfx with all the right information. No error messages though either, though when i purposefully leave my alias blank or mispell it, i do get the appropriate error messages. When I tried to use the trigger method, I get the same error as Scaby.
Joshua R. said: Hey, Roll20 community,&nbsp; I didn't know where else to post this since this thread mentioned the desire for a script that calls jukebox tracks with an API command (!example) without a trigger attached, and since I didn't technically write this myself - instead, I kinda Frankensteined a bunch of scripts together that seemed to make sense to me and it ended up working. If this post belongs elsewhere, please move it to its more appropriate designation.&nbsp; So, without further ado, here is the script I stitched together that allowed me to call jukebox tracks with API commands: on("ready", function() { &nbsp; &nbsp; on("chat:message", function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api" && msg.content === "!hit") &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PlaySound('Doctor13', 9000); &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api" && msg.content === "!dark") &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PlaySound('FlowerCrown', 9000); &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; }); }); function PlaySound(trackname, time) { &nbsp; &nbsp; var track = findObjs({type: 'jukeboxtrack', title: trackname})[0]; &nbsp; &nbsp; track.set('playing',false); &nbsp; &nbsp; track.set('softstop',false); &nbsp; &nbsp; track.set('volume', 100); &nbsp; &nbsp; log(track); &nbsp; &nbsp; if(track) { &nbsp; &nbsp; &nbsp; &nbsp; track.set('playing',true); &nbsp; &nbsp; &nbsp; &nbsp; log('playing'); &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(function() {track.set('playing',false);log('stopping sound');}, time); &nbsp; &nbsp; &nbsp; &nbsp; log(track); &nbsp; &nbsp; } &nbsp; &nbsp; else { &nbsp; &nbsp; &nbsp; &nbsp; log("No track found"); &nbsp; &nbsp; } } "!hit" and "!dark" are the commands I chose to call the tracks "Doctor13" and "FlowerCrown" in my jukebox. So far, the script is working great for me, as I have tested it in both the chat window and within macros. I'm very, very, very API illiterate so if there are any scripts that this is incompatible with, I do not know. Also, if for some reason it doesn't work for you, I'll try to help but - like I said - this is really just a patchwork script taken from samples of other scripts already out there (and a bit from the API wiki docs).&nbsp; Hope this helps you guys!&nbsp; (ps Some of my players have a hard time hearing my SFX, thus I set the volume in the script to max [100]. Be aware of this lest you blow out your eardrums playing your sounds. :) ) &nbsp;OH! One more thing; as far as I know, you can add as many tracks to this script as you wish with the&nbsp; if (msg.type === "api" && msg.content === "!hit") { PlaySound('Doctor13', 9000); }; &nbsp;line. Just replace "!hit" with your own API chat command and "Doctor13" with your desired track's name. Update: The bulk of this script is borrowed from the script posted in&nbsp; DXWarlock's post . When I try to use your script Joshua I get this error: Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again. More info... For reference, the error message generated was:&nbsp; /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Cannot call method 'set' of undefined at PlaySound (evalmachine.&lt;anonymous&gt;:15:11) at evalmachine.&lt;anonymous&gt;:5:13 at eval (
1446011852

Edited 1446012721
Kiyomi N.
Sheet Author
Nevermind Brian, I figured out why !play wasn't working. Bah, it was that duration bug you ran into before but it's fixed now. So my new question is this... How can I call a sound using !play via a macro? Is it possible? To put it into context, I'd like for the sound to play when a particular ability is used. Update: I actually managed to figure this out on my own :)
1446057919

Edited 1446059313
Scaby79
Sheet Author
API Scripter
Kiyomi N. said: Nevermind Brian, I figured out why !play wasn't working. Bah, it was that duration bug you ran into before but it's fixed now. So my new question is this... How can I call a sound using !play via a macro? Is it possible? To put it into context, I'd like for the sound to play when a particular ability is used. Update: I actually managed to figure this out on my own :) Hey Kiyomi, if you don't need the flexibility to configure your sound effects from ingame and if you just want to trigger a bunch of tracks by certain actions or events, you might want to take a look at&nbsp; this script . The advantage is probably in the absence of the duration bug you already noticed and you don't have to recover any aliases after a script update. Actually I use both scripts myself as they have different advantages.&nbsp;&nbsp;
While it is not completely user friendly there are many handy guides between here and the link posted by Scabby. Its really great, I want to start using this and have things trigger on chat messages etc. I hopefully will get around to doing such things. I would love it to be more easily accessible to just type "Rock falls" or "Fireball" etc in chat to have the related sounds play.