When you click on 'Add script', you will see a few new options, one of which will say 'Add audio (NEW)'.
This will bring up this screen, where you can select a sound from your computer, just like the old play sound
.
Using the sync option does NOT actually interrupt play. It only keeps the player from entering commands until the sound has finished, but we can add a script to run once the sound has finished to accomplish our needs.
Here is an example where a sound "interrupts play" in between rooms:
You can stop all sounds with DestroyAllAudio
. (This even stops sounds played with the old play sound
script command.)
You can stop one sound with DestroyAudio(id)
, but you must know the ID. (An ID can be assigned when adding audio.)
The mp3 format will not work in the desktop player when using these functions. It will, however, play an ogg file. To exacerbate things, I am not sure if the Safari browser will play the ogg format. My solution is to include both formats, as seen in the above example.
To make sure your sound will work in the desktop player, either include an ogg along with an mp3, or use the old play sound
script command.
autoplay
.This works just like stopping audio. You can use DestroyAllVideo
or DestroyVideo(id)
.
You can add backup sources for browser compatibility
However, the backup sources do not have to be on an external server (as in the example)?
And the good thing about this solution is that you can play several music pieces/sounds at the same time.
Would you give us additional functions to stop and resume the music? That would be very nice : -)
However, the backup sources do not have to be on an external server
Correct!
the good thing about this solution is that you can play several music pieces/sounds at the same time.
Definitely!
additional functions to stop and resume the music
They are already in there, I just didn't add them to the GUI yet.
I just added video functions to the library, as well.
Here's a link to a list of all the functions:
http://media.textadventures.co.uk/games/PHVys9dICUiMSSpr_m9WYQ/documentation.html
This is truly amazing... being able to add an ambient sound with no effort at all, and not having it conflict with the sound effects is incredible, and I feel it can add a lot to the ambience in certain types of videogames.
Furthermore, it's compatible with the old play sound
function, so I could add it to my game on the fly. Truly a life saver.
Only one question, though... any details I should know as to how you should be credited, or how am I allowed to use it? I'd hate to piss someone off due to my own ignorance.
This is exactly what I'm looking for at the moment and... obviously I'd already found it and forgotten all about it.
One question: does it work to not upload anything and use the "backup" source only? If you understand what I mean?
The mp3 and mp4 formats will not work in the desktop player when using these functions. It will, however, play an ogg or ogv file. To exacerbate things, I don't think the Safari browser will play the ogg and ogv formats. My solution is to include both formats, as seen in the above example.
Yeah; I got that :)
The one thing I'm still unsure of is if the user have to bundle the sound into the game or is it possible to ONLY use external (linked) files (no matter what the file extension)?
The one thing I'm still unsure of is if the user have to bundle the sound into the game or is it possible to ONLY use external (linked) files (no matter what the file extension)?
If you have the sound hosted on an external site and you only link to that from within your game, there is no need to include the audio file in your game.
So, if your source is like https://whatever.com/mysound.mp3
, you do not need to add the file to your game folder.
But, if your source is loading a local file, like GetFileURL("mysound.mp3")
, you DO need to add the file to your game folder.
This applies to all file extensions and all file types.
If you are accessing a local file during play, that file must be in your main game's folder AND you must be sure the extension is included in game.publishfileextensions.
Just to have the code in more than one place, here's the most recent AudioVideoLib.aslx file, which should work with v550 or v580 games.
<library>
<!--
This library has been modified to work with Quest 5.8.
The documentation can be found here:
http://textadventures.co.uk/games/view/phvys9dicuimsspr_m9wyq/audiovideolib
-->
<function name="PlaySound" parameters="src, sync, loop, id, controls, addscript, callback">
firsttime {
SendToJsEval(play_audio_lib_stuff.js)
}
if (sync and loop) {
error ("Attempted to loop and sync the same sound!")
}
src = GetSrc(src)
if (id = "") {
id = CreateAudioID()
}
id = Replace(id, " ", "_")
JS.makeAudio (src, sync, loop, id, controls)
if (addscript) {
SetAudioCallback (id, callback)
}
if (sync) {
DoAudioSync
}
</function>
<function name="CreateAudioID" type="string">
if (not HasAttribute(game,"audiofilesplayed")) {
game.audiofilesplayed = 0
}
game.audiofilesplayed = game.audiofilesplayed + 1
return ("audio-" + game.audiofilesplayed)
</function>
<function name="SetAudioCallback" parameters="id, callback">
js = "$('#"+id+"').on('ended', function(){ASLEvent('EndAudioSyncAndInvoke',$(this).attr('id'));$(this).remove();});"
JS.eval (js)
if (not HasAttribute(game, "audiofinishedcallback")) {
game.audiofinishedcallback = NewScriptDictionary()
}
dictionary add (game.audiofinishedcallback, id, callback)
</function>
<function name="DestroyAudio" parameters="id">
JS.eval ("$('#"+id+"').remove();")
</function>
<function name="DestroyAllAudio">
stop sound
JS.eval ("$('audio').remove();")
EndAudioSync("")
game.audiofinishedcallback = NewScriptDictionary()
</function>
<function name="DestroyAudioAndRunScript" parameters="id">
JS.eval ("$('#"+id+"').remove();")
EndAudioSyncAndInvoke(id)
</function>
<function name="DoAudioSync">
firsttime {
JS.eval ("var sendCommandBak = sendCommand;")
}
game.audiosyncing = true
JS.eval ("sendCommand = function(){$('input#txtCommand').val();};")
</function>
<function name="EndAudioSync" parameters="bs">
game.preventturnscripts = true
game.audiosyncing = false
JS.endAudioSync()
</function>
<function name="EndAudioSyncAndInvoke" parameters="id">
game.preventturnscripts = true
game.audiosyncing = false
JS.endAudioSync()
if (HasAttribute(game, "audiofinishedcallback")) {
if (DictionaryContains(game.audiofinishedcallback,id)) {
invoke (ScriptDictionaryItem(game.audiofinishedcallback,id))
dictionary remove(game.audiofinishedcallback,id)
if (DictionaryCount(game.audiofinishedcallback)>0){
DoAudioSync
}
}
}
</function>
<function name="GetSrc" parameters="src" type="string">
src = Split(src,";")
online = false
pres = Split("http;ftp",";")
tags = NewStringList()
foreach (url, src) {
foreach (pre, pres) {
if (StartsWith(url,pre)) {
online = true
}
}
arr = Split(url,".")
type = arr[ListCount(arr)-1]
if (online) {
thisurl = url
}
else {
thisurl = (GetFileURL(url))
}
list add (tags, Chr(60)+"source src=\""+thisurl+"\" type=\"audio/"+type+"\" "+Chr(62))
}
srctags = Join(tags,"")
srctags = Replace(srctags,"/ogv","/ogg")
return (srctags)
</function>
<!--
FinishTurn modified function to keep turn scripts from firing when ending a sync
-->
<function name="FinishTurn">
<![CDATA[
// Modded by KV to handle multiple commands, v550, and v580 correctly
if (HasAttribute (game, "runturnscripts") or GetAttribute(game, "aslversion") = "580" or GetBoolean(game, "multiplecommands")){
if (not GetBoolean(game, "suppressturnscripts")) {
if (GetBoolean (game, "runturnscripts")){
RunTurnScripts
}
}
game.runturnscripts = false
}
else if (not GetBoolean(game, "suppressturnscripts")) {
if (GetBoolean (game, "feature_turncount")){
IncreaseObjectCounter(game, "turncount")
}
RunTurnScripts
}
// END OF MOD
game.suppressturnscripts = false
UpdateStatusAttributes
CheckDarkness
UpdateObjectLinks
]]></function>
-->
<!-- EXTRAS -->
<!--
The following functions are technically unnecessary, but I think they are nice to have.
-->
<function name="PlayAudio" parameters="src">
PlaySound (src, false, false, "", false, false) {
}
</function>
<function name="PlayAudioID" parameters="src, id">
PlaySound (src, false, false, id, false, false) {
}
</function>
<function name="PlayAudioLooped" parameters="src">
PlaySound (src, false, true, "", false, false) {
}
</function>
<function name="PlayAudioLoopedID" parameters="src, id">
PlaySound (src, false, true, id, false, false) {
}
</function>
<function name="PlayAudioSynced" parameters="src">
PlaySound (src, true, false, "", false, false) {
}
</function>
<function name="PlayAudioSyncedID" parameters="src, id">
PlaySound (src, true, false, id, false, false) {
}
</function>
<function name="PlayAudioSyncedWithCallback" parameters="src, callback">
PlaySound (src, true, false, "", false, true, callback)
</function>
<function name="PlayAudioSyncedIDWithCallback" parameters="src, id, callback">
PlaySound (src, true, false, id, false, true, callback)
</function>
<function name="PlayAudioControls" parameters="src">
PlaySound (src, false, false, "", true, false) {
}
</function>
<function name="PlayAudioIDControls" parameters="src, id">
PlaySound (src, false, false, id, true, false) {
}
</function>
<function name="PlayAudioLoopedControls" parameters="src">
PlaySound (src, false, true, "", true, false) {
}
</function>
<function name="PlayAudioLoopedIDControls" parameters="src, id">
PlaySound (src, false, true, id, true, false) {
}
</function>
<function name="PlayAudioSyncedControls" parameters="src">
PlaySound (src, true, false, "", true, false) {
}
</function>
<function name="PlayAudioSyncedIDControls" parameters="src, id">
PlaySound (src, true, false, id, true, false) {
}
</function>
<function name="PlayAudioSyncedWithCallbackControls" parameters="src, callback">
PlaySound (src, true, false, "", true, true, callback)
</function>
<function name="PlayAudioSyncedIDWithCallbackControls" parameters="src, id, callback">
PlaySound (src, true, false, id, true, true, callback)
</function>
<function name="PauseAudio" parameters="id">
JS.pauseAudio(id)
</function>
<function name="ResumePausedAudio" parameters="id">
JS.resumePausedAudio(id)
</function>
<function name="SetAudioVolume" parameters="id,vol">
// vol must be between 0 and 1
JS.setAudioVolume(id,vol)
</function>
<function name="MuteAudio" parameters="id">
JS.muteAudio(id)
</function>
<function name="UnmuteAudio" parameters="id">
JS.unmuteAudio(id)
</function>
<function name="MuteAllAudio">
JS.muteAllAudio()
</function>
<function name="UnmuteAllAudio">
JS.unmuteAllAudio()
</function>
<function name="PauseAllAudio">
JS.pauseAllAudio()
</function>
<function name="RestartAllPausedAudio">
JS.restartAllPausedAudio()
</function>
<function name="SetAllAudioVolume" parameters="vol">
// vol must be between 0 and 1
JS.setAllAudioVolume(vol)
</function>
<function name="SetAudioPosition" parameters="id,pos">
JS.setAudioPosition(id,pos)
</function>
<function name="IncreaseVolume" parameters="id">
<![CDATA[
// vol must be between 0 and 1
JS.increaseVolume(id)
]]>
</function>
<function name="DecreaseVolume" parameters="id">
<![CDATA[
// vol must be between 0 and 1
JS.decreaseVolume(id)
]]>
</function>
<function name="IncreaseAllVolume" parameters="id">
JS.increaseAllVolume()
</function>
<function name="DecreaseAllVolume" parameters="id">
JS.decreaseAllVolume()
</function>
<!-- END OF UNNECESSARY FUNCTIONS -->
<!--
DEBUGGING FUNCTIONS
-->
<!--
AudioLog and TestAudio are not used by any functions.
They are only included for debugging purposes.
-->
<function name="AudioLog" parameters="text">
game.preventturnscripts = true
Log (text)
</function>
<function name="TestAudio" parameters="src">
s = Chr(60)+"audio src='"+GetSrc(src)+"' '"
JS.testAudio (s)
</function>
<!-- Javascript stuff -->
<function name="SendToJsEval" parameters="data">
<![CDATA[
regEx = "//"
js = Split(data,Chr(60)+"br/"+Chr(62))
notes = NewStringList()
foreach (line, js) {
if (StartsWith(line,"//")) {
list add (notes, line)
}
}
js = ListExclude(js,notes)
finaljs = NewStringList()
foreach (line, js) {
code = line
if (IsRegExMatch(regEx,line)) {
list = Split(line,"//")
code = list[0]
}
list add (finaljs, code)
}
js = Join(finaljs,"")
js = Replace(js, "[br]", Chr(60)+"br/"+Chr(62))
js = Replace(js, "[br/]", Chr(60)+"br/"+Chr(62))
js = Replace(js, "[break]", Chr(60)+"br/"+Chr(62))
js = Replace(js, "[linebreak]", Chr(60)+"br/"+Chr(62))
JS.eval (js)
]]>
</function>
<command name="play_audio_lib_stuff">
<parent>game</parent>
<js>
<![CDATA[
function isMobilePlayer(){if (typeof(currentTab) === 'string'){return true;}return false;};
function makeAudio(src,sync,loop,id,controls,callback){
if (sync && loop){
throw new Error('makeAudio(): Attempted to sync and loop the same sound.');
}
var s = String.fromCharCode(60)+'audio ';
if(typeof(id)==="string"){
s += 'id=\''+id+'\' ';
}
if(controls){
s += ' controls controlsList=\'nodownload\' ';
}
if(loop){
s += ' loop ';
}
s += ' autoplay' + String.fromCharCode(62) +''+src;
s += String.fromCharCode(60)+'/audio'+String.fromCharCode(62);
var thisTag = s;
if(isMobilePlayer()){
var repl = String.fromCharCode(60);
repl += 'audio controls controlsList=\'nodownload\' class=\'mob-aud\'';
thisTag = thisTag.replace(String.fromCharCode(60)+'audio', repl);
var tag = String.fromCharCode(60)+'p'+String.fromCharCode(62);
tag += thisTag+''+String.fromCharCode(60);
tag += '/p'+String.fromCharCode(62);
addText(tag);
if(typeof($('.mob-aud').last().on('ended'))==='function'){
onEndBak = $('.mob-aud').last().on('ended');
}else{
onEndBak=function(){};
}
$('.mob-aud').last().insertAfter($('#txtCommandDiv')).on('ended',function(){
onEndBak();
$(this).remove();
}).css('margin-top','4px');
}else if (controls){
var addon = String.fromCharCode(60)+'p'+String.fromCharCode(62);
addon += thisTag+''+String.fromCharCode(60)+'/p'+String.fromCharCode(62);
$("#divOutput").after(addon);
}else{
$('body').after(thisTag);
}
}
var safeBreak = String.fromCharCode(60)+'br/'+String.fromCharCode(62);
var noSoundMsg = safeBreak+'There is no sound playing.';
function endAudioSync(){
if (typeof(sendCommandBak) === 'function'){sendCommand = sendCommandBak;}
}
function increaseVolume(id){
var thisAud = document.getElementById(id);
if(!thisAud){
addTextAndScroll(safeBreak+'There is no sound playing.');
}
else if(thisAud.volume*10<10){
thisAud.volume = (thisAud.volume*10+1)/10;
addTextAndScroll(safeBreak+'The volume has been increased.');
}
else{
addTextAndScroll(safeBreak+'The volume is already at the maximum level.');
}
}
function increaseAllVolume(){
$('audio').each(function(){
if (this.volume!=1){this.volume = this.volume + .1};
});
}
function decreaseVolume (id) {
var thisAud = document.getElementById(id);
if(!thisAud){
addTextAndScroll(safeBreak+'There is no sound playing.');
}else if(thisAud.volume*10>0){
thisAud.volume = (thisAud.volume*10-1)/10;
addTextAndScroll(safeBreak+ 'The volume has been decreased.');
}else{
addTextAndScroll(safeBreak+'The volume is already all the way down.');
}
}
function decreaseAllVolume(){
$('audio').each(function(){
if (this.volume>=0.1){this.volume = this.volume - .1};
});
}
function endAudioSync(){
if (typeof(sendCommandBak) === 'function'){
sendCommand = sendCommandBak;
}
}
function setAllAudioVolume(vol){
var audios = document.getElementsByTagName('audio');
for(aud in audios){
audios[aud].volume = vol;
}
}
function setAudioCurrentTime(id,pos){
document.getElementById(id).currentTime = pos;
}
function pauseAudio(id){
var thisAud = document.getElementById(id);
thisAud.pause();
}
function resumePausedAudio(id){
var thisAud = document.getElementById(id);
thisAud.play();
}
function restartPausedAudio(id){
var thisAud = document.getElementById(id);
thisAud.load();
thisAud.play()
}
function setAudioVolume(id,vol){
document.getElementById(id).volume = vol;
}
function muteAudio(id){
var aud = document.getElementById(id);
aud.volbak = aud.volume;
setAudioVolume(id,0);
}
function unmuteAudio(id){
var aud = document.getElementById(id);
aud.volume = aud.volbak;
}
function muteAllAudio(){
$('audio').each(function(){
$(this).attr('volbak',this.volume);
});
var audios = document.getElementsByTagName('audio');
for(aud in audios){
if (typeof(audios[aud].volume)!='undefined'){
audios[aud].volume=0;
}
}
}
function unmuteAllAudio(){
$('audio').each(function(){
$(this).prop('volume',$(this).attr('volbak'));
});
}
function pauseAllAudio(){
var audios = document.getElementsByTagName('audio');
for(aud in audios){
audios[aud].pause();
}
}
function destroyAllAudio(){
$('audio').remove();
}
function restartAllPausedAudio(){
var audios = document.getElementsByTagName('audio');
for(aud in audios){
audios[aud].audios[aud].play();
}
}
function setAllAudioVolume(vol){
var audios = document.getElementsByTagName('audio');
for(aud in audios){
audios[aud].volume = vol;
}
}
function setAudioPosition(id,pos){
document.getElementById(id).currentTime = pos;
}
function testAudio(s){
s = s + " onloadstart='ASLEvent(\"AudioLog\",\"Loading \"+$(this).attr(\"src\"));$(this).remove();'";
s = s + " onerror='ASLEvent(\"AudioLog\",$(this).attr(\"src\")+\" failed to load.\");$(this).remove();'";
s = s + "/"+Chr(62);
addText(s);
}
]]>
</js>
</command>
<function name="AddVideo" parameters="src, sync, loop, id, controls, autoplay, addscript, callback">
if (sync and loop) {
error ("Attempted to loop and sync the same sound!")
}
src = GetSrc(src)
lp = ""
if (loop){
lp = " loop "
}
ctrls = ""
if (controls) {
ctrls = " controls "
}
aplay = ""
if (autoplay) {
aplay = " autoplay "
}
if (id = "") {
id = CreateVideoID()
}
id = Replace(id, " ", "_")
s = Chr(60) + "video " + ctrls + " " + lp + " " + aplay
s = s + " style='width:100%;'"
s = s + "id='" + id + "'" + Chr(62)
s = s + src
s = s + Chr(60)+"/video"+Chr(62)
msg (s)
if (addscript) {
SetVideoCallback (id, callback)
}
if (sync) {
DoVideoSync
}
</function>
<function name="HideVideo" parameters="id">
JS.uiHide(id)
</function>
<function name="DestroyVideo" parameters="id">
JS.eval("$('#"+id+"').remove();")
</function>
<function name="ShowHiddenVideo" parameters="id">
JS.uiShow(id)
</function>
<function name="PauseVideo" parameters="id">
JS.eval("document.getElementById('"+id+"').pause();")
</function>
<function name="ResumePausedVideo" parameters="id">
JS.eval("document.getElementById('"+id+"').play();")
</function>
<function name="RestartPausedVideo" parameters="id">
JS.eval("document.getElementById('"+id+"').load();")
</function>
<function name="SetVideoCurrentTime" parameters="id,time">
JS.eval("document.getElementById('"+id+"').currentTime = "+time+";")
</function>
<function name="CreateVideoID" type="string">
if (not HasAttribute(game,"videofilesplayed")) {
game.videofilesplayed = 0
}
game.videofilesplayed = game.videofilesplayed + 1
return ("video-" + game.videofilesplayed)
</function>
<function name="SetVideoCallback" parameters="id, callback">
js = "$('#"+id+"').on('ended',function(){ASLEvent('EndVideoSyncAndInvoke',$(this).attr('id'));/*$(this).remove();*/});"
JS.eval (js)
if (not HasAttribute(game, "videofinishedcallback")) {
game.videofinishedcallback = NewScriptDictionary()
}
dictionary add (game.videofinishedcallback, id, callback)
</function>
<function name="EndVideoSync" parameters="bs">
game.preventturnscripts = true
game.videosyncing = false
JS.endAudioSync()
</function>
<function name="EndVideoSyncAndInvoke" parameters="id">
game.preventturnscripts = true
game.audiosyncing = false
JS.endAudioSync()
if (HasAttribute(game, "videofinishedcallback")) {
if (DictionaryContains(game.videofinishedcallback,id)) {
invoke (ScriptDictionaryItem(game.videofinishedcallback,id))
dictionary remove(game.videofinishedcallback,id)
if (DictionaryCount(game.videofinishedcallback)>0){
DoVideoSync
}
}
}
</function>
<function name="DoVideoSync">
firsttime {
JS.eval ("var sendCommandBak = sendCommand;")
}
game.videosyncing = true
JS.eval ("sendCommand = function(){$('input#txtCommand').val();};")
</function>
<function name="DestroyAllVideo">
JS.eval("$('video').remove();")
</function>
<!--
GUI Stuff
-->
<editor>
<appliesto>(function)PlaySound</appliesto>
<display>Add sound: #0</display>
<category>[EditorScriptsOutputOutput]</category>
<create>PlaySound ("", false, false, "", false, false){}</create>
<add>Add sound (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>[EditorScriptsOutputPlaysound]</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>0</attribute>
<simple>filename</simple>
<simpleeditor>file</simpleeditor>
<source>*.wav;*.mp3;*.ogg</source>
<filefiltername>Sound Files</filefiltername>
</control>
<control>
<controltype>label</controltype>
<caption>ID (Optional):</caption>
<breakbefore/>
</control>
<control>
<controltype>textbox</controltype>
<attribute>3</attribute>
</control>
<control>
<controltype>label</controltype>
<caption>[EditorScriptsOutputWaitforsound]</caption>
<breakbefore/>
</control>
<control>
<controltype>expression</controltype>
<attribute>1</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>[EditorScriptsOutputLoop]</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>2</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>Show controls</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>4</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>Add a callback script</caption>
<breakbefore/>
</control>
<control>
<controltype>expression</controltype>
<attribute>5</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>
Script to run after sound has finished (Optional)
(You must set "Add a callback script" to yes for this script to run!)
</caption>
<breakbefore/>
</control>
<control>
<onlydisplayif>#5</onlydisplayif>
<controltype>script</controltype>
<attribute>script</attribute>
</control>
</editor>
<editor>
<appliesto>(function)DestroyAllAudio</appliesto>
<display>Destroy all audio</display>
<category>[EditorScriptsOutputOutput]</category>
<create>DestroyAllAudio</create>
<add>Destroy all audio (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>Destroy all audio</caption>
</control>
</editor>
<editor>
<appliesto>(function)DestroyAudio</appliesto>
<display>Destroy audio #0</display>
<category>[EditorScriptsOutputOutput]</category>
<create>DestroyAudio("")</create>
<add>Destroy audio (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>Destroy audio with ID:</caption>
</control>
<control>
<controltype>textbox</controltype>
<attribute>0</attribute>
</control>
</editor>
<editor>
<appliesto>(function)AddVideo</appliesto>
<display>Add video: #0</display>
<category>[EditorScriptsOutputOutput]</category>
<create>AddVideo ("", false, false, "", true, false, false){}</create>
<add>Add video (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>Add a video</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>0</attribute>
<simple>filename</simple>
<simpleeditor>file</simpleeditor>
<source>*.mp4;*.ogv</source>
<filefiltername>Video Files</filefiltername>
</control>
<control>
<controltype>label</controltype>
<caption>ID (Optional):</caption>
<breakbefore/>
</control>
<control>
<controltype>textbox</controltype>
<attribute>3</attribute>
</control>
<control>
<controltype>label</controltype>
<caption>Wait for video to finish playing</caption>
<breakbefore/>
</control>
<control>
<controltype>expression</controltype>
<attribute>1</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>[EditorScriptsOutputLoop]</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>2</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>Show controls</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>4</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>Autoplay</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>5</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>Add a callback script</caption>
</control>
<control>
<controltype>expression</controltype>
<attribute>6</attribute>
<simpleeditor>boolean</simpleeditor>
</control>
<control>
<controltype>label</controltype>
<caption>
Script to run after video has finished (Optional)
(You must set "Add a callback script" to yes for this script to run!)
</caption>
<breakbefore/>
</control>
<control>
<onlydisplayif>#5</onlydisplayif>
<controltype>script</controltype>
<attribute>script</attribute>
</control>
</editor>
<editor>
<appliesto>(function)DestroyAllVideo</appliesto>
<display>Destroy all video</display>
<category>[EditorScriptsOutputOutput]</category>
<create>DestroyAllVideo</create>
<add>Destroy all video (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>Destroy all video</caption>
</control>
</editor>
<editor>
<appliesto>(function)DestroyVideo</appliesto>
<display>Destroy video #0</display>
<category>[EditorScriptsOutputOutput]</category>
<create>DestroyVideo("")</create>
<add>Destroy video (NEW)</add>
<advanced />
<control>
<controltype>label</controltype>
<caption>Destroy video with ID:</caption>
</control>
<control>
<controltype>textbox</controltype>
<attribute>0</attribute>
</control>
</editor>
</library>
HOW DID THEY DO THAT?!?
As far as I can tell, it's just an <audio>
element, started automatically by calling its .play()
method.
I noticed that if the game has the option "clear screen" for every turn, this could be a problem because the game clears everything inserted in the page, including the<audio>
statements.
So, remember to NOT enable this option.