diff --git a/static/extensions/MrNooberDude/decimal-plus.js b/static/extensions/MrNooberDude/decimal-plus.js new file mode 100644 index 00000000..bd459e6a --- /dev/null +++ b/static/extensions/MrNooberDude/decimal-plus.js @@ -0,0 +1,168 @@ +/* + This extension was made with TurboBuilder! + https://turbobuilder-steel.vercel.app/ +*/ + +//Name: Decimal+ +//Description: Do things with numbers like converting them to hex, binary and more! +// +//MIT license, idk how that stuff works + +(function(Scratch) { + const variables = {}; + const blocks = []; + const menus = []; + + + function doSound(ab, cd) { + const audioEngine = Scratch.vm.runtime.audioEngine; + + const fetchAsArrayBufferWithTimeout = (url) => + new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + let timeout = setTimeout(() => { + xhr.abort(); + reject(new Error("Timed out")); + }, 5000); + xhr.onload = () => { + clearTimeout(timeout); + if (xhr.status === 200) { + resolve(xhr.response); + } else { + reject(new Error(`HTTP error ${xhr.status} while fetching ${url}`)); + } + }; + xhr.onerror = () => { + clearTimeout(timeout); + reject(new Error(`Failed to request ${url}`)); + }; + xhr.responseType = "arraybuffer"; + xhr.open("GET", url); + xhr.send(); + }); + + const soundPlayerCache = new Map(); + + const decodeSoundPlayer = async (url) => { + const cached = soundPlayerCache.get(url); + if (cached) { + if (cached.sound) { + return cached.sound; + } + throw cached.error; + } + + try { + const arrayBuffer = await fetchAsArrayBufferWithTimeout(url); + const soundPlayer = await audioEngine.decodeSoundPlayer({ + data: { + buffer: arrayBuffer, + }, + }); + soundPlayerCache.set(url, { + sound: soundPlayer, + error: null, + }); + return soundPlayer; + } catch (e) { + soundPlayerCache.set(url, { + sound: null, + error: e, + }); + throw e; + } + }; + + const playWithAudioEngine = async (url, target) => { + const soundBank = target.sprite.soundBank; + + let soundPlayer; + try { + const originalSoundPlayer = await decodeSoundPlayer(url); + soundPlayer = originalSoundPlayer.take(); + } catch (e) { + console.warn( + "Could not fetch audio; falling back to primitive approach", + e + ); + return false; + } + + soundBank.addSoundPlayer(soundPlayer); + await soundBank.playSound(target, soundPlayer.id); + + delete soundBank.soundPlayers[soundPlayer.id]; + soundBank.playerTargets.delete(soundPlayer.id); + soundBank.soundEffects.delete(soundPlayer.id); + + return true; + }; + + const playWithAudioElement = (url, target) => + new Promise((resolve, reject) => { + const mediaElement = new Audio(url); + + mediaElement.volume = target.volume / 100; + + mediaElement.onended = () => { + resolve(); + }; + mediaElement + .play() + .then(() => { + // Wait for onended + }) + .catch((err) => { + reject(err); + }); + }); + + const playSound = async (url, target) => { + try { + if (!(await Scratch.canFetch(url))) { + throw new Error(`Permission to fetch ${url} denied`); + } + + const success = await playWithAudioEngine(url, target); + if (!success) { + return await playWithAudioElement(url, target); + } + } catch (e) { + console.warn(`All attempts to play ${url} failed`, e); + } + }; + + playSound(ab, cd) + } + class Extension { + getInfo() { + return { + "id": "mrnooberdude_toString", + "name": "Decimal+", + "color1": "#ff007b", + "color2": "#80003e", + "blocks": blocks + } + } + } + blocks.push({ + opcode: `toStringBlock`, + blockType: Scratch.BlockType.REPORTER, + text: `convert [num] to [base] decimal`, + arguments: { + "num": { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 15, + }, + "base": { + type: Scratch.ArgumentType.STRING, + defaultValue: 16, + }, + } + }) + Extension.prototype[`toStringBlock`] = (args, util) => { + return args["num"].toString(args["base"]); + } + + Scratch.extensions.register(new Extension()); +})(Scratch);