diff --git a/New-project/c2runtime.js b/New-project/c2runtime.js index 560de7c..ec1230b 100644 --- a/New-project/c2runtime.js +++ b/New-project/c2runtime.js @@ -15220,6 +15220,3106 @@ cr.system_object.prototype.loadFromJSON = function (o) cr.shaders = {}; ; ; +cr.plugins_.Audio = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var pluginProto = cr.plugins_.Audio.prototype; + pluginProto.Type = function(plugin) + { + this.plugin = plugin; + this.runtime = plugin.runtime; + }; + var typeProto = pluginProto.Type.prototype; + typeProto.onCreate = function() + { + }; + var audRuntime = null; + var audInst = null; + var audTag = ""; + var appPath = ""; // for Cordova only + var API_HTML5 = 0; + var API_WEBAUDIO = 1; + var API_CORDOVA = 2; + var API_APPMOBI = 3; + var api = API_HTML5; + var context = null; + var audioBuffers = []; // cache of buffers + var audioInstances = []; // cache of instances + var lastAudio = null; + var useOgg = false; // determined at create time + var timescale_mode = 0; + var silent = false; + var masterVolume = 1; + var listenerX = 0; + var listenerY = 0; + var isContextSuspended = false; + var panningModel = 1; // HRTF + var distanceModel = 1; // Inverse + var refDistance = 10; + var maxDistance = 10000; + var rolloffFactor = 1; + var micSource = null; + var micTag = ""; + var useNextTouchWorkaround = false; // heuristic in case play() does not return a promise and we have to guess if the play was blocked + var playOnNextInput = []; // C2AudioInstances with HTMLAudioElements to play on next input event + var playMusicAsSoundWorkaround = false; // play music tracks with Web Audio API + var hasPlayedDummyBuffer = false; // dummy buffer played to unblock AudioContext on some platforms + function addAudioToPlayOnNextInput(a) + { + var i = playOnNextInput.indexOf(a); + if (i === -1) + playOnNextInput.push(a); + }; + function tryPlayAudioElement(a) + { + var audioElem = a.instanceObject; + var playRet; + try { + playRet = audioElem.play(); + } + catch (err) { + addAudioToPlayOnNextInput(a); + return; + } + if (playRet) // promise was returned + { + playRet.catch(function (err) + { + addAudioToPlayOnNextInput(a); + }); + } + else if (useNextTouchWorkaround && !audRuntime.isInUserInputEvent) + { + addAudioToPlayOnNextInput(a); + } + }; + function playQueuedAudio() + { + var i, len, m, playRet; + if (!hasPlayedDummyBuffer && !isContextSuspended && context) + { + playDummyBuffer(); + if (context["state"] === "running") + hasPlayedDummyBuffer = true; + } + var tryPlay = playOnNextInput.slice(0); + cr.clearArray(playOnNextInput); + if (!silent) + { + for (i = 0, len = tryPlay.length; i < len; ++i) + { + m = tryPlay[i]; + if (!m.stopped && !m.is_paused) + { + playRet = m.instanceObject.play(); + if (playRet) + { + playRet.catch(function (err) + { + addAudioToPlayOnNextInput(m); + }); + } + } + } + } + }; + function playDummyBuffer() + { + if (context["state"] === "suspended" && context["resume"]) + context["resume"](); + if (!context["createBuffer"]) + return; + var buffer = context["createBuffer"](1, 220, 22050); + var source = context["createBufferSource"](); + source["buffer"] = buffer; + source["connect"](context["destination"]); + startSource(source); + }; + document.addEventListener("pointerup", playQueuedAudio, true); + document.addEventListener("touchend", playQueuedAudio, true); + document.addEventListener("click", playQueuedAudio, true); + document.addEventListener("keydown", playQueuedAudio, true); + document.addEventListener("gamepadconnected", playQueuedAudio, true); + function dbToLinear(x) + { + var v = dbToLinear_nocap(x); + if (!isFinite(v)) // accidentally passing a string can result in NaN; set volume to 0 if so + v = 0; + if (v < 0) + v = 0; + if (v > 1) + v = 1; + return v; + }; + function linearToDb(x) + { + if (x < 0) + x = 0; + if (x > 1) + x = 1; + return linearToDb_nocap(x); + }; + function dbToLinear_nocap(x) + { + return Math.pow(10, x / 20); + }; + function linearToDb_nocap(x) + { + return (Math.log(x) / Math.log(10)) * 20; + }; + var effects = {}; + function getDestinationForTag(tag) + { + tag = tag.toLowerCase(); + if (effects.hasOwnProperty(tag)) + { + if (effects[tag].length) + return effects[tag][0].getInputNode(); + } + return context["destination"]; + }; + function createGain() + { + if (context["createGain"]) + return context["createGain"](); + else + return context["createGainNode"](); + }; + function createDelay(d) + { + if (context["createDelay"]) + return context["createDelay"](d); + else + return context["createDelayNode"](d); + }; + function startSource(s, scheduledTime) + { + if (s["start"]) + s["start"](scheduledTime || 0); + else + s["noteOn"](scheduledTime || 0); + }; + function startSourceAt(s, x, d, scheduledTime) + { + if (s["start"]) + s["start"](scheduledTime || 0, x); + else + s["noteGrainOn"](scheduledTime || 0, x, d - x); + }; + function stopSource(s) + { + try { + if (s["stop"]) + s["stop"](0); + else + s["noteOff"](0); + } + catch (e) {} + }; + function setAudioParam(ap, value, ramp, time) + { + if (!ap) + return; // iOS is missing some parameters + ap["cancelScheduledValues"](0); + if (time === 0) + { + ap["value"] = value; + return; + } + var curTime = context["currentTime"]; + time += curTime; + switch (ramp) { + case 0: // step + ap["setValueAtTime"](value, time); + break; + case 1: // linear + ap["setValueAtTime"](ap["value"], curTime); // to set what to ramp from + ap["linearRampToValueAtTime"](value, time); + break; + case 2: // exponential + ap["setValueAtTime"](ap["value"], curTime); // to set what to ramp from + ap["exponentialRampToValueAtTime"](value, time); + break; + } + }; + var filterTypes = ["lowpass", "highpass", "bandpass", "lowshelf", "highshelf", "peaking", "notch", "allpass"]; + function FilterEffect(type, freq, detune, q, gain, mix) + { + this.type = "filter"; + this.params = [type, freq, detune, q, gain, mix]; + this.inputNode = createGain(); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix; + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - mix; + this.filterNode = context["createBiquadFilter"](); + if (typeof this.filterNode["type"] === "number") + this.filterNode["type"] = type; + else + this.filterNode["type"] = filterTypes[type]; + this.filterNode["frequency"]["value"] = freq; + if (this.filterNode["detune"]) // iOS 6 doesn't have detune yet + this.filterNode["detune"]["value"] = detune; + this.filterNode["Q"]["value"] = q; + this.filterNode["gain"]["value"] = gain; + this.inputNode["connect"](this.filterNode); + this.inputNode["connect"](this.dryNode); + this.filterNode["connect"](this.wetNode); + }; + FilterEffect.prototype.connectTo = function (node) + { + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + }; + FilterEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.filterNode["disconnect"](); + this.wetNode["disconnect"](); + this.dryNode["disconnect"](); + }; + FilterEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + FilterEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[5] = value; + setAudioParam(this.wetNode["gain"], value, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - value, ramp, time); + break; + case 1: // filter frequency + this.params[1] = value; + setAudioParam(this.filterNode["frequency"], value, ramp, time); + break; + case 2: // filter detune + this.params[2] = value; + setAudioParam(this.filterNode["detune"], value, ramp, time); + break; + case 3: // filter Q + this.params[3] = value; + setAudioParam(this.filterNode["Q"], value, ramp, time); + break; + case 4: // filter/delay gain (note value is in dB here) + this.params[4] = value; + setAudioParam(this.filterNode["gain"], value, ramp, time); + break; + } + }; + function DelayEffect(delayTime, delayGain, mix) + { + this.type = "delay"; + this.params = [delayTime, delayGain, mix]; + this.inputNode = createGain(); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix; + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - mix; + this.mainNode = createGain(); + this.delayNode = createDelay(delayTime); + this.delayNode["delayTime"]["value"] = delayTime; + this.delayGainNode = createGain(); + this.delayGainNode["gain"]["value"] = delayGain; + this.inputNode["connect"](this.mainNode); + this.inputNode["connect"](this.dryNode); + this.mainNode["connect"](this.wetNode); + this.mainNode["connect"](this.delayNode); + this.delayNode["connect"](this.delayGainNode); + this.delayGainNode["connect"](this.mainNode); + }; + DelayEffect.prototype.connectTo = function (node) + { + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + }; + DelayEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.mainNode["disconnect"](); + this.delayNode["disconnect"](); + this.delayGainNode["disconnect"](); + this.wetNode["disconnect"](); + this.dryNode["disconnect"](); + }; + DelayEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + DelayEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[2] = value; + setAudioParam(this.wetNode["gain"], value, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - value, ramp, time); + break; + case 4: // filter/delay gain (note value is passed in dB but needs to be linear here) + this.params[1] = dbToLinear(value); + setAudioParam(this.delayGainNode["gain"], dbToLinear(value), ramp, time); + break; + case 5: // delay time + this.params[0] = value; + setAudioParam(this.delayNode["delayTime"], value, ramp, time); + break; + } + }; + function ConvolveEffect(buffer, normalize, mix, src) + { + this.type = "convolve"; + this.params = [normalize, mix, src]; + this.inputNode = createGain(); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix; + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - mix; + this.convolveNode = context["createConvolver"](); + if (buffer) + { + this.convolveNode["normalize"] = normalize; + this.convolveNode["buffer"] = buffer; + } + this.inputNode["connect"](this.convolveNode); + this.inputNode["connect"](this.dryNode); + this.convolveNode["connect"](this.wetNode); + }; + ConvolveEffect.prototype.connectTo = function (node) + { + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + }; + ConvolveEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.convolveNode["disconnect"](); + this.wetNode["disconnect"](); + this.dryNode["disconnect"](); + }; + ConvolveEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + ConvolveEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[1] = value; + setAudioParam(this.wetNode["gain"], value, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - value, ramp, time); + break; + } + }; + function FlangerEffect(delay, modulation, freq, feedback, mix) + { + this.type = "flanger"; + this.params = [delay, modulation, freq, feedback, mix]; + this.inputNode = createGain(); + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - (mix / 2); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix / 2; + this.feedbackNode = createGain(); + this.feedbackNode["gain"]["value"] = feedback; + this.delayNode = createDelay(delay + modulation); + this.delayNode["delayTime"]["value"] = delay; + this.oscNode = context["createOscillator"](); + this.oscNode["frequency"]["value"] = freq; + this.oscGainNode = createGain(); + this.oscGainNode["gain"]["value"] = modulation; + this.inputNode["connect"](this.delayNode); + this.inputNode["connect"](this.dryNode); + this.delayNode["connect"](this.wetNode); + this.delayNode["connect"](this.feedbackNode); + this.feedbackNode["connect"](this.delayNode); + this.oscNode["connect"](this.oscGainNode); + this.oscGainNode["connect"](this.delayNode["delayTime"]); + startSource(this.oscNode); + }; + FlangerEffect.prototype.connectTo = function (node) + { + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + }; + FlangerEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.delayNode["disconnect"](); + this.oscNode["disconnect"](); + this.oscGainNode["disconnect"](); + this.dryNode["disconnect"](); + this.wetNode["disconnect"](); + this.feedbackNode["disconnect"](); + }; + FlangerEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + FlangerEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[4] = value; + setAudioParam(this.wetNode["gain"], value / 2, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - (value / 2), ramp, time); + break; + case 6: // modulation + this.params[1] = value / 1000; + setAudioParam(this.oscGainNode["gain"], value / 1000, ramp, time); + break; + case 7: // modulation frequency + this.params[2] = value; + setAudioParam(this.oscNode["frequency"], value, ramp, time); + break; + case 8: // feedback + this.params[3] = value / 100; + setAudioParam(this.feedbackNode["gain"], value / 100, ramp, time); + break; + } + }; + function PhaserEffect(freq, detune, q, modulation, modfreq, mix) + { + this.type = "phaser"; + this.params = [freq, detune, q, modulation, modfreq, mix]; + this.inputNode = createGain(); + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - (mix / 2); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix / 2; + this.filterNode = context["createBiquadFilter"](); + if (typeof this.filterNode["type"] === "number") + this.filterNode["type"] = 7; // all-pass + else + this.filterNode["type"] = "allpass"; + this.filterNode["frequency"]["value"] = freq; + if (this.filterNode["detune"]) // iOS 6 doesn't have detune yet + this.filterNode["detune"]["value"] = detune; + this.filterNode["Q"]["value"] = q; + this.oscNode = context["createOscillator"](); + this.oscNode["frequency"]["value"] = modfreq; + this.oscGainNode = createGain(); + this.oscGainNode["gain"]["value"] = modulation; + this.inputNode["connect"](this.filterNode); + this.inputNode["connect"](this.dryNode); + this.filterNode["connect"](this.wetNode); + this.oscNode["connect"](this.oscGainNode); + this.oscGainNode["connect"](this.filterNode["frequency"]); + startSource(this.oscNode); + }; + PhaserEffect.prototype.connectTo = function (node) + { + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + }; + PhaserEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.filterNode["disconnect"](); + this.oscNode["disconnect"](); + this.oscGainNode["disconnect"](); + this.dryNode["disconnect"](); + this.wetNode["disconnect"](); + }; + PhaserEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + PhaserEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[5] = value; + setAudioParam(this.wetNode["gain"], value / 2, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - (value / 2), ramp, time); + break; + case 1: // filter frequency + this.params[0] = value; + setAudioParam(this.filterNode["frequency"], value, ramp, time); + break; + case 2: // filter detune + this.params[1] = value; + setAudioParam(this.filterNode["detune"], value, ramp, time); + break; + case 3: // filter Q + this.params[2] = value; + setAudioParam(this.filterNode["Q"], value, ramp, time); + break; + case 6: // modulation + this.params[3] = value; + setAudioParam(this.oscGainNode["gain"], value, ramp, time); + break; + case 7: // modulation frequency + this.params[4] = value; + setAudioParam(this.oscNode["frequency"], value, ramp, time); + break; + } + }; + function GainEffect(g) + { + this.type = "gain"; + this.params = [g]; + this.node = createGain(); + this.node["gain"]["value"] = g; + }; + GainEffect.prototype.connectTo = function (node_) + { + this.node["disconnect"](); + this.node["connect"](node_); + }; + GainEffect.prototype.remove = function () + { + this.node["disconnect"](); + }; + GainEffect.prototype.getInputNode = function () + { + return this.node; + }; + GainEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 4: // gain + this.params[0] = dbToLinear(value); + setAudioParam(this.node["gain"], dbToLinear(value), ramp, time); + break; + } + }; + function TremoloEffect(freq, mix) + { + this.type = "tremolo"; + this.params = [freq, mix]; + this.node = createGain(); + this.node["gain"]["value"] = 1 - (mix / 2); + this.oscNode = context["createOscillator"](); + this.oscNode["frequency"]["value"] = freq; + this.oscGainNode = createGain(); + this.oscGainNode["gain"]["value"] = mix / 2; + this.oscNode["connect"](this.oscGainNode); + this.oscGainNode["connect"](this.node["gain"]); + startSource(this.oscNode); + }; + TremoloEffect.prototype.connectTo = function (node_) + { + this.node["disconnect"](); + this.node["connect"](node_); + }; + TremoloEffect.prototype.remove = function () + { + this.oscNode["disconnect"](); + this.oscGainNode["disconnect"](); + this.node["disconnect"](); + }; + TremoloEffect.prototype.getInputNode = function () + { + return this.node; + }; + TremoloEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[1] = value; + setAudioParam(this.node["gain"]["value"], 1 - (value / 2), ramp, time); + setAudioParam(this.oscGainNode["gain"]["value"], value / 2, ramp, time); + break; + case 7: // modulation frequency + this.params[0] = value; + setAudioParam(this.oscNode["frequency"], value, ramp, time); + break; + } + }; + function RingModulatorEffect(freq, mix) + { + this.type = "ringmod"; + this.params = [freq, mix]; + this.inputNode = createGain(); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix; + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - mix; + this.ringNode = createGain(); + this.ringNode["gain"]["value"] = 0; + this.oscNode = context["createOscillator"](); + this.oscNode["frequency"]["value"] = freq; + this.oscNode["connect"](this.ringNode["gain"]); + startSource(this.oscNode); + this.inputNode["connect"](this.ringNode); + this.inputNode["connect"](this.dryNode); + this.ringNode["connect"](this.wetNode); + }; + RingModulatorEffect.prototype.connectTo = function (node_) + { + this.wetNode["disconnect"](); + this.wetNode["connect"](node_); + this.dryNode["disconnect"](); + this.dryNode["connect"](node_); + }; + RingModulatorEffect.prototype.remove = function () + { + this.oscNode["disconnect"](); + this.ringNode["disconnect"](); + this.inputNode["disconnect"](); + this.wetNode["disconnect"](); + this.dryNode["disconnect"](); + }; + RingModulatorEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + RingModulatorEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[1] = value; + setAudioParam(this.wetNode["gain"], value, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - value, ramp, time); + break; + case 7: // modulation frequency + this.params[0] = value; + setAudioParam(this.oscNode["frequency"], value, ramp, time); + break; + } + }; + function DistortionEffect(threshold, headroom, drive, makeupgain, mix) + { + this.type = "distortion"; + this.params = [threshold, headroom, drive, makeupgain, mix]; + this.inputNode = createGain(); + this.preGain = createGain(); + this.postGain = createGain(); + this.setDrive(drive, dbToLinear_nocap(makeupgain)); + this.wetNode = createGain(); + this.wetNode["gain"]["value"] = mix; + this.dryNode = createGain(); + this.dryNode["gain"]["value"] = 1 - mix; + this.waveShaper = context["createWaveShaper"](); + this.curve = new Float32Array(65536); + this.generateColortouchCurve(threshold, headroom); + this.waveShaper.curve = this.curve; + this.inputNode["connect"](this.preGain); + this.inputNode["connect"](this.dryNode); + this.preGain["connect"](this.waveShaper); + this.waveShaper["connect"](this.postGain); + this.postGain["connect"](this.wetNode); + }; + DistortionEffect.prototype.setDrive = function (drive, makeupgain) + { + if (drive < 0.01) + drive = 0.01; + this.preGain["gain"]["value"] = drive; + this.postGain["gain"]["value"] = Math.pow(1 / drive, 0.6) * makeupgain; + }; + function e4(x, k) + { + return 1.0 - Math.exp(-k * x); + } + DistortionEffect.prototype.shape = function (x, linearThreshold, linearHeadroom) + { + var maximum = 1.05 * linearHeadroom * linearThreshold; + var kk = (maximum - linearThreshold); + var sign = x < 0 ? -1 : +1; + var absx = x < 0 ? -x : x; + var shapedInput = absx < linearThreshold ? absx : linearThreshold + kk * e4(absx - linearThreshold, 1.0 / kk); + shapedInput *= sign; + return shapedInput; + }; + DistortionEffect.prototype.generateColortouchCurve = function (threshold, headroom) + { + var linearThreshold = dbToLinear_nocap(threshold); + var linearHeadroom = dbToLinear_nocap(headroom); + var n = 65536; + var n2 = n / 2; + var x = 0; + for (var i = 0; i < n2; ++i) { + x = i / n2; + x = this.shape(x, linearThreshold, linearHeadroom); + this.curve[n2 + i] = x; + this.curve[n2 - i - 1] = -x; + } + }; + DistortionEffect.prototype.connectTo = function (node) + { + this.wetNode["disconnect"](); + this.wetNode["connect"](node); + this.dryNode["disconnect"](); + this.dryNode["connect"](node); + }; + DistortionEffect.prototype.remove = function () + { + this.inputNode["disconnect"](); + this.preGain["disconnect"](); + this.waveShaper["disconnect"](); + this.postGain["disconnect"](); + this.wetNode["disconnect"](); + this.dryNode["disconnect"](); + }; + DistortionEffect.prototype.getInputNode = function () + { + return this.inputNode; + }; + DistortionEffect.prototype.setParam = function(param, value, ramp, time) + { + switch (param) { + case 0: // mix + value = value / 100; + if (value < 0) value = 0; + if (value > 1) value = 1; + this.params[4] = value; + setAudioParam(this.wetNode["gain"], value, ramp, time); + setAudioParam(this.dryNode["gain"], 1 - value, ramp, time); + break; + } + }; + function CompressorEffect(threshold, knee, ratio, attack, release) + { + this.type = "compressor"; + this.params = [threshold, knee, ratio, attack, release]; + this.node = context["createDynamicsCompressor"](); + try { + this.node["threshold"]["value"] = threshold; + this.node["knee"]["value"] = knee; + this.node["ratio"]["value"] = ratio; + this.node["attack"]["value"] = attack; + this.node["release"]["value"] = release; + } + catch (e) {} + }; + CompressorEffect.prototype.connectTo = function (node_) + { + this.node["disconnect"](); + this.node["connect"](node_); + }; + CompressorEffect.prototype.remove = function () + { + this.node["disconnect"](); + }; + CompressorEffect.prototype.getInputNode = function () + { + return this.node; + }; + CompressorEffect.prototype.setParam = function(param, value, ramp, time) + { + }; + function AnalyserEffect(fftSize, smoothing) + { + this.type = "analyser"; + this.params = [fftSize, smoothing]; + this.node = context["createAnalyser"](); + this.node["fftSize"] = fftSize; + this.node["smoothingTimeConstant"] = smoothing; + this.freqBins = new Float32Array(this.node["frequencyBinCount"]); + this.signal = new Uint8Array(fftSize); + this.peak = 0; + this.rms = 0; + }; + AnalyserEffect.prototype.tick = function () + { + this.node["getFloatFrequencyData"](this.freqBins); + this.node["getByteTimeDomainData"](this.signal); + var fftSize = this.node["fftSize"]; + var i = 0; + this.peak = 0; + var rmsSquaredSum = 0; + var s = 0; + for ( ; i < fftSize; i++) + { + s = (this.signal[i] - 128) / 128; + if (s < 0) + s = -s; + if (this.peak < s) + this.peak = s; + rmsSquaredSum += s * s; + } + this.peak = linearToDb(this.peak); + this.rms = linearToDb(Math.sqrt(rmsSquaredSum / fftSize)); + }; + AnalyserEffect.prototype.connectTo = function (node_) + { + this.node["disconnect"](); + this.node["connect"](node_); + }; + AnalyserEffect.prototype.remove = function () + { + this.node["disconnect"](); + }; + AnalyserEffect.prototype.getInputNode = function () + { + return this.node; + }; + AnalyserEffect.prototype.setParam = function(param, value, ramp, time) + { + }; + function ObjectTracker() + { + this.obj = null; + this.loadUid = 0; + }; + ObjectTracker.prototype.setObject = function (obj_) + { + this.obj = obj_; + }; + ObjectTracker.prototype.hasObject = function () + { + return !!this.obj; + }; + ObjectTracker.prototype.tick = function (dt) + { + }; + function C2AudioBuffer(src_, is_music) + { + this.src = src_; + this.myapi = api; + this.is_music = is_music; + this.added_end_listener = false; + var self = this; + this.outNode = null; + this.mediaSourceNode = null; + this.panWhenReady = []; // for web audio API positioned sounds + this.seekWhenReady = 0; + this.pauseWhenReady = false; + this.supportWebAudioAPI = false; + this.failedToLoad = false; + this.wasEverReady = false; // if a buffer is ever marked as ready, it's permanently considered ready after then. + if (api === API_WEBAUDIO && is_music && !playMusicAsSoundWorkaround) + { + this.myapi = API_HTML5; + this.outNode = createGain(); + } + this.bufferObject = null; // actual audio object + this.audioData = null; // web audio api: ajax request result (compressed audio that needs decoding) + var request; + switch (this.myapi) { + case API_HTML5: + this.bufferObject = new Audio(); + this.bufferObject.crossOrigin = "anonymous"; + this.bufferObject.addEventListener("canplaythrough", function () { + self.wasEverReady = true; // update loaded state so preload is considered complete + }); + if (api === API_WEBAUDIO && context["createMediaElementSource"] && !/wiiu/i.test(navigator.userAgent)) + { + this.supportWebAudioAPI = true; // can be routed through web audio api + this.bufferObject.addEventListener("canplay", function () + { + if (!self.mediaSourceNode && self.bufferObject) + { + self.mediaSourceNode = context["createMediaElementSource"](self.bufferObject); + self.mediaSourceNode["connect"](self.outNode); + } + }); + } + this.bufferObject.autoplay = false; // this is only a source buffer, not an instance + this.bufferObject.preload = "auto"; + this.bufferObject.src = src_; + break; + case API_WEBAUDIO: + if (audRuntime.isWKWebView) + { + audRuntime.fetchLocalFileViaCordovaAsArrayBuffer(src_, function (arrayBuffer) + { + self.audioData = arrayBuffer; + self.decodeAudioBuffer(); + }, function (err) + { + self.failedToLoad = true; + }); + } + else + { + request = new XMLHttpRequest(); + request.open("GET", src_, true); + request.responseType = "arraybuffer"; + request.onload = function () { + self.audioData = request.response; + self.decodeAudioBuffer(); + }; + request.onerror = function () { + self.failedToLoad = true; + }; + request.send(); + } + break; + case API_CORDOVA: + this.bufferObject = true; + break; + case API_APPMOBI: + this.bufferObject = true; + break; + } + }; + C2AudioBuffer.prototype.release = function () + { + var i, len, j, a; + for (i = 0, j = 0, len = audioInstances.length; i < len; ++i) + { + a = audioInstances[i]; + audioInstances[j] = a; + if (a.buffer === this) + a.stop(); + else + ++j; // keep + } + audioInstances.length = j; + if (this.mediaSourceNode) + { + this.mediaSourceNode["disconnect"](); + this.mediaSourceNode = null; + } + if (this.outNode) + { + this.outNode["disconnect"](); + this.outNode = null; + } + this.bufferObject = null; + this.audioData = null; + }; + C2AudioBuffer.prototype.decodeAudioBuffer = function () + { + if (this.bufferObject || !this.audioData) + return; // audio already decoded or AJAX request not yet complete + var self = this; + if (context["decodeAudioData"]) + { + context["decodeAudioData"](this.audioData, function (buffer) { + self.bufferObject = buffer; + self.audioData = null; // clear AJAX response to allow GC and save memory, only need the bufferObject now + var p, i, len, a; + if (!cr.is_undefined(self.playTagWhenReady) && !silent) + { + if (self.panWhenReady.length) + { + for (i = 0, len = self.panWhenReady.length; i < len; i++) + { + p = self.panWhenReady[i]; + a = new C2AudioInstance(self, p.thistag); + a.setPannerEnabled(true); + if (typeof p.objUid !== "undefined") + { + p.obj = audRuntime.getObjectByUID(p.objUid); + if (!p.obj) + continue; + } + if (p.obj) + { + var px = cr.rotatePtAround(p.obj.x, p.obj.y, -p.obj.layer.getAngle(), listenerX, listenerY, true); + var py = cr.rotatePtAround(p.obj.x, p.obj.y, -p.obj.layer.getAngle(), listenerX, listenerY, false); + a.setPan(px, py, cr.to_degrees(p.obj.angle - p.obj.layer.getAngle()), p.ia, p.oa, p.og); + a.setObject(p.obj); + } + else + { + a.setPan(p.x, p.y, p.a, p.ia, p.oa, p.og); + } + a.play(self.loopWhenReady, self.volumeWhenReady, self.seekWhenReady); + if (self.pauseWhenReady) + a.pause(); + audioInstances.push(a); + } + cr.clearArray(self.panWhenReady); + } + else + { + a = new C2AudioInstance(self, self.playTagWhenReady || ""); // sometimes playTagWhenReady is not set - TODO: why? + a.play(self.loopWhenReady, self.volumeWhenReady, self.seekWhenReady); + if (self.pauseWhenReady) + a.pause(); + audioInstances.push(a); + } + } + else if (!cr.is_undefined(self.convolveWhenReady)) + { + var convolveNode = self.convolveWhenReady.convolveNode; + convolveNode["normalize"] = self.normalizeWhenReady; + convolveNode["buffer"] = buffer; + } + }, function (e) { + self.failedToLoad = true; + }); + } + else + { + this.bufferObject = context["createBuffer"](this.audioData, false); + this.audioData = null; // clear AJAX response to allow GC and save memory, only need the bufferObject now + if (!cr.is_undefined(this.playTagWhenReady) && !silent) + { + var a = new C2AudioInstance(this, this.playTagWhenReady); + a.play(this.loopWhenReady, this.volumeWhenReady, this.seekWhenReady); + if (this.pauseWhenReady) + a.pause(); + audioInstances.push(a); + } + else if (!cr.is_undefined(this.convolveWhenReady)) + { + var convolveNode = this.convolveWhenReady.convolveNode; + convolveNode["normalize"] = this.normalizeWhenReady; + convolveNode["buffer"] = this.bufferObject; + } + } + }; + C2AudioBuffer.prototype.isLoaded = function () + { + switch (this.myapi) { + case API_HTML5: + var ret = this.bufferObject["readyState"] >= 4; // HAVE_ENOUGH_DATA + if (ret) + this.wasEverReady = true; + return ret || this.wasEverReady; + case API_WEBAUDIO: + return !!this.audioData || !!this.bufferObject; + case API_CORDOVA: + return true; + case API_APPMOBI: + return true; + } + return false; + }; + C2AudioBuffer.prototype.isLoadedAndDecoded = function () + { + switch (this.myapi) { + case API_HTML5: + return this.isLoaded(); // no distinction between loaded and decoded in HTML5 audio, just rely on ready state + case API_WEBAUDIO: + return !!this.bufferObject; + case API_CORDOVA: + return true; + case API_APPMOBI: + return true; + } + return false; + }; + C2AudioBuffer.prototype.hasFailedToLoad = function () + { + switch (this.myapi) { + case API_HTML5: + return !!this.bufferObject["error"]; + case API_WEBAUDIO: + return this.failedToLoad; + } + return false; + }; + function C2AudioInstance(buffer_, tag_) + { + var self = this; + this.tag = tag_; + this.fresh = true; + this.stopped = true; + this.src = buffer_.src; + this.buffer = buffer_; + this.myapi = api; + this.is_music = buffer_.is_music; + this.playbackRate = 1; + this.hasPlaybackEnded = true; // ended flag + this.resume_me = false; // make sure resumes when leaving suspend + this.is_paused = false; + this.resume_position = 0; // for web audio api to resume from correct playback position + this.looping = false; + this.is_muted = false; + this.is_silent = false; + this.volume = 1; + this.onended_handler = function (e) + { + if (self.is_paused || self.resume_me) + return; + var bufferThatEnded = this; + if (!bufferThatEnded) + bufferThatEnded = e.target; + if (bufferThatEnded !== self.active_buffer) + return; + self.hasPlaybackEnded = true; + self.stopped = true; + audTag = self.tag; + audRuntime.trigger(cr.plugins_.Audio.prototype.cnds.OnEnded, audInst); + }; + this.active_buffer = null; + this.isTimescaled = ((timescale_mode === 1 && !this.is_music) || timescale_mode === 2); + this.mutevol = 1; + this.startTime = (this.isTimescaled ? audRuntime.kahanTime.sum : audRuntime.wallTime.sum); + this.gainNode = null; + this.pannerNode = null; + this.pannerEnabled = false; + this.objectTracker = null; + this.panX = 0; + this.panY = 0; + this.panAngle = 0; + this.panConeInner = 0; + this.panConeOuter = 0; + this.panConeOuterGain = 0; + this.instanceObject = null; + var add_end_listener = false; + if (this.myapi === API_WEBAUDIO && this.buffer.myapi === API_HTML5 && !this.buffer.supportWebAudioAPI) + this.myapi = API_HTML5; + switch (this.myapi) { + case API_HTML5: + if (this.is_music) + { + this.instanceObject = buffer_.bufferObject; + add_end_listener = !buffer_.added_end_listener; + buffer_.added_end_listener = true; + } + else + { + this.instanceObject = new Audio(); + this.instanceObject.crossOrigin = "anonymous"; + this.instanceObject.autoplay = false; + this.instanceObject.src = buffer_.bufferObject.src; + add_end_listener = true; + } + if (add_end_listener) + { + this.instanceObject.addEventListener('ended', function () { + audTag = self.tag; + self.stopped = true; + audRuntime.trigger(cr.plugins_.Audio.prototype.cnds.OnEnded, audInst); + }); + } + break; + case API_WEBAUDIO: + this.gainNode = createGain(); + this.gainNode["connect"](getDestinationForTag(tag_)); + if (this.buffer.myapi === API_WEBAUDIO) + { + if (buffer_.bufferObject) + { + this.instanceObject = context["createBufferSource"](); + this.instanceObject["buffer"] = buffer_.bufferObject; + this.instanceObject["connect"](this.gainNode); + } + } + else + { + this.instanceObject = this.buffer.bufferObject; // reference the audio element + this.buffer.outNode["connect"](this.gainNode); + if (!this.buffer.added_end_listener) + { + this.buffer.added_end_listener = true; + this.buffer.bufferObject.addEventListener('ended', function () { + audTag = self.tag; + self.stopped = true; + audRuntime.trigger(cr.plugins_.Audio.prototype.cnds.OnEnded, audInst); + }); + } + } + break; + case API_CORDOVA: + this.instanceObject = new window["Media"](appPath + this.src, null, null, function (status) { + if (status === window["Media"]["MEDIA_STOPPED"]) + { + self.hasPlaybackEnded = true; + self.stopped = true; + audTag = self.tag; + audRuntime.trigger(cr.plugins_.Audio.prototype.cnds.OnEnded, audInst); + } + }); + break; + case API_APPMOBI: + this.instanceObject = true; + break; + } + }; + C2AudioInstance.prototype.hasEnded = function () + { + var time; + switch (this.myapi) { + case API_HTML5: + return this.instanceObject.ended; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + if (!this.fresh && !this.stopped && this.instanceObject["loop"]) + return false; + if (this.is_paused) + return false; + return this.hasPlaybackEnded; + } + else + return this.instanceObject.ended; + case API_CORDOVA: + return this.hasPlaybackEnded; + case API_APPMOBI: + true; // recycling an AppMobi sound does not matter because it will just do another throwaway playSound + } + return true; + }; + C2AudioInstance.prototype.canBeRecycled = function () + { + if (this.fresh || this.stopped) + return true; // not yet used or is not playing + return this.hasEnded(); + }; + C2AudioInstance.prototype.setPannerEnabled = function (enable_) + { + if (api !== API_WEBAUDIO) + return; + if (!this.pannerEnabled && enable_) + { + if (!this.gainNode) + return; + if (!this.pannerNode) + { + this.pannerNode = context["createPanner"](); + if (typeof this.pannerNode["panningModel"] === "number") + this.pannerNode["panningModel"] = panningModel; + else + this.pannerNode["panningModel"] = ["equalpower", "HRTF", "soundfield"][panningModel]; + if (typeof this.pannerNode["distanceModel"] === "number") + this.pannerNode["distanceModel"] = distanceModel; + else + this.pannerNode["distanceModel"] = ["linear", "inverse", "exponential"][distanceModel]; + this.pannerNode["refDistance"] = refDistance; + this.pannerNode["maxDistance"] = maxDistance; + this.pannerNode["rolloffFactor"] = rolloffFactor; + } + this.gainNode["disconnect"](); + this.gainNode["connect"](this.pannerNode); + this.pannerNode["connect"](getDestinationForTag(this.tag)); + this.pannerEnabled = true; + } + else if (this.pannerEnabled && !enable_) + { + if (!this.gainNode) + return; + this.pannerNode["disconnect"](); + this.gainNode["disconnect"](); + this.gainNode["connect"](getDestinationForTag(this.tag)); + this.pannerEnabled = false; + } + }; + C2AudioInstance.prototype.setPan = function (x, y, angle, innerangle, outerangle, outergain) + { + if (!this.pannerEnabled || api !== API_WEBAUDIO) + return; + this.pannerNode["setPosition"](x, y, 0); + this.pannerNode["setOrientation"](Math.cos(cr.to_radians(angle)), Math.sin(cr.to_radians(angle)), 0); + this.pannerNode["coneInnerAngle"] = innerangle; + this.pannerNode["coneOuterAngle"] = outerangle; + this.pannerNode["coneOuterGain"] = outergain; + this.panX = x; + this.panY = y; + this.panAngle = angle; + this.panConeInner = innerangle; + this.panConeOuter = outerangle; + this.panConeOuterGain = outergain; + }; + C2AudioInstance.prototype.setObject = function (o) + { + if (!this.pannerEnabled || api !== API_WEBAUDIO) + return; + if (!this.objectTracker) + this.objectTracker = new ObjectTracker(); + this.objectTracker.setObject(o); + }; + C2AudioInstance.prototype.tick = function (dt) + { + if (!this.pannerEnabled || api !== API_WEBAUDIO || !this.objectTracker || !this.objectTracker.hasObject() || !this.isPlaying()) + { + return; + } + this.objectTracker.tick(dt); + var inst = this.objectTracker.obj; + var px = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, true); + var py = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, false); + this.pannerNode["setPosition"](px, py, 0); + var a = 0; + if (typeof this.objectTracker.obj.angle !== "undefined") + { + a = inst.angle - inst.layer.getAngle(); + this.pannerNode["setOrientation"](Math.cos(a), Math.sin(a), 0); + } + }; + C2AudioInstance.prototype.play = function (looping, vol, fromPosition, scheduledTime) + { + var instobj = this.instanceObject; + this.looping = looping; + this.volume = vol; + var seekPos = fromPosition || 0; + scheduledTime = scheduledTime || 0; + switch (this.myapi) { + case API_HTML5: + if (instobj.playbackRate !== 1.0) + instobj.playbackRate = 1.0; + if (instobj.volume !== vol * masterVolume) + instobj.volume = vol * masterVolume; + if (instobj.loop !== looping) + instobj.loop = looping; + if (instobj.muted) + instobj.muted = false; + if (instobj.currentTime !== seekPos) + { + try { + instobj.currentTime = seekPos; + } + catch (err) + { +; + } + } + tryPlayAudioElement(this); + break; + case API_WEBAUDIO: + this.muted = false; + this.mutevol = 1; + if (this.buffer.myapi === API_WEBAUDIO) + { + this.gainNode["gain"]["value"] = vol * masterVolume; + if (!this.fresh) + { + this.instanceObject = context["createBufferSource"](); + this.instanceObject["buffer"] = this.buffer.bufferObject; + this.instanceObject["connect"](this.gainNode); + } + this.instanceObject["onended"] = this.onended_handler; + this.active_buffer = this.instanceObject; + this.instanceObject.loop = looping; + this.hasPlaybackEnded = false; + if (seekPos === 0) + startSource(this.instanceObject, scheduledTime); + else + startSourceAt(this.instanceObject, seekPos, this.getDuration(), scheduledTime); + } + else + { + if (instobj.playbackRate !== 1.0) + instobj.playbackRate = 1.0; + if (instobj.loop !== looping) + instobj.loop = looping; + instobj.volume = vol * masterVolume; + if (instobj.currentTime !== seekPos) + { + try { + instobj.currentTime = seekPos; + } + catch (err) + { +; + } + } + tryPlayAudioElement(this); + } + break; + case API_CORDOVA: + if ((!this.fresh && this.stopped) || seekPos !== 0) + instobj["seekTo"](seekPos); + instobj["play"](); + this.hasPlaybackEnded = false; + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["playSound"](this.src, looping); + else + AppMobi["player"]["playSound"](this.src, looping); + break; + } + this.playbackRate = 1; + this.startTime = (this.isTimescaled ? audRuntime.kahanTime.sum : audRuntime.wallTime.sum) - seekPos; + this.fresh = false; + this.stopped = false; + this.is_paused = false; + }; + C2AudioInstance.prototype.stop = function () + { + switch (this.myapi) { + case API_HTML5: + if (!this.instanceObject.paused) + this.instanceObject.pause(); + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + stopSource(this.instanceObject); + else + { + if (!this.instanceObject.paused) + this.instanceObject.pause(); + } + break; + case API_CORDOVA: + this.instanceObject["stop"](); + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["stopSound"](this.src); + break; + } + this.stopped = true; + this.is_paused = false; + }; + C2AudioInstance.prototype.pause = function () + { + if (this.fresh || this.stopped || this.hasEnded() || this.is_paused) + return; + switch (this.myapi) { + case API_HTML5: + if (!this.instanceObject.paused) + this.instanceObject.pause(); + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + this.resume_position = this.getPlaybackTime(true); + if (this.looping) + this.resume_position = this.resume_position % this.getDuration(); + this.is_paused = true; + stopSource(this.instanceObject); + } + else + { + if (!this.instanceObject.paused) + this.instanceObject.pause(); + } + break; + case API_CORDOVA: + this.instanceObject["pause"](); + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["stopSound"](this.src); + break; + } + this.is_paused = true; + }; + C2AudioInstance.prototype.resume = function () + { + if (this.fresh || this.stopped || this.hasEnded() || !this.is_paused) + return; + switch (this.myapi) { + case API_HTML5: + tryPlayAudioElement(this); + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + this.instanceObject = context["createBufferSource"](); + this.instanceObject["buffer"] = this.buffer.bufferObject; + this.instanceObject["connect"](this.gainNode); + this.instanceObject["onended"] = this.onended_handler; + this.active_buffer = this.instanceObject; + this.instanceObject.loop = this.looping; + this.gainNode["gain"]["value"] = masterVolume * this.volume * this.mutevol; + this.updatePlaybackRate(); + this.startTime = (this.isTimescaled ? audRuntime.kahanTime.sum : audRuntime.wallTime.sum) - (this.resume_position / (this.playbackRate || 0.001)); + startSourceAt(this.instanceObject, this.resume_position, this.getDuration()); + } + else + { + tryPlayAudioElement(this); + } + break; + case API_CORDOVA: + this.instanceObject["play"](); + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["resumeSound"](this.src); + break; + } + this.is_paused = false; + }; + C2AudioInstance.prototype.seek = function (pos) + { + if (this.fresh || this.stopped || this.hasEnded()) + return; + switch (this.myapi) { + case API_HTML5: + try { + this.instanceObject.currentTime = pos; + } + catch (e) {} + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + if (this.is_paused) + this.resume_position = pos; + else + { + this.pause(); + this.resume_position = pos; + this.resume(); + } + } + else + { + try { + this.instanceObject.currentTime = pos; + } + catch (e) {} + } + break; + case API_CORDOVA: + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["seekSound"](this.src, pos); + break; + } + }; + C2AudioInstance.prototype.reconnect = function (toNode) + { + if (this.myapi !== API_WEBAUDIO) + return; + if (this.pannerEnabled) + { + this.pannerNode["disconnect"](); + this.pannerNode["connect"](toNode); + } + else + { + this.gainNode["disconnect"](); + this.gainNode["connect"](toNode); + } + }; + C2AudioInstance.prototype.getDuration = function (applyPlaybackRate) + { + var ret = 0; + switch (this.myapi) { + case API_HTML5: + if (typeof this.instanceObject.duration !== "undefined") + ret = this.instanceObject.duration; + break; + case API_WEBAUDIO: + ret = this.buffer.bufferObject["duration"]; + break; + case API_CORDOVA: + ret = this.instanceObject["getDuration"](); + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + ret = AppMobi["context"]["getDurationSound"](this.src); + break; + } + if (applyPlaybackRate) + ret /= (this.playbackRate || 0.001); // avoid divide-by-zero + return ret; + }; + C2AudioInstance.prototype.getPlaybackTime = function (applyPlaybackRate) + { + var duration = this.getDuration(); + var ret = 0; + switch (this.myapi) { + case API_HTML5: + if (typeof this.instanceObject.currentTime !== "undefined") + ret = this.instanceObject.currentTime; + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + if (this.is_paused) + return this.resume_position; + else + ret = (this.isTimescaled ? audRuntime.kahanTime.sum : audRuntime.wallTime.sum) - this.startTime; + } + else if (typeof this.instanceObject.currentTime !== "undefined") + ret = this.instanceObject.currentTime; + break; + case API_CORDOVA: + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + ret = AppMobi["context"]["getPlaybackTimeSound"](this.src); + break; + } + if (applyPlaybackRate) + ret *= this.playbackRate; + if (!this.looping && ret > duration) + ret = duration; + return ret; + }; + C2AudioInstance.prototype.isPlaying = function () + { + return !this.is_paused && !this.fresh && !this.stopped && !this.hasEnded(); + }; + C2AudioInstance.prototype.shouldSave = function () + { + return !this.fresh && !this.stopped && !this.hasEnded(); + }; + C2AudioInstance.prototype.setVolume = function (v) + { + this.volume = v; + this.updateVolume(); + }; + C2AudioInstance.prototype.updateVolume = function () + { + var volToSet = this.volume * masterVolume; + if (!isFinite(volToSet)) + volToSet = 0; // HTMLMediaElement throws if setting non-finite volume + switch (this.myapi) { + case API_HTML5: + if (typeof this.instanceObject.volume !== "undefined" && this.instanceObject.volume !== volToSet) + this.instanceObject.volume = volToSet; + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + this.gainNode["gain"]["value"] = volToSet * this.mutevol; + } + else + { + if (typeof this.instanceObject.volume !== "undefined" && this.instanceObject.volume !== volToSet) + this.instanceObject.volume = volToSet; + } + break; + case API_CORDOVA: + break; + case API_APPMOBI: + break; + } + }; + C2AudioInstance.prototype.getVolume = function () + { + return this.volume; + }; + C2AudioInstance.prototype.doSetMuted = function (m) + { + switch (this.myapi) { + case API_HTML5: + if (this.instanceObject.muted !== !!m) + this.instanceObject.muted = !!m; + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + this.mutevol = (m ? 0 : 1); + this.gainNode["gain"]["value"] = masterVolume * this.volume * this.mutevol; + } + else + { + if (this.instanceObject.muted !== !!m) + this.instanceObject.muted = !!m; + } + break; + case API_CORDOVA: + break; + case API_APPMOBI: + break; + } + }; + C2AudioInstance.prototype.setMuted = function (m) + { + this.is_muted = !!m; + this.doSetMuted(this.is_muted || this.is_silent); + }; + C2AudioInstance.prototype.setSilent = function (m) + { + this.is_silent = !!m; + this.doSetMuted(this.is_muted || this.is_silent); + }; + C2AudioInstance.prototype.setLooping = function (l) + { + this.looping = l; + switch (this.myapi) { + case API_HTML5: + if (this.instanceObject.loop !== !!l) + this.instanceObject.loop = !!l; + break; + case API_WEBAUDIO: + if (this.instanceObject.loop !== !!l) + this.instanceObject.loop = !!l; + break; + case API_CORDOVA: + break; + case API_APPMOBI: + if (audRuntime.isDirectCanvas) + AppMobi["context"]["setLoopingSound"](this.src, l); + break; + } + }; + C2AudioInstance.prototype.setPlaybackRate = function (r) + { + this.playbackRate = r; + this.updatePlaybackRate(); + }; + C2AudioInstance.prototype.updatePlaybackRate = function () + { + var r = this.playbackRate; + if (this.isTimescaled) + r *= audRuntime.timescale; + switch (this.myapi) { + case API_HTML5: + if (this.instanceObject.playbackRate !== r) + this.instanceObject.playbackRate = r; + break; + case API_WEBAUDIO: + if (this.buffer.myapi === API_WEBAUDIO) + { + if (this.instanceObject["playbackRate"]["value"] !== r) + this.instanceObject["playbackRate"]["value"] = r; + } + else + { + if (this.instanceObject.playbackRate !== r) + this.instanceObject.playbackRate = r; + } + break; + case API_CORDOVA: + break; + case API_APPMOBI: + break; + } + }; + C2AudioInstance.prototype.setSuspended = function (s) + { + switch (this.myapi) { + case API_HTML5: + if (s) + { + if (this.isPlaying()) + { + this.resume_me = true; + this.instanceObject["pause"](); + } + else + this.resume_me = false; + } + else + { + if (this.resume_me) + { + this.instanceObject["play"](); + this.resume_me = false; + } + } + break; + case API_WEBAUDIO: + if (s) + { + if (this.isPlaying()) + { + this.resume_me = true; + if (this.buffer.myapi === API_WEBAUDIO) + { + this.resume_position = this.getPlaybackTime(true); + if (this.looping) + this.resume_position = this.resume_position % this.getDuration(); + stopSource(this.instanceObject); + } + else + this.instanceObject["pause"](); + } + else + this.resume_me = false; + } + else + { + if (this.resume_me) + { + if (this.buffer.myapi === API_WEBAUDIO) + { + this.instanceObject = context["createBufferSource"](); + this.instanceObject["buffer"] = this.buffer.bufferObject; + this.instanceObject["connect"](this.gainNode); + this.instanceObject["onended"] = this.onended_handler; + this.active_buffer = this.instanceObject; + this.instanceObject.loop = this.looping; + this.gainNode["gain"]["value"] = masterVolume * this.volume * this.mutevol; + this.updatePlaybackRate(); + this.startTime = (this.isTimescaled ? audRuntime.kahanTime.sum : audRuntime.wallTime.sum) - (this.resume_position / (this.playbackRate || 0.001)); + startSourceAt(this.instanceObject, this.resume_position, this.getDuration()); + } + else + { + this.instanceObject["play"](); + } + this.resume_me = false; + } + } + break; + case API_CORDOVA: + if (s) + { + if (this.isPlaying()) + { + this.instanceObject["pause"](); + this.resume_me = true; + } + else + this.resume_me = false; + } + else + { + if (this.resume_me) + { + this.resume_me = false; + this.instanceObject["play"](); + } + } + break; + case API_APPMOBI: + break; + } + }; + pluginProto.Instance = function(type) + { + this.type = type; + this.runtime = type.runtime; + audRuntime = this.runtime; + audInst = this; + this.listenerTracker = null; + this.listenerZ = -600; + if (this.runtime.isWKWebView) + playMusicAsSoundWorkaround = true; + if ((this.runtime.isiOS || (this.runtime.isAndroid && (this.runtime.isChrome || this.runtime.isAndroidStockBrowser))) && !this.runtime.isCrosswalk && !this.runtime.isDomFree && !this.runtime.isAmazonWebApp && !playMusicAsSoundWorkaround) + { + useNextTouchWorkaround = true; + } + context = null; + if (typeof AudioContext !== "undefined") + { + api = API_WEBAUDIO; + context = new AudioContext(); + } + else if (typeof webkitAudioContext !== "undefined") + { + api = API_WEBAUDIO; + context = new webkitAudioContext(); + } + if (this.runtime.isiOS && context) + { + if (context.close) + context.close(); + if (typeof AudioContext !== "undefined") + context = new AudioContext(); + else if (typeof webkitAudioContext !== "undefined") + context = new webkitAudioContext(); + } + if (api !== API_WEBAUDIO) + { + if (this.runtime.isCordova && typeof window["Media"] !== "undefined") + api = API_CORDOVA; + else if (this.runtime.isAppMobi) + api = API_APPMOBI; + } + if (api === API_CORDOVA) + { + appPath = location.href; + var i = appPath.lastIndexOf("/"); + if (i > -1) + appPath = appPath.substr(0, i + 1); + appPath = appPath.replace("file://", ""); + } + if (this.runtime.isSafari && this.runtime.isWindows && typeof Audio === "undefined") + { + alert("It looks like you're using Safari for Windows without Quicktime. Audio cannot be played until Quicktime is installed."); + this.runtime.DestroyInstance(this); + } + else + { + if (this.runtime.isDirectCanvas) + useOgg = this.runtime.isAndroid; // AAC on iOS, OGG on Android + else + { + try { + useOgg = !!(new Audio().canPlayType('audio/ogg; codecs="vorbis"')) && + !this.runtime.isWindows10; + } + catch (e) + { + useOgg = false; + } + } + switch (api) { + case API_HTML5: +; + break; + case API_WEBAUDIO: +; + break; + case API_CORDOVA: +; + break; + case API_APPMOBI: +; + break; + default: +; + } + this.runtime.tickMe(this); + } + }; + var instanceProto = pluginProto.Instance.prototype; + instanceProto.onCreate = function () + { + this.runtime.audioInstance = this; + timescale_mode = this.properties[0]; // 0 = off, 1 = sounds only, 2 = all + this.saveload = this.properties[1]; // 0 = all, 1 = sounds only, 2 = music only, 3 = none + this.playinbackground = (this.properties[2] !== 0); + this.nextPlayTime = 0; + panningModel = this.properties[3]; // 0 = equalpower, 1 = hrtf, 3 = soundfield + distanceModel = this.properties[4]; // 0 = linear, 1 = inverse, 2 = exponential + this.listenerZ = -this.properties[5]; + refDistance = this.properties[6]; + maxDistance = this.properties[7]; + rolloffFactor = this.properties[8]; + this.listenerTracker = new ObjectTracker(); + var draw_width = (this.runtime.draw_width || this.runtime.width); + var draw_height = (this.runtime.draw_height || this.runtime.height); + if (api === API_WEBAUDIO) + { + context["listener"]["setPosition"](draw_width / 2, draw_height / 2, this.listenerZ); + context["listener"]["setOrientation"](0, 0, 1, 0, -1, 0); + window["c2OnAudioMicStream"] = function (localMediaStream, tag) + { + if (micSource) + micSource["disconnect"](); + micTag = tag.toLowerCase(); + micSource = context["createMediaStreamSource"](localMediaStream); + micSource["connect"](getDestinationForTag(micTag)); + }; + } + this.runtime.addSuspendCallback(function(s) + { + audInst.onSuspend(s); + }); + var self = this; + this.runtime.addDestroyCallback(function (inst) + { + self.onInstanceDestroyed(inst); + }); + }; + instanceProto.onInstanceDestroyed = function (inst) + { + var i, len, a; + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + if (a.objectTracker) + { + if (a.objectTracker.obj === inst) + { + a.objectTracker.obj = null; + if (a.pannerEnabled && a.isPlaying() && a.looping) + a.stop(); + } + } + } + if (this.listenerTracker.obj === inst) + this.listenerTracker.obj = null; + }; + instanceProto.saveToJSON = function () + { + var o = { + "silent": silent, + "masterVolume": masterVolume, + "listenerZ": this.listenerZ, + "listenerUid": this.listenerTracker.hasObject() ? this.listenerTracker.obj.uid : -1, + "playing": [], + "effects": {} + }; + var playingarr = o["playing"]; + var i, len, a, d, p, panobj, playbackTime; + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + if (!a.shouldSave()) + continue; // no need to save stopped sounds + if (this.saveload === 3) // not saving/loading any sounds/music + continue; + if (a.is_music && this.saveload === 1) // not saving/loading music + continue; + if (!a.is_music && this.saveload === 2) // not saving/loading sound + continue; + playbackTime = a.getPlaybackTime(); + if (a.looping) + playbackTime = playbackTime % a.getDuration(); + d = { + "tag": a.tag, + "buffersrc": a.buffer.src, + "is_music": a.is_music, + "playbackTime": playbackTime, + "volume": a.volume, + "looping": a.looping, + "muted": a.is_muted, + "playbackRate": a.playbackRate, + "paused": a.is_paused, + "resume_position": a.resume_position + }; + if (a.pannerEnabled) + { + d["pan"] = {}; + panobj = d["pan"]; + if (a.objectTracker && a.objectTracker.hasObject()) + { + panobj["objUid"] = a.objectTracker.obj.uid; + } + else + { + panobj["x"] = a.panX; + panobj["y"] = a.panY; + panobj["a"] = a.panAngle; + } + panobj["ia"] = a.panConeInner; + panobj["oa"] = a.panConeOuter; + panobj["og"] = a.panConeOuterGain; + } + playingarr.push(d); + } + var fxobj = o["effects"]; + var fxarr; + for (p in effects) + { + if (effects.hasOwnProperty(p)) + { + fxarr = []; + for (i = 0, len = effects[p].length; i < len; i++) + { + fxarr.push({ "type": effects[p][i].type, "params": effects[p][i].params }); + } + fxobj[p] = fxarr; + } + } + return o; + }; + var objectTrackerUidsToLoad = []; + instanceProto.loadFromJSON = function (o) + { + var setSilent = o["silent"]; + masterVolume = o["masterVolume"]; + this.listenerZ = o["listenerZ"]; + this.listenerTracker.setObject(null); + var listenerUid = o["listenerUid"]; + if (listenerUid !== -1) + { + this.listenerTracker.loadUid = listenerUid; + objectTrackerUidsToLoad.push(this.listenerTracker); + } + var playingarr = o["playing"]; + var i, len, d, src, is_music, tag, playbackTime, looping, vol, b, a, p, pan, panObjUid; + if (this.saveload !== 3) + { + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + if (a.is_music && this.saveload === 1) + continue; // only saving/loading sound: leave music playing + if (!a.is_music && this.saveload === 2) + continue; // only saving/loading music: leave sound playing + a.stop(); + } + } + var fxarr, fxtype, fxparams, fx; + for (p in effects) + { + if (effects.hasOwnProperty(p)) + { + for (i = 0, len = effects[p].length; i < len; i++) + effects[p][i].remove(); + } + } + cr.wipe(effects); + for (p in o["effects"]) + { + if (o["effects"].hasOwnProperty(p)) + { + fxarr = o["effects"][p]; + for (i = 0, len = fxarr.length; i < len; i++) + { + fxtype = fxarr[i]["type"]; + fxparams = fxarr[i]["params"]; + switch (fxtype) { + case "filter": + addEffectForTag(p, new FilterEffect(fxparams[0], fxparams[1], fxparams[2], fxparams[3], fxparams[4], fxparams[5])); + break; + case "delay": + addEffectForTag(p, new DelayEffect(fxparams[0], fxparams[1], fxparams[2])); + break; + case "convolve": + src = fxparams[2]; + b = this.getAudioBuffer(src, false); + if (b.bufferObject) + { + fx = new ConvolveEffect(b.bufferObject, fxparams[0], fxparams[1], src); + } + else + { + fx = new ConvolveEffect(null, fxparams[0], fxparams[1], src); + b.normalizeWhenReady = fxparams[0]; + b.convolveWhenReady = fx; + } + addEffectForTag(p, fx); + break; + case "flanger": + addEffectForTag(p, new FlangerEffect(fxparams[0], fxparams[1], fxparams[2], fxparams[3], fxparams[4])); + break; + case "phaser": + addEffectForTag(p, new PhaserEffect(fxparams[0], fxparams[1], fxparams[2], fxparams[3], fxparams[4], fxparams[5])); + break; + case "gain": + addEffectForTag(p, new GainEffect(fxparams[0])); + break; + case "tremolo": + addEffectForTag(p, new TremoloEffect(fxparams[0], fxparams[1])); + break; + case "ringmod": + addEffectForTag(p, new RingModulatorEffect(fxparams[0], fxparams[1])); + break; + case "distortion": + addEffectForTag(p, new DistortionEffect(fxparams[0], fxparams[1], fxparams[2], fxparams[3], fxparams[4])); + break; + case "compressor": + addEffectForTag(p, new CompressorEffect(fxparams[0], fxparams[1], fxparams[2], fxparams[3], fxparams[4])); + break; + case "analyser": + addEffectForTag(p, new AnalyserEffect(fxparams[0], fxparams[1])); + break; + } + } + } + } + for (i = 0, len = playingarr.length; i < len; i++) + { + if (this.saveload === 3) // not saving/loading any sounds/music + continue; + d = playingarr[i]; + src = d["buffersrc"]; + is_music = d["is_music"]; + tag = d["tag"]; + playbackTime = d["playbackTime"]; + looping = d["looping"]; + vol = d["volume"]; + pan = d["pan"]; + panObjUid = (pan && pan.hasOwnProperty("objUid")) ? pan["objUid"] : -1; + if (is_music && this.saveload === 1) // not saving/loading music + continue; + if (!is_music && this.saveload === 2) // not saving/loading sound + continue; + a = this.getAudioInstance(src, tag, is_music, looping, vol); + if (!a) + { + b = this.getAudioBuffer(src, is_music); + b.seekWhenReady = playbackTime; + b.pauseWhenReady = d["paused"]; + if (pan) + { + if (panObjUid !== -1) + { + b.panWhenReady.push({ objUid: panObjUid, ia: pan["ia"], oa: pan["oa"], og: pan["og"], thistag: tag }); + } + else + { + b.panWhenReady.push({ x: pan["x"], y: pan["y"], a: pan["a"], ia: pan["ia"], oa: pan["oa"], og: pan["og"], thistag: tag }); + } + } + continue; + } + a.resume_position = d["resume_position"]; + a.setPannerEnabled(!!pan); + a.play(looping, vol, playbackTime); + a.updatePlaybackRate(); + a.updateVolume(); + a.doSetMuted(a.is_muted || a.is_silent); + if (d["paused"]) + a.pause(); + if (d["muted"]) + a.setMuted(true); + a.doSetMuted(a.is_muted || a.is_silent); + if (pan) + { + if (panObjUid !== -1) + { + a.objectTracker = a.objectTracker || new ObjectTracker(); + a.objectTracker.loadUid = panObjUid; + objectTrackerUidsToLoad.push(a.objectTracker); + } + else + { + a.setPan(pan["x"], pan["y"], pan["a"], pan["ia"], pan["oa"], pan["og"]); + } + } + } + if (setSilent && !silent) // setting silent + { + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].setSilent(true); + silent = true; + } + else if (!setSilent && silent) // setting not silent + { + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].setSilent(false); + silent = false; + } + }; + instanceProto.afterLoad = function () + { + var i, len, ot, inst; + for (i = 0, len = objectTrackerUidsToLoad.length; i < len; i++) + { + ot = objectTrackerUidsToLoad[i]; + inst = this.runtime.getObjectByUID(ot.loadUid); + ot.setObject(inst); + ot.loadUid = -1; + if (inst) + { + listenerX = inst.x; + listenerY = inst.y; + } + } + cr.clearArray(objectTrackerUidsToLoad); + }; + instanceProto.onSuspend = function (s) + { + if (this.playinbackground) + return; + if (!s && context && context["resume"]) + { + context["resume"](); + isContextSuspended = false; + } + var i, len; + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].setSuspended(s); + if (s && context && context["suspend"]) + { + context["suspend"](); + isContextSuspended = true; + } + }; + instanceProto.tick = function () + { + var dt = this.runtime.dt; + var i, len, a; + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + a.tick(dt); + if (timescale_mode !== 0) + a.updatePlaybackRate(); + } + var p, arr, f; + for (p in effects) + { + if (effects.hasOwnProperty(p)) + { + arr = effects[p]; + for (i = 0, len = arr.length; i < len; i++) + { + f = arr[i]; + if (f.tick) + f.tick(); + } + } + } + if (api === API_WEBAUDIO && this.listenerTracker.hasObject()) + { + this.listenerTracker.tick(dt); + listenerX = this.listenerTracker.obj.x; + listenerY = this.listenerTracker.obj.y; + context["listener"]["setPosition"](this.listenerTracker.obj.x, this.listenerTracker.obj.y, this.listenerZ); + } + }; + var preload_list = []; + instanceProto.setPreloadList = function (arr) + { + var i, len, p, filename, size, isOgg; + var total_size = 0; + for (i = 0, len = arr.length; i < len; ++i) + { + p = arr[i]; + filename = p[0]; + size = p[1] * 2; + isOgg = (filename.length > 4 && filename.substr(filename.length - 4) === ".ogg"); + if ((isOgg && useOgg) || (!isOgg && !useOgg)) + { + preload_list.push({ + filename: filename, + size: size, + obj: null + }); + total_size += size; + } + } + return total_size; + }; + instanceProto.startPreloads = function () + { + var i, len, p, src; + for (i = 0, len = preload_list.length; i < len; ++i) + { + p = preload_list[i]; + src = this.runtime.files_subfolder + p.filename; + p.obj = this.getAudioBuffer(src, false); + } + }; + instanceProto.getPreloadedSize = function () + { + var completed = 0; + var i, len, p; + for (i = 0, len = preload_list.length; i < len; ++i) + { + p = preload_list[i]; + if (p.obj.isLoadedAndDecoded() || p.obj.hasFailedToLoad() || this.runtime.isDomFree || this.runtime.isAndroidStockBrowser) + { + completed += p.size; + } + else if (p.obj.isLoaded()) // downloaded but not decoded: only happens in Web Audio API, count as half-way progress + { + completed += Math.floor(p.size / 2); + } + }; + return completed; + }; + instanceProto.releaseAllMusicBuffers = function () + { + var i, len, j, b; + for (i = 0, j = 0, len = audioBuffers.length; i < len; ++i) + { + b = audioBuffers[i]; + audioBuffers[j] = b; + if (b.is_music) + b.release(); + else + ++j; // keep + } + audioBuffers.length = j; + }; + instanceProto.getAudioBuffer = function (src_, is_music, dont_create) + { + var i, len, a, ret = null, j, k, lenj, ai; + for (i = 0, len = audioBuffers.length; i < len; i++) + { + a = audioBuffers[i]; + if (a.src === src_) + { + ret = a; + break; + } + } + if (!ret && !dont_create) + { + if (playMusicAsSoundWorkaround && is_music) + this.releaseAllMusicBuffers(); + ret = new C2AudioBuffer(src_, is_music); + audioBuffers.push(ret); + } + return ret; + }; + instanceProto.getAudioInstance = function (src_, tag, is_music, looping, vol) + { + var i, len, a; + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + if (a.src === src_ && (a.canBeRecycled() || is_music)) + { + a.tag = tag; + return a; + } + } + var b = this.getAudioBuffer(src_, is_music); + if (!b.bufferObject) + { + if (tag !== "") + { + b.playTagWhenReady = tag; + b.loopWhenReady = looping; + b.volumeWhenReady = vol; + } + return null; + } + a = new C2AudioInstance(b, tag); + audioInstances.push(a); + return a; + }; + var taggedAudio = []; + function SortByIsPlaying(a, b) + { + var an = a.isPlaying() ? 1 : 0; + var bn = b.isPlaying() ? 1 : 0; + if (an === bn) + return 0; + else if (an < bn) + return 1; + else + return -1; + }; + function getAudioByTag(tag, sort_by_playing) + { + cr.clearArray(taggedAudio); + if (!tag.length) + { + if (!lastAudio || lastAudio.hasEnded()) + return; + else + { + cr.clearArray(taggedAudio); + taggedAudio[0] = lastAudio; + return; + } + } + var i, len, a; + for (i = 0, len = audioInstances.length; i < len; i++) + { + a = audioInstances[i]; + if (cr.equals_nocase(tag, a.tag)) + taggedAudio.push(a); + } + if (sort_by_playing) + taggedAudio.sort(SortByIsPlaying); + }; + function reconnectEffects(tag) + { + var i, len, arr, n, toNode = context["destination"]; + if (effects.hasOwnProperty(tag)) + { + arr = effects[tag]; + if (arr.length) + { + toNode = arr[0].getInputNode(); + for (i = 0, len = arr.length; i < len; i++) + { + n = arr[i]; + if (i + 1 === len) + n.connectTo(context["destination"]); + else + n.connectTo(arr[i + 1].getInputNode()); + } + } + } + getAudioByTag(tag); + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].reconnect(toNode); + if (micSource && micTag === tag) + { + micSource["disconnect"](); + micSource["connect"](toNode); + } + }; + function addEffectForTag(tag, fx) + { + if (!effects.hasOwnProperty(tag)) + effects[tag] = [fx]; + else + effects[tag].push(fx); + reconnectEffects(tag); + }; + function Cnds() {}; + Cnds.prototype.OnEnded = function (t) + { + return cr.equals_nocase(audTag, t); + }; + Cnds.prototype.PreloadsComplete = function () + { + var i, len; + for (i = 0, len = audioBuffers.length; i < len; i++) + { + if (!audioBuffers[i].isLoadedAndDecoded() && !audioBuffers[i].hasFailedToLoad()) + return false; + } + return true; + }; + Cnds.prototype.AdvancedAudioSupported = function () + { + return api === API_WEBAUDIO; + }; + Cnds.prototype.IsSilent = function () + { + return silent; + }; + Cnds.prototype.IsAnyPlaying = function () + { + var i, len; + for (i = 0, len = audioInstances.length; i < len; i++) + { + if (audioInstances[i].isPlaying()) + return true; + } + return false; + }; + Cnds.prototype.IsTagPlaying = function (tag) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + { + if (taggedAudio[i].isPlaying()) + return true; + } + return false; + }; + pluginProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.Play = function (file, looping, vol, tag) + { + if (silent) + return; + var v = dbToLinear(vol); + var is_music = file[1]; + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + return; + lastAudio.setPannerEnabled(false); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.PlayAtPosition = function (file, looping, vol, x_, y_, angle_, innerangle_, outerangle_, outergain_, tag) + { + if (silent) + return; + var v = dbToLinear(vol); + var is_music = file[1]; + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + { + var b = this.getAudioBuffer(src, is_music); + b.panWhenReady.push({ x: x_, y: y_, a: angle_, ia: innerangle_, oa: outerangle_, og: dbToLinear(outergain_), thistag: tag }); + return; + } + lastAudio.setPannerEnabled(true); + lastAudio.setPan(x_, y_, angle_, innerangle_, outerangle_, dbToLinear(outergain_)); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.PlayAtObject = function (file, looping, vol, obj, innerangle, outerangle, outergain, tag) + { + if (silent || !obj) + return; + var inst = obj.getFirstPicked(); + if (!inst) + return; + var v = dbToLinear(vol); + var is_music = file[1]; + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + { + var b = this.getAudioBuffer(src, is_music); + b.panWhenReady.push({ obj: inst, ia: innerangle, oa: outerangle, og: dbToLinear(outergain), thistag: tag }); + return; + } + lastAudio.setPannerEnabled(true); + var px = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, true); + var py = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, false); + lastAudio.setPan(px, py, cr.to_degrees(inst.angle - inst.layer.getAngle()), innerangle, outerangle, dbToLinear(outergain)); + lastAudio.setObject(inst); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.PlayByName = function (folder, filename, looping, vol, tag) + { + if (silent) + return; + var v = dbToLinear(vol); + var is_music = (folder === 1); + var src = this.runtime.files_subfolder + filename.toLowerCase() + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + return; + lastAudio.setPannerEnabled(false); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.PlayAtPositionByName = function (folder, filename, looping, vol, x_, y_, angle_, innerangle_, outerangle_, outergain_, tag) + { + if (silent) + return; + var v = dbToLinear(vol); + var is_music = (folder === 1); + var src = this.runtime.files_subfolder + filename.toLowerCase() + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + { + var b = this.getAudioBuffer(src, is_music); + b.panWhenReady.push({ x: x_, y: y_, a: angle_, ia: innerangle_, oa: outerangle_, og: dbToLinear(outergain_), thistag: tag }); + return; + } + lastAudio.setPannerEnabled(true); + lastAudio.setPan(x_, y_, angle_, innerangle_, outerangle_, dbToLinear(outergain_)); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.PlayAtObjectByName = function (folder, filename, looping, vol, obj, innerangle, outerangle, outergain, tag) + { + if (silent || !obj) + return; + var inst = obj.getFirstPicked(); + if (!inst) + return; + var v = dbToLinear(vol); + var is_music = (folder === 1); + var src = this.runtime.files_subfolder + filename.toLowerCase() + (useOgg ? ".ogg" : ".m4a"); + lastAudio = this.getAudioInstance(src, tag, is_music, looping!==0, v); + if (!lastAudio) + { + var b = this.getAudioBuffer(src, is_music); + b.panWhenReady.push({ obj: inst, ia: innerangle, oa: outerangle, og: dbToLinear(outergain), thistag: tag }); + return; + } + lastAudio.setPannerEnabled(true); + var px = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, true); + var py = cr.rotatePtAround(inst.x, inst.y, -inst.layer.getAngle(), listenerX, listenerY, false); + lastAudio.setPan(px, py, cr.to_degrees(inst.angle - inst.layer.getAngle()), innerangle, outerangle, dbToLinear(outergain)); + lastAudio.setObject(inst); + lastAudio.play(looping!==0, v, 0, this.nextPlayTime); + this.nextPlayTime = 0; + }; + Acts.prototype.SetLooping = function (tag, looping) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].setLooping(looping === 0); + }; + Acts.prototype.SetMuted = function (tag, muted) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].setMuted(muted === 0); + }; + Acts.prototype.SetVolume = function (tag, vol) + { + getAudioByTag(tag); + var v = dbToLinear(vol); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].setVolume(v); + }; + Acts.prototype.Preload = function (file) + { + if (silent) + return; + var is_music = file[1]; + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + if (api === API_APPMOBI) + { + if (this.runtime.isDirectCanvas) + AppMobi["context"]["loadSound"](src); + else + AppMobi["player"]["loadSound"](src); + return; + } + else if (api === API_CORDOVA) + { + return; + } + this.getAudioInstance(src, "", is_music, false); + }; + Acts.prototype.PreloadByName = function (folder, filename) + { + if (silent) + return; + var is_music = (folder === 1); + var src = this.runtime.files_subfolder + filename.toLowerCase() + (useOgg ? ".ogg" : ".m4a"); + if (api === API_APPMOBI) + { + if (this.runtime.isDirectCanvas) + AppMobi["context"]["loadSound"](src); + else + AppMobi["player"]["loadSound"](src); + return; + } + else if (api === API_CORDOVA) + { + return; + } + this.getAudioInstance(src, "", is_music, false); + }; + Acts.prototype.SetPlaybackRate = function (tag, rate) + { + getAudioByTag(tag); + if (rate < 0.0) + rate = 0; + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].setPlaybackRate(rate); + }; + Acts.prototype.Stop = function (tag) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + taggedAudio[i].stop(); + }; + Acts.prototype.StopAll = function () + { + var i, len; + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].stop(); + }; + Acts.prototype.SetPaused = function (tag, state) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + { + if (state === 0) + taggedAudio[i].pause(); + else + taggedAudio[i].resume(); + } + }; + Acts.prototype.Seek = function (tag, pos) + { + getAudioByTag(tag); + var i, len; + for (i = 0, len = taggedAudio.length; i < len; i++) + { + taggedAudio[i].seek(pos); + } + }; + Acts.prototype.SetSilent = function (s) + { + var i, len; + if (s === 2) // toggling + s = (silent ? 1 : 0); // choose opposite state + if (s === 0 && !silent) // setting silent + { + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].setSilent(true); + silent = true; + } + else if (s === 1 && silent) // setting not silent + { + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].setSilent(false); + silent = false; + } + }; + Acts.prototype.SetMasterVolume = function (vol) + { + masterVolume = dbToLinear(vol); + var i, len; + for (i = 0, len = audioInstances.length; i < len; i++) + audioInstances[i].updateVolume(); + }; + Acts.prototype.AddFilterEffect = function (tag, type, freq, detune, q, gain, mix) + { + if (api !== API_WEBAUDIO || type < 0 || type >= filterTypes.length || !context["createBiquadFilter"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new FilterEffect(type, freq, detune, q, gain, mix)); + }; + Acts.prototype.AddDelayEffect = function (tag, delay, gain, mix) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new DelayEffect(delay, dbToLinear(gain), mix)); + }; + Acts.prototype.AddFlangerEffect = function (tag, delay, modulation, freq, feedback, mix) + { + if (api !== API_WEBAUDIO || !context["createOscillator"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new FlangerEffect(delay / 1000, modulation / 1000, freq, feedback / 100, mix)); + }; + Acts.prototype.AddPhaserEffect = function (tag, freq, detune, q, mod, modfreq, mix) + { + if (api !== API_WEBAUDIO || !context["createOscillator"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new PhaserEffect(freq, detune, q, mod, modfreq, mix)); + }; + Acts.prototype.AddConvolutionEffect = function (tag, file, norm, mix) + { + if (api !== API_WEBAUDIO || !context["createConvolver"]) + return; + var doNormalize = (norm === 0); + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + var b = this.getAudioBuffer(src, false); + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + var fx; + if (b.bufferObject) + { + fx = new ConvolveEffect(b.bufferObject, doNormalize, mix, src); + } + else + { + fx = new ConvolveEffect(null, doNormalize, mix, src); + b.normalizeWhenReady = doNormalize; + b.convolveWhenReady = fx; + } + addEffectForTag(tag, fx); + }; + Acts.prototype.AddGainEffect = function (tag, g) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + addEffectForTag(tag, new GainEffect(dbToLinear(g))); + }; + Acts.prototype.AddMuteEffect = function (tag) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + addEffectForTag(tag, new GainEffect(0)); // re-use gain effect with 0 gain + }; + Acts.prototype.AddTremoloEffect = function (tag, freq, mix) + { + if (api !== API_WEBAUDIO || !context["createOscillator"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new TremoloEffect(freq, mix)); + }; + Acts.prototype.AddRingModEffect = function (tag, freq, mix) + { + if (api !== API_WEBAUDIO || !context["createOscillator"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new RingModulatorEffect(freq, mix)); + }; + Acts.prototype.AddDistortionEffect = function (tag, threshold, headroom, drive, makeupgain, mix) + { + if (api !== API_WEBAUDIO || !context["createWaveShaper"]) + return; + tag = tag.toLowerCase(); + mix = mix / 100; + if (mix < 0) mix = 0; + if (mix > 1) mix = 1; + addEffectForTag(tag, new DistortionEffect(threshold, headroom, drive, makeupgain, mix)); + }; + Acts.prototype.AddCompressorEffect = function (tag, threshold, knee, ratio, attack, release) + { + if (api !== API_WEBAUDIO || !context["createDynamicsCompressor"]) + return; + tag = tag.toLowerCase(); + addEffectForTag(tag, new CompressorEffect(threshold, knee, ratio, attack / 1000, release / 1000)); + }; + Acts.prototype.AddAnalyserEffect = function (tag, fftSize, smoothing) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + addEffectForTag(tag, new AnalyserEffect(fftSize, smoothing)); + }; + Acts.prototype.RemoveEffects = function (tag) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + var i, len, arr; + if (effects.hasOwnProperty(tag)) + { + arr = effects[tag]; + if (arr.length) + { + for (i = 0, len = arr.length; i < len; i++) + arr[i].remove(); + cr.clearArray(arr); + reconnectEffects(tag); + } + } + }; + Acts.prototype.SetEffectParameter = function (tag, index, param, value, ramp, time) + { + if (api !== API_WEBAUDIO) + return; + tag = tag.toLowerCase(); + index = Math.floor(index); + var arr; + if (!effects.hasOwnProperty(tag)) + return; + arr = effects[tag]; + if (index < 0 || index >= arr.length) + return; + arr[index].setParam(param, value, ramp, time); + }; + Acts.prototype.SetListenerObject = function (obj_) + { + if (!obj_ || api !== API_WEBAUDIO) + return; + var inst = obj_.getFirstPicked(); + if (!inst) + return; + this.listenerTracker.setObject(inst); + listenerX = inst.x; + listenerY = inst.y; + }; + Acts.prototype.SetListenerZ = function (z) + { + this.listenerZ = z; + }; + Acts.prototype.ScheduleNextPlay = function (t) + { + if (!context) + return; // needs Web Audio API + this.nextPlayTime = t; + }; + Acts.prototype.UnloadAudio = function (file) + { + var is_music = file[1]; + var src = this.runtime.files_subfolder + file[0] + (useOgg ? ".ogg" : ".m4a"); + var b = this.getAudioBuffer(src, is_music, true /* don't create if missing */); + if (!b) + return; // not loaded + b.release(); + cr.arrayFindRemove(audioBuffers, b); + }; + Acts.prototype.UnloadAudioByName = function (folder, filename) + { + var is_music = (folder === 1); + var src = this.runtime.files_subfolder + filename.toLowerCase() + (useOgg ? ".ogg" : ".m4a"); + var b = this.getAudioBuffer(src, is_music, true /* don't create if missing */); + if (!b) + return; // not loaded + b.release(); + cr.arrayFindRemove(audioBuffers, b); + }; + Acts.prototype.UnloadAll = function () + { + var i, len; + for (i = 0, len = audioBuffers.length; i < len; ++i) + { + audioBuffers[i].release(); + }; + cr.clearArray(audioBuffers); + }; + pluginProto.acts = new Acts(); + function Exps() {}; + Exps.prototype.Duration = function (ret, tag) + { + getAudioByTag(tag, true); + if (taggedAudio.length) + ret.set_float(taggedAudio[0].getDuration()); + else + ret.set_float(0); + }; + Exps.prototype.PlaybackTime = function (ret, tag) + { + getAudioByTag(tag, true); + if (taggedAudio.length) + ret.set_float(taggedAudio[0].getPlaybackTime(true)); + else + ret.set_float(0); + }; + Exps.prototype.Volume = function (ret, tag) + { + getAudioByTag(tag, true); + if (taggedAudio.length) + { + var v = taggedAudio[0].getVolume(); + ret.set_float(linearToDb(v)); + } + else + ret.set_float(0); + }; + Exps.prototype.MasterVolume = function (ret) + { + ret.set_float(linearToDb(masterVolume)); + }; + Exps.prototype.EffectCount = function (ret, tag) + { + tag = tag.toLowerCase(); + var arr = null; + if (effects.hasOwnProperty(tag)) + arr = effects[tag]; + ret.set_int(arr ? arr.length : 0); + }; + function getAnalyser(tag, index) + { + var arr = null; + if (effects.hasOwnProperty(tag)) + arr = effects[tag]; + if (arr && index >= 0 && index < arr.length && arr[index].freqBins) + return arr[index]; + else + return null; + }; + Exps.prototype.AnalyserFreqBinCount = function (ret, tag, index) + { + tag = tag.toLowerCase(); + index = Math.floor(index); + var analyser = getAnalyser(tag, index); + ret.set_int(analyser ? analyser.node["frequencyBinCount"] : 0); + }; + Exps.prototype.AnalyserFreqBinAt = function (ret, tag, index, bin) + { + tag = tag.toLowerCase(); + index = Math.floor(index); + bin = Math.floor(bin); + var analyser = getAnalyser(tag, index); + if (!analyser) + ret.set_float(0); + else if (bin < 0 || bin >= analyser.node["frequencyBinCount"]) + ret.set_float(0); + else + ret.set_float(analyser.freqBins[bin]); + }; + Exps.prototype.AnalyserPeakLevel = function (ret, tag, index) + { + tag = tag.toLowerCase(); + index = Math.floor(index); + var analyser = getAnalyser(tag, index); + if (analyser) + ret.set_float(analyser.peak); + else + ret.set_float(0); + }; + Exps.prototype.AnalyserRMSLevel = function (ret, tag, index) + { + tag = tag.toLowerCase(); + index = Math.floor(index); + var analyser = getAnalyser(tag, index); + if (analyser) + ret.set_float(analyser.rms); + else + ret.set_float(0); + }; + Exps.prototype.SampleRate = function (ret) + { + ret.set_int(context ? context.sampleRate : 0); + }; + Exps.prototype.CurrentTime = function (ret) + { + ret.set_float(context ? context.currentTime : cr.performance_now()); + }; + pluginProto.exps = new Exps(); +}()); +; +; cr.plugins_.Browser = function(runtime) { this.runtime = runtime; @@ -16022,6 +19122,205 @@ cr.plugins_.Browser = function(runtime) }()); ; ; +cr.plugins_.Function = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var pluginProto = cr.plugins_.Function.prototype; + pluginProto.Type = function(plugin) + { + this.plugin = plugin; + this.runtime = plugin.runtime; + }; + var typeProto = pluginProto.Type.prototype; + typeProto.onCreate = function() + { + }; + pluginProto.Instance = function(type) + { + this.type = type; + this.runtime = type.runtime; + }; + var instanceProto = pluginProto.Instance.prototype; + var funcStack = []; + var funcStackPtr = -1; + var isInPreview = false; // set in onCreate + function FuncStackEntry() + { + this.name = ""; + this.retVal = 0; + this.params = []; + }; + function pushFuncStack() + { + funcStackPtr++; + if (funcStackPtr === funcStack.length) + funcStack.push(new FuncStackEntry()); + return funcStack[funcStackPtr]; + }; + function getCurrentFuncStack() + { + if (funcStackPtr < 0) + return null; + return funcStack[funcStackPtr]; + }; + function getOneAboveFuncStack() + { + if (!funcStack.length) + return null; + var i = funcStackPtr + 1; + if (i >= funcStack.length) + i = funcStack.length - 1; + return funcStack[i]; + }; + function popFuncStack() + { +; + funcStackPtr--; + }; + instanceProto.onCreate = function() + { + isInPreview = (typeof cr_is_preview !== "undefined"); + var self = this; + window["c2_callFunction"] = function (name_, params_) + { + var i, len, v; + var fs = pushFuncStack(); + fs.name = name_.toLowerCase(); + fs.retVal = 0; + if (params_) + { + fs.params.length = params_.length; + for (i = 0, len = params_.length; i < len; ++i) + { + v = params_[i]; + if (typeof v === "number" || typeof v === "string") + fs.params[i] = v; + else if (typeof v === "boolean") + fs.params[i] = (v ? 1 : 0); + else + fs.params[i] = 0; + } + } + else + { + cr.clearArray(fs.params); + } + self.runtime.trigger(cr.plugins_.Function.prototype.cnds.OnFunction, self, fs.name); + popFuncStack(); + return fs.retVal; + }; + }; + function Cnds() {}; + Cnds.prototype.OnFunction = function (name_) + { + var fs = getCurrentFuncStack(); + if (!fs) + return false; + return cr.equals_nocase(name_, fs.name); + }; + Cnds.prototype.CompareParam = function (index_, cmp_, value_) + { + var fs = getCurrentFuncStack(); + if (!fs) + return false; + index_ = cr.floor(index_); + if (index_ < 0 || index_ >= fs.params.length) + return false; + return cr.do_cmp(fs.params[index_], cmp_, value_); + }; + pluginProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.CallFunction = function (name_, params_) + { + var fs = pushFuncStack(); + fs.name = name_.toLowerCase(); + fs.retVal = 0; + cr.shallowAssignArray(fs.params, params_); + var ran = this.runtime.trigger(cr.plugins_.Function.prototype.cnds.OnFunction, this, fs.name); + if (isInPreview && !ran) + { +; + } + popFuncStack(); + }; + Acts.prototype.SetReturnValue = function (value_) + { + var fs = getCurrentFuncStack(); + if (fs) + fs.retVal = value_; + else +; + }; + Acts.prototype.CallExpression = function (unused) + { + }; + pluginProto.acts = new Acts(); + function Exps() {}; + Exps.prototype.ReturnValue = function (ret) + { + var fs = getOneAboveFuncStack(); + if (fs) + ret.set_any(fs.retVal); + else + ret.set_int(0); + }; + Exps.prototype.ParamCount = function (ret) + { + var fs = getCurrentFuncStack(); + if (fs) + ret.set_int(fs.params.length); + else + { +; + ret.set_int(0); + } + }; + Exps.prototype.Param = function (ret, index_) + { + index_ = cr.floor(index_); + var fs = getCurrentFuncStack(); + if (fs) + { + if (index_ >= 0 && index_ < fs.params.length) + { + ret.set_any(fs.params[index_]); + } + else + { +; + ret.set_int(0); + } + } + else + { +; + ret.set_int(0); + } + }; + Exps.prototype.Call = function (ret, name_) + { + var fs = pushFuncStack(); + fs.name = name_.toLowerCase(); + fs.retVal = 0; + cr.clearArray(fs.params); + var i, len; + for (i = 2, len = arguments.length; i < len; i++) + fs.params.push(arguments[i]); + var ran = this.runtime.trigger(cr.plugins_.Function.prototype.cnds.OnFunction, this, fs.name); + if (isInPreview && !ran) + { +; + } + popFuncStack(); + ret.set_any(fs.retVal); + }; + pluginProto.exps = new Exps(); +}()); +; +; cr.plugins_.SenaPlugin = function (runtime) { this.runtime = runtime; }; @@ -16187,17 +19486,50 @@ cr.plugins_.SenaPlugin = function (runtime) { this.totalPausedTime = 0; } }; - Acts.prototype.CalcObjectPositions = function (count, objectWidth, margin, maxWidth) { - var self = this; - this.calculatedPositions = []; - var totalWidth = count * objectWidth + (count - 1) * margin; - var startX = (maxWidth - totalWidth) / 2; - for (var i = 0; i < count; i++) { - var posX = startX + i * (objectWidth + margin) + objectWidth / 2; - this.calculatedPositions.push(posX); + Acts.prototype.CalcObjectPositions = function ( + count, + objectWidth, + margin, + maxWidth, + rowBreak, + rowGap, + type +) { + this.calculatedPositions = []; + if (count <= 0) return; + var rows = []; + if (rowBreak > 0) { + for (var i = 0; i < count; i += rowBreak) { + rows.push(Math.min(rowBreak, count - i)); } - console.log('Calculated positions:', this.calculatedPositions); - }; + } else { + if (count <= 5) { + rows.push(count); + } else { + var top = Math.ceil((count + 1) / 2); + var bottom = count - top; + rows.push(top); + rows.push(bottom); + } + } + var baseY = 0; + if (type === "word") { + baseY = rowGap * rows.length; // word luôn nằm dưới slot + } + var index = 0; + for (var r = 0; r < rows.length; r++) { + var itemsInRow = rows[r]; + var rowWidth = itemsInRow * objectWidth + (itemsInRow - 1) * margin; + var startX = (maxWidth - rowWidth) / 2; + for (var i = 0; i < itemsInRow; i++) { + this.calculatedPositions.push({ + x: startX + i * (objectWidth + margin) + objectWidth / 2, + y: baseY + r * rowGap + }); + index++; + } + } +}; pluginProto.acts = new Acts(); function Exps() { }; @@ -16339,12 +19671,19 @@ cr.plugins_.SenaPlugin = function (runtime) { } }; Exps.prototype.getPosXbyIndex = function (ret, index) { - if (this.calculatedPositions && index >= 0 && index < this.calculatedPositions.length) { - ret.set_float(this.calculatedPositions[index]); - } else { - ret.set_float(0); - } - }; + if (this.calculatedPositions[index]) { + ret.set_float(this.calculatedPositions[index].x); + } else { + ret.set_float(0); + } +}; +Exps.prototype.getPosYbyIndex = function (ret, index) { + if (this.calculatedPositions[index]) { + ret.set_float(this.calculatedPositions[index].y); + } else { + ret.set_float(0); + } +}; pluginProto.exps = new Exps(); }()); ; @@ -17630,6 +20969,747 @@ cr.plugins_.Sprite = function(runtime) }; pluginProto.exps = new Exps(); }()); +/* global cr,log,assert2 */ +/* jshint globalstrict: true */ +/* jshint strict: true */ +; +; +var jText = ''; +cr.plugins_.SpriteFontPlus = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var pluginProto = cr.plugins_.SpriteFontPlus.prototype; + pluginProto.onCreate = function () + { + }; + pluginProto.Type = function(plugin) + { + this.plugin = plugin; + this.runtime = plugin.runtime; + }; + var typeProto = pluginProto.Type.prototype; + typeProto.onCreate = function() + { + if (this.is_family) + return; + this.texture_img = new Image(); + this.texture_img["idtkLoadDisposed"] = true; + this.texture_img.src = this.texture_file; + this.runtime.wait_for_textures.push(this.texture_img); + this.webGL_texture = null; + }; + typeProto.onLostWebGLContext = function () + { + if (this.is_family) + return; + this.webGL_texture = null; + }; + typeProto.onRestoreWebGLContext = function () + { + if (this.is_family || !this.instances.length) + return; + if (!this.webGL_texture) + { + this.webGL_texture = this.runtime.glwrap.loadTexture(this.texture_img, false, this.runtime.linearSampling, this.texture_pixelformat); + } + var i, len; + for (i = 0, len = this.instances.length; i < len; i++) + this.instances[i].webGL_texture = this.webGL_texture; + }; + typeProto.unloadTextures = function () + { + if (this.is_family || this.instances.length || !this.webGL_texture) + return; + this.runtime.glwrap.deleteTexture(this.webGL_texture); + this.webGL_texture = null; + }; + typeProto.preloadCanvas2D = function (ctx) + { + ctx.drawImage(this.texture_img, 0, 0); + }; + pluginProto.Instance = function(type) + { + this.type = type; + this.runtime = type.runtime; + }; + var instanceProto = pluginProto.Instance.prototype; + instanceProto.onDestroy = function() + { + freeAllLines (this.lines); + freeAllClip (this.clipList); + freeAllClipUV(this.clipUV); + cr.wipe(this.characterWidthList); + }; + instanceProto.onCreate = function() + { + this.texture_img = this.type.texture_img; + this.characterWidth = this.properties[0]; + this.characterHeight = this.properties[1]; + this.characterSet = this.properties[2]; + this.text = this.properties[3]; + this.characterScale = this.properties[4]; + this.visible = (this.properties[5] === 0); // 0=visible, 1=invisible + this.halign = this.properties[6]/2.0; // 0=left, 1=center, 2=right + this.valign = this.properties[7]/2.0; // 0=top, 1=center, 2=bottom + this.wrapbyword = (this.properties[9] === 0); // 0=word, 1=character + this.characterSpacing = this.properties[10]; + this.lineHeight = this.properties[11]; + this.textWidth = 0; + this.textHeight = 0; + this.charWidthJSON = this.properties[12]; + this.spaceWidth = this.properties[13]; + jText = this.charWidthJSON; + if (this.recycled) + { + this.lines.length = 0; + cr.wipe(this.clipList); + cr.wipe(this.clipUV); + cr.wipe(this.characterWidthList); + } + else + { + this.lines = []; + this.clipList = {}; + this.clipUV = {}; + this.characterWidthList = {}; + } + try{ + if(this.charWidthJSON){ + if(this.charWidthJSON.indexOf('""c2array""') !== -1) { + var jStr = jQuery.parseJSON(this.charWidthJSON.replace(/""/g,'"')); + var l = jStr.size[1]; + for(var s = 0; s < l; s++) { + var cs = jStr.data[1][s][0]; + var w = jStr.data[0][s][0]; + for(var c = 0; c < cs.length; c++) { + this.characterWidthList[cs.charAt(c)] = w + } + } + } else { + var jStr = jQuery.parseJSON(this.charWidthJSON); + var l = jStr.length; + for(var s = 0; s < l; s++) { + var cs = jStr[s][1]; + var w = jStr[s][0]; + for(var c = 0; c < cs.length; c++) { + this.characterWidthList[cs.charAt(c)] = w + } + } + } + } + if(this.spaceWidth !== -1) { + this.characterWidthList[' '] = this.spaceWidth; + } + } + catch(e){ + if(window.console && window.console.log) { + window.console.log('SpriteFont+ Failure: ' + e); + } + } + this.text_changed = true; + this.lastwrapwidth = this.width; + if (this.runtime.glwrap) + { + if (!this.type.webGL_texture) + { + this.type.webGL_texture = this.runtime.glwrap.loadTexture(this.type.texture_img, false, this.runtime.linearSampling, this.type.texture_pixelformat); + } + this.webGL_texture = this.type.webGL_texture; + } + this.SplitSheet(); + }; + instanceProto.saveToJSON = function () + { + var save = { + "t": this.text, + "csc": this.characterScale, + "csp": this.characterSpacing, + "lh": this.lineHeight, + "tw": this.textWidth, + "th": this.textHeight, + "lrt": this.last_render_tick, + "cw": {} + }; + for (var ch in this.characterWidthList) + save["cw"][ch] = this.characterWidthList[ch]; + return save; + }; + instanceProto.loadFromJSON = function (o) + { + this.text = o["t"]; + this.characterScale = o["csc"]; + this.characterSpacing = o["csp"]; + this.lineHeight = o["lh"]; + this.textWidth = o["tw"]; + this.textHeight = o["th"]; + this.last_render_tick = o["lrt"]; + for(var ch in o["cw"]) + this.characterWidthList[ch] = o["cw"][ch]; + this.text_changed = true; + this.lastwrapwidth = this.width; + }; + function trimRight(text) + { + return text.replace(/\s\s*$/, ''); + } + var MAX_CACHE_SIZE = 1000; + function alloc(cache,Constructor) + { + if (cache.length) + return cache.pop(); + else + return new Constructor(); + } + function free(cache,data) + { + if (cache.length < MAX_CACHE_SIZE) + { + cache.push(data); + } + } + function freeAll(cache,dataList,isArray) + { + if (isArray) { + var i, len; + for (i = 0, len = dataList.length; i < len; i++) + { + free(cache,dataList[i]); + } + dataList.length = 0; + } else { + var prop; + for(prop in dataList) { + if(Object.prototype.hasOwnProperty.call(dataList,prop)) { + free(cache,dataList[prop]); + delete dataList[prop]; + } + } + } + } + function addLine(inst,lineIndex,cur_line) { + var lines = inst.lines; + var line; + cur_line = trimRight(cur_line); + if (lineIndex >= lines.length) + lines.push(allocLine()); + line = lines[lineIndex]; + line.text = cur_line; + line.width = inst.measureWidth(cur_line); + inst.textWidth = cr.max(inst.textWidth,line.width); + } + var linesCache = []; + function allocLine() { return alloc(linesCache,Object); } + function freeLine(l) { free(linesCache,l); } + function freeAllLines(arr) { freeAll(linesCache,arr,true); } + function addClip(obj,property,x,y,w,h) { + if (obj[property] === undefined) { + obj[property] = alloc(clipCache,Object); + } + obj[property].x = x; + obj[property].y = y; + obj[property].w = w; + obj[property].h = h; + } + var clipCache = []; + function allocClip() { return alloc(clipCache,Object); } + function freeAllClip(obj) { freeAll(clipCache,obj,false);} + function addClipUV(obj,property,left,top,right,bottom) { + if (obj[property] === undefined) { + obj[property] = alloc(clipUVCache,cr.rect); + } + obj[property].left = left; + obj[property].top = top; + obj[property].right = right; + obj[property].bottom = bottom; + } + var clipUVCache = []; + function allocClipUV() { return alloc(clipUVCache,cr.rect);} + function freeAllClipUV(obj) { freeAll(clipUVCache,obj,false);} + instanceProto.SplitSheet = function() { + var texture = this.texture_img; + var texWidth = texture.width; + var texHeight = texture.height; + var charWidth = this.characterWidth; + var charHeight = this.characterHeight; + var charU = charWidth /texWidth; + var charV = charHeight/texHeight; + var charSet = this.characterSet ; + var cols = Math.floor(texWidth/charWidth); + var rows = Math.floor(texHeight/charHeight); + for ( var c = 0; c < charSet.length; c++) { + if (c >= cols * rows) break; + var x = c%cols; + var y = Math.floor(c/cols); + var letter = charSet.charAt(c); + if (this.runtime.glwrap) { + addClipUV( + this.clipUV, letter, + x * charU , + y * charV , + (x+1) * charU , + (y+1) * charV + ); + } else { + addClip( + this.clipList, letter, + x * charWidth, + y * charHeight, + charWidth, + charHeight + ); + } + } + }; + /* + * Word-Wrapping + */ + var wordsCache = []; + pluginProto.TokeniseWords = function (text) + { + wordsCache.length = 0; + var cur_word = ""; + var ch; + var i = 0; + while (i < text.length) + { + ch = text.charAt(i); + if (ch === "\n") + { + if (cur_word.length) + { + wordsCache.push(cur_word); + cur_word = ""; + } + wordsCache.push("\n"); + ++i; + } + else if (ch === " " || ch === "\t" || ch === "-") + { + do { + cur_word += text.charAt(i); + i++; + } + while (i < text.length && (text.charAt(i) === " " || text.charAt(i) === "\t")); + wordsCache.push(cur_word); + cur_word = ""; + } + else if (i < text.length) + { + cur_word += ch; + i++; + } + } + if (cur_word.length) + wordsCache.push(cur_word); + }; + pluginProto.WordWrap = function (inst) + { + var text = inst.text; + var lines = inst.lines; + if (!text || !text.length) + { + freeAllLines(lines); + return; + } + var width = inst.width; + if (width <= 2.0) + { + freeAllLines(lines); + return; + } + var charWidth = inst.characterWidth; + var charScale = inst.characterScale; + var charSpacing = inst.characterSpacing; + if ( (text.length * (charWidth * charScale + charSpacing) - charSpacing) <= width && text.indexOf("\n") === -1) + { + var all_width = inst.measureWidth(text); + if (all_width <= width) + { + freeAllLines(lines); + lines.push(allocLine()); + lines[0].text = text; + lines[0].width = all_width; + inst.textWidth = all_width; + inst.textHeight = inst.characterHeight * charScale + inst.lineHeight; + return; + } + } + var wrapbyword = inst.wrapbyword; + this.WrapText(inst); + inst.textHeight = lines.length * (inst.characterHeight * charScale + inst.lineHeight); + }; + pluginProto.WrapText = function (inst) + { + var wrapbyword = inst.wrapbyword; + var text = inst.text; + var lines = inst.lines; + var width = inst.width; + var wordArray; + if (wrapbyword) { + this.TokeniseWords(text); // writes to wordsCache + wordArray = wordsCache; + } else { + wordArray = text; + } + var cur_line = ""; + var prev_line; + var line_width; + var i; + var lineIndex = 0; + var line; + var ignore_newline = false; + for (i = 0; i < wordArray.length; i++) + { + if (wordArray[i] === "\n") + { + if (ignore_newline === true) { + ignore_newline = false; + } else { + addLine(inst,lineIndex,cur_line); + lineIndex++; + } + cur_line = ""; + continue; + } + ignore_newline = false; + prev_line = cur_line; + cur_line += wordArray[i]; + line_width = inst.measureWidth(trimRight(cur_line)); + if (line_width > width) + { + if (prev_line === "") { + addLine(inst,lineIndex,cur_line); + cur_line = ""; + ignore_newline = true; + } else { + addLine(inst,lineIndex,prev_line); + cur_line = wordArray[i]; + } + lineIndex++; + if (!wrapbyword && cur_line === " ") + cur_line = ""; + } + } + if (trimRight(cur_line).length) + { + addLine(inst,lineIndex,cur_line); + lineIndex++; + } + for (i = lineIndex; i < lines.length; i++) + freeLine(lines[i]); + lines.length = lineIndex; + }; + instanceProto.measureWidth = function(text) { + var spacing = this.characterSpacing; + var len = text.length; + var width = 0; + for (var i = 0; i < len; i++) { + width += this.getCharacterWidth(text.charAt(i)) * this.characterScale + spacing; + } + width -= (width > 0) ? spacing : 0; + return width; + }; + /***/ + instanceProto.getCharacterWidth = function(character) { + var widthList = this.characterWidthList; + if (widthList[character] !== undefined) { + return widthList[character]; + } else { + return this.characterWidth; + } + }; + instanceProto.rebuildText = function() { + if (this.text_changed || this.width !== this.lastwrapwidth) { + this.textWidth = 0; + this.textHeight = 0; + this.type.plugin.WordWrap(this); + this.text_changed = false; + this.lastwrapwidth = this.width; + } + }; + var EPSILON = 0.00001; + instanceProto.draw = function(ctx, glmode) + { + var texture = this.texture_img; + if (this.text !== "" && texture != null) { + this.rebuildText(); + if (this.height < this.characterHeight*this.characterScale + this.lineHeight) { + return; + } + ctx.globalAlpha = this.opacity; + var myx = this.x; + var myy = this.y; + if (this.runtime.pixel_rounding) + { + myx = (myx + 0.5) | 0; + myy = (myy + 0.5) | 0; + } + ctx.save(); + ctx.translate(myx, myy); + ctx.rotate(this.angle); + var ha = this.halign; + var va = this.valign; + var scale = this.characterScale; + var charHeight = this.characterHeight * scale; + var lineHeight = this.lineHeight; + var charSpace = this.characterSpacing; + var lines = this.lines; + var textHeight = this.textHeight; + var halign; + var valign = va * cr.max(0,(this.height - textHeight)); + var offx = -(this.hotspotX * this.width); + var offy = -(this.hotspotY * this.height); + offy += valign; + var drawX ; + var drawY = offy; + for(var i = 0; i < lines.length; i++) { + var line = lines[i].text; + var len = lines[i].width; + halign = ha * cr.max(0,this.width - len); + drawX = offx + halign; + drawY += lineHeight; + for(var j = 0; j < line.length; j++) { + var letter = line.charAt(j); + var clip = this.clipList[letter]; + if ( drawX + this.getCharacterWidth(letter) * scale > this.width + EPSILON ) { + break; + } + if (clip !== undefined) { + ctx.drawImage( this.texture_img, + clip.x, clip.y, clip.w, clip.h, + Math.round(drawX),Math.round(drawY),clip.w*scale,clip.h*scale); + } + drawX += this.getCharacterWidth(letter) * scale + charSpace; + } + drawY += charHeight; + if ( drawY + charHeight + lineHeight > this.height) { + break; + } + } + ctx.restore(); + } + }; + var dQuad = new cr.quad(); + function rotateQuad(quad,cosa,sina) { + var x_temp; + x_temp = (quad.tlx * cosa) - (quad.tly * sina); + quad.tly = (quad.tly * cosa) + (quad.tlx * sina); + quad.tlx = x_temp; + x_temp = (quad.trx * cosa) - (quad.try_ * sina); + quad.try_ = (quad.try_ * cosa) + (quad.trx * sina); + quad.trx = x_temp; + x_temp = (quad.blx * cosa) - (quad.bly * sina); + quad.bly = (quad.bly * cosa) + (quad.blx * sina); + quad.blx = x_temp; + x_temp = (quad.brx * cosa) - (quad.bry * sina); + quad.bry = (quad.bry * cosa) + (quad.brx * sina); + quad.brx = x_temp; + } + instanceProto.drawGL = function(glw) + { + glw.setTexture(this.webGL_texture); + glw.setOpacity(this.opacity); + if (this.text !== "") { + this.rebuildText(); + if (this.height < this.characterHeight*this.characterScale + this.lineHeight) { + return; + } + this.update_bbox(); + var q = this.bquad; + var ox = 0; + var oy = 0; + if (this.runtime.pixel_rounding) + { + ox = ((this.x + 0.5) | 0) - this.x; + oy = ((this.y + 0.5) | 0) - this.y; + } + var angle = this.angle; + var ha = this.halign; + var va = this.valign; + var scale = this.characterScale; + var charHeight = this.characterHeight * scale; // to precalculate in onCreate or on change + var lineHeight = this.lineHeight; + var charSpace = this.characterSpacing; + var lines = this.lines; + var textHeight = this.textHeight; + var cosa,sina; + if (angle !== 0) + { + cosa = Math.cos(angle); + sina = Math.sin(angle); + } + var halign; + var valign = va * cr.max(0,(this.height - textHeight)); + var offx = q.tlx + ox; + var offy = q.tly + oy; + var drawX ; + var drawY = valign; + for(var i = 0; i < lines.length; i++) { + var line = lines[i].text; + var lineWidth = lines[i].width; + halign = ha * cr.max(0,this.width - lineWidth); + drawX = halign; + drawY += lineHeight; + for(var j = 0; j < line.length; j++) { + var letter = line.charAt(j); + var clipUV = this.clipUV[letter]; + if ( drawX + this.getCharacterWidth(letter) * scale > this.width + EPSILON) { + break; + } + if (clipUV !== undefined) { + var clipWidth = this.characterWidth*scale; + var clipHeight = this.characterHeight*scale; + dQuad.tlx = drawX; + dQuad.tly = drawY; + dQuad.trx = drawX + clipWidth; + dQuad.try_ = drawY ; + dQuad.blx = drawX; + dQuad.bly = drawY + clipHeight; + dQuad.brx = drawX + clipWidth; + dQuad.bry = drawY + clipHeight; + if(angle !== 0) + { + rotateQuad(dQuad,cosa,sina); + } + dQuad.offset(offx,offy); + glw.quadTex( + dQuad.tlx, dQuad.tly, + dQuad.trx, dQuad.try_, + dQuad.brx, dQuad.bry, + dQuad.blx, dQuad.bly, + clipUV + ); + } + drawX += this.getCharacterWidth(letter) * scale + charSpace; + } + drawY += charHeight; + if ( drawY + charHeight + lineHeight > this.height) { + break; + } + } + } + }; + function Cnds() {} + Cnds.prototype.CompareText = function(text_to_compare, case_sensitive) + { + if (case_sensitive) + return this.text == text_to_compare; + else + return cr.equals_nocase(this.text, text_to_compare); + }; + pluginProto.cnds = new Cnds(); + function Acts() {} + Acts.prototype.SetText = function(param) + { + if (cr.is_number(param) && param < 1e9) + param = Math.round(param * 1e10) / 1e10; // round to nearest ten billionth - hides floating point errors + var text_to_set = param.toString(); + if (this.text !== text_to_set) + { + this.text = text_to_set; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + Acts.prototype.AppendText = function(param) + { + if (cr.is_number(param)) + param = Math.round(param * 1e10) / 1e10; // round to nearest ten billionth - hides floating point errors + var text_to_append = param.toString(); + if (text_to_append) // not empty + { + this.text += text_to_append; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + Acts.prototype.SetScale = function(param) + { + if (param !== this.characterScale) { + this.characterScale = param; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + Acts.prototype.SetCharacterSpacing = function(param) + { + if (param !== this.CharacterSpacing) { + this.characterSpacing = param; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + Acts.prototype.SetLineHeight = function(param) + { + if (param !== this.lineHeight) { + this.lineHeight = param; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + instanceProto.SetCharWidth = function(character,width) { + var w = parseInt(width,10); + if (this.characterWidthList[character] !== w) { + this.characterWidthList[character] = w; + this.text_changed = true; + this.runtime.redraw = true; + } + }; + Acts.prototype.SetCharacterWidth = function(characterSet,width) + { + if (characterSet !== "") { + for(var c = 0; c < characterSet.length; c++) { + this.SetCharWidth(characterSet.charAt(c),width); + } + } + }; + Acts.prototype.SetEffect = function (effect) + { + this.compositeOp = cr.effectToCompositeOp(effect); + cr.setGLBlend(this, effect, this.runtime.gl); + this.runtime.redraw = true; + }; + pluginProto.acts = new Acts(); + function Exps() {} + Exps.prototype.CharacterWidth = function(ret,character) + { + ret.set_int(this.getCharacterWidth(character)); + }; + Exps.prototype.CharacterHeight = function(ret) + { + ret.set_int(this.characterHeight); + }; + Exps.prototype.CharacterScale = function(ret) + { + ret.set_float(this.characterScale); + }; + Exps.prototype.CharacterSpacing = function(ret) + { + ret.set_int(this.characterSpacing); + }; + Exps.prototype.LineHeight = function(ret) + { + ret.set_int(this.lineHeight); + }; + Exps.prototype.Text = function(ret) + { + ret.set_string(this.text); + }; + Exps.prototype.TextWidth = function (ret) + { + this.rebuildText(); + ret.set_float(this.textWidth); + }; + Exps.prototype.TextHeight = function (ret) + { + this.rebuildText(); + ret.set_float(this.textHeight); + }; + pluginProto.exps = new Exps(); +}()); ; ; cr.plugins_.Touch = function(runtime) @@ -18855,13 +22935,1415 @@ cr.plugins_.Touch = function(runtime) }; pluginProto.exps = new Exps(); }()); +; +; +cr.behaviors.DragnDrop = function(runtime) +{ + this.runtime = runtime; + var self = this; + if (!this.runtime.isDomFree) + { + jQuery(document).mousemove( + function(info) { + self.onMouseMove(info); + } + ); + jQuery(document).mousedown( + function(info) { + self.onMouseDown(info); + } + ); + jQuery(document).mouseup( + function(info) { + self.onMouseUp(info); + } + ); + } + var elem = (this.runtime.fullscreen_mode > 0) ? document : this.runtime.canvas; + if (this.runtime.isDirectCanvas) + elem = window["Canvas"]; + else if (this.runtime.isCocoonJs) + elem = window; + if (typeof PointerEvent !== "undefined") + { + elem.addEventListener("pointerdown", + function(info) { + self.onPointerStart(info); + }, + false + ); + elem.addEventListener("pointermove", + function(info) { + self.onPointerMove(info); + }, + false + ); + elem.addEventListener("pointerup", + function(info) { + self.onPointerEnd(info); + }, + false + ); + elem.addEventListener("pointercancel", + function(info) { + self.onPointerEnd(info); + }, + false + ); + } + else if (window.navigator["msPointerEnabled"]) + { + elem.addEventListener("MSPointerDown", + function(info) { + self.onPointerStart(info); + }, + false + ); + elem.addEventListener("MSPointerMove", + function(info) { + self.onPointerMove(info); + }, + false + ); + elem.addEventListener("MSPointerUp", + function(info) { + self.onPointerEnd(info); + }, + false + ); + elem.addEventListener("MSPointerCancel", + function(info) { + self.onPointerEnd(info); + }, + false + ); + } + else + { + elem.addEventListener("touchstart", + function(info) { + self.onTouchStart(info); + }, + false + ); + elem.addEventListener("touchmove", + function(info) { + self.onTouchMove(info); + }, + false + ); + elem.addEventListener("touchend", + function(info) { + self.onTouchEnd(info); + }, + false + ); + elem.addEventListener("touchcancel", + function(info) { + self.onTouchEnd(info); + }, + false + ); + } +}; +(function () +{ + var behaviorProto = cr.behaviors.DragnDrop.prototype; + var dummyoffset = {left: 0, top: 0}; + function GetDragDropBehavior(inst) + { + var i, len; + for (i = 0, len = inst.behavior_insts.length; i < len; i++) + { + if (inst.behavior_insts[i] instanceof behaviorProto.Instance) + return inst.behavior_insts[i]; + } + return null; + }; + behaviorProto.onMouseDown = function (info) + { + if (info.which !== 1) + return; // not left mouse button + this.onInputDown("leftmouse", info.pageX, info.pageY); + }; + behaviorProto.onMouseMove = function (info) + { + if (info.which !== 1) + return; // not left mouse button + this.onInputMove("leftmouse", info.pageX, info.pageY); + }; + behaviorProto.onMouseUp = function (info) + { + if (info.which !== 1) + return; // not left mouse button + this.onInputUp("leftmouse"); + }; + behaviorProto.onTouchStart = function (info) + { + if (info.preventDefault && cr.isCanvasInputEvent(info)) + info.preventDefault(); + var i, len, t, id; + for (i = 0, len = info.changedTouches.length; i < len; i++) + { + t = info.changedTouches[i]; + id = t.identifier; + this.onInputDown(id ? id.toString() : "", t.pageX, t.pageY); + } + }; + behaviorProto.onTouchMove = function (info) + { + if (info.preventDefault) + info.preventDefault(); + var i, len, t, id; + for (i = 0, len = info.changedTouches.length; i < len; i++) + { + t = info.changedTouches[i]; + id = t.identifier; + this.onInputMove(id ? id.toString() : "", t.pageX, t.pageY); + } + }; + behaviorProto.onTouchEnd = function (info) + { + if (info.preventDefault && cr.isCanvasInputEvent(info)) + info.preventDefault(); + var i, len, t, id; + for (i = 0, len = info.changedTouches.length; i < len; i++) + { + t = info.changedTouches[i]; + id = t.identifier; + this.onInputUp(id ? id.toString() : ""); + } + }; + behaviorProto.onPointerStart = function (info) + { + if (info["pointerType"] === info["MSPOINTER_TYPE_MOUSE"] || info["pointerType"] === "mouse") + return; + if (info.preventDefault && cr.isCanvasInputEvent(info)) + info.preventDefault(); + this.onInputDown(info["pointerId"].toString(), info.pageX, info.pageY); + }; + behaviorProto.onPointerMove = function (info) + { + if (info["pointerType"] === info["MSPOINTER_TYPE_MOUSE"] || info["pointerType"] === "mouse") + return; + if (info.preventDefault) + info.preventDefault(); + this.onInputMove(info["pointerId"].toString(), info.pageX, info.pageY); + }; + behaviorProto.onPointerEnd = function (info) + { + if (info["pointerType"] === info["MSPOINTER_TYPE_MOUSE"] || info["pointerType"] === "mouse") + return; + if (info.preventDefault && cr.isCanvasInputEvent(info)) + info.preventDefault(); + this.onInputUp(info["pointerId"].toString()); + }; + behaviorProto.onInputDown = function (src, pageX, pageY) + { + var offset = this.runtime.isDomFree ? dummyoffset : jQuery(this.runtime.canvas).offset(); + var x = pageX - offset.left; + var y = pageY - offset.top; + var lx, ly, topx, topy; + var arr = this.my_instances.valuesRef(); + var i, len, b, inst, topmost = null; + for (i = 0, len = arr.length; i < len; i++) + { + inst = arr[i]; + b = GetDragDropBehavior(inst); + if (!b.enabled || b.dragging) + continue; // don't consider disabled or already-dragging instances + lx = inst.layer.canvasToLayer(x, y, true); + ly = inst.layer.canvasToLayer(x, y, false); + inst.update_bbox(); + if (!inst.contains_pt(lx, ly)) + continue; // don't consider instances not over this point + if (!topmost) + { + topmost = inst; + topx = lx; + topy = ly; + continue; + } + if (inst.layer.index > topmost.layer.index) + { + topmost = inst; + topx = lx; + topy = ly; + continue; + } + if (inst.layer.index === topmost.layer.index && inst.get_zindex() > topmost.get_zindex()) + { + topmost = inst; + topx = lx; + topy = ly; + continue; + } + } + if (topmost) + GetDragDropBehavior(topmost).onDown(src, topx, topy); + }; + behaviorProto.onInputMove = function (src, pageX, pageY) + { + var offset = this.runtime.isDomFree ? dummyoffset : jQuery(this.runtime.canvas).offset(); + var x = pageX - offset.left; + var y = pageY - offset.top; + var lx, ly; + var arr = this.my_instances.valuesRef(); + var i, len, b, inst; + for (i = 0, len = arr.length; i < len; i++) + { + inst = arr[i]; + b = GetDragDropBehavior(inst); + if (!b.enabled || !b.dragging || (b.dragging && b.dragsource !== src)) + continue; // don't consider disabled, not-dragging, or dragging by other sources + lx = inst.layer.canvasToLayer(x, y, true); + ly = inst.layer.canvasToLayer(x, y, false); + b.onMove(lx, ly); + } + }; + behaviorProto.onInputUp = function (src) + { + var arr = this.my_instances.valuesRef(); + var i, len, b, inst; + for (i = 0, len = arr.length; i < len; i++) + { + inst = arr[i]; + b = GetDragDropBehavior(inst); + if (b.dragging && b.dragsource === src) + b.onUp(); + } + }; + behaviorProto.Type = function(behavior, objtype) + { + this.behavior = behavior; + this.objtype = objtype; + this.runtime = behavior.runtime; + }; + var behtypeProto = behaviorProto.Type.prototype; + behtypeProto.onCreate = function() + { + }; + behaviorProto.Instance = function(type, inst) + { + this.type = type; + this.behavior = type.behavior; + this.inst = inst; // associated object instance to modify + this.runtime = type.runtime; + }; + var behinstProto = behaviorProto.Instance.prototype; + behinstProto.onCreate = function() + { + this.dragging = false; + this.dx = 0; + this.dy = 0; + this.dragsource = ""; + this.axes = this.properties[0]; + this.enabled = (this.properties[1] !== 0); + }; + behinstProto.saveToJSON = function () + { + return { "enabled": this.enabled }; + }; + behinstProto.loadFromJSON = function (o) + { + this.enabled = o["enabled"]; + this.dragging = false; + }; + behinstProto.onDown = function(src, x, y) + { + this.dx = x - this.inst.x; + this.dy = y - this.inst.y; + this.dragging = true; + this.dragsource = src; + this.runtime.isInUserInputEvent = true; + this.runtime.trigger(cr.behaviors.DragnDrop.prototype.cnds.OnDragStart, this.inst); + this.runtime.isInUserInputEvent = false; + }; + behinstProto.onMove = function(x, y) + { + var newx = x - this.dx; + var newy = y - this.dy; + if (this.axes === 0) // both + { + if (this.inst.x !== newx || this.inst.y !== newy) + { + this.inst.x = newx; + this.inst.y = newy; + this.inst.set_bbox_changed(); + } + } + else if (this.axes === 1) // horizontal + { + if (this.inst.x !== newx) + { + this.inst.x = newx; + this.inst.set_bbox_changed(); + } + } + else if (this.axes === 2) // vertical + { + if (this.inst.y !== newy) + { + this.inst.y = newy; + this.inst.set_bbox_changed(); + } + } + }; + behinstProto.onUp = function() + { + this.dragging = false; + this.runtime.isInUserInputEvent = true; + this.runtime.trigger(cr.behaviors.DragnDrop.prototype.cnds.OnDrop, this.inst); + this.runtime.isInUserInputEvent = false; + }; + behinstProto.tick = function () + { + }; + function Cnds() {}; + Cnds.prototype.IsDragging = function () + { + return this.dragging; + }; + Cnds.prototype.OnDragStart = function () + { + return true; + }; + Cnds.prototype.OnDrop = function () + { + return true; + }; + Cnds.prototype.IsEnabled = function () + { + return !!this.enabled; + }; + behaviorProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.SetEnabled = function (s) + { + this.enabled = (s !== 0); + if (!this.enabled) + this.dragging = false; + }; + Acts.prototype.Drop = function () + { + if (this.dragging) + this.onUp(); + }; + behaviorProto.acts = new Acts(); + function Exps() {}; + behaviorProto.exps = new Exps(); +}()); +; +; +cr.behaviors.Fade = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var behaviorProto = cr.behaviors.Fade.prototype; + behaviorProto.Type = function(behavior, objtype) + { + this.behavior = behavior; + this.objtype = objtype; + this.runtime = behavior.runtime; + }; + var behtypeProto = behaviorProto.Type.prototype; + behtypeProto.onCreate = function() + { + }; + behaviorProto.Instance = function(type, inst) + { + this.type = type; + this.behavior = type.behavior; + this.inst = inst; // associated object instance to modify + this.runtime = type.runtime; + }; + var behinstProto = behaviorProto.Instance.prototype; + behinstProto.onCreate = function() + { + this.activeAtStart = this.properties[0] === 1; + this.setMaxOpacity = false; // used to retrieve maxOpacity once in first 'Start fade' action if initially inactive + this.fadeInTime = this.properties[1]; + this.waitTime = this.properties[2]; + this.fadeOutTime = this.properties[3]; + this.destroy = this.properties[4]; // 0 = no, 1 = after fade out + this.stage = this.activeAtStart ? 0 : 3; // 0 = fade in, 1 = wait, 2 = fade out, 3 = done + if (this.recycled) + this.stageTime.reset(); + else + this.stageTime = new cr.KahanAdder(); + this.maxOpacity = (this.inst.opacity ? this.inst.opacity : 1.0); + if (this.activeAtStart) + { + if (this.fadeInTime === 0) + { + this.stage = 1; + if (this.waitTime === 0) + this.stage = 2; + } + else + { + this.inst.opacity = 0; + this.runtime.redraw = true; + } + } + }; + behinstProto.saveToJSON = function () + { + return { + "fit": this.fadeInTime, + "wt": this.waitTime, + "fot": this.fadeOutTime, + "s": this.stage, + "st": this.stageTime.sum, + "mo": this.maxOpacity, + }; + }; + behinstProto.loadFromJSON = function (o) + { + this.fadeInTime = o["fit"]; + this.waitTime = o["wt"]; + this.fadeOutTime = o["fot"]; + this.stage = o["s"]; + this.stageTime.reset(); + this.stageTime.sum = o["st"]; + this.maxOpacity = o["mo"]; + }; + behinstProto.tick = function () + { + this.stageTime.add(this.runtime.getDt(this.inst)); + if (this.stage === 0) + { + this.inst.opacity = (this.stageTime.sum / this.fadeInTime) * this.maxOpacity; + this.runtime.redraw = true; + if (this.inst.opacity >= this.maxOpacity) + { + this.inst.opacity = this.maxOpacity; + this.stage = 1; // wait stage + this.stageTime.reset(); + this.runtime.trigger(cr.behaviors.Fade.prototype.cnds.OnFadeInEnd, this.inst); + } + } + if (this.stage === 1) + { + if (this.stageTime.sum >= this.waitTime) + { + this.stage = 2; // fade out stage + this.stageTime.reset(); + this.runtime.trigger(cr.behaviors.Fade.prototype.cnds.OnWaitEnd, this.inst); + } + } + if (this.stage === 2) + { + if (this.fadeOutTime !== 0) + { + this.inst.opacity = this.maxOpacity - ((this.stageTime.sum / this.fadeOutTime) * this.maxOpacity); + this.runtime.redraw = true; + if (this.inst.opacity < 0) + { + this.inst.opacity = 0; + this.stage = 3; // done + this.stageTime.reset(); + this.runtime.trigger(cr.behaviors.Fade.prototype.cnds.OnFadeOutEnd, this.inst); + if (this.destroy === 1) + this.runtime.DestroyInstance(this.inst); + } + } + } + }; + behinstProto.doStart = function () + { + this.stage = 0; + this.stageTime.reset(); + if (this.fadeInTime === 0) + { + this.stage = 1; + if (this.waitTime === 0) + this.stage = 2; + } + else + { + this.inst.opacity = 0; + this.runtime.redraw = true; + } + }; + function Cnds() {}; + Cnds.prototype.OnFadeOutEnd = function () + { + return true; + }; + Cnds.prototype.OnFadeInEnd = function () + { + return true; + }; + Cnds.prototype.OnWaitEnd = function () + { + return true; + }; + behaviorProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.StartFade = function () + { + if (!this.activeAtStart && !this.setMaxOpacity) + { + this.maxOpacity = (this.inst.opacity ? this.inst.opacity : 1.0); + this.setMaxOpacity = true; + } + if (this.stage === 3) + this.doStart(); + }; + Acts.prototype.RestartFade = function () + { + this.doStart(); + }; + Acts.prototype.SetFadeInTime = function (t) + { + if (t < 0) + t = 0; + this.fadeInTime = t; + }; + Acts.prototype.SetWaitTime = function (t) + { + if (t < 0) + t = 0; + this.waitTime = t; + }; + Acts.prototype.SetFadeOutTime = function (t) + { + if (t < 0) + t = 0; + this.fadeOutTime = t; + }; + behaviorProto.acts = new Acts(); + function Exps() {}; + Exps.prototype.FadeInTime = function (ret) + { + ret.set_float(this.fadeInTime); + }; + Exps.prototype.WaitTime = function (ret) + { + ret.set_float(this.waitTime); + }; + Exps.prototype.FadeOutTime = function (ret) + { + ret.set_float(this.fadeOutTime); + }; + behaviorProto.exps = new Exps(); +}()); +; +; +cr.behaviors.Pin = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var behaviorProto = cr.behaviors.Pin.prototype; + behaviorProto.Type = function(behavior, objtype) + { + this.behavior = behavior; + this.objtype = objtype; + this.runtime = behavior.runtime; + }; + var behtypeProto = behaviorProto.Type.prototype; + behtypeProto.onCreate = function() + { + }; + behaviorProto.Instance = function(type, inst) + { + this.type = type; + this.behavior = type.behavior; + this.inst = inst; // associated object instance to modify + this.runtime = type.runtime; + }; + var behinstProto = behaviorProto.Instance.prototype; + behinstProto.onCreate = function() + { + this.pinObject = null; + this.pinObjectUid = -1; // for loading + this.pinAngle = 0; + this.pinDist = 0; + this.myStartAngle = 0; + this.theirStartAngle = 0; + this.lastKnownAngle = 0; + this.mode = 0; // 0 = position & angle; 1 = position; 2 = angle; 3 = rope; 4 = bar + var self = this; + if (!this.recycled) + { + this.myDestroyCallback = (function(inst) { + self.onInstanceDestroyed(inst); + }); + } + this.runtime.addDestroyCallback(this.myDestroyCallback); + }; + behinstProto.saveToJSON = function () + { + return { + "uid": this.pinObject ? this.pinObject.uid : -1, + "pa": this.pinAngle, + "pd": this.pinDist, + "msa": this.myStartAngle, + "tsa": this.theirStartAngle, + "lka": this.lastKnownAngle, + "m": this.mode + }; + }; + behinstProto.loadFromJSON = function (o) + { + this.pinObjectUid = o["uid"]; // wait until afterLoad to look up + this.pinAngle = o["pa"]; + this.pinDist = o["pd"]; + this.myStartAngle = o["msa"]; + this.theirStartAngle = o["tsa"]; + this.lastKnownAngle = o["lka"]; + this.mode = o["m"]; + }; + behinstProto.afterLoad = function () + { + if (this.pinObjectUid === -1) + this.pinObject = null; + else + { + this.pinObject = this.runtime.getObjectByUID(this.pinObjectUid); +; + } + this.pinObjectUid = -1; + }; + behinstProto.onInstanceDestroyed = function (inst) + { + if (this.pinObject == inst) + this.pinObject = null; + }; + behinstProto.onDestroy = function() + { + this.pinObject = null; + this.runtime.removeDestroyCallback(this.myDestroyCallback); + }; + behinstProto.tick = function () + { + }; + behinstProto.tick2 = function () + { + if (!this.pinObject) + return; + if (this.lastKnownAngle !== this.inst.angle) + this.myStartAngle = cr.clamp_angle(this.myStartAngle + (this.inst.angle - this.lastKnownAngle)); + var newx = this.inst.x; + var newy = this.inst.y; + if (this.mode === 3 || this.mode === 4) // rope mode or bar mode + { + var dist = cr.distanceTo(this.inst.x, this.inst.y, this.pinObject.x, this.pinObject.y); + if ((dist > this.pinDist) || (this.mode === 4 && dist < this.pinDist)) + { + var a = cr.angleTo(this.pinObject.x, this.pinObject.y, this.inst.x, this.inst.y); + newx = this.pinObject.x + Math.cos(a) * this.pinDist; + newy = this.pinObject.y + Math.sin(a) * this.pinDist; + } + } + else + { + newx = this.pinObject.x + Math.cos(this.pinObject.angle + this.pinAngle) * this.pinDist; + newy = this.pinObject.y + Math.sin(this.pinObject.angle + this.pinAngle) * this.pinDist; + } + var newangle = cr.clamp_angle(this.myStartAngle + (this.pinObject.angle - this.theirStartAngle)); + this.lastKnownAngle = newangle; + if ((this.mode === 0 || this.mode === 1 || this.mode === 3 || this.mode === 4) + && (this.inst.x !== newx || this.inst.y !== newy)) + { + this.inst.x = newx; + this.inst.y = newy; + this.inst.set_bbox_changed(); + } + if ((this.mode === 0 || this.mode === 2) && (this.inst.angle !== newangle)) + { + this.inst.angle = newangle; + this.inst.set_bbox_changed(); + } + }; + function Cnds() {}; + Cnds.prototype.IsPinned = function () + { + return !!this.pinObject; + }; + behaviorProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.Pin = function (obj, mode_) + { + if (!obj) + return; + var otherinst = obj.getFirstPicked(this.inst); + if (!otherinst) + return; + this.pinObject = otherinst; + this.pinAngle = cr.angleTo(otherinst.x, otherinst.y, this.inst.x, this.inst.y) - otherinst.angle; + this.pinDist = cr.distanceTo(otherinst.x, otherinst.y, this.inst.x, this.inst.y); + this.myStartAngle = this.inst.angle; + this.lastKnownAngle = this.inst.angle; + this.theirStartAngle = otherinst.angle; + this.mode = mode_; + }; + Acts.prototype.Unpin = function () + { + this.pinObject = null; + }; + behaviorProto.acts = new Acts(); + function Exps() {}; + Exps.prototype.PinnedUID = function (ret) + { + ret.set_int(this.pinObject ? this.pinObject.uid : -1); + }; + behaviorProto.exps = new Exps(); +}()); +; +; +cr.behaviors.Rex_MoveTo = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var behaviorProto = cr.behaviors.Rex_MoveTo.prototype; + behaviorProto.Type = function(behavior, objtype) + { + this.behavior = behavior; + this.objtype = objtype; + this.runtime = behavior.runtime; + }; + var behtypeProto = behaviorProto.Type.prototype; + behtypeProto.onCreate = function() + { + }; + behaviorProto.Instance = function(type, inst) + { + this.type = type; + this.behavior = type.behavior; + this.inst = inst; // associated object instance to modify + this.runtime = type.runtime; + }; + var behinstProto = behaviorProto.Instance.prototype; + behinstProto.onCreate = function() + { + this.enabled = (this.properties[0] == 1); + if (!this.recycled) + { + this.move = {"max":0, + "acc":0, + "dec":0}; + } + this.move["max"] = this.properties[1]; + this.move["acc"] = this.properties[2]; + this.move["dec"] = this.properties[3]; + if (!this.recycled) + { + this.target = {"x":0 , "y":0, "a":0}; + } + this.is_moving = false; + this.current_speed = 0; + this.remain_distance = 0; + this.is_hit_target = false; + if (!this.recycled) + { + this._pre_pos = {"x":0,"y":0}; + } + this._pre_pos["x"] = 0; + this._pre_pos["y"] = 0; + if (!this.recycled) + { + this._moving_angle_info = {"x":0,"y":0,"a":(-1)}; + } + this._moving_angle_info["x"] = 0; + this._moving_angle_info["y"] = 0; + this._moving_angle_info["a"] = -1; + this._last_tick = null; + this.is_my_call = false; + }; + behinstProto.tick = function () + { + if (this.is_hit_target) + { + if ((this.inst.x == this.target["x"]) && (this.inst.y == this.target["y"])) + { + this.is_my_call = true; + this.runtime.trigger(cr.behaviors.Rex_MoveTo.prototype.cnds.OnHitTarget, this.inst); + this.is_my_call = false; + } + this.is_hit_target = false; + } + if ( (!this.enabled) || (!this.is_moving) ) + { + return; + } + var dt = this.runtime.getDt(this.inst); + if (dt==0) // can not move if dt == 0 + return; + if ((this._pre_pos["x"] != this.inst.x) || (this._pre_pos["y"] != this.inst.y)) + this._reset_current_pos(); // reset this.remain_distance + var is_slow_down = false; + if (this.move["dec"] != 0) + { + var _speed = this.current_speed; + var _distance = (_speed*_speed)/(2*this.move["dec"]); // (v*v)/(2*a) + is_slow_down = (_distance >= this.remain_distance); + } + var acc = (is_slow_down)? (-this.move["dec"]):this.move["acc"]; + if (acc != 0) + { + this.SetCurrentSpeed( this.current_speed + (acc * dt) ); + } + var distance = this.current_speed * dt; + this.remain_distance -= distance; + if ( (this.remain_distance <= 0) || (this.current_speed <= 0) ) + { + this.is_moving = false; + this.inst.x = this.target["x"]; + this.inst.y = this.target["y"]; + this.SetCurrentSpeed(0); + this.moving_angle_get(); + this.is_hit_target = true; + } + else + { + var angle = this.target["a"]; + this.inst.x += (distance * Math.cos(angle)); + this.inst.y += (distance * Math.sin(angle)); + } + this.inst.set_bbox_changed(); + this._pre_pos["x"] = this.inst.x; + this._pre_pos["y"] = this.inst.y; + }; + behinstProto.tick2 = function () + { + this._moving_angle_info["x"] = this.inst.x; + this._moving_angle_info["y"] = this.inst.y; + }; + behinstProto.SetCurrentSpeed = function(speed) + { + if (speed != null) + { + this.current_speed = (speed > this.move["max"])? + this.move["max"]: speed; + } + else if (this.move["acc"]==0) + { + this.current_speed = this.move["max"]; + } + }; + behinstProto._reset_current_pos = function () + { + var dx = this.target["x"] - this.inst.x; + var dy = this.target["y"] - this.inst.y; + this.target["a"] = Math.atan2(dy, dx); + this.remain_distance = Math.sqrt( (dx*dx) + (dy*dy) ); + this._pre_pos["x"] = this.inst.x; + this._pre_pos["y"] = this.inst.y; + }; + behinstProto.SetTargetPos = function (_x, _y) + { + this.is_moving = true; + this.target["x"] = _x; + this.target["y"] = _y; + this._reset_current_pos(); + this.SetCurrentSpeed(null); + this._moving_angle_info["x"] = this.inst.x; + this._moving_angle_info["y"] = this.inst.y; + }; + behinstProto.KENSetTargetPos = function (_x, _y) + { + this.target["x"] = _x; + this.target["y"] = _y; + this._reset_current_pos(); + this.is_moving = false; + this.inst.x = this.target["x"]; + this.inst.y = this.target["y"]; + this.SetCurrentSpeed(0); + this.moving_angle_get(); + this.is_moving = true; + }; + behinstProto.is_tick_changed = function () + { + var cur_tick = this.runtime.tickcount; + var tick_changed = (this._last_tick != cur_tick); + this._last_tick = cur_tick; + return tick_changed; + }; + behinstProto.moving_angle_get = function (ret) + { + if (this.is_tick_changed()) + { + var dx = this.inst.x - this._moving_angle_info["x"]; + var dy = this.inst.y - this._moving_angle_info["y"]; + if ((dx!=0) || (dy!=0)) + this._moving_angle_info["a"] = cr.to_clamped_degrees(Math.atan2(dy,dx)); + } + return this._moving_angle_info["a"]; + }; + behinstProto.saveToJSON = function () + { + return { "en": this.enabled, + "v": this.move, + "t": this.target, + "is_m": this.is_moving, + "c_spd" : this.current_speed, + "rd" : this.remain_distance, + "is_ht" : this.is_hit_target, + "pp": this._pre_pos, + "ma": this._moving_angle_info, + "lt": this._last_tick, + }; + }; + behinstProto.loadFromJSON = function (o) + { + this.enabled = o["en"]; + this.move = o["v"]; + this.target = o["t"]; + this.is_moving = o["is_m"]; + this.current_speed = o["c_spd"]; + this.remain_distance = o["rd"]; + this.is_hit_target = o["is_ht"]; + this._pre_pos = o["pp"]; + this._moving_angle_info = o["ma"]; + this._last_tick = o["lt"]; + }; + function Cnds() {}; + behaviorProto.cnds = new Cnds(); + Cnds.prototype.OnHitTarget = function () + { + return (this.is_my_call); + }; + Cnds.prototype.CompareSpeed = function (cmp, s) + { + return cr.do_cmp(this.current_speed, cmp, s); + }; + Cnds.prototype.OnMoving = function () // deprecated + { + return false; + }; + Cnds.prototype.IsMoving = function () + { + return (this.enabled && this.is_moving); + }; + Cnds.prototype.CompareMovingAngle = function (cmp, s) + { + var angle = this.moving_angle_get(); + if (angle != (-1)) + return cr.do_cmp(this.moving_angle_get(), cmp, s); + else + return false; + }; + function Acts() {}; + behaviorProto.acts = new Acts(); + Acts.prototype.SetEnabled = function (en) + { + this.enabled = (en === 1); + }; + Acts.prototype.SetMaxSpeed = function (s) + { + this.move["max"] = s; + this.SetCurrentSpeed(null); + }; + Acts.prototype.SetAcceleration = function (a) + { + this.move["acc"] = a; + this.SetCurrentSpeed(null); + }; + Acts.prototype.SetDeceleration = function (a) + { + this.move["dec"] = a; + }; + Acts.prototype.SetTargetPos = function (_x, _y) + { + this.SetTargetPos(_x, _y) + }; + Acts.prototype.KENSetTargetPos = function (_x, _y) + { + this.KENSetTargetPos(_x, _y) + }; + Acts.prototype.SetCurrentSpeed = function (s) + { + this.SetCurrentSpeed(s); + }; + Acts.prototype.SetTargetPosOnObject = function (objtype) + { + if (!objtype) + return; + var inst = objtype.getFirstPicked(); + if (inst != null) + this.SetTargetPos(inst.x, inst.y); + }; + Acts.prototype.SetTargetPosByDeltaXY = function (dx, dy) + { + this.SetTargetPos(this.inst.x + dx, this.inst.y + dy); + }; + Acts.prototype.SetTargetPosByDistanceAngle = function (distance, angle) + { + var a = cr.to_clamped_radians(angle); + var dx = distance*Math.cos(a); + var dy = distance*Math.sin(a); + this.SetTargetPos(this.inst.x + dx, this.inst.y + dy); + }; + Acts.prototype.Stop = function () + { + this.is_moving = false; + }; + function Exps() {}; + behaviorProto.exps = new Exps(); + Exps.prototype.Activated = function (ret) + { + ret.set_int((this.enabled)? 1:0); + }; + Exps.prototype.Speed = function (ret) + { + ret.set_float(this.current_speed); + }; + Exps.prototype.MaxSpeed = function (ret) + { + ret.set_float(this.move["max"]); + }; + Exps.prototype.Acc = function (ret) + { + ret.set_float(this.move["acc"]); + }; + Exps.prototype.Dec = function (ret) + { + ret.set_float(this.move["dec"]); + }; + Exps.prototype.TargetX = function (ret) + { + ret.set_float(this.target["x"]); + }; + Exps.prototype.TargetY = function (ret) + { + ret.set_float(this.target["y"]); + }; + Exps.prototype.MovingAngle = function (ret) + { + ret.set_float(this.moving_angle_get()); + }; +}()); +; +; +cr.behaviors.Sin = function(runtime) +{ + this.runtime = runtime; +}; +(function () +{ + var behaviorProto = cr.behaviors.Sin.prototype; + behaviorProto.Type = function(behavior, objtype) + { + this.behavior = behavior; + this.objtype = objtype; + this.runtime = behavior.runtime; + }; + var behtypeProto = behaviorProto.Type.prototype; + behtypeProto.onCreate = function() + { + }; + behaviorProto.Instance = function(type, inst) + { + this.type = type; + this.behavior = type.behavior; + this.inst = inst; // associated object instance to modify + this.runtime = type.runtime; + this.i = 0; // period offset (radians) + }; + var behinstProto = behaviorProto.Instance.prototype; + var _2pi = 2 * Math.PI; + var _pi_2 = Math.PI / 2; + var _3pi_2 = (3 * Math.PI) / 2; + behinstProto.onCreate = function() + { + this.active = (this.properties[0] === 1); + this.movement = this.properties[1]; // 0=Horizontal|1=Vertical|2=Size|3=Width|4=Height|5=Angle|6=Opacity|7=Value only + this.wave = this.properties[2]; // 0=Sine|1=Triangle|2=Sawtooth|3=Reverse sawtooth|4=Square + this.period = this.properties[3]; + this.period += Math.random() * this.properties[4]; // period random + if (this.period === 0) + this.i = 0; + else + { + this.i = (this.properties[5] / this.period) * _2pi; // period offset + this.i += ((Math.random() * this.properties[6]) / this.period) * _2pi; // period offset random + } + this.mag = this.properties[7]; // magnitude + this.mag += Math.random() * this.properties[8]; // magnitude random + this.initialValue = 0; + this.initialValue2 = 0; + this.ratio = 0; + if (this.movement === 5) // angle + this.mag = cr.to_radians(this.mag); + this.init(); + }; + behinstProto.saveToJSON = function () + { + return { + "i": this.i, + "a": this.active, + "mv": this.movement, + "w": this.wave, + "p": this.period, + "mag": this.mag, + "iv": this.initialValue, + "iv2": this.initialValue2, + "r": this.ratio, + "lkv": this.lastKnownValue, + "lkv2": this.lastKnownValue2 + }; + }; + behinstProto.loadFromJSON = function (o) + { + this.i = o["i"]; + this.active = o["a"]; + this.movement = o["mv"]; + this.wave = o["w"]; + this.period = o["p"]; + this.mag = o["mag"]; + this.initialValue = o["iv"]; + this.initialValue2 = o["iv2"] || 0; + this.ratio = o["r"]; + this.lastKnownValue = o["lkv"]; + this.lastKnownValue2 = o["lkv2"] || 0; + }; + behinstProto.init = function () + { + switch (this.movement) { + case 0: // horizontal + this.initialValue = this.inst.x; + break; + case 1: // vertical + this.initialValue = this.inst.y; + break; + case 2: // size + this.initialValue = this.inst.width; + this.ratio = this.inst.height / this.inst.width; + break; + case 3: // width + this.initialValue = this.inst.width; + break; + case 4: // height + this.initialValue = this.inst.height; + break; + case 5: // angle + this.initialValue = this.inst.angle; + break; + case 6: // opacity + this.initialValue = this.inst.opacity; + break; + case 7: + this.initialValue = 0; + break; + case 8: // forwards/backwards + this.initialValue = this.inst.x; + this.initialValue2 = this.inst.y; + break; + default: +; + } + this.lastKnownValue = this.initialValue; + this.lastKnownValue2 = this.initialValue2; + }; + behinstProto.waveFunc = function (x) + { + x = x % _2pi; + switch (this.wave) { + case 0: // sine + return Math.sin(x); + case 1: // triangle + if (x <= _pi_2) + return x / _pi_2; + else if (x <= _3pi_2) + return 1 - (2 * (x - _pi_2) / Math.PI); + else + return (x - _3pi_2) / _pi_2 - 1; + case 2: // sawtooth + return 2 * x / _2pi - 1; + case 3: // reverse sawtooth + return -2 * x / _2pi + 1; + case 4: // square + return x < Math.PI ? -1 : 1; + }; + return 0; + }; + behinstProto.tick = function () + { + var dt = this.runtime.getDt(this.inst); + if (!this.active || dt === 0) + return; + if (this.period === 0) + this.i = 0; + else + { + this.i += (dt / this.period) * _2pi; + this.i = this.i % _2pi; + } + this.updateFromPhase(); + }; + behinstProto.updateFromPhase = function () + { + switch (this.movement) { + case 0: // horizontal + if (this.inst.x !== this.lastKnownValue) + this.initialValue += this.inst.x - this.lastKnownValue; + this.inst.x = this.initialValue + this.waveFunc(this.i) * this.mag; + this.lastKnownValue = this.inst.x; + break; + case 1: // vertical + if (this.inst.y !== this.lastKnownValue) + this.initialValue += this.inst.y - this.lastKnownValue; + this.inst.y = this.initialValue + this.waveFunc(this.i) * this.mag; + this.lastKnownValue = this.inst.y; + break; + case 2: // size + this.inst.width = this.initialValue + this.waveFunc(this.i) * this.mag; + this.inst.height = this.inst.width * this.ratio; + break; + case 3: // width + this.inst.width = this.initialValue + this.waveFunc(this.i) * this.mag; + break; + case 4: // height + this.inst.height = this.initialValue + this.waveFunc(this.i) * this.mag; + break; + case 5: // angle + if (this.inst.angle !== this.lastKnownValue) + this.initialValue = cr.clamp_angle(this.initialValue + (this.inst.angle - this.lastKnownValue)); + this.inst.angle = cr.clamp_angle(this.initialValue + this.waveFunc(this.i) * this.mag); + this.lastKnownValue = this.inst.angle; + break; + case 6: // opacity + this.inst.opacity = this.initialValue + (this.waveFunc(this.i) * this.mag) / 100; + if (this.inst.opacity < 0) + this.inst.opacity = 0; + else if (this.inst.opacity > 1) + this.inst.opacity = 1; + break; + case 8: // forwards/backwards + if (this.inst.x !== this.lastKnownValue) + this.initialValue += this.inst.x - this.lastKnownValue; + if (this.inst.y !== this.lastKnownValue2) + this.initialValue2 += this.inst.y - this.lastKnownValue2; + this.inst.x = this.initialValue + Math.cos(this.inst.angle) * this.waveFunc(this.i) * this.mag; + this.inst.y = this.initialValue2 + Math.sin(this.inst.angle) * this.waveFunc(this.i) * this.mag; + this.lastKnownValue = this.inst.x; + this.lastKnownValue2 = this.inst.y; + break; + } + this.inst.set_bbox_changed(); + }; + behinstProto.onSpriteFrameChanged = function (prev_frame, next_frame) + { + switch (this.movement) { + case 2: // size + this.initialValue *= (next_frame.width / prev_frame.width); + this.ratio = next_frame.height / next_frame.width; + break; + case 3: // width + this.initialValue *= (next_frame.width / prev_frame.width); + break; + case 4: // height + this.initialValue *= (next_frame.height / prev_frame.height); + break; + } + }; + function Cnds() {}; + Cnds.prototype.IsActive = function () + { + return this.active; + }; + Cnds.prototype.CompareMovement = function (m) + { + return this.movement === m; + }; + Cnds.prototype.ComparePeriod = function (cmp, v) + { + return cr.do_cmp(this.period, cmp, v); + }; + Cnds.prototype.CompareMagnitude = function (cmp, v) + { + if (this.movement === 5) + return cr.do_cmp(this.mag, cmp, cr.to_radians(v)); + else + return cr.do_cmp(this.mag, cmp, v); + }; + Cnds.prototype.CompareWave = function (w) + { + return this.wave === w; + }; + behaviorProto.cnds = new Cnds(); + function Acts() {}; + Acts.prototype.SetActive = function (a) + { + this.active = (a === 1); + }; + Acts.prototype.SetPeriod = function (x) + { + this.period = x; + }; + Acts.prototype.SetMagnitude = function (x) + { + this.mag = x; + if (this.movement === 5) // angle + this.mag = cr.to_radians(this.mag); + }; + Acts.prototype.SetMovement = function (m) + { + if (this.movement === 5 && m !== 5) + this.mag = cr.to_degrees(this.mag); + this.movement = m; + this.init(); + }; + Acts.prototype.SetWave = function (w) + { + this.wave = w; + }; + Acts.prototype.SetPhase = function (x) + { + this.i = (x * _2pi) % _2pi; + this.updateFromPhase(); + }; + Acts.prototype.UpdateInitialState = function () + { + this.init(); + }; + behaviorProto.acts = new Acts(); + function Exps() {}; + Exps.prototype.CyclePosition = function (ret) + { + ret.set_float(this.i / _2pi); + }; + Exps.prototype.Period = function (ret) + { + ret.set_float(this.period); + }; + Exps.prototype.Magnitude = function (ret) + { + if (this.movement === 5) // angle + ret.set_float(cr.to_degrees(this.mag)); + else + ret.set_float(this.mag); + }; + Exps.prototype.Value = function (ret) + { + ret.set_float(this.waveFunc(this.i) * this.mag); + }; + behaviorProto.exps = new Exps(); +}()); cr.getObjectRefTable = function () { return [ + cr.plugins_.Audio, cr.plugins_.Browser, + cr.plugins_.Function, cr.plugins_.Sprite, cr.plugins_.SenaPlugin, + cr.plugins_.SpriteFontPlus, cr.plugins_.Touch, + cr.behaviors.Fade, + cr.behaviors.DragnDrop, + cr.behaviors.Rex_MoveTo, + cr.behaviors.Sin, + cr.behaviors.Pin, cr.system_object.prototype.cnds.OnLayoutStart, cr.plugins_.SenaPlugin.prototype.acts.Load, + cr.system_object.prototype.acts.SetLayerVisible, cr.plugins_.SenaPlugin.prototype.cnds.OnLoad, cr.plugins_.Browser.prototype.acts.ConsoleLog, cr.plugins_.SenaPlugin.prototype.exps.getGuide, @@ -18873,21 +24355,76 @@ cr.getObjectRefTable = function () { return [ cr.plugins_.SenaPlugin.prototype.exps.getRequestValue, cr.plugins_.SenaPlugin.prototype.exps.getOptionsCount, cr.plugins_.SenaPlugin.prototype.exps.getHintCount, - cr.system_object.prototype.cnds.For, + cr.plugins_.Sprite.prototype.acts.Destroy, + cr.system_object.prototype.acts.SetVar, cr.system_object.prototype.exps["int"], + cr.plugins_.SpriteFontPlus.prototype.acts.SetText, + cr.behaviors.Pin.prototype.acts.Pin, + cr.plugins_.Sprite.prototype.acts.SetInstanceVar, + cr.plugins_.Sprite.prototype.exps.X, + cr.plugins_.Sprite.prototype.exps.Y, + cr.plugins_.Sprite.prototype.acts.SetPos, + cr.plugins_.SenaPlugin.prototype.acts.CalcObjectPositions, + cr.plugins_.Sprite.prototype.exps.Width, + cr.system_object.prototype.cnds.Repeat, cr.system_object.prototype.exps.loopindex, - cr.plugins_.SenaPlugin.prototype.exps.getOptionsType, - cr.plugins_.SenaPlugin.prototype.exps.getOptionsValue, cr.plugins_.SenaPlugin.prototype.exps.getHintType, cr.plugins_.SenaPlugin.prototype.exps.getHintValue, + cr.system_object.prototype.acts.CreateObject, + cr.plugins_.SenaPlugin.prototype.exps.getPosXbyIndex, + cr.plugins_.SenaPlugin.prototype.exps.getPosYbyIndex, + cr.system_object.prototype.cnds.Compare, + cr.plugins_.Sprite.prototype.acts.SetBoolInstanceVar, + cr.plugins_.Sprite.prototype.acts.SetAnimFrame, + cr.system_object.prototype.cnds.Else, + cr.plugins_.Sprite.prototype.acts.SetY, + cr.plugins_.SenaPlugin.prototype.exps.getOptionsType, + cr.plugins_.SenaPlugin.prototype.exps.getOptionsValue, cr.plugins_.Touch.prototype.cnds.OnTouchObject, - cr.plugins_.SenaPlugin.prototype.acts.Finish, - cr.plugins_.SenaPlugin.prototype.cnds.OnCorrect, - cr.plugins_.Browser.prototype.acts.Alert, - cr.plugins_.SenaPlugin.prototype.cnds.OnWrong, + cr.plugins_.Sprite.prototype.cnds.IsVisible, + cr.system_object.prototype.cnds.CompareVar, + cr.plugins_.Audio.prototype.acts.Play, cr.plugins_.SenaPlugin.prototype.acts.PauseGame, + cr.behaviors.DragnDrop.prototype.acts.SetEnabled, + cr.plugins_.Function.prototype.acts.CallFunction, + cr.system_object.prototype.acts.Wait, + cr.plugins_.SenaPlugin.prototype.cnds.OnCorrect, + cr.plugins_.SenaPlugin.prototype.cnds.OnWrong, cr.plugins_.SenaPlugin.prototype.acts.ResumeGame, cr.plugins_.SenaPlugin.prototype.cnds.OnPause, - cr.plugins_.SenaPlugin.prototype.cnds.OnResume + cr.plugins_.SenaPlugin.prototype.cnds.OnResume, + cr.system_object.prototype.cnds.EveryTick, + cr.plugins_.SenaPlugin.prototype.exps.getTimeLimit, + cr.system_object.prototype.exps.max, + cr.plugins_.SenaPlugin.prototype.exps.getElapsedTime, + cr.system_object.prototype.cnds.TriggerOnce, + cr.plugins_.SpriteFontPlus.prototype.acts.Destroy, + cr.behaviors.Fade.prototype.acts.StartFade, + cr.plugins_.SenaPlugin.prototype.acts.Finish, + cr.plugins_.Function.prototype.cnds.OnFunction, + cr.system_object.prototype.cnds.For, + cr.system_object.prototype.cnds.PickByComparison, + cr.system_object.prototype.exps.left, + cr.system_object.prototype.exps.len, + cr.plugins_.Sprite.prototype.cnds.CompareY, + cr.behaviors.Rex_MoveTo.prototype.acts.SetTargetPos, + cr.behaviors.Rex_MoveTo.prototype.acts.SetTargetPosOnObject, + cr.plugins_.Sprite.prototype.cnds.CompareFrame, + cr.plugins_.Audio.prototype.acts.SetSilent, + cr.system_object.prototype.cnds.LayerVisible, + cr.behaviors.DragnDrop.prototype.cnds.OnDragStart, + cr.plugins_.Sprite.prototype.cnds.CompareInstanceVar, + cr.plugins_.Sprite.prototype.cnds.IsOverlapping, + cr.plugins_.Sprite.prototype.acts.MoveToTop, + cr.plugins_.SpriteFontPlus.prototype.acts.MoveToTop, + cr.behaviors.DragnDrop.prototype.cnds.OnDrop, + cr.plugins_.Sprite.prototype.cnds.IsBoolInstanceVarSet, + cr.plugins_.Sprite.prototype.cnds.PickDistance, + cr.behaviors.Rex_MoveTo.prototype.acts.SetMaxSpeed, + cr.system_object.prototype.acts.AddVar, + cr.behaviors.DragnDrop.prototype.cnds.IsDragging, + cr.plugins_.Touch.prototype.exps.X, + cr.plugins_.Touch.prototype.exps.Y, + cr.plugins_.Sprite.prototype.acts.SetVisible ];}; diff --git a/New-project/data.js b/New-project/data.js index ba19408..f5103a4 100644 --- a/New-project/data.js +++ b/New-project/data.js @@ -1 +1 @@ -{"project": [null,null,[[0,true,false,false,false,false,false,false,false,false],[1,false,true,true,true,true,true,true,true,false],[2,true,false,false,false,false,false,false,false,false],[3,true,false,false,false,false,false,false,false,false]],[["t0",2,false,[],0,0,null,null,[],false,false,394152958375253,[],null,["G2500S1T45"]],["t1",0,false,[],0,0,null,null,[],false,false,181015701933739,[],null,[]],["t2",1,false,[],0,0,null,[["Default",5,false,1,0,false,266653407798345,[["images/correct-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,870372553390403,[],null],["t3",1,false,[],0,0,null,[["Default",5,false,1,0,false,644390976254011,[["images/wrong-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,726240664871372,[],null],["t4",3,false,[],0,0,null,null,[],false,false,288430412484243,[],null,[1]],["t5",1,false,[],0,0,null,[["Default",5,false,1,0,false,974942116247628,[["images/correct-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,829278278494442,[],null],["t6",1,false,[],0,0,null,[["Default",5,false,1,0,false,830476950235748,[["images/correct-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,250461366236378,[],null]],[],[["Layout 1",854,480,false,"Event sheet 1",148229480160171,[["Layer 0",0,715835324311419,true,[255,255,255],false,1,1,1,false,false,1,0,0,[[[212,239,0,250,250,0,0,1,0.5,0.5,0,0,[]],2,2,[],[],[0,"Default",0,1]],[[616,243,0,250,250,0,0,1,0.5,0.5,0,0,[]],3,3,[],[],[0,"Default",0,1]],[[805.5712890625,46.07132720947266,0,58,49,0,0,1,0.5,0.5,0,0,[]],5,5,[],[],[0,"Default",0,1]],[[804,115,0,58.32666778564453,58.32666778564453,0,0,1,0.5,0.5,0,0,[]],6,6,[],[],[0,"Default",0,1]]],[]]],[],[]]],[["Event sheet 1",[[0,null,false,null,421297551205104,[[-1,4,null,1,false,false,false,438843515576193,false]],[[0,5,null,551138518888793,false]]],[0,null,false,null,432411265738905,[[0,6,null,1,false,false,false,913106290597646,false]],[[1,7,null,260483465573520,false,[[3,0],[7,[2,"Load dữ liệu xong"]]]],[1,7,null,330854144982241,false,[[3,0],[7,[20,0,8,true,null]]]]],[[0,null,false,null,122100426567399,[],[[0,9,null,458181517098292,false]]]]],[0,null,false,null,495673204159818,[[0,10,null,1,false,false,false,157454832331304,false]],[[1,7,null,816803828558793,false,[[3,0],[7,[10,[10,[10,[2,"Question :"],[20,0,11,true,null]],[2," with value : "]],[20,0,12,true,null]]]]],[1,7,null,585706784629547,false,[[3,0],[7,[10,[10,[10,[2,"Request :"],[20,0,13,true,null]],[2," with value : "]],[20,0,14,true,null]]]]],[1,7,null,103090682922262,false,[[3,0],[7,[10,[2,"Options Count :"],[20,0,15,false,null]]]]],[1,7,null,460050924307031,false,[[3,0],[7,[10,[2,"Hint Count :"],[20,0,16,false,null]]]]]],[[0,null,false,null,441467613146144,[[-1,17,null,0,true,false,false,218190693390519,false,[[1,[2,""]],[0,[0,0]],[0,[5,[19,18,[[20,0,15,false,null]]],[0,1]]]]]],[[1,7,null,901551014325770,false,[[3,0],[7,[10,[10,[10,[10,[10,[2,"Options "],[19,19]],[2," : "]],[20,0,20,true,null]],[2," with value : "]],[20,0,21,true,null,[[19,19]]]]]]]]],[0,null,false,null,452078189778132,[[-1,17,null,0,true,false,false,488889777784546,false,[[1,[2,""]],[0,[0,0]],[0,[5,[19,18,[[20,0,16,false,null]]],[0,1]]]]]],[[1,7,null,239886316843096,false,[[3,0],[7,[10,[10,[10,[10,[10,[2,"Hint "],[19,19]],[2," : "]],[20,0,22,true,null]],[2," with value : "]],[20,0,23,false,null,[[19,19]]]]]]]]]]],[0,null,false,null,391531229850255,[[4,24,null,1,false,false,false,541795463553529,false,[[4,2]]]],[[0,25,null,103117520878571,false,[[7,[2,"I|LIKE|TO|EAT|APPLES"]]]]]],[0,null,false,null,866863525099821,[[4,24,null,1,false,false,false,974201409974649,false,[[4,3]]]],[[0,25,null,286981086983136,false,[[7,[2,"wrong"]]]]]],[0,null,false,null,131646557054595,[[0,26,null,1,false,false,false,891894169376380,false]],[[1,27,null,199585234737951,false,[[7,[2,"Correct"]]]]]],[0,null,false,null,626804407280781,[[0,28,null,1,false,false,false,435087545862561,false]],[[1,27,null,396505785276944,false,[[7,[2,"Wrong"]]]]]],[0,null,false,null,138784311293898,[[4,24,null,1,false,false,false,318840334321068,false,[[4,5]]]],[[0,29,null,188346907636434,false]]],[0,null,false,null,144690028489488,[[4,24,null,1,false,false,false,961657910924384,false,[[4,6]]]],[[0,30,null,863067724909837,false]]],[0,null,false,null,339829265544415,[[0,31,null,1,false,false,false,425081282629100,false]],[[1,27,null,893764481095634,false,[[7,[2,"Game Pause"]]]]]],[0,null,false,null,619901953302901,[[0,32,null,1,false,false,false,453788771302771,false]],[[1,27,null,305993959250131,false,[[7,[2,"Resume Game"]]]],[0,5,null,517239799743314,false]]]]]],[],"media/",false,854,480,4,true,true,true,"1.0.0.0",true,false,4,0,7,false,true,1,true,"New project",0,[]]} \ No newline at end of file +{"project": [null,null,[[0,true,false,false,false,false,false,false,false,false],[1,true,false,false,false,false,false,false,false,false],[2,true,false,false,false,false,false,false,false,false],[3,false,true,true,true,true,true,true,true,false],[4,true,false,false,false,false,false,false,false,false],[5,false,true,true,true,true,true,true,true,true],[6,true,false,false,false,false,false,false,false,false]],[["t0",4,false,[],0,0,null,null,[],false,false,394152958375253,[],null,["G2800S1T30"]],["t1",1,false,[],0,0,null,null,[],false,false,181015701933739,[],null,[]],["t2",3,false,[],0,0,null,[["Default",5,false,1,0,false,266653407798345,[["images/btn_check-sheet0.png",17703,0,0,165,75,1,0.5030303001403809,0.5066666603088379,[],[],0]]]],[],false,false,870372553390403,[],null],["t3",3,false,[],0,0,null,[["Default",5,false,1,0,false,644390976254011,[["images/wrong-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,726240664871372,[],null],["t4",6,false,[],0,0,null,null,[],false,false,288430412484243,[],null,[1]],["t5",3,false,[],0,0,null,[["Default",5,false,1,0,false,974942116247628,[["images/pause-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,829278278494442,[],null],["t6",3,false,[],0,0,null,[["Default",5,false,1,0,false,830476950235748,[["images/pause-sheet0.png",155,0,0,250,250,1,0.5,0.5,[],[],1]]]],[],false,false,250461366236378,[],null],["t7",3,false,[839027338172447,370467464601183,403859397610033],1,0,null,[["Default",0,false,1,0,false,201845729772152,[["images/slot-sheet0.png",36041,1,1,200,75,1,0.5,0.5066666603088379,[],[],0],["images/slot-sheet0.png",36041,1,78,200,75,1,0.5,0.4933333396911621,[],[],0],["images/slot-sheet0.png",36041,1,155,200,75,1,0.4350000023841858,0.5199999809265137,[],[],0]]]],[["Fade",7,588103285968005]],false,false,530929310100717,[],null],["t8",3,false,[401281652261798,308058330719086,937883104346632,243525000976275,435711195864159],3,0,null,[["Default",5,false,1,0,false,344548683716056,[["images/slot-sheet0.png",36041,1,78,200,75,1,0.5,0.4933333396911621,[],[],0]]]],[["DragDrop",8,551257499299552],["Fade",7,430149822241515],["MoveTo",9,551694077436381]],false,false,515230787966511,[],null],["t9",2,false,[],0,0,null,null,[],false,false,825652157577718,[],null,[]],["t10",5,false,[],0,0,["images/txt_texttimer.png",94512,0],null,[],false,false,428453985749595,[],null],["t11",5,false,[],0,0,["images/txt_worditem.png",94801,0],null,[],false,false,125516006976486,[],null],["t12",5,false,[],0,0,["images/txt_texttimer.png",94512,0],null,[],false,false,680183373657896,[],null],["t13",3,false,[],0,0,null,[["Default",5,false,1,0,false,943124209669759,[["images/5sosarahtakesoff-sheet0.png",1099565,0,0,1400,900,1,0.5,0.5,[],[],1]]]],[],false,false,663734962307467,[],null],["t14",3,false,[],0,0,null,[["Default",5,false,1,0,false,174194635978617,[["images/senaaikhoi-sheet0.png",230528,0,0,1145,446,1,0.4995633065700531,0.4977578520774841,[],[],0]]]],[],false,false,577948289650662,[],null],["t15",3,false,[],0,0,null,[["Default",0,false,1,0,false,329974099612225,[["images/checker_wrong_correct-sheet0.png",10219,0,0,140,140,1,0.5,0.5,[],[-0.3642860054969788,-0.3642860054969788,0,-0.4357143044471741,0.3642860054969788,-0.3642860054969788,0.3999999761581421,0,0.3142859935760498,0.3142859935760498,0,0.442857027053833,-0.2928569912910461,0.2928569912910461,-0.3857139945030212,0],0],["images/checker_wrong_correct-sheet1.png",7978,0,0,140,140,1,0.5,0.5,[],[-0.357142984867096,-0.357142984867096,0,-0.4357143044471741,0.357142984867096,-0.357142984867096,0.3857139945030212,0,0.3642860054969788,0.3642860054969788,0,0.4142860174179077,-0.2857140004634857,0.2857139706611633,-0.3857139945030212,0],0]]]],[],false,false,246032193737445,[],null],["t16",0,false,[],0,0,null,null,[],false,false,396522085041537,[],null,[0,0,0,1,1,600,600,10000,1]],["t17",3,false,[],0,0,null,[["Default",5,false,1,0,false,857466576876240,[["images/btn_setting-sheet0.png",13202,0,0,99,91,1,0.5050504803657532,0.5054945349693298,[],[-0.3656864762306213,-0.3547005355358124,-0.006272494792938232,-0.5028490424156189,0.355585515499115,-0.3547005355358124,0.485169529914856,-0.005494534969329834,0.3604755401611328,0.349002480506897,-0.006272494792938232,0.4865684509277344,-0.3681314587593079,0.3463574647903442,-0.4977155327796936,-0.005494534969329834],0]]]],[],false,false,444899307061590,[],null],["t18",3,false,[],0,0,null,[["Default",5,false,1,0,false,922486781068681,[["images/panel-sheet0.png",105765,0,0,815,474,1,0.5141104459762573,0.4852320551872253,[],[-0.4453988373279572,0.4156119227409363,-0.5067484974861145,-5.960464477539063e-008,-0.433128833770752,-0.3945147395133972,-4.172325134277344e-007,-0.4704641699790955,0.4184045791625977,-0.3691980540752411,0.4797545671463013,-5.960464477539063e-008,0.4294475317001343,0.3881859183311462,-4.172325134277344e-007,0.5084389448165894],0]]]],[],false,false,150393696478915,[],null],["t19",5,false,[],0,0,["images/txt_question.png",192019,0],null,[],false,false,389192760965508,[],null],["t20",3,false,[637523801130517,567457434227301],1,0,null,[["Default",5,false,1,0,false,177577261579169,[["images/btn_pause-sheet0.png",11757,0,0,99,91,1,0.5050504803657532,0.5054945349693298,[],[-0.365747481584549,-0.3577375411987305,-0.005050480365753174,-0.5028560161590576,0.3556455373764038,-0.3577375411987305,0.4899744987487793,-0.006813526153564453,0.3581334948539734,0.34938645362854,-0.005050480365753174,0.4892284870147705,-0.365747481584549,0.3467484712600708,-0.4975878000259399,-0.006813526153564453],0]]]],[["MoveTo",9,345261300394347]],false,false,680660539195378,[],null],["t21",3,false,[546775332106909,966775272495183],1,0,null,[["Default",0,false,1,0,false,632596314970396,[["images/btn_music-sheet0.png",13358,0,0,99,91,1,0.5050504803657532,0.5054945349693298,[],[],0],["images/btn_music-sheet1.png",14207,0,0,99,91,1,0.5050504803657532,0.5054945349693298,[],[],0]]]],[["MoveTo",9,561713266057788]],false,false,470943728107764,[],null],["t22",3,false,[],0,0,null,[["Default",5,false,1,0,false,804798480075980,[["images/panel_pause-sheet0.png",168,0,0,250,250,1,0.5,0.5,[],[],0]]]],[],false,false,103999013142366,[],null],["t23",3,false,[],1,0,null,[["Default",5,false,1,0,false,794524614026990,[["images/layer-sheet0.png",111520,0,0,400,376,1,0.5,0.5,[],[-0.362500011920929,-0.3537229895591736,0,-0.5,0.362500011920929,-0.3537229895591736,0.497499942779541,0,0.3650000095367432,0.3563830256462097,0,0.5,-0.3650000095367432,0.3563830256462097,-0.5,0],0]]]],[["Sine",10,152768910804631]],false,false,822735679292648,[],null],["t24",3,false,[],0,0,null,[["Default",5,false,1,0,false,185281331107930,[["images/newwordpng-sheet0.png",166389,0,0,500,341,1,0.5,0.5014662742614746,[],[-0.3939999938011169,-0.3460412621498108,0,-0.4398826658725739,0.1480000019073486,0.01466274261474609,0.2919999957084656,-0.00293228030204773,0.4660000205039978,0.4486806988716126,0,0.4721407294273377,-0.4620000123977661,0.4428157210350037,-0.2820000052452087,-0.00293228030204773],0]]]],[],false,false,139959116973831,[],null],["t25",5,true,[],1,0,null,null,[["Pin",11,693926857619114]],false,false,154178255437462,[],null],["t26",3,true,[],0,0,null,null,[],false,false,909098946188328,[],null]],[[25,19,12,10,11],[26,21,20,17,23]],[["Layout 1",1200,1200,false,"Event sheet 1",148229480160171,[["BG",0,977906834634586,true,[255,255,255],true,1,1,1,false,false,1,0,0,[[[600,600,0,1946.035888671875,1251.023071289063,0,0,1,0.5,0.5,0,0,[]],13,13,[],[],[0,"Default",0,1]]],[]],["Main",1,715835324311419,true,[255,255,255],true,1,1,1,false,false,1,0,0,[[[600.5625,863,0,185.6243591308594,84.37471008300781,0,0,1,0.5030303001403809,0.5066666603088379,0,0,[]],2,2,[],[],[0,"Default",0,1]],[[998,-788,0,250,250,0,0,1,0.5,0.5,0,0,[]],3,3,[],[],[0,"Default",0,1]],[[314,-701,0,58,49,0,0,1,0.5,0.5,0,0,[]],5,5,[],[],[0,"Default",0,1]],[[313,-632,0,58.32666778564453,58.32666778564453,0,0,1,0.5,0.5,0,0,[]],6,6,[],[],[0,"Default",0,1]],[[209,-866,0,200,75,0,0,1,0.5,0.5066666603088379,0,0,[]],7,7,[[0],[""],[0]],[[0,0,0,2,1]],[0,"Default",0,1]],[[-35,-863,0,200,75,0,0,1,0.5,0.4933333396911621,0,0,[]],8,8,[[""],[0],[0],[-1],[0]],[[0,1],[0,0,0,2,1],[1,1200,0,0]],[0,"Default",0,1]],[[668,-675,0,160.2111206054688,55.53988647460938,0,0,1,0.5,0.5,0,0,[]],11,11,[],[[]],[76,83,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,;:?!-_~#\"'&()[]|`\\/@°+=*$£€<>%","Text",0.5,0,1,1,1,0,0,0,"[[34,\" \"],[14,\"|\"],[16,\"il\"],[17,\"I.:'\"],[18,\";!\"],[19,\",\"],[22,\"`\"],[24,\")\"],[25,\"(\\\\/\"],[26,\"[\"],[27,\"j]\"],[28,\"-\"],[29,\"°\"],[32,\"t1\"],[33,\"\\\"\"],[34,\"r\"],[35,\"f\"],[36,\"*\"],[39,\"s\"],[40,\"kx\"],[41,\"Jhnu\"],[42,\"v7?+=<>\"],[43,\"Faceyz0238\"],[44,\"L569_~$\"],[45,\"bdgopq\"],[46,\"P#\"],[47,\"EX\"],[48,\"S4€\"],[49,\"Y£\"],[50,\"BNR\"],[51,\"DHKTU\"],[52,\"VZ\"],[53,\"C\"],[54,\"A\"],[55,\"&\"],[56,\"GM\"],[57,\"O\"],[60,\"Q\"],[62,\"mw\"],[65,\"%\"],[72,\"W\"],[74,\"@\"]]",-1]],[[474,-928,0,160.2109985351563,55.54000091552734,0,0,1,0.5,0.5,0,0,[]],12,12,[],[[]],[76,83,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,;:?!-_~#\"'&()[]|`\\/@°+=*$£€<>%","Text",0.5,0,1,1,1,0,0,0,"[[34,\" \"],[14,\"|\"],[16,\"il\"],[17,\"I.:'\"],[18,\";!\"],[19,\",\"],[22,\"`\"],[24,\")\"],[25,\"(\\\\/\"],[26,\"[\"],[27,\"j]\"],[28,\"-\"],[29,\"°\"],[32,\"t1\"],[33,\"\\\"\"],[34,\"r\"],[35,\"f\"],[36,\"*\"],[39,\"s\"],[40,\"kx\"],[41,\"Jhnu\"],[42,\"v7?+=<>\"],[43,\"Faceyz0238\"],[44,\"L569_~$\"],[45,\"bdgopq\"],[46,\"P#\"],[47,\"EX\"],[48,\"S4€\"],[49,\"Y£\"],[50,\"BNR\"],[51,\"DHKTU\"],[52,\"VZ\"],[53,\"C\"],[54,\"A\"],[55,\"&\"],[56,\"GM\"],[57,\"O\"],[60,\"Q\"],[62,\"mw\"],[65,\"%\"],[72,\"W\"],[74,\"@\"]]",-1]],[[1052,70,0,255.0779113769531,99.35787963867188,0,0,1,0.4995633065700531,0.4977578520774841,0,0,[]],14,14,[],[],[0,"Default",0,1]],[[1080,72,0,132,77,0,0,1,0.5,0.5,0,0,[]],10,10,[],[[]],[76,83,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,;:?!-_~#\"'&()[]|`\\/@°+=*$£€<>%","TIME",0.7,0,1,1,1,0,0,0,"[[34,\" \"],[14,\"|\"],[16,\"il\"],[17,\"I.:'\"],[18,\";!\"],[19,\",\"],[22,\"`\"],[24,\")\"],[25,\"(\\\\/\"],[26,\"[\"],[27,\"j]\"],[28,\"-\"],[29,\"°\"],[32,\"t1\"],[33,\"\\\"\"],[34,\"r\"],[35,\"f\"],[36,\"*\"],[39,\"s\"],[40,\"kx\"],[41,\"Jhnu\"],[42,\"v7?+=<>\"],[43,\"Faceyz0238\"],[44,\"L569_~$\"],[45,\"bdgopq\"],[46,\"P#\"],[47,\"EX\"],[48,\"S4€\"],[49,\"Y£\"],[50,\"BNR\"],[51,\"DHKTU\"],[52,\"VZ\"],[53,\"C\"],[54,\"A\"],[55,\"&\"],[56,\"GM\"],[57,\"O\"],[60,\"Q\"],[62,\"mw\"],[65,\"%\"],[72,\"W\"],[74,\"@\"]]",-1]],[[109,-653,0,140,140,0,0,1,0.5,0.5,0,0,[]],15,15,[],[],[0,"Default",0,1]],[[610.8635864257813,343,0,769.8975830078125,447.7686462402344,0,0,1,0.5141104459762573,0.4852320551872253,0,0,[]],18,18,[],[],[0,"Default",0,1]],[[600,356,0,684,349,0,0,1,0.5,0.5,0,0,[]],19,19,[],[[]],[73,98,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,;:?!-_~#\"'&()[]|`/@°+=*$£€<>%ÁÀẢẠÃĂẰẮẶẲẴÂẦẤẬẨẪĐÉÈẺẸẼÊỀẾỆỂỄÍÌỊỈĨÓÒỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠÚÙỤỦŨƯỪỨỰỬỮÝỲỴỶỸáàảạãăằắặẳẵâầấậẩẫđéèẻẹẽêềếệểễíìịỉĩóòọỏõôồốộổỗơờớợởỡúùụủũưừứựửữýỳỵỷỹ","Sắp xếp các từ sau thành câu đúng",0.85,0,1,1,1,0,0,0,"[[34,\" \"],[14,\"|\"],[16,\"il\"],[17,\"I.:'\"],[18,\";!\"],[19,\",ỊỈịỉ\"],[21,\"Ííì\"],[22,\"`Ì\"],[24,\")\"],[25,\"(/\"],[26,\"[\"],[27,\"j]\"],[28,\"-\"],[29,\"°\"],[32,\"t1ĩ\"],[33,\"\\\"Ĩ\"],[34,\"r\"],[35,\"f\"],[36,\"*\"],[37,\"ẺẸẼỆỄ\"],[39,\"sảạăằắặẳẵậẫ\"],[40,\"kx\"],[41,\"Jhnuẻẹẽệễúùụủũ\"],[42,\"v7?+=<>Ể\"],[43,\"Faceyz0238áàãâéèêý\"],[44,\"L569_~$ẩ\"],[45,\"bdgopqểóòõô\"],[46,\"P#ọỏộỗỳỵỷỹ\"],[47,\"EXÉÈÊỀẾầềổ\"],[48,\"S4€ỤỦŨ\"],[49,\"Y£Ýấđơờớợởỡ\"],[50,\"BNRỲỴỶỸế\"],[51,\"DHKTUÚÙồưừứựửữ\"],[52,\"VZố\"],[53,\"C\"],[54,\"AÁÀÃÂ\"],[55,\"&\"],[56,\"GMỌỎỒỘỔỖ\"],[57,\"OẢẠĂẰẮẶẲẴẦẤẬẨẪĐÓÒÕÔỐ\"],[59,\"ƯỪỨỰỬỮ\"],[60,\"Q\"],[62,\"mwƠỜỚỢỞỠ\"],[65,\"%\"],[72,\"W\"],[74,\"@\"]]",-1]],[[1136.894897460938,1055.94287109375,0,82.66699981689453,75.98699951171875,0,0,1,0.5050504803657532,0.5054945349693298,0,0,[]],20,20,[[0],[0]],[[1,400,0,0]],[0,"Default",0,1]],[[1136.535278320313,964.1973876953125,0,82.66699981689453,75.98699951171875,0,0,1,0.5050504803657532,0.5054945349693298,0,0,[]],21,21,[[0],[0]],[[1,400,0,0]],[0,"Default",0,1]],[[1137.084106445313,1146.424194335938,0,82.66677093505859,75.98662567138672,0,0,1,0.5050504803657532,0.5054945349693298,0,0,[]],17,17,[],[],[0,"Default",0,1]]],[]],["Pause",2,621954870190361,true,[255,255,255],true,1,1,1,false,false,1,0,0,[[[600,600,0,1946.036010742188,1251.02294921875,0,0,1,0.5,0.5,0,0,[]],22,22,[],[],[0,"Default",0,1]],[[600,600,0,400,376,0,0,1,0.5,0.5,0,0,[]],23,23,[],[[1,2,0,3,0,0,0,50,0]],[0,"Default",0,1]]],[]],["Logo",3,899027236628199,true,[255,255,255],true,1,1,1,false,false,1,0,0,[[[110,77,0,195.7390747070313,133.4940490722656,0,0,1,0.5,0.5014662742614746,0,0,[]],24,24,[],[],[0,"Default",0,1]]],[]]],[],[]]],[["Event sheet 1",[[1,"Paused",0,0,false,false,881036884152158,false],[2,"DrapDrop",false],[1,"end",0,-1,false,false,348658772353398,false],[1,"isTimeUp",0,0,false,false,617056362802034,false],[1,"timeLeft",0,0,false,false,670843326082385,false],[1,"answer",1,"",false,false,538561721013949,false],[0,null,false,null,421297551205104,[[-1,12,null,1,false,false,false,438843515576193,false]],[[0,13,null,551138518888793,false],[-1,14,null,392038834754127,false,[[5,[0,2]],[3,0]]]]],[0,null,false,null,432411265738905,[[0,15,null,1,false,false,false,913106290597646,false]],[[1,16,null,260483465573520,false,[[3,0],[7,[2,"Load dữ liệu xong"]]]],[1,16,null,330854144982241,false,[[3,0],[7,[20,0,17,true,null]]]]],[[0,null,false,null,122100426567399,[],[[0,18,null,458181517098292,false]]]]],[0,null,false,null,495673204159818,[[0,19,null,1,false,false,false,157454832331304,false]],[[1,16,null,816803828558793,false,[[3,0],[7,[10,[10,[10,[2,"Question :"],[20,0,20,true,null]],[2," with value : "]],[20,0,21,true,null]]]]],[1,16,null,585706784629547,false,[[3,0],[7,[10,[10,[10,[2,"Request :"],[20,0,22,true,null]],[2," with value : "]],[20,0,23,true,null]]]]],[1,16,null,103090682922262,false,[[3,0],[7,[10,[2,"Options Count :"],[20,0,24,false,null]]]]],[1,16,null,460050924307031,false,[[3,0],[7,[10,[2,"Hint Count :"],[20,0,25,false,null]]]]],[7,26,null,227093858363506,false],[8,26,null,601277174090980,false],[-1,27,null,623599131030475,false,[[11,"isTimeUp"],[7,[0,0]]]],[-1,27,null,425755884896431,false,[[11,"end"],[7,[19,28,[[20,0,24,false,null]]]]]],[19,29,null,808593987399542,false,[[7,[20,0,21,true,null]]]],[10,30,"Pin",636254900159958,false,[[4,14],[3,0]]],[19,30,"Pin",210783341114782,false,[[4,18],[3,0]]],[20,31,null,756761854102448,false,[[10,0],[7,[20,20,32,false,null]]]],[20,31,null,843231659647898,false,[[10,1],[7,[20,20,33,false,null]]]],[20,34,null,429067541495196,false,[[0,[20,17,32,false,null]],[0,[20,17,33,false,null]]]],[21,31,null,312955471850139,false,[[10,0],[7,[20,21,32,false,null]]]],[21,31,null,725880314927928,false,[[10,1],[7,[20,21,33,false,null]]]],[21,34,null,588637745430653,false,[[0,[20,17,32,false,null]],[0,[20,17,33,false,null]]]]],[[0,null,false,null,278599510819277,[],[[0,35,null,505162364268873,false,[[0,[19,28,[[20,0,25,false,null]]]],[0,[20,7,36,false,null]],[0,[0,20]],[0,[0,1200]],[0,[0,0]],[0,[0,100]],[1,[2,"slot"]]]]],[[0,null,false,null,452078189778132,[[-1,37,null,0,true,false,false,488889777784546,false,[[0,[19,28,[[20,0,25,false,null]]]]]]],[[1,16,null,239886316843096,false,[[3,0],[7,[10,[10,[10,[10,[10,[2,"Hint "],[19,38]],[2," : "]],[20,0,39,true,null]],[2," with value : "]],[20,0,40,false,null,[[19,38]]]]]]],[-1,41,null,371942430718793,false,[[4,7],[5,[0,1]],[0,[20,0,42,false,null,[[19,38]]]],[0,[4,[20,0,43,false,null,[[19,38]]],[0,650]]]]],[7,31,null,933941275549609,false,[[10,0],[7,[19,38]]]],[7,31,null,380164134533232,false,[[10,1],[7,[20,0,40,false,null,[[19,38]]]]]]],[[0,null,false,null,698796573985720,[[-1,44,null,0,false,false,false,410553190492367,false,[[7,[20,0,40,false,null,[[19,38]]]],[8,1],[7,[2,"_"]]]]],[[7,45,null,847566670403732,false,[[10,2],[3,1]]],[-1,41,null,521667370636870,false,[[4,12],[5,[0,1]],[0,[20,7,32,false,null]],[0,[20,7,33,false,null]]]],[12,30,"Pin",361028315192679,false,[[4,7],[3,0]]],[12,29,null,466267976699500,false,[[7,[21,7,true,null,1]]]],[7,46,null,354611702724504,false,[[0,[0,1]]]]]],[0,null,false,null,848543107448972,[[-1,47,null,0,false,false,false,386888311054006,false]],[[7,45,null,590812225579568,false,[[10,2],[3,0]]]]]]]]],[0,null,false,null,822104816469346,[],[[0,35,null,737719939649407,false,[[0,[19,28,[[20,0,24,false,null]]]],[0,[20,8,36,false,null]],[0,[0,20]],[0,[0,1200]],[0,[0,0]],[0,[0,100]],[1,[2,"word"]]]],[2,48,null,256704970269789,false,[[0,[4,[20,0,43,false,null,[[0,0]]],[0,700]]]]]],[[0,null,false,null,441467613146144,[[-1,37,null,0,true,false,false,218190693390519,false,[[0,[19,28,[[20,0,24,false,null]]]]]]],[[1,16,null,901551014325770,false,[[3,0],[7,[10,[10,[10,[10,[10,[2,"Options "],[19,38]],[2," : "]],[20,0,49,true,null]],[2," with value : "]],[20,0,50,true,null,[[19,38]]]]]]],[-1,41,null,722355474670048,false,[[4,8],[5,[0,1]],[0,[20,0,42,false,null,[[19,38]]]],[0,[4,[20,0,43,false,null,[[19,38]]],[0,700]]]]],[8,31,null,424845902591780,false,[[10,0],[7,[20,0,50,true,null,[[19,38]]]]]],[8,31,null,732477610518970,false,[[10,3],[7,[0,-1]]]],[8,31,null,972534679995256,false,[[10,1],[7,[20,8,32,false,null]]]],[8,31,null,955022957314574,false,[[10,2],[7,[20,8,33,false,null]]]],[-1,41,null,820542104698850,false,[[4,11],[5,[0,1]],[0,[20,8,32,false,null]],[0,[20,8,33,false,null]]]],[11,30,"Pin",165265909130423,false,[[4,8],[3,0]]],[11,29,null,752256115955919,false,[[7,[21,8,true,null,0]]]]]]]]]],[0,null,false,null,391531229850255,[[4,51,null,1,false,false,false,541795463553529,false,[[4,2]]],[2,52,null,0,false,false,false,463624702778654,false],[-1,53,null,0,false,false,false,211208220731414,false,[[11,"Paused"],[8,0],[7,[0,0]]]]],[[16,54,null,933729384541080,false,[[2,["click",false]],[3,0],[0,[0,-2]],[1,[2,""]]]],[0,55,null,256977907477815,false],[8,56,"DragDrop",500676445420163,false,[[3,0]]],[-1,27,null,392747038186299,false,[[11,"answer"],[7,[2,""]]]],[9,57,null,286145656469424,false,[[1,[2,"currentAnswer"]],[13]]],[-1,58,null,870335272692108,false,[[0,[0,3]]]]]],[0,null,false,null,131646557054595,[[0,59,null,1,false,false,false,891894169376380,false]],[[16,54,null,327930580854185,false,[[2,["correct",false]],[3,0],[0,[0,-2]],[1,[2,""]]]],[-1,41,null,202907159105342,false,[[4,15],[5,[0,1]],[0,[20,2,32,false,null]],[0,[20,2,33,false,null]]]],[15,46,null,145728902691754,false,[[0,[0,0]]]]]],[0,null,false,null,626804407280781,[[0,60,null,1,false,false,false,435087545862561,false]],[[16,54,null,217938364629081,false,[[2,["error-010-206498",false]],[3,0],[0,[0,-2]],[1,[2,""]]]],[-1,41,null,522820795913632,false,[[4,15],[5,[0,1]],[0,[20,2,32,false,null]],[0,[20,2,33,false,null]]]],[15,46,null,743250840849647,false,[[0,[0,1]]]]]],[0,null,false,null,138784311293898,[[4,51,null,1,false,false,false,318840334321068,false,[[4,5]]]],[[0,55,null,188346907636434,false]]],[0,null,false,null,144690028489488,[[4,51,null,1,false,false,false,961657910924384,false,[[4,6]]]],[[0,61,null,863067724909837,false]]],[0,null,false,null,339829265544415,[[0,62,null,1,false,false,false,425081282629100,false]],[[-1,27,null,357857564221621,false,[[11,"Paused"],[7,[0,1]]]]]],[0,null,false,null,619901953302901,[[0,63,null,1,false,false,false,453788771302771,false]],[[-1,27,null,986855891964228,false,[[11,"Paused"],[7,[0,0]]]]]],[0,null,false,null,678278685100726,[[-1,64,null,0,false,false,false,839154243379294,false]],[],[[0,null,false,null,203029406704081,[[-1,44,null,0,false,false,false,812877676162386,false,[[7,[20,0,65,false,null]],[8,4],[7,[0,0]]]]],[[-1,27,null,282958384255218,false,[[11,"timeLeft"],[7,[19,66,[[0,0],[5,[20,0,65,false,null],[20,0,67,false,null]]]]]]],[10,29,null,175097790282221,false,[[7,[19,28,[[23,"timeLeft"]]]]]]]]]],[0,null,false,null,978751838447749,[[-1,64,null,0,false,false,false,740586896137774,false]],[],[[0,null,false,null,539759871180422,[[-1,44,null,0,false,false,false,735943013123850,false,[[7,[20,0,67,false,null]],[8,4],[7,[20,0,65,false,null]]]],[-1,53,null,0,false,false,false,856670007560900,false,[[11,"isTimeUp"],[8,0],[7,[0,0]]]],[-1,68,null,0,false,false,false,955668488059869,false]],[[-1,27,null,302945892896402,false,[[11,"isTimeUp"],[7,[0,1]]]],[8,56,"DragDrop",118986934409651,false,[[3,0]]],[11,69,null,739058330936640,false],[8,70,"Fade",429052538282797,false],[-1,58,null,917300360080570,false,[[0,[1,1]]]],[7,70,"Fade",315915830094512,false],[8,26,null,585032189291227,false],[12,69,null,239984847558684,false],[0,71,null,474781657260693,false,[[7,[23,"answer"]]]]]]]],[0,null,false,null,365785861310817,[[9,72,null,2,false,false,false,466620429321609,false,[[1,[2,"currentAnswer"]]]]],[],[[0,null,false,null,780375794781622,[[-1,73,null,0,true,false,false,143001263185103,false,[[1,[2,"i"]],[0,[0,0]],[0,[5,[19,28,[[20,0,25,false,null]]],[0,1]]]]]],[],[[0,null,false,null,623354472074576,[[-1,74,null,0,false,false,false,929134158340487,false,[[4,7],[7,[21,7,false,null,0]],[8,0],[7,[19,38]]]]],[[-1,27,null,483299828391284,false,[[11,"answer"],[7,[10,[10,[23,"answer"],[21,7,true,null,1]],[2,"|"]]]]]]]]],[0,null,false,null,475666535596674,[],[[-1,27,null,374977936278745,false,[[11,"answer"],[7,[19,75,[[23,"answer"],[5,[19,76,[[23,"answer"]]],[0,1]]]]]]],[0,71,null,103117520878571,false,[[7,[23,"answer"]]]]]]]],[0,null,false,null,600608562107578,[[4,51,null,1,false,false,false,891500002256313,false,[[4,17]]]],[],[[0,null,false,null,426459896580949,[[21,77,null,0,false,false,false,811423894111416,false,[[8,0],[0,[20,17,33,false,null]]]]],[[20,78,"MoveTo",576994443738303,false,[[0,[21,20,false,null,0]],[0,[21,20,false,null,1]]]],[21,78,"MoveTo",664066818448917,false,[[0,[21,21,false,null,0]],[0,[21,21,false,null,1]]]]]],[0,null,false,null,813987173387856,[[21,77,null,0,false,false,false,360548133253360,false,[[8,0],[0,[21,21,false,null,1]]]]],[[20,79,"MoveTo",564863130284639,false,[[4,17]]],[21,79,"MoveTo",753250951346862,false,[[4,17]]]]]]],[0,null,false,null,398375489714286,[[4,51,null,1,false,false,false,723806263526938,false,[[4,21]]],[21,77,null,0,false,false,false,181942908228041,false,[[8,0],[0,[21,21,false,null,1]]]]],[],[[0,null,false,null,859972771487505,[[21,80,null,0,false,false,false,990148759371186,false,[[8,0],[0,[0,0]]]]],[[21,46,null,728229426682011,false,[[0,[0,1]]]],[16,81,null,436791612138112,false,[[3,0]]]]],[0,null,false,null,474877987440232,[[-1,47,null,0,false,false,false,904405232089990,false]],[[21,46,null,569169335937351,false,[[0,[0,0]]]],[16,81,null,898083323827850,false,[[3,1]]]]]]],[0,null,false,null,246743788520867,[[4,51,null,1,false,false,false,801931205987650,false,[[4,20]]],[20,77,null,0,false,false,false,551526414582339,false,[[8,0],[0,[21,20,false,null,1]]]]],[[0,55,null,135302385113891,false],[20,79,"MoveTo",959639910199972,false,[[4,17]]],[21,79,"MoveTo",258657396501857,false,[[4,17]]],[-1,58,null,387073202837793,false,[[0,[1,0.5]]]],[-1,14,null,357224634786112,false,[[5,[0,1]],[3,0]]],[-1,14,null,853002410411529,false,[[5,[0,2]],[3,1]]]]],[0,null,false,null,600080256108869,[[4,51,null,1,false,false,false,304672810310041,false,[[4,23]]],[-1,82,null,0,false,false,false,303482445048985,false,[[5,[0,2]]]]],[[0,61,null,684013340592645,false],[-1,14,null,519113282566716,false,[[5,[0,1]],[3,1]]],[-1,14,null,494131448394392,false,[[5,[0,2]],[3,0]]]]],[0,null,false,null,265453471250122,[[4,51,null,1,false,false,false,394936313563062,false,[[4,26]]]],[[16,54,null,625219449389702,false,[[2,["click",false]],[3,0],[0,[0,-2]],[1,[2,""]]]]]]]],["DrapDrop",[[1,"filledCount",0,0,false,false,528865922993012,false],[0,null,false,null,197106660861514,[[8,83,"DragDrop",1,false,false,false,528907557634308,false]],[[16,54,null,162558464641912,false,[[2,["click",false]],[3,0],[0,[0,-2]],[1,[2,""]]]]],[[0,null,false,null,266963171745346,[[8,84,null,0,false,false,false,673397366023432,false,[[10,3],[8,1],[7,[0,-1]]]],[7,84,null,0,false,false,false,577869128870380,false,[[10,0],[8,0],[7,[21,8,false,null,3]]]],[8,85,null,0,false,false,false,609479521709627,false,[[4,11]]]],[[7,31,null,445026196152632,false,[[10,1],[7,[2,"_"]]]],[8,86,null,670463517581139,false],[11,87,null,538995332098798,false]]],[0,null,false,null,816493828433722,[[-1,47,null,0,false,false,false,390659514117980,false]],[],[[0,null,false,null,487754364377713,[[8,85,null,0,false,false,false,443159185077976,false,[[4,11]]]],[[8,86,null,774809908055048,false],[11,87,null,501986465343455,false]]]]]]],[0,null,false,null,946639210805430,[[8,88,"DragDrop",1,false,false,false,155941787306139,false]],[[16,54,null,361413524752870,false,[[2,["immersivecontrol-button-click-sound-463065",false]],[3,0],[0,[0,-2]],[1,[2,""]]]]],[[0,null,false,null,504792991445212,[[8,85,null,0,false,false,false,845450333794375,false,[[4,7]]],[7,89,null,0,false,true,false,204552588897544,false,[[10,2]]]],[],[[0,null,false,null,106550985509374,[[7,90,null,0,false,false,true,170480452496238,false,[[3,0],[0,[20,8,32,false,null]],[0,[20,8,33,false,null]]]],[7,84,null,0,false,false,false,938809230173413,false,[[10,1],[8,0],[7,[2,"_"]]]]],[[8,91,"MoveTo",350887864650832,false,[[0,[0,350]]]],[8,78,"MoveTo",122919247741976,false,[[0,[20,7,32,false,null]],[0,[20,7,33,false,null]]]],[7,31,null,568930528296173,false,[[10,1],[7,[21,8,true,null,0]]]]],[[0,null,false,null,101266177713061,[[8,84,null,0,false,false,false,148334850256636,false,[[10,3],[8,0],[7,[0,-1]]]]],[[8,31,null,762068200313175,false,[[10,3],[7,[21,7,false,null,0]]]],[-1,92,null,348122173801647,false,[[11,"filledCount"],[7,[0,1]]]]]],[0,null,false,null,296319278611324,[[-1,47,null,0,false,false,false,250133201929726,false]],[[8,31,null,116855994129968,false,[[10,3],[7,[21,7,false,null,0]]]]]]]],[0,null,false,null,180540551233675,[[-1,47,null,0,false,false,false,806523891610870,false],[8,84,null,0,false,false,false,831308228851461,false,[[10,3],[8,1],[7,[0,-1]]]]],[[8,91,"MoveTo",416883713281691,false,[[0,[0,1200]]]],[8,78,"MoveTo",572186182608955,false,[[0,[21,8,false,null,1]],[0,[21,8,false,null,2]]]],[8,31,null,370498434376498,false,[[10,3],[7,[0,-1]]]],[-1,92,null,250504698972287,false,[[11,"filledCount"],[7,[0,-1]]]]]],[0,null,false,null,664272208282422,[[-1,47,null,0,false,false,false,895425177786413,false],[8,84,null,0,false,false,false,246894625675163,false,[[10,3],[8,0],[7,[0,-1]]]]],[[8,91,"MoveTo",888826482377214,false,[[0,[0,1200]]]],[8,78,"MoveTo",393405307018971,false,[[0,[21,8,false,null,1]],[0,[21,8,false,null,2]]]],[8,31,null,503673017513230,false,[[10,3],[7,[0,-1]]]]]]]],[0,null,false,null,818745098688947,[[-1,47,null,0,false,false,false,929804756669469,false],[8,84,null,0,false,false,false,177859681995434,false,[[10,3],[8,1],[7,[0,-1]]]]],[[8,91,"MoveTo",449724002535088,false,[[0,[0,1200]]]],[8,78,"MoveTo",721292388859295,false,[[0,[21,8,false,null,1]],[0,[21,8,false,null,2]]]],[8,31,null,733212651291432,false,[[10,3],[7,[0,-1]]]],[-1,92,null,739300525987860,false,[[11,"filledCount"],[7,[0,-1]]]]]],[0,null,false,null,358120937494399,[[-1,47,null,0,false,false,false,416712700522674,false],[8,84,null,0,false,false,false,261187518957115,false,[[10,3],[8,0],[7,[0,-1]]]]],[[8,91,"MoveTo",431242330954619,false,[[0,[0,1200]]]],[8,78,"MoveTo",754072653542168,false,[[0,[21,8,false,null,1]],[0,[21,8,false,null,2]]]],[8,31,null,272960877861772,false,[[10,3],[7,[0,-1]]]]]]]],[0,null,false,null,580675938654997,[[8,93,"DragDrop",0,false,false,false,411147921527630,false]],[[8,34,null,610567804677855,false,[[0,[20,4,94,false,null]],[0,[20,4,95,false,null]]]]]],[0,null,false,null,622060364017684,[[-1,64,null,0,false,false,false,228576696549219,false]],[],[[0,null,false,null,108730370076990,[[-1,53,null,0,false,false,false,538413628199561,false,[[11,"filledCount"],[8,0],[7,[23,"end"]]]]],[[2,96,null,445242465744130,false,[[3,1]]]]],[0,null,false,null,218835501607731,[[-1,47,null,0,false,false,false,933470660702724,false]],[[2,96,null,797052197521566,false,[[3,0]]]]]]]]]],[["click.ogg",24620],["correct.ogg",60630],["error-010-206498.ogg",11425],["immersivecontrol-button-click-sound-463065.ogg",3830]],"media/",false,1200,1200,4,true,true,true,"1.0.0.0",true,false,4,0,25,false,true,1,true,"New project",0,[]]} \ No newline at end of file diff --git a/New-project/images/5sosarahtakesoff-sheet0.png b/New-project/images/5sosarahtakesoff-sheet0.png new file mode 100644 index 0000000..16015c4 Binary files /dev/null and b/New-project/images/5sosarahtakesoff-sheet0.png differ diff --git a/New-project/images/btn_check-sheet0.png b/New-project/images/btn_check-sheet0.png new file mode 100644 index 0000000..b7ff061 Binary files /dev/null and b/New-project/images/btn_check-sheet0.png differ diff --git a/New-project/images/btn_music-sheet0.png b/New-project/images/btn_music-sheet0.png new file mode 100644 index 0000000..d8da2aa Binary files /dev/null and b/New-project/images/btn_music-sheet0.png differ diff --git a/New-project/images/btn_music-sheet1.png b/New-project/images/btn_music-sheet1.png new file mode 100644 index 0000000..6a94568 Binary files /dev/null and b/New-project/images/btn_music-sheet1.png differ diff --git a/New-project/images/btn_pause-sheet0.png b/New-project/images/btn_pause-sheet0.png new file mode 100644 index 0000000..0171eb1 Binary files /dev/null and b/New-project/images/btn_pause-sheet0.png differ diff --git a/New-project/images/btn_setting-sheet0.png b/New-project/images/btn_setting-sheet0.png new file mode 100644 index 0000000..de69472 Binary files /dev/null and b/New-project/images/btn_setting-sheet0.png differ diff --git a/New-project/images/checker_wrong_correct-sheet0.png b/New-project/images/checker_wrong_correct-sheet0.png new file mode 100644 index 0000000..9ddf603 Binary files /dev/null and b/New-project/images/checker_wrong_correct-sheet0.png differ diff --git a/New-project/images/checker_wrong_correct-sheet1.png b/New-project/images/checker_wrong_correct-sheet1.png new file mode 100644 index 0000000..d26d553 Binary files /dev/null and b/New-project/images/checker_wrong_correct-sheet1.png differ diff --git a/New-project/images/layer-sheet0.png b/New-project/images/layer-sheet0.png new file mode 100644 index 0000000..93eca23 Binary files /dev/null and b/New-project/images/layer-sheet0.png differ diff --git a/New-project/images/newwordpng-sheet0.png b/New-project/images/newwordpng-sheet0.png new file mode 100644 index 0000000..739d176 Binary files /dev/null and b/New-project/images/newwordpng-sheet0.png differ diff --git a/New-project/images/panel-sheet0.png b/New-project/images/panel-sheet0.png new file mode 100644 index 0000000..255d806 Binary files /dev/null and b/New-project/images/panel-sheet0.png differ diff --git a/New-project/images/panel_pause-sheet0.png b/New-project/images/panel_pause-sheet0.png new file mode 100644 index 0000000..2b709cf Binary files /dev/null and b/New-project/images/panel_pause-sheet0.png differ diff --git a/New-project/images/correct-sheet0.png b/New-project/images/pause-sheet0.png similarity index 100% rename from New-project/images/correct-sheet0.png rename to New-project/images/pause-sheet0.png diff --git a/New-project/images/senaaikhoi-sheet0.png b/New-project/images/senaaikhoi-sheet0.png new file mode 100644 index 0000000..7f29f08 Binary files /dev/null and b/New-project/images/senaaikhoi-sheet0.png differ diff --git a/New-project/images/slot-sheet0.png b/New-project/images/slot-sheet0.png new file mode 100644 index 0000000..d45a87f Binary files /dev/null and b/New-project/images/slot-sheet0.png differ diff --git a/New-project/images/txt_question.png b/New-project/images/txt_question.png new file mode 100644 index 0000000..554a52c Binary files /dev/null and b/New-project/images/txt_question.png differ diff --git a/New-project/images/txt_texttimer.png b/New-project/images/txt_texttimer.png new file mode 100644 index 0000000..a756f4c Binary files /dev/null and b/New-project/images/txt_texttimer.png differ diff --git a/New-project/images/txt_worditem.png b/New-project/images/txt_worditem.png new file mode 100644 index 0000000..18d3a82 Binary files /dev/null and b/New-project/images/txt_worditem.png differ diff --git a/New-project/index.html b/New-project/index.html index b0d2c8f..d5c0e6b 100644 --- a/New-project/index.html +++ b/New-project/index.html @@ -64,7 +64,7 @@ - + diff --git a/New-project/media/click.ogg b/New-project/media/click.ogg new file mode 100644 index 0000000..e6fef65 Binary files /dev/null and b/New-project/media/click.ogg differ diff --git a/New-project/media/correct.ogg b/New-project/media/correct.ogg new file mode 100644 index 0000000..1d08e7f Binary files /dev/null and b/New-project/media/correct.ogg differ diff --git a/New-project/media/error-010-206498.ogg b/New-project/media/error-010-206498.ogg new file mode 100644 index 0000000..9ebb79f Binary files /dev/null and b/New-project/media/error-010-206498.ogg differ diff --git a/New-project/media/immersivecontrol-button-click-sound-463065.ogg b/New-project/media/immersivecontrol-button-click-sound-463065.ogg new file mode 100644 index 0000000..b74fc89 Binary files /dev/null and b/New-project/media/immersivecontrol-button-click-sound-463065.ogg differ diff --git a/New-project/offline.js b/New-project/offline.js index d4c9dd8..206a677 100644 --- a/New-project/offline.js +++ b/New-project/offline.js @@ -1,18 +1,40 @@ { - "version": 1769247218, + "version": 1769506337, "fileList": [ "data.js", "c2runtime.js", "jquery-3.4.1.min.js", "offlineClient.js", - "images/correct-sheet0.png", + "images/btn_check-sheet0.png", "images/wrong-sheet0.png", + "images/pause-sheet0.png", + "images/slot-sheet0.png", + "images/txt_texttimer.png", + "images/txt_worditem.png", + "images/5sosarahtakesoff-sheet0.png", + "images/senaaikhoi-sheet0.png", + "images/checker_wrong_correct-sheet0.png", + "images/checker_wrong_correct-sheet1.png", + "images/btn_setting-sheet0.png", + "images/panel-sheet0.png", + "images/txt_question.png", + "images/btn_pause-sheet0.png", + "images/btn_music-sheet0.png", + "images/btn_music-sheet1.png", + "images/panel_pause-sheet0.png", + "images/layer-sheet0.png", + "images/newwordpng-sheet0.png", + "media/click.ogg", + "media/correct.ogg", + "media/error-010-206498.ogg", + "media/immersivecontrol-button-click-sound-463065.ogg", "icon-16.png", "icon-32.png", "icon-114.png", "icon-128.png", "icon-256.png", "loading-logo.png", + "tdv_sdk.js", "sena_sdk.js" ] } \ No newline at end of file diff --git a/New-project/sena_sdk.js b/New-project/sena_sdk.js index 21eed1a..fff48b0 100644 --- a/New-project/sena_sdk.js +++ b/New-project/sena_sdk.js @@ -3,11 +3,11 @@ * @param {Object} config - Configuration object for the SDK * @param {Object} config.data - Quiz data containing question, options, and answer */ -function SenaSDK(gid = 'G2510S1T30') { +function SenaSDK(gid) { // Initialize data this.data = null; this.correctAnswer = null; - this.gameCode = gid; + this.gameCode = gid || window.SENA_GAME_CODE || 'G2510S1T30'; // Initialize properties this.timeLimit = 0; this.shuffle = true; @@ -35,14 +35,10 @@ SenaSDK.prototype.shuffleArray = function(array) { [array[i], array[j]] = [array[j], array[i]]; } }; -SenaSDK.prototype.load = function(callback,template = 'G2510S1T30') { +SenaSDK.prototype.load = function(callback,template) { let self = this; - // get parameter LID from URL - const urlParams = new URLSearchParams(window.location.search); - const LID = urlParams.get('LID'); - if (LID) { - self.gameCode = LID; - }; + + self.gameCode = self.gameCode || window.SENA_GAME_CODE || template; fetch(`https://senaai.tech/sample/${self.gameCode}.json`) .then(response => response.json()) .then(data => { diff --git a/New-project/tdv_sdk.js b/New-project/tdv_sdk.js new file mode 100644 index 0000000..3bba28c --- /dev/null +++ b/New-project/tdv_sdk.js @@ -0,0 +1,25 @@ +(function () { + // Default game code + var DEFAULT_GAME_CODE = 'G2510S1T30'; + + var gameCode = DEFAULT_GAME_CODE; + + // 1️⃣ Trường hợp: ?gid=G2510S1T30 + var params = new URLSearchParams(window.location.search); + if (params.has('gid')) { + gameCode = params.get('gid'); + } + + // 2️⃣ Trường hợp: ?G2510S1T30 (không key) + else if (window.location.search.length > 1) { + var raw = window.location.search.substring(1); + if (/^G\d+/.test(raw)) { + gameCode = raw; + } + } + + // Expose globally + window.SENA_GAME_CODE = gameCode; + + console.log('[SENA] Game code detected:', gameCode); +})();