commit
ed42b49e70
1
docs/assets/js/crypto/core.min.js
vendored
Normal file
1
docs/assets/js/crypto/core.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(t,n){"object"==typeof exports?module.exports=exports=n():"function"==typeof define&&define.amd?define([],n):t.CryptoJS=n()}(this,function(){var t=t||function(f){var t;if("undefined"!=typeof window&&window.crypto&&(t=window.crypto),!t&&"undefined"!=typeof window&&window.msCrypto&&(t=window.msCrypto),!t&&"undefined"!=typeof global&&global.crypto&&(t=global.crypto),!t&&"function"==typeof require)try{t=require("crypto")}catch(t){}function i(){if(t){if("function"==typeof t.getRandomValues)try{return t.getRandomValues(new Uint32Array(1))[0]}catch(t){}if("function"==typeof t.randomBytes)try{return t.randomBytes(4).readInt32LE()}catch(t){}}throw new Error("Native crypto module could not be used to get secure random number.")}var e=Object.create||function(t){var n;return r.prototype=t,n=new r,r.prototype=null,n};function r(){}var n={},o=n.lib={},s=o.Base={extend:function(t){var n=e(this);return t&&n.mixIn(t),n.hasOwnProperty("init")&&this.init!==n.init||(n.init=function(){n.$super.init.apply(this,arguments)}),(n.init.prototype=n).$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var n in t)t.hasOwnProperty(n)&&(this[n]=t[n]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}},p=o.WordArray=s.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=null!=n?n:4*t.length},toString:function(t){return(t||c).stringify(this)},concat:function(t){var n=this.words,e=t.words,i=this.sigBytes,r=t.sigBytes;if(this.clamp(),i%4)for(var o=0;o<r;o++){var s=e[o>>>2]>>>24-o%4*8&255;n[i+o>>>2]|=s<<24-(i+o)%4*8}else for(o=0;o<r;o+=4)n[i+o>>>2]=e[o>>>2];return this.sigBytes+=r,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=f.ceil(n/4)},clone:function(){var t=s.clone.call(this);return t.words=this.words.slice(0),t},random:function(t){for(var n=[],e=0;e<t;e+=4)n.push(i());return new p.init(n,t)}}),a=n.enc={},c=a.Hex={stringify:function(t){for(var n=t.words,e=t.sigBytes,i=[],r=0;r<e;r++){var o=n[r>>>2]>>>24-r%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(t){for(var n=t.length,e=[],i=0;i<n;i+=2)e[i>>>3]|=parseInt(t.substr(i,2),16)<<24-i%8*4;return new p.init(e,n/2)}},u=a.Latin1={stringify:function(t){for(var n=t.words,e=t.sigBytes,i=[],r=0;r<e;r++){var o=n[r>>>2]>>>24-r%4*8&255;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var n=t.length,e=[],i=0;i<n;i++)e[i>>>2]|=(255&t.charCodeAt(i))<<24-i%4*8;return new p.init(e,n)}},d=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},h=o.BufferedBlockAlgorithm=s.extend({reset:function(){this._data=new p.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=d.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(t){var n,e=this._data,i=e.words,r=e.sigBytes,o=this.blockSize,s=r/(4*o),a=(s=t?f.ceil(s):f.max((0|s)-this._minBufferSize,0))*o,c=f.min(4*a,r);if(a){for(var u=0;u<a;u+=o)this._doProcessBlock(i,u);n=i.splice(0,a),e.sigBytes-=c}return new p.init(n,c)},clone:function(){var t=s.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),l=(o.Hasher=h.extend({cfg:s.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){h.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){return t&&this._append(t),this._doFinalize()},blockSize:16,_createHelper:function(e){return function(t,n){return new e.init(n).finalize(t)}},_createHmacHelper:function(e){return function(t,n){return new l.HMAC.init(e,n).finalize(t)}}}),n.algo={});return n}(Math);return t});
|
268
docs/assets/js/crypto/md5.js
Normal file
268
docs/assets/js/crypto/md5.js
Normal file
@ -0,0 +1,268 @@
|
||||
;(function (root, factory) {
|
||||
if (typeof exports === "object") {
|
||||
// CommonJS
|
||||
module.exports = exports = factory(require("./core"));
|
||||
}
|
||||
else if (typeof define === "function" && define.amd) {
|
||||
// AMD
|
||||
define(["./core"], factory);
|
||||
}
|
||||
else {
|
||||
// Global (browser)
|
||||
factory(root.CryptoJS);
|
||||
}
|
||||
}(this, function (CryptoJS) {
|
||||
|
||||
(function (Math) {
|
||||
// Shortcuts
|
||||
var C = CryptoJS;
|
||||
var C_lib = C.lib;
|
||||
var WordArray = C_lib.WordArray;
|
||||
var Hasher = C_lib.Hasher;
|
||||
var C_algo = C.algo;
|
||||
|
||||
// Constants table
|
||||
var T = [];
|
||||
|
||||
// Compute constants
|
||||
(function () {
|
||||
for (var i = 0; i < 64; i++) {
|
||||
T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
|
||||
}
|
||||
}());
|
||||
|
||||
/**
|
||||
* MD5 hash algorithm.
|
||||
*/
|
||||
var MD5 = C_algo.MD5 = Hasher.extend({
|
||||
_doReset: function () {
|
||||
this._hash = new WordArray.init([
|
||||
0x67452301, 0xefcdab89,
|
||||
0x98badcfe, 0x10325476
|
||||
]);
|
||||
},
|
||||
|
||||
_doProcessBlock: function (M, offset) {
|
||||
// Swap endian
|
||||
for (var i = 0; i < 16; i++) {
|
||||
// Shortcuts
|
||||
var offset_i = offset + i;
|
||||
var M_offset_i = M[offset_i];
|
||||
|
||||
M[offset_i] = (
|
||||
(((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
|
||||
(((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
|
||||
);
|
||||
}
|
||||
|
||||
// Shortcuts
|
||||
var H = this._hash.words;
|
||||
|
||||
var M_offset_0 = M[offset + 0];
|
||||
var M_offset_1 = M[offset + 1];
|
||||
var M_offset_2 = M[offset + 2];
|
||||
var M_offset_3 = M[offset + 3];
|
||||
var M_offset_4 = M[offset + 4];
|
||||
var M_offset_5 = M[offset + 5];
|
||||
var M_offset_6 = M[offset + 6];
|
||||
var M_offset_7 = M[offset + 7];
|
||||
var M_offset_8 = M[offset + 8];
|
||||
var M_offset_9 = M[offset + 9];
|
||||
var M_offset_10 = M[offset + 10];
|
||||
var M_offset_11 = M[offset + 11];
|
||||
var M_offset_12 = M[offset + 12];
|
||||
var M_offset_13 = M[offset + 13];
|
||||
var M_offset_14 = M[offset + 14];
|
||||
var M_offset_15 = M[offset + 15];
|
||||
|
||||
// Working varialbes
|
||||
var a = H[0];
|
||||
var b = H[1];
|
||||
var c = H[2];
|
||||
var d = H[3];
|
||||
|
||||
// Computation
|
||||
a = FF(a, b, c, d, M_offset_0, 7, T[0]);
|
||||
d = FF(d, a, b, c, M_offset_1, 12, T[1]);
|
||||
c = FF(c, d, a, b, M_offset_2, 17, T[2]);
|
||||
b = FF(b, c, d, a, M_offset_3, 22, T[3]);
|
||||
a = FF(a, b, c, d, M_offset_4, 7, T[4]);
|
||||
d = FF(d, a, b, c, M_offset_5, 12, T[5]);
|
||||
c = FF(c, d, a, b, M_offset_6, 17, T[6]);
|
||||
b = FF(b, c, d, a, M_offset_7, 22, T[7]);
|
||||
a = FF(a, b, c, d, M_offset_8, 7, T[8]);
|
||||
d = FF(d, a, b, c, M_offset_9, 12, T[9]);
|
||||
c = FF(c, d, a, b, M_offset_10, 17, T[10]);
|
||||
b = FF(b, c, d, a, M_offset_11, 22, T[11]);
|
||||
a = FF(a, b, c, d, M_offset_12, 7, T[12]);
|
||||
d = FF(d, a, b, c, M_offset_13, 12, T[13]);
|
||||
c = FF(c, d, a, b, M_offset_14, 17, T[14]);
|
||||
b = FF(b, c, d, a, M_offset_15, 22, T[15]);
|
||||
|
||||
a = GG(a, b, c, d, M_offset_1, 5, T[16]);
|
||||
d = GG(d, a, b, c, M_offset_6, 9, T[17]);
|
||||
c = GG(c, d, a, b, M_offset_11, 14, T[18]);
|
||||
b = GG(b, c, d, a, M_offset_0, 20, T[19]);
|
||||
a = GG(a, b, c, d, M_offset_5, 5, T[20]);
|
||||
d = GG(d, a, b, c, M_offset_10, 9, T[21]);
|
||||
c = GG(c, d, a, b, M_offset_15, 14, T[22]);
|
||||
b = GG(b, c, d, a, M_offset_4, 20, T[23]);
|
||||
a = GG(a, b, c, d, M_offset_9, 5, T[24]);
|
||||
d = GG(d, a, b, c, M_offset_14, 9, T[25]);
|
||||
c = GG(c, d, a, b, M_offset_3, 14, T[26]);
|
||||
b = GG(b, c, d, a, M_offset_8, 20, T[27]);
|
||||
a = GG(a, b, c, d, M_offset_13, 5, T[28]);
|
||||
d = GG(d, a, b, c, M_offset_2, 9, T[29]);
|
||||
c = GG(c, d, a, b, M_offset_7, 14, T[30]);
|
||||
b = GG(b, c, d, a, M_offset_12, 20, T[31]);
|
||||
|
||||
a = HH(a, b, c, d, M_offset_5, 4, T[32]);
|
||||
d = HH(d, a, b, c, M_offset_8, 11, T[33]);
|
||||
c = HH(c, d, a, b, M_offset_11, 16, T[34]);
|
||||
b = HH(b, c, d, a, M_offset_14, 23, T[35]);
|
||||
a = HH(a, b, c, d, M_offset_1, 4, T[36]);
|
||||
d = HH(d, a, b, c, M_offset_4, 11, T[37]);
|
||||
c = HH(c, d, a, b, M_offset_7, 16, T[38]);
|
||||
b = HH(b, c, d, a, M_offset_10, 23, T[39]);
|
||||
a = HH(a, b, c, d, M_offset_13, 4, T[40]);
|
||||
d = HH(d, a, b, c, M_offset_0, 11, T[41]);
|
||||
c = HH(c, d, a, b, M_offset_3, 16, T[42]);
|
||||
b = HH(b, c, d, a, M_offset_6, 23, T[43]);
|
||||
a = HH(a, b, c, d, M_offset_9, 4, T[44]);
|
||||
d = HH(d, a, b, c, M_offset_12, 11, T[45]);
|
||||
c = HH(c, d, a, b, M_offset_15, 16, T[46]);
|
||||
b = HH(b, c, d, a, M_offset_2, 23, T[47]);
|
||||
|
||||
a = II(a, b, c, d, M_offset_0, 6, T[48]);
|
||||
d = II(d, a, b, c, M_offset_7, 10, T[49]);
|
||||
c = II(c, d, a, b, M_offset_14, 15, T[50]);
|
||||
b = II(b, c, d, a, M_offset_5, 21, T[51]);
|
||||
a = II(a, b, c, d, M_offset_12, 6, T[52]);
|
||||
d = II(d, a, b, c, M_offset_3, 10, T[53]);
|
||||
c = II(c, d, a, b, M_offset_10, 15, T[54]);
|
||||
b = II(b, c, d, a, M_offset_1, 21, T[55]);
|
||||
a = II(a, b, c, d, M_offset_8, 6, T[56]);
|
||||
d = II(d, a, b, c, M_offset_15, 10, T[57]);
|
||||
c = II(c, d, a, b, M_offset_6, 15, T[58]);
|
||||
b = II(b, c, d, a, M_offset_13, 21, T[59]);
|
||||
a = II(a, b, c, d, M_offset_4, 6, T[60]);
|
||||
d = II(d, a, b, c, M_offset_11, 10, T[61]);
|
||||
c = II(c, d, a, b, M_offset_2, 15, T[62]);
|
||||
b = II(b, c, d, a, M_offset_9, 21, T[63]);
|
||||
|
||||
// Intermediate hash value
|
||||
H[0] = (H[0] + a) | 0;
|
||||
H[1] = (H[1] + b) | 0;
|
||||
H[2] = (H[2] + c) | 0;
|
||||
H[3] = (H[3] + d) | 0;
|
||||
},
|
||||
|
||||
_doFinalize: function () {
|
||||
// Shortcuts
|
||||
var data = this._data;
|
||||
var dataWords = data.words;
|
||||
|
||||
var nBitsTotal = this._nDataBytes * 8;
|
||||
var nBitsLeft = data.sigBytes * 8;
|
||||
|
||||
// Add padding
|
||||
dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
|
||||
|
||||
var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
|
||||
var nBitsTotalL = nBitsTotal;
|
||||
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
|
||||
(((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
|
||||
(((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00)
|
||||
);
|
||||
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
|
||||
(((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
|
||||
(((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00)
|
||||
);
|
||||
|
||||
data.sigBytes = (dataWords.length + 1) * 4;
|
||||
|
||||
// Hash final blocks
|
||||
this._process();
|
||||
|
||||
// Shortcuts
|
||||
var hash = this._hash;
|
||||
var H = hash.words;
|
||||
|
||||
// Swap endian
|
||||
for (var i = 0; i < 4; i++) {
|
||||
// Shortcut
|
||||
var H_i = H[i];
|
||||
|
||||
H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
|
||||
(((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);
|
||||
}
|
||||
|
||||
// Return final computed hash
|
||||
return hash;
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
var clone = Hasher.clone.call(this);
|
||||
clone._hash = this._hash.clone();
|
||||
|
||||
return clone;
|
||||
}
|
||||
});
|
||||
|
||||
function FF(a, b, c, d, x, s, t) {
|
||||
var n = a + ((b & c) | (~b & d)) + x + t;
|
||||
return ((n << s) | (n >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
function GG(a, b, c, d, x, s, t) {
|
||||
var n = a + ((b & d) | (c & ~d)) + x + t;
|
||||
return ((n << s) | (n >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
function HH(a, b, c, d, x, s, t) {
|
||||
var n = a + (b ^ c ^ d) + x + t;
|
||||
return ((n << s) | (n >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
function II(a, b, c, d, x, s, t) {
|
||||
var n = a + (c ^ (b | ~d)) + x + t;
|
||||
return ((n << s) | (n >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut function to the hasher's object interface.
|
||||
*
|
||||
* @param {WordArray|string} message The message to hash.
|
||||
*
|
||||
* @return {WordArray} The hash.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* var hash = CryptoJS.MD5('message');
|
||||
* var hash = CryptoJS.MD5(wordArray);
|
||||
*/
|
||||
C.MD5 = Hasher._createHelper(MD5);
|
||||
|
||||
/**
|
||||
* Shortcut function to the HMAC's object interface.
|
||||
*
|
||||
* @param {WordArray|string} message The message to hash.
|
||||
* @param {WordArray|string} key The secret key.
|
||||
*
|
||||
* @return {WordArray} The HMAC.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* var hmac = CryptoJS.HmacMD5(message, key);
|
||||
*/
|
||||
C.HmacMD5 = Hasher._createHmacHelper(MD5);
|
||||
}(Math));
|
||||
|
||||
|
||||
return CryptoJS.MD5;
|
||||
|
||||
}));
|
@ -50,6 +50,12 @@ function update() {
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
||||
// If draw is being called, the user has interacted with the page at least once.
|
||||
// This signal can be used to notify the audio permission handler
|
||||
unlockAudioPermission();
|
||||
|
||||
// Handle game state
|
||||
switch (globalState) {
|
||||
// title screen
|
||||
case globalStates.titleScreen:
|
||||
@ -110,6 +116,25 @@ function onAssetsLoaded() {
|
||||
|
||||
setup(60);
|
||||
|
||||
// Hide the preloader
|
||||
// This should actually run after all assets have been downloaded
|
||||
page_preloader.hide(false);
|
||||
/* Preload actions */
|
||||
|
||||
// To make something happen before the preloader is hidden, add it to this list
|
||||
// The function must take a callback that will be run when the function finishes
|
||||
let actions = [preCacheSounds];
|
||||
let actionsCompleted = 0;
|
||||
|
||||
// Loop through every action, and load it
|
||||
actions.forEach((action) => {
|
||||
|
||||
// Run the action & handle loading
|
||||
action(() => {
|
||||
|
||||
// Incr the number of successfully loaded actions
|
||||
actionsCompleted += 1;
|
||||
|
||||
// If this is the last aciton, hide the loader
|
||||
if (actionsCompleted == actions.length) {
|
||||
page_preloader.hide(false);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
22
docs/assets/js/sounds/permissionhandler.js
Normal file
22
docs/assets/js/sounds/permissionhandler.js
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* This file just exists to keep track of weather the user has interacted with the
|
||||
* webpage. Most browsers will block autoplay if no interaction has been made.
|
||||
*/
|
||||
|
||||
|
||||
// Tracker for permission unlock
|
||||
let _audioPermUnlock = false;
|
||||
|
||||
/**
|
||||
* Call this when the user interacts with the page
|
||||
*/
|
||||
function unlockAudioPermission() {
|
||||
_audioPermUnlock = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if autoplay is enabled
|
||||
*/
|
||||
function canPlayAudio() {
|
||||
return _audioPermUnlock;
|
||||
}
|
152
docs/assets/js/sounds/soundcontext.js
Normal file
152
docs/assets/js/sounds/soundcontext.js
Normal file
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* This file contains classes for playing sounds.
|
||||
* The SoundContext works by providing multiple audio channels,
|
||||
* just like an old ATARI, or even GameBoy sound system. Each
|
||||
* channel can be controlled individually.
|
||||
*
|
||||
* ---- Usage ----
|
||||
*
|
||||
* // Load all sounds
|
||||
* preCacheSounds(()=>{
|
||||
* // Code can be run here as soon as all sounds are loaded
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* // Play a sound
|
||||
* globalSoundContext.playSound(globalSoundContext.channels.<channel>, sounds.<soundname>);
|
||||
*
|
||||
* // Stop a channel
|
||||
* globalSoundContext.mute(globalSoundContext.channels.<channel>);
|
||||
*/
|
||||
|
||||
/**
|
||||
* A sound channel can play 1 sound at a time, and supports sound queueing
|
||||
*/
|
||||
class _SoundChannel {
|
||||
|
||||
/**
|
||||
* Create a sound channel
|
||||
* @param {number} max_queue_size Maximum number of sounds that can be queued before sounds are skipped
|
||||
*/
|
||||
constructor(max_queue_size) {
|
||||
this.max_size = max_queue_size
|
||||
this.sound_queue = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a snippet to the queue
|
||||
* @param {SoundSnippet} snippet
|
||||
*/
|
||||
enqueue(snippet) {
|
||||
|
||||
// If the queue is full, cut out the next sound in the queue to make room
|
||||
if (this.sound_queue.length >= this.max_size) {
|
||||
this.sound_queue.splice(1, 1);
|
||||
}
|
||||
|
||||
// Append the sound to the queue
|
||||
this.sound_queue.push(snippet);
|
||||
|
||||
// If this is the first sound in the queue, spawn a watcher job, and play it
|
||||
if (this.sound_queue.length == 1) {
|
||||
this.sound_queue[0].play();
|
||||
this._spawnWatcher(this.sound_queue[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a job to run when the sound finishes to remove the sound from the queue
|
||||
* @param {SoundSnippet} snippet
|
||||
*/
|
||||
_spawnWatcher(snippet) {
|
||||
|
||||
// Read the snippet length
|
||||
let length = snippet.getLengthSeconds();
|
||||
|
||||
// Spawn a clean action for that time in the future
|
||||
setTimeout(() => {
|
||||
this._cleanQueue(snippet);
|
||||
}, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be run when every sound finishes. This will remove that
|
||||
* sound from from the queue, start the next sound, and spawn a
|
||||
* new watcher for that sound.
|
||||
* @param {SoundSnippet} snippet
|
||||
*/
|
||||
_cleanQueue(snippet) {
|
||||
|
||||
// Get the snippet hash
|
||||
let hash = snippet.getHash();
|
||||
|
||||
// Make sure there are actually sounds playing
|
||||
if (this.sound_queue.length > 0) {
|
||||
|
||||
// If the first snippet in the queue matches this hash, remove it.
|
||||
// If not, something must have happened. Just ignore it, and move on
|
||||
if (this.sound_queue[0].getHash() == hash) {
|
||||
|
||||
// Popoff the snippet
|
||||
this.sound_queue.shift();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Spawn a watcher for the next sound & play it
|
||||
if (this.sound_queue.length > 0) {
|
||||
this.sound_queue[0].play();
|
||||
this._spawnWatcher(this.sound_queue[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the entire queue, and stop all sounds
|
||||
*/
|
||||
clear() {
|
||||
|
||||
// Stop every sound
|
||||
this.sound_queue.forEach((sound) => {
|
||||
sound.stop();
|
||||
})
|
||||
|
||||
// Clear the queue
|
||||
this.sound_queue = [];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _SoundContext {
|
||||
|
||||
constructor() {
|
||||
|
||||
// Define all sound channels
|
||||
this.channels = {
|
||||
bgm: new _SoundChannel(2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a sound in a channel
|
||||
* @param {*} channel
|
||||
* @param {SoundSnippet} snippet
|
||||
*/
|
||||
playSound(channel, snippet) {
|
||||
console.log(`[SoundContext] Playing snippet: ${snippet.getName()}`);
|
||||
channel.enqueue(snippet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all sounds in a channel
|
||||
* @param {*} channel
|
||||
*/
|
||||
mute(channel) {
|
||||
channel.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The global context for sounds
|
||||
let globalSoundContext = new _SoundContext();
|
63
docs/assets/js/sounds/sounds.js
Normal file
63
docs/assets/js/sounds/sounds.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* This file handles all sound assets, and loading them
|
||||
* To add a new sound asset:
|
||||
* 1) Make a mapping from the asset name to it's filename in soundAssetMap
|
||||
* 2) Define the SoundSnippet in soundAssets
|
||||
*
|
||||
* The preloader will handle asset loading for you.
|
||||
* Make sure to check the console for any errors with loading your file
|
||||
*/
|
||||
|
||||
|
||||
// A mapping of asset names to their files
|
||||
// This exists to give nicer names to files
|
||||
let soundAssetMap = {
|
||||
"debug-ding":"/assets/sounds/debug-ding.mp3"
|
||||
}
|
||||
|
||||
// All available sounds
|
||||
let soundAssets = {
|
||||
debug_ding: new SoundSnippet("debug-ding")
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache all sounds in browser, then notify a callback of success
|
||||
* @param {function} callback Callback for completion
|
||||
*/
|
||||
function preCacheSounds(callback) {
|
||||
|
||||
// Counter for number of sounds cached
|
||||
let cachedCount = 0;
|
||||
|
||||
Object.keys(soundAssets).forEach((key) => {
|
||||
|
||||
// Get the SoundSnippet
|
||||
let sound = soundAssets[key];
|
||||
|
||||
// Cache the sound
|
||||
sound.cache(() => {
|
||||
|
||||
// Incr the cache count
|
||||
cachedCount += 1;
|
||||
|
||||
// If this is the last sound, fire off the callback
|
||||
if (cachedCount == Object.keys(soundAssets).length) {
|
||||
callback();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Spawn a notifier for loading issues
|
||||
setTimeout(() => {
|
||||
|
||||
// If not all sounds have been cached by the time this is called, send a warning
|
||||
if (cachedCount < Object.keys(soundAssets).length) {
|
||||
console.warn(`[preCacheSounds] Only ${cachedCount} of ${Object.keys(soundAssets).length} sounds have been cached after 2 seconds. Is there a missing asset? or is the user on a slow connection?`);
|
||||
}
|
||||
|
||||
}, 2000);
|
||||
|
||||
}
|
81
docs/assets/js/sounds/soundsnippet.js
Normal file
81
docs/assets/js/sounds/soundsnippet.js
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
// Counter for hash generation
|
||||
let _hashCounter = 0;
|
||||
|
||||
class SoundSnippet {
|
||||
|
||||
/**
|
||||
* Load a sound asset to a snipper
|
||||
* @param {string} asset_name Asset name as defined in soundassetmap.js
|
||||
*/
|
||||
constructor(asset_name) {
|
||||
|
||||
// Store asset name
|
||||
this.asset_name = asset_name;
|
||||
|
||||
// Compute an asset hash
|
||||
this.asset_hash = CryptoJS.MD5(`ASSET:${asset_name}::${_hashCounter}`);
|
||||
_hashCounter += 1;
|
||||
|
||||
// Read actual asset path
|
||||
this.assetPath = soundAssetMap[asset_name];
|
||||
|
||||
// Set up the audio object
|
||||
this.audio = new Audio();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache this sound, then notify a callback of completion
|
||||
* @param {function} callback callback to notify
|
||||
*/
|
||||
cache(callback) {
|
||||
|
||||
// Set the audio SRC
|
||||
this.audio.src = this.assetPath;
|
||||
|
||||
// Create a callback for loading finished
|
||||
this.audio.addEventListener("loadeddata", callback, true);
|
||||
}
|
||||
|
||||
|
||||
play() {
|
||||
|
||||
// If autoplay is disabled, we notify the console
|
||||
if (canPlayAudio()) {
|
||||
// Play the snippet
|
||||
this.audio.play();
|
||||
} else {
|
||||
console.warn("[SoundSnippet] Tried to play audio with autoplay disabled. The user must press the play button before you can play audio");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
||||
// Stop the snippet
|
||||
this.audio.stop();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sound length in seconds
|
||||
*/
|
||||
getLengthSeconds() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the asset name
|
||||
*/
|
||||
getName() {
|
||||
return this.asset_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this asset's hash. This can be used for comparing objects efficiently.
|
||||
*/
|
||||
getHash() {
|
||||
return this.asset_hash;
|
||||
}
|
||||
}
|
BIN
docs/assets/sounds/debug-ding.mp3
Normal file
BIN
docs/assets/sounds/debug-ding.mp3
Normal file
Binary file not shown.
@ -24,6 +24,10 @@
|
||||
<!-- Graphics Library -->
|
||||
<script src="assets/js/game.js"></script>
|
||||
|
||||
<!-- Crypto -->
|
||||
<script src="assets/js/crypto/core.min.js"></script>
|
||||
<script src="assets/js/crypto/md5.js"></script>
|
||||
|
||||
<!-- Constants & Globals -->
|
||||
<script src="assets/js/constants.js"></script>
|
||||
<script src="assets/js/utils.js"></script>
|
||||
@ -45,6 +49,12 @@
|
||||
<script src="assets/js/injection/cssinjector.js"></script>
|
||||
<script src="assets/js/preloader/preloader.js"></script>
|
||||
|
||||
<!-- Sounds -->
|
||||
<script src="assets/js/sounds/soundsnippet.js"></script>
|
||||
<script src="assets/js/sounds/sounds.js"></script>
|
||||
<script src="assets/js/sounds/soundcontext.js"></script>
|
||||
<script src="assets/js/sounds/permissionhandler.js"></script>
|
||||
|
||||
<!-- Game -->
|
||||
<script src="assets/js/index.js"></script>
|
||||
</body>
|
||||
|
Reference in New Issue
Block a user