diff options
| -rw-r--r-- | .eslintignore | 3 | ||||
| -rw-r--r-- | .eslintrc.js | 35 | ||||
| -rw-r--r-- | package.json | 6 | ||||
| -rw-r--r-- | webAO/backgrounds.js | 48 | ||||
| -rw-r--r-- | webAO/characters.js | 104 | ||||
| -rw-r--r-- | webAO/client.js | 5021 | ||||
| -rw-r--r-- | webAO/encoding.js | 97 | ||||
| -rw-r--r-- | webAO/evidence.js | 18 | ||||
| -rw-r--r-- | webAO/lib/gify.min.js | 12 | ||||
| -rw-r--r-- | webAO/lib/jdataview.min.js | 168 | ||||
| -rw-r--r-- | webAO/lib/jquery.ui.touch-punch.min.js | 2 | ||||
| -rw-r--r-- | webAO/master.js | 281 | ||||
| -rw-r--r-- | webAO/music.js | 102 | ||||
| -rw-r--r-- | webAO/sounds.js | 262 | ||||
| -rw-r--r-- | webAO/styles/chatbox/chatboxes.js | 52 | ||||
| -rw-r--r-- | webAO/ui.js | 76 | ||||
| -rw-r--r-- | webpack.config.js | 46 |
17 files changed, 3196 insertions, 3137 deletions
diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..2f1e71b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +webAO/lib/ +webAO/golden/
\ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 3cd51ec..83d8348 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,22 +1,15 @@ module.exports = { - "env": { - "browser": true, - "es6": true, - "jquery": true - }, - "extends": "eslint:recommended", - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - "no-console": "off", - "no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], - "eqeqeq": ["error", "smart"], - "semi": ["error", "always"] - } -};
\ No newline at end of file + env: { + browser: true, + es2021: true, + }, + extends: [ + 'airbnb-base', + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: { + }, +}; diff --git a/package.json b/package.json index 6f6d802..7971138 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "deploy": "cross-env NODE_ENV=production webpack -p", "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --config webpack.config.js", - "start": "webpack serve --config webpack.config.js" + "start": "webpack serve --config webpack.config.js", + "lint": "eslint . --ext .js", + "lint:fix": "eslint --fix . --ext .js" }, "repository": { "type": "git", @@ -26,6 +28,8 @@ "babel-loader": "^8.2.3", "dotenv": "^16.0.0", "eslint": "^8.10.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.25.4", "webpack": "^5.69.1", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4" diff --git a/webAO/backgrounds.js b/webAO/backgrounds.js index 449f4b2..c1807ce 100644 --- a/webAO/backgrounds.js +++ b/webAO/backgrounds.js @@ -1,25 +1,25 @@ export default [ - "Anime", - "birthday", - "Christmas", - "CountyCourt", - "CruiseCourt", - "default", - "DGSEnglishCourt", - "DGSJapanCourt", - "DualDestinies", - "EnglishCourt", - "gs4", - "GS4Night", - "HD", - "Khura'in", - "mlp", - "NewCourt", - "RuinedCourt", - "Sky", - "SpaceCourt", - "Themis", - "TouhouCourt", - "WitchTrialCourt", - "Zetta" -];
\ No newline at end of file + 'Anime', + 'birthday', + 'Christmas', + 'CountyCourt', + 'CruiseCourt', + 'default', + 'DGSEnglishCourt', + 'DGSJapanCourt', + 'DualDestinies', + 'EnglishCourt', + 'gs4', + 'GS4Night', + 'HD', + "Khura'in", + 'mlp', + 'NewCourt', + 'RuinedCourt', + 'Sky', + 'SpaceCourt', + 'Themis', + 'TouhouCourt', + 'WitchTrialCourt', + 'Zetta', +]; diff --git a/webAO/characters.js b/webAO/characters.js index b7f77ba..e046cf8 100644 --- a/webAO/characters.js +++ b/webAO/characters.js @@ -1,53 +1,53 @@ -export default [ - "Adrian", - "Apollo", - "April", - "Armstrong", - "Atmey", - "Butz", - "Diego", - "Edgeworth", - "Edgeworthw", - "Ema", - "Emaskye", - "Franny", - "Franziska", - "Gant", - "Gavin", - "Gavin K", - "Godot", - "Gregory", - "Grossberg", - "Gumshoe", - "Gumshoey", - "Hawk", - "Hobo_Phoenix", - "Ini", - "Judge", - "Judge's Bro", - "Klav", - "Klavier", - "Kristoph", - "Lana", - "Layton", - "Lotta", - "Luis", - "Maggey", - "Manfred", - "Marshall", - "Matt", - "Maya", - "Mia", - "Miles", - "Oldbag", - "Payne", - "Pearl", - "Phoenix", - "Valant", - "Vasquez", - "Wellington", - "Winston", - "Winstonpayne", - "Young Mia", - "Zak", +export default [ + 'Adrian', + 'Apollo', + 'April', + 'Armstrong', + 'Atmey', + 'Butz', + 'Diego', + 'Edgeworth', + 'Edgeworthw', + 'Ema', + 'Emaskye', + 'Franny', + 'Franziska', + 'Gant', + 'Gavin', + 'Gavin K', + 'Godot', + 'Gregory', + 'Grossberg', + 'Gumshoe', + 'Gumshoey', + 'Hawk', + 'Hobo_Phoenix', + 'Ini', + 'Judge', + "Judge's Bro", + 'Klav', + 'Klavier', + 'Kristoph', + 'Lana', + 'Layton', + 'Lotta', + 'Luis', + 'Maggey', + 'Manfred', + 'Marshall', + 'Matt', + 'Maya', + 'Mia', + 'Miles', + 'Oldbag', + 'Payne', + 'Pearl', + 'Phoenix', + 'Valant', + 'Vasquez', + 'Wellington', + 'Winston', + 'Winstonpayne', + 'Young Mia', + 'Zak', ]; diff --git a/webAO/client.js b/webAO/client.js index dafd371..86abb63 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -6,17 +6,18 @@ import Fingerprint2 from 'fingerprintjs2'; -import { escapeChat, encodeChat, prepChat, safe_tags } from './encoding.js'; +import { EventEmitter } from 'events'; +import { + escapeChat, encodeChat, prepChat, safe_tags, +} from './encoding.js'; // Load some defaults for the background and evidence dropdowns -import vanilla_character_arr from "./characters.js"; -import vanilla_music_arr from "./music.js"; -import vanilla_background_arr from "./backgrounds.js"; -import vanilla_evidence_arr from "./evidence.js"; +import vanilla_character_arr from './characters.js'; +import vanilla_music_arr from './music.js'; +import vanilla_background_arr from './backgrounds.js'; +import vanilla_evidence_arr from './evidence.js'; -import chatbox_arr from "./styles/chatbox/chatboxes.js"; - -import { EventEmitter } from "events"; +import chatbox_arr from './styles/chatbox/chatboxes.js'; const version = process.env.npm_package_version @@ -25,21 +26,21 @@ let viewport; // Get the arguments from the URL bar const queryDict = {}; -location.search.substr(1).split("&").forEach(function (item) { - queryDict[item.split("=")[0]] = item.split("=")[1]; +location.search.substr(1).split('&').forEach((item) => { + queryDict[item.split('=')[0]] = item.split('=')[1]; }); const serverIP = queryDict.ip; -let mode = queryDict.mode; +let { mode } = queryDict; // Unless there is an asset URL specified, use the wasabi one -const DEFAULT_HOST = "http://attorneyoffline.de/base/"; +const DEFAULT_HOST = 'http://attorneyoffline.de/base/'; let AO_HOST = queryDict.asset || DEFAULT_HOST; -const THEME = queryDict.theme || "default"; +const THEME = queryDict.theme || 'default'; const UPDATE_INTERVAL = 60; -const transparentPNG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="; +const transparentPNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; /** * Toggles AO1-style loading using paginated music packets for mobile platforms. * The old loading uses more smaller packets instead of a single big one, @@ -48,245 +49,243 @@ const transparentPNG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCA let oldLoading = false; // presettings -let selectedEffect = 0; +const selectedEffect = 0; let selectedMenu = 1; let selectedShout = 0; let extrafeatures = []; let hdid; -const options = { fonts: { extendedJsFonts: true, userDefinedFonts: ["Ace Attorney", "8bitoperator", "DINEngschrift"] }, excludes: { userAgent: true, enumerateDevices: true } }; +const options = { fonts: { extendedJsFonts: true, userDefinedFonts: ['Ace Attorney', '8bitoperator', 'DINEngschrift'] }, excludes: { userAgent: true, enumerateDevices: true } }; function isLowMemory() { - if (/webOS|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|PlayStation|Nintendo|Opera Mini/i.test(navigator.userAgent)) { - oldLoading = true; - } + if (/webOS|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|PlayStation|Nintendo|Opera Mini/i.test(navigator.userAgent)) { + oldLoading = true; + } } if (window.requestIdleCallback) { - requestIdleCallback(function () { - Fingerprint2.get(options, function (components) { - hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); - client = new Client(serverIP); - viewport = new Viewport(); - - isLowMemory(); - client.loadResources(); - }); - }); + requestIdleCallback(() => { + Fingerprint2.get(options, (components) => { + hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); + client = new Client(serverIP); + viewport = new Viewport(); + + isLowMemory(); + client.loadResources(); + }); + }); } else { - setTimeout(function () { - Fingerprint2.get(options, function (components) { - hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); - client = new Client(serverIP); - viewport = new Viewport(); + setTimeout(() => { + Fingerprint2.get(options, (components) => { + hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); + client = new Client(serverIP); + viewport = new Viewport(); - isLowMemory(); - client.loadResources(); - }); - }, 500); + isLowMemory(); + client.loadResources(); + }); + }, 500); } - let lastICMessageTime = new Date(0); class Client extends EventEmitter { - constructor(address) { - super(); - console.log("mode: " + mode); - if (mode !== "replay") { - this.serv = new WebSocket("ws://" + address); - // Assign the websocket events - this.serv.addEventListener("open", this.emit.bind(this, "open")); - this.serv.addEventListener("close", this.emit.bind(this, "close")); - this.serv.addEventListener("message", this.emit.bind(this, "message")); - this.serv.addEventListener("error", this.emit.bind(this, "error")); - } else { - this.joinServer(); - } - - this.on("open", this.onOpen.bind(this)); - this.on("close", this.onClose.bind(this)); - this.on("message", this.onMessage.bind(this)); - this.on("error", this.onError.bind(this)); - - // Preset some of the variables - - this.hp = [0, 0]; - - this.playerID = 1; - this.charID = -1; - this.char_list_length = 0; - this.evidence_list_length = 0; - this.music_list_length = 0; - this.testimonyID = 0; - - this.chars = []; - this.emotes = []; - this.evidences = []; - this.areas = []; - this.musics = []; - - this.musics_time = false; - - this.callwords = []; - - this.banned = false; - - this.resources = { - "holdit": { - "src": AO_HOST + "misc/default/holdit_bubble.png", - "duration": 720 - }, - "objection": { - "src": AO_HOST + "misc/default/objection_bubble.png", - "duration": 720 - }, - "takethat": { - "src": AO_HOST + "misc/default/takethat_bubble.png", - "duration": 840 - }, - "custom": { - "src": "", - "duration": 840 - }, - "witnesstestimony": { - "src": AO_HOST + "themes/" + THEME + "/witnesstestimony.gif", - "duration": 1560, - "sfx": AO_HOST + "sounds/general/sfx-testimony.opus" - }, - "crossexamination": { - "src": AO_HOST + "themes/" + THEME + "/crossexamination.gif", - "duration": 1600, - "sfx": AO_HOST + "sounds/general/sfx-testimony2.opus" - }, - "guilty": { - "src": AO_HOST + "themes/" + THEME + "/guilty.gif", - "duration": 2870, - "sfx": AO_HOST + "sounds/general/sfx-guilty.opus" - }, - "notguilty": { - "src": AO_HOST + "themes/" + THEME + "/notguilty.gif", - "duration": 2440, - "sfx": AO_HOST + "sounds/general/sfx-notguilty.opus" - }, - }; - - this.selectedEmote = -1; - this.selectedEvidence = 0; - - this.checkUpdater = null; - - /** + constructor(address) { + super(); + console.log(`mode: ${mode}`); + if (mode !== 'replay') { + this.serv = new WebSocket(`ws://${address}`); + // Assign the websocket events + this.serv.addEventListener('open', this.emit.bind(this, 'open')); + this.serv.addEventListener('close', this.emit.bind(this, 'close')); + this.serv.addEventListener('message', this.emit.bind(this, 'message')); + this.serv.addEventListener('error', this.emit.bind(this, 'error')); + } else { + this.joinServer(); + } + + this.on('open', this.onOpen.bind(this)); + this.on('close', this.onClose.bind(this)); + this.on('message', this.onMessage.bind(this)); + this.on('error', this.onError.bind(this)); + + // Preset some of the variables + + this.hp = [0, 0]; + + this.playerID = 1; + this.charID = -1; + this.char_list_length = 0; + this.evidence_list_length = 0; + this.music_list_length = 0; + this.testimonyID = 0; + + this.chars = []; + this.emotes = []; + this.evidences = []; + this.areas = []; + this.musics = []; + + this.musics_time = false; + + this.callwords = []; + + this.banned = false; + + this.resources = { + holdit: { + src: `${AO_HOST}misc/default/holdit_bubble.png`, + duration: 720, + }, + objection: { + src: `${AO_HOST}misc/default/objection_bubble.png`, + duration: 720, + }, + takethat: { + src: `${AO_HOST}misc/default/takethat_bubble.png`, + duration: 840, + }, + custom: { + src: '', + duration: 840, + }, + witnesstestimony: { + src: `${AO_HOST}themes/${THEME}/witnesstestimony.gif`, + duration: 1560, + sfx: `${AO_HOST}sounds/general/sfx-testimony.opus`, + }, + crossexamination: { + src: `${AO_HOST}themes/${THEME}/crossexamination.gif`, + duration: 1600, + sfx: `${AO_HOST}sounds/general/sfx-testimony2.opus`, + }, + guilty: { + src: `${AO_HOST}themes/${THEME}/guilty.gif`, + duration: 2870, + sfx: `${AO_HOST}sounds/general/sfx-guilty.opus`, + }, + notguilty: { + src: `${AO_HOST}themes/${THEME}/notguilty.gif`, + duration: 2440, + sfx: `${AO_HOST}sounds/general/sfx-notguilty.opus`, + }, + }; + + this.selectedEmote = -1; + this.selectedEvidence = 0; + + this.checkUpdater = null; + + /** * Assign handlers for all commands * If you implement a new command, you need to add it here */ - this.on("MS", this.handleMS.bind(this)); - this.on("CT", this.handleCT.bind(this)); - this.on("MC", this.handleMC.bind(this)); - this.on("RMC", this.handleRMC.bind(this)); - this.on("CI", this.handleCI.bind(this)); - this.on("SC", this.handleSC.bind(this)); - this.on("EI", this.handleEI.bind(this)); - this.on("FL", this.handleFL.bind(this)); - this.on("LE", this.handleLE.bind(this)); - this.on("EM", this.handleEM.bind(this)); - this.on("FM", this.handleFM.bind(this)); - this.on("FA", this.handleFA.bind(this)); - this.on("SM", this.handleSM.bind(this)); - this.on("MM", this.handleMM.bind(this)); - this.on("BD", this.handleBD.bind(this)); - this.on("BB", this.handleBB.bind(this)); - this.on("KB", this.handleKB.bind(this)); - this.on("KK", this.handleKK.bind(this)); - this.on("DONE", this.handleDONE.bind(this)); - this.on("BN", this.handleBN.bind(this)); - this.on("HP", this.handleHP.bind(this)); - this.on("RT", this.handleRT.bind(this)); - this.on("TI", this.handleTI.bind(this)); - this.on("ZZ", this.handleZZ.bind(this)); - this.on("HI", this.handleHI.bind(this)); - this.on("ID", this.handleID.bind(this)); - this.on("PN", this.handlePN.bind(this)); - this.on("SI", this.handleSI.bind(this)); - this.on("ARUP", this.handleARUP.bind(this)); - this.on("askchaa", this.handleaskchaa.bind(this)); - this.on("CC", this.handleCC.bind(this)); - this.on("RC", this.handleRC.bind(this)); - this.on("RM", this.handleRM.bind(this)); - this.on("RD", this.handleRD.bind(this)); - this.on("CharsCheck", this.handleCharsCheck.bind(this)); - this.on("PV", this.handlePV.bind(this)); - this.on("ASS", this.handleASS.bind(this)); - this.on("CHECK", () => { }); - this.on("CH", () => { }); - - this._lastTimeICReceived = new Date(0); - } - - /** + this.on('MS', this.handleMS.bind(this)); + this.on('CT', this.handleCT.bind(this)); + this.on('MC', this.handleMC.bind(this)); + this.on('RMC', this.handleRMC.bind(this)); + this.on('CI', this.handleCI.bind(this)); + this.on('SC', this.handleSC.bind(this)); + this.on('EI', this.handleEI.bind(this)); + this.on('FL', this.handleFL.bind(this)); + this.on('LE', this.handleLE.bind(this)); + this.on('EM', this.handleEM.bind(this)); + this.on('FM', this.handleFM.bind(this)); + this.on('FA', this.handleFA.bind(this)); + this.on('SM', this.handleSM.bind(this)); + this.on('MM', this.handleMM.bind(this)); + this.on('BD', this.handleBD.bind(this)); + this.on('BB', this.handleBB.bind(this)); + this.on('KB', this.handleKB.bind(this)); + this.on('KK', this.handleKK.bind(this)); + this.on('DONE', this.handleDONE.bind(this)); + this.on('BN', this.handleBN.bind(this)); + this.on('HP', this.handleHP.bind(this)); + this.on('RT', this.handleRT.bind(this)); + this.on('TI', this.handleTI.bind(this)); + this.on('ZZ', this.handleZZ.bind(this)); + this.on('HI', this.handleHI.bind(this)); + this.on('ID', this.handleID.bind(this)); + this.on('PN', this.handlePN.bind(this)); + this.on('SI', this.handleSI.bind(this)); + this.on('ARUP', this.handleARUP.bind(this)); + this.on('askchaa', this.handleaskchaa.bind(this)); + this.on('CC', this.handleCC.bind(this)); + this.on('RC', this.handleRC.bind(this)); + this.on('RM', this.handleRM.bind(this)); + this.on('RD', this.handleRD.bind(this)); + this.on('CharsCheck', this.handleCharsCheck.bind(this)); + this.on('PV', this.handlePV.bind(this)); + this.on('ASS', this.handleASS.bind(this)); + this.on('CHECK', () => { }); + this.on('CH', () => { }); + + this._lastTimeICReceived = new Date(0); + } + + /** * Gets the current player's character. */ - get character() { - return this.chars[this.charID]; - } + get character() { + return this.chars[this.charID]; + } - /** + /** * Gets the player's currently selected emote. */ - get emote() { - return this.emotes[this.selectedEmote]; - } + get emote() { + return this.emotes[this.selectedEmote]; + } - /** + /** * Gets the current evidence ID unless the player doesn't want to present any evidence */ - get evidence() { - return (document.getElementById("button_present").classList.contains("dark")) ? this.selectedEvidence : 0; - } + get evidence() { + return (document.getElementById('button_present').classList.contains('dark')) ? this.selectedEvidence : 0; + } - /** + /** * Hook for sending messages to the server * @param {string} message the message to send */ - sendServer(message) { - console.debug("C: " + message); - if (mode === "replay") { - this.sendSelf(message); - } else { - this.serv.send(message); - } - } + sendServer(message) { + console.debug(`C: ${message}`); + if (mode === 'replay') { + this.sendSelf(message); + } else { + this.serv.send(message); + } + } - /** + /** * Hook for sending messages to the client * @param {string} message the message to send */ - handleSelf(message) { - const message_event = new MessageEvent('websocket', { data: message }); - setTimeout(() => this.onMessage(message_event), 1); - } + handleSelf(message) { + const message_event = new MessageEvent('websocket', { data: message }); + setTimeout(() => this.onMessage(message_event), 1); + } - /** + /** * Hook for sending messages to the client * @param {string} message the message to send */ - sendSelf(message) { - document.getElementById("client_ooclog").value += message + "\r\n"; - this.handleSelf(message); - } - + sendSelf(message) { + document.getElementById('client_ooclog').value += `${message}\r\n`; + this.handleSelf(message); + } - /** + /** * Sends an out-of-character chat message. * @param {string} message the message to send */ - sendOOC(message) { - setCookie("OOC_name", document.getElementById("OOC_name").value); - this.sendServer(`CT#${escapeChat(encodeChat(document.getElementById("OOC_name").value))}#${escapeChat(encodeChat(message))}#%`); - } + sendOOC(message) { + setCookie('OOC_name', document.getElementById('OOC_name').value); + this.sendServer(`CT#${escapeChat(encodeChat(document.getElementById('OOC_name').value))}#${escapeChat(encodeChat(message))}#%`); + } - /** + /** * Sends an in-character chat message. * @param {string} deskmod currently unused * @param {string} speaking who is speaking @@ -307,1950 +306,1945 @@ class Client extends EventEmitter { * @param {number} self_offset offset to paired character (optional) * @param {number} noninterrupting_preanim play the full preanim (optional) */ - sendIC(deskmod, preanim, name, emote, message, side, sfx_name, emote_modifier, sfx_delay, objection_modifier, evidence, flip, - realization, text_color, showname, other_charid, self_hoffset, self_yoffset, noninterrupting_preanim, looping_sfx, screenshake, - frame_screenshake, frame_realization, frame_sfx, additive, effect) { - let extra_cccc = ``; - let other_emote = ``; - let other_offset = ``; - let extra_27 = ``; - let extra_28 = ``; - - if (extrafeatures.includes("cccc_ic_support")) { - const self_offset = extrafeatures.includes("y_offset") ? self_hoffset+'<and>'+self_yoffset : self_hoffset; // HACK: this should be an & but client fucked it up and all the servers adopted it - if (mode === "replay") { - other_emote = `##`; - other_offset = `#0#0`; - } - extra_cccc = `${showname}#${other_charid}${other_emote}#${self_offset}${other_offset}#${noninterrupting_preanim}#`; - - if (extrafeatures.includes("looping_sfx")) { - extra_27 = `${looping_sfx}#${screenshake}#${frame_screenshake}#${frame_realization}#${frame_sfx}#`; - if (extrafeatures.includes("effects")) { - extra_28 = `${additive}#${effect}#`; - } - } - } - - const serverMessage = `MS#${deskmod}#${preanim}#${name}#${emote}` + - `#${escapeChat(encodeChat(message))}#${side}#${sfx_name}#${emote_modifier}` + - `#${this.charID}#${sfx_delay}#${objection_modifier}#${evidence}#${flip}#${realization}#${text_color}#${extra_cccc}${extra_27}${extra_28}%`; - - this.sendServer(serverMessage); - if (mode === "replay") { - document.getElementById("client_ooclog").value += "wait#" + document.getElementById("client_replaytimer").value + "#%\r\n"; - } - } - - /** + sendIC( + deskmod, + preanim, + name, + emote, + message, + side, + sfx_name, + emote_modifier, + sfx_delay, + objection_modifier, + evidence, + flip, + realization, + text_color, + showname, + other_charid, + self_hoffset, + self_yoffset, + noninterrupting_preanim, + looping_sfx, + screenshake, + frame_screenshake, + frame_realization, + frame_sfx, + additive, + effect, + ) { + let extra_cccc = ''; + let other_emote = ''; + let other_offset = ''; + let extra_27 = ''; + let extra_28 = ''; + + if (extrafeatures.includes('cccc_ic_support')) { + const self_offset = extrafeatures.includes('y_offset') ? `${self_hoffset}<and>${self_yoffset}` : self_hoffset; // HACK: this should be an & but client fucked it up and all the servers adopted it + if (mode === 'replay') { + other_emote = '##'; + other_offset = '#0#0'; + } + extra_cccc = `${showname}#${other_charid}${other_emote}#${self_offset}${other_offset}#${noninterrupting_preanim}#`; + + if (extrafeatures.includes('looping_sfx')) { + extra_27 = `${looping_sfx}#${screenshake}#${frame_screenshake}#${frame_realization}#${frame_sfx}#`; + if (extrafeatures.includes('effects')) { + extra_28 = `${additive}#${effect}#`; + } + } + } + + const serverMessage = `MS#${deskmod}#${preanim}#${name}#${emote}` + + `#${escapeChat(encodeChat(message))}#${side}#${sfx_name}#${emote_modifier}` + + `#${this.charID}#${sfx_delay}#${objection_modifier}#${evidence}#${flip}#${realization}#${text_color}#${extra_cccc}${extra_27}${extra_28}%`; + + this.sendServer(serverMessage); + if (mode === 'replay') { + document.getElementById('client_ooclog').value += `wait#${document.getElementById('client_replaytimer').value}#%\r\n`; + } + } + + /** * Sends add evidence command. * @param {string} evidence name * @param {string} evidence description * @param {string} evidence image filename */ - sendPE(name, desc, img) { - this.sendServer(`PE#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); - } + sendPE(name, desc, img) { + this.sendServer(`PE#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); + } - /** + /** * Sends edit evidence command. * @param {number} evidence id * @param {string} evidence name * @param {string} evidence description * @param {string} evidence image filename */ - sendEE(id, name, desc, img) { - this.sendServer(`EE#${id}#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); - } + sendEE(id, name, desc, img) { + this.sendServer(`EE#${id}#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); + } - /** + /** * Sends delete evidence command. * @param {number} evidence id */ - sendDE(id) { - this.sendServer(`DE#${id}#%`); - } + sendDE(id) { + this.sendServer(`DE#${id}#%`); + } - /** + /** * Sends health point command. * @param {number} side the position * @param {number} hp the health point */ - sendHP(side, hp) { - this.sendServer(`HP#${side}#${hp}#%`); - } + sendHP(side, hp) { + this.sendServer(`HP#${side}#${hp}#%`); + } - /** + /** * Sends call mod command. * @param {string} message to mod */ - sendZZ(msg) { - if (extrafeatures.includes("modcall_reason")) { - this.sendServer(`ZZ#${msg}#%`); - } else { - this.sendServer(`ZZ#%`); - } - } + sendZZ(msg) { + if (extrafeatures.includes('modcall_reason')) { + this.sendServer(`ZZ#${msg}#%`); + } else { + this.sendServer('ZZ#%'); + } + } - /** + /** * Sends testimony command. * @param {string} testimony type */ - sendRT(testimony) { - if (this.chars[this.charID].side === "jud") { - this.sendServer(`RT#${testimony}#%`); - } - } + sendRT(testimony) { + if (this.chars[this.charID].side === 'jud') { + this.sendServer(`RT#${testimony}#%`); + } + } - /** + /** * Requests to change the music to the specified track. * @param {string} track the track ID */ - sendMusicChange(track) { - this.sendServer(`MC#${track}#${this.charID}#%`); - } + sendMusicChange(track) { + this.sendServer(`MC#${track}#${this.charID}#%`); + } - /** + /** * Begins the handshake process by sending an identifier * to the server. */ - joinServer() { - console.log(`Your emulated HDID is ${hdid}`); + joinServer() { + console.log(`Your emulated HDID is ${hdid}`); - this.sendServer(`HI#${hdid}#%`); - this.sendServer(`ID#webAO#webAO#%`); - if (mode !== "replay") - this.checkUpdater = setInterval(() => this.sendCheck(), 5000); - } + this.sendServer(`HI#${hdid}#%`); + this.sendServer('ID#webAO#webAO#%'); + if (mode !== 'replay') { this.checkUpdater = setInterval(() => this.sendCheck(), 5000); } + } - /** + /** * Load game resources and stored settings. */ - loadResources() { - document.getElementById("client_version").innerText = "version " + version; + loadResources() { + document.getElementById('client_version').innerText = `version ${version}`; - // Load background array to select - const background_select = document.getElementById("bg_select"); - background_select.add(new Option("Custom", 0)); - vanilla_background_arr.forEach(background => { - background_select.add(new Option(background)); - }); + // Load background array to select + const background_select = document.getElementById('bg_select'); + background_select.add(new Option('Custom', 0)); + vanilla_background_arr.forEach((background) => { + background_select.add(new Option(background)); + }); - // Load evidence array to select - const evidence_select = document.getElementById("evi_select"); - evidence_select.add(new Option("Custom", 0)); - vanilla_evidence_arr.forEach(evidence => { - evidence_select.add(new Option(evidence)); - }); + // Load evidence array to select + const evidence_select = document.getElementById('evi_select'); + evidence_select.add(new Option('Custom', 0)); + vanilla_evidence_arr.forEach((evidence) => { + evidence_select.add(new Option(evidence)); + }); - // Read cookies and set the UI to its values - document.getElementById("OOC_name").value = getCookie("OOC_name") || "web"+parseInt(Math.random()*100+10); + // Read cookies and set the UI to its values + document.getElementById('OOC_name').value = getCookie('OOC_name') || `web${parseInt(Math.random() * 100 + 10)}`; - // Read cookies and set the UI to its values - var cookietheme = getCookie("theme") || "default"; + // Read cookies and set the UI to its values + const cookietheme = getCookie('theme') || 'default'; - document.querySelector('#client_themeselect [value="' + cookietheme + '"]').selected = true; - reloadTheme(); + document.querySelector(`#client_themeselect [value="${cookietheme}"]`).selected = true; + reloadTheme(); - var cookiechatbox = getCookie("chatbox") || "dynamic"; + const cookiechatbox = getCookie('chatbox') || 'dynamic'; - document.querySelector('#client_chatboxselect [value="' + cookiechatbox + '"]').selected = true; - setChatbox(cookiechatbox); + document.querySelector(`#client_chatboxselect [value="${cookiechatbox}"]`).selected = true; + setChatbox(cookiechatbox); - document.getElementById("client_mvolume").value = getCookie("musicVolume") || 1; - changeMusicVolume(); - document.getElementById("client_sfxaudio").volume = getCookie("sfxVolume") || 1; - changeSFXVolume(); - document.getElementById("client_shoutaudio").volume = getCookie("shoutVolume") || 1; - changeShoutVolume(); - document.getElementById("client_testimonyaudio").volume = getCookie("testimonyVolume") || 1; - changeTestimonyVolume(); - document.getElementById("client_bvolume").value = getCookie("blipVolume") || 1; - changeBlipVolume(); + document.getElementById('client_mvolume').value = getCookie('musicVolume') || 1; + changeMusicVolume(); + document.getElementById('client_sfxaudio').volume = getCookie('sfxVolume') || 1; + changeSFXVolume(); + document.getElementById('client_shoutaudio').volume = getCookie('shoutVolume') || 1; + changeShoutVolume(); + document.getElementById('client_testimonyaudio').volume = getCookie('testimonyVolume') || 1; + changeTestimonyVolume(); + document.getElementById('client_bvolume').value = getCookie('blipVolume') || 1; + changeBlipVolume(); - document.getElementById("ic_chat_name").value = getCookie("ic_chat_name"); - document.getElementById("showname").checked = getCookie("showname"); - showname_click(); + document.getElementById('ic_chat_name').value = getCookie('ic_chat_name'); + document.getElementById('showname').checked = getCookie('showname'); + showname_click(); - document.getElementById("client_callwords").value = getCookie("callwords"); - } + document.getElementById('client_callwords').value = getCookie('callwords'); + } - /** + /** * Requests to play as a specified character. * @param {number} character the character ID */ - sendCharacter(character) { - if (this.chars[character].name) - this.sendServer(`CC#${this.playerID}#${character}#web#%`); - } + sendCharacter(character) { + if (this.chars[character].name) { this.sendServer(`CC#${this.playerID}#${character}#web#%`); } + } - /** + /** * Requests to select a music track. * @param {number?} song the song to be played */ - sendMusic(song) { - this.sendServer(`MC#${song}#${this.charID}#%`); - } + sendMusic(song) { + this.sendServer(`MC#${song}#${this.charID}#%`); + } - /** + /** * Sends a keepalive packet. */ - sendCheck() { - this.sendServer(`CH#${this.charID}#%`); - } + sendCheck() { + this.sendServer(`CH#${this.charID}#%`); + } - /** + /** * Triggered when a connection is established to the server. */ - onOpen(_e) { - client.joinServer(); - } + onOpen(_e) { + client.joinServer(); + } - /** + /** * Triggered when the connection to the server closes. * @param {CloseEvent} e */ - onClose(e) { - console.error(`The connection was closed: ${e.reason} (${e.code})`); - if (extrafeatures.length == 0 && this.banned === false) { - document.getElementById("client_errortext").textContent = "Could not connect to the server"; - } - document.getElementById("client_error").style.display = "flex"; - document.getElementById("client_loading").style.display = "none"; - document.getElementById("error_id").textContent = e.code; - this.cleanup(); - } - - /** + onClose(e) { + console.error(`The connection was closed: ${e.reason} (${e.code})`); + if (extrafeatures.length == 0 && this.banned === false) { + document.getElementById('client_errortext').textContent = 'Could not connect to the server'; + } + document.getElementById('client_error').style.display = 'flex'; + document.getElementById('client_loading').style.display = 'none'; + document.getElementById('error_id').textContent = e.code; + this.cleanup(); + } + + /** * Triggered when a packet is received from the server. * @param {MessageEvent} e */ - onMessage(e) { - const msg = e.data; - console.debug("S: " + msg); - - const lines = msg.split("%"); - - for (const msg of lines) { - if(msg === "") - break; - - const args = msg.split("#"); - const header = args[0]; - - if (!this.emit(header, args)) { - console.warn(`Invalid packet header ${header}`); - } - } - } - - /** + onMessage(e) { + const msg = e.data; + console.debug(`S: ${msg}`); + + const lines = msg.split('%'); + + for (const msg of lines) { + if (msg === '') { break; } + + const args = msg.split('#'); + const header = args[0]; + + if (!this.emit(header, args)) { + console.warn(`Invalid packet header ${header}`); + } + } + } + + /** * Triggered when an network error occurs. - * @param {ErrorEvent} e + * @param {ErrorEvent} e */ - onError(e) { - console.error(`A network error occurred: ${e.reason} (${e.code})`); - document.getElementById("client_error").style.display = "flex"; - document.getElementById("error_id").textContent = e.code; - this.cleanup(); - } + onError(e) { + console.error(`A network error occurred: ${e.reason} (${e.code})`); + document.getElementById('client_error').style.display = 'flex'; + document.getElementById('error_id').textContent = e.code; + this.cleanup(); + } - /** + /** * Stop sending keepalives to the server. */ - cleanup() { - clearInterval(this.checkUpdater); + cleanup() { + clearInterval(this.checkUpdater); - // the connection got rekt, get rid of the old musiclist - this.resetMusicList(); - document.getElementById("client_chartable").innerHTML = ""; - } + // the connection got rekt, get rid of the old musiclist + this.resetMusicList(); + document.getElementById('client_chartable').innerHTML = ''; + } - /** + /** * Parse the lines in the OOC and play them * @param {*} args packet arguments */ - handleReplay() { - const ooclog = document.getElementById("client_ooclog"); - const rawLog = false; - let rtime = document.getElementById("client_replaytimer").value; - - const clines = ooclog.value.split(/\r?\n/); - if (clines[0]) { - const currentLine = String(clines[0]); - this.handleSelf(currentLine); - ooclog.value = clines.slice(1).join("\r\n"); - if (currentLine.substr(0,4)==="wait" && rawLog === false) { - rtime = currentLine.split("#")[1]; - } else if (currentLine.substr(0,2)!=="MS"){ - rtime = 0; - } - - setTimeout(() => onReplayGo(""), rtime); - } - } - - /** + handleReplay() { + const ooclog = document.getElementById('client_ooclog'); + const rawLog = false; + let rtime = document.getElementById('client_replaytimer').value; + + const clines = ooclog.value.split(/\r?\n/); + if (clines[0]) { + const currentLine = String(clines[0]); + this.handleSelf(currentLine); + ooclog.value = clines.slice(1).join('\r\n'); + if (currentLine.substr(0, 4) === 'wait' && rawLog === false) { + rtime = currentLine.split('#')[1]; + } else if (currentLine.substr(0, 2) !== 'MS') { + rtime = 0; + } + + setTimeout(() => onReplayGo(''), rtime); + } + } + + /** * Handles an in-character chat message. * @param {*} args packet arguments */ - handleMS(args) { - // TODO: this if-statement might be a bug. - if (args[4] !== viewport.chatmsg.content) { - document.getElementById("client_inner_chat").innerHTML = ""; - - const char_id = Number(args[9]); - const char_name = safe_tags(args[3]); - - let msg_nameplate = args[3]; - let msg_blips = "male"; - let char_chatbox = "default"; - let char_muted = false; - - try { - msg_nameplate = this.chars[char_id].showname; - msg_blips = this.chars[char_id].blips; - char_chatbox = this.chars[char_id].chat; - char_muted = this.chars[char_id].muted; - - if (this.chars[char_id].name !== char_name) { - console.info(this.chars[char_id].name + " is iniediting to " + char_name); - const chargs = (char_name + "&" + "iniediter").split("&"); - this.handleCharacterInfo(chargs, char_id); - } - } catch (e) { - msg_nameplate = args[3]; - msg_blips = "male"; - char_chatbox = "default"; - char_muted = false; - console.error("we're still missing some character data"); - } - - if (char_muted === false) { - - let chatmsg = { - deskmod: safe_tags(args[1]).toLowerCase(), - preanim: safe_tags(args[2]).toLowerCase(), // get preanim - nameplate: msg_nameplate, - chatbox: char_chatbox, - name: char_name, - sprite: safe_tags(args[4]).toLowerCase(), - content: prepChat(args[5]), // Escape HTML tags - side: args[6].toLowerCase(), - sound: safe_tags(args[7]).toLowerCase(), - blips: safe_tags(msg_blips), - type: Number(args[8]), - charid: char_id, - snddelay: Number(args[10]), - objection: Number(args[11]), - evidence: safe_tags(args[12]), - flip: Number(args[13]), - flash: Number(args[14]), - color: Number(args[15]) - }; - - if (extrafeatures.includes("cccc_ic_support")) { - const extra_cccc = { - showname: safe_tags(args[16]), - other_charid: Number(args[17]), - other_name: safe_tags(args[18]), - other_emote: safe_tags(args[19]), - self_offset: args[20].split('<and>'), // HACK: here as well, client is fucked and uses this instead of & - other_offset: args[21].split('<and>'), - other_flip: Number(args[22]), - noninterrupting_preanim: Number(args[23]) - }; - chatmsg = Object.assign(extra_cccc, chatmsg); - - if (extrafeatures.includes("looping_sfx")) { - const extra_27 = { - looping_sfx: Number(args[24]), - screenshake: Number(args[25]), - frame_screenshake: safe_tags(args[26]), - frame_realization: safe_tags(args[27]), - frame_sfx: safe_tags(args[28]) - }; - chatmsg = Object.assign(extra_27, chatmsg); - - if (extrafeatures.includes("effects")) { - const extra_28 = { - additive: Number(args[29]), - effects: args[30].split('|') - }; - chatmsg = Object.assign(extra_28, chatmsg); - } else { - const extra_28 = { - additive: 0, - effects: ['','',''] - }; - chatmsg = Object.assign(extra_28, chatmsg); - } - - } else { - const extra_27 = { - looping_sfx: 0, - screenshake: 0, - frame_screenshake: "", - frame_realization: "", - frame_sfx: "" - }; - chatmsg = Object.assign(extra_27, chatmsg); - const extra_28 = { - additive: 0, - effects: ['','',''] - }; - chatmsg = Object.assign(extra_28, chatmsg); - } - } else { - const extra_cccc = { - showname: "", - other_charid: 0, - other_name: "", - other_emote: "", - self_offset: [0,0], - other_offset: [0,0], - other_flip: 0, - noninterrupting_preanim: 0 - }; - chatmsg = Object.assign(extra_cccc, chatmsg); - const extra_27 = { - looping_sfx: 0, - screenshake: 0, - frame_screenshake: "", - frame_realization: "", - frame_sfx: "" - }; - chatmsg = Object.assign(extra_27, chatmsg); - const extra_28 = { - additive: 0, - effects: ['','',''] - }; - chatmsg = Object.assign(extra_28, chatmsg); - } - - // our own message appeared, reset the buttons - if (chatmsg.charid === this.charID) { - resetICParams(); - } - - viewport.say(chatmsg); // no await - } - } - } - - /** + handleMS(args) { + // TODO: this if-statement might be a bug. + if (args[4] !== viewport.chatmsg.content) { + document.getElementById('client_inner_chat').innerHTML = ''; + + const char_id = Number(args[9]); + const char_name = safe_tags(args[3]); + + let msg_nameplate = args[3]; + let msg_blips = 'male'; + let char_chatbox = 'default'; + let char_muted = false; + + try { + msg_nameplate = this.chars[char_id].showname; + msg_blips = this.chars[char_id].blips; + char_chatbox = this.chars[char_id].chat; + char_muted = this.chars[char_id].muted; + + if (this.chars[char_id].name !== char_name) { + console.info(`${this.chars[char_id].name} is iniediting to ${char_name}`); + const chargs = (`${char_name}&` + 'iniediter').split('&'); + this.handleCharacterInfo(chargs, char_id); + } + } catch (e) { + msg_nameplate = args[3]; + msg_blips = 'male'; + char_chatbox = 'default'; + char_muted = false; + console.error("we're still missing some character data"); + } + + if (char_muted === false) { + let chatmsg = { + deskmod: safe_tags(args[1]).toLowerCase(), + preanim: safe_tags(args[2]).toLowerCase(), // get preanim + nameplate: msg_nameplate, + chatbox: char_chatbox, + name: char_name, + sprite: safe_tags(args[4]).toLowerCase(), + content: prepChat(args[5]), // Escape HTML tags + side: args[6].toLowerCase(), + sound: safe_tags(args[7]).toLowerCase(), + blips: safe_tags(msg_blips), + type: Number(args[8]), + charid: char_id, + snddelay: Number(args[10]), + objection: Number(args[11]), + evidence: safe_tags(args[12]), + flip: Number(args[13]), + flash: Number(args[14]), + color: Number(args[15]), + }; + + if (extrafeatures.includes('cccc_ic_support')) { + const extra_cccc = { + showname: safe_tags(args[16]), + other_charid: Number(args[17]), + other_name: safe_tags(args[18]), + other_emote: safe_tags(args[19]), + self_offset: args[20].split('<and>'), // HACK: here as well, client is fucked and uses this instead of & + other_offset: args[21].split('<and>'), + other_flip: Number(args[22]), + noninterrupting_preanim: Number(args[23]), + }; + chatmsg = Object.assign(extra_cccc, chatmsg); + + if (extrafeatures.includes('looping_sfx')) { + const extra_27 = { + looping_sfx: Number(args[24]), + screenshake: Number(args[25]), + frame_screenshake: safe_tags(args[26]), + frame_realization: safe_tags(args[27]), + frame_sfx: safe_tags(args[28]), + }; + chatmsg = Object.assign(extra_27, chatmsg); + + if (extrafeatures.includes('effects')) { + const extra_28 = { + additive: Number(args[29]), + effects: args[30].split('|'), + }; + chatmsg = Object.assign(extra_28, chatmsg); + } else { + const extra_28 = { + additive: 0, + effects: ['', '', ''], + }; + chatmsg = Object.assign(extra_28, chatmsg); + } + } else { + const extra_27 = { + looping_sfx: 0, + screenshake: 0, + frame_screenshake: '', + frame_realization: '', + frame_sfx: '', + }; + chatmsg = Object.assign(extra_27, chatmsg); + const extra_28 = { + additive: 0, + effects: ['', '', ''], + }; + chatmsg = Object.assign(extra_28, chatmsg); + } + } else { + const extra_cccc = { + showname: '', + other_charid: 0, + other_name: '', + other_emote: '', + self_offset: [0, 0], + other_offset: [0, 0], + other_flip: 0, + noninterrupting_preanim: 0, + }; + chatmsg = Object.assign(extra_cccc, chatmsg); + const extra_27 = { + looping_sfx: 0, + screenshake: 0, + frame_screenshake: '', + frame_realization: '', + frame_sfx: '', + }; + chatmsg = Object.assign(extra_27, chatmsg); + const extra_28 = { + additive: 0, + effects: ['', '', ''], + }; + chatmsg = Object.assign(extra_28, chatmsg); + } + + // our own message appeared, reset the buttons + if (chatmsg.charid === this.charID) { + resetICParams(); + } + + viewport.say(chatmsg); // no await + } + } + } + + /** * Handles an out-of-character chat message. * @param {Array} args packet arguments */ - handleCT(args) { - if (mode !== "replay") { - const oocLog = document.getElementById("client_ooclog"); - oocLog.innerHTML += `${prepChat(args[1])}: ${prepChat(args[2])}\r\n`; - if (oocLog.scrollTop > oocLog.scrollHeight - 600) { - oocLog.scrollTop = oocLog.scrollHeight; - } - } - } - - /** + handleCT(args) { + if (mode !== 'replay') { + const oocLog = document.getElementById('client_ooclog'); + oocLog.innerHTML += `${prepChat(args[1])}: ${prepChat(args[2])}\r\n`; + if (oocLog.scrollTop > oocLog.scrollHeight - 600) { + oocLog.scrollTop = oocLog.scrollHeight; + } + } + } + + /** * Handles a music change to an arbitrary resource. * @param {Array} args packet arguments */ - handleMC(args) { - const track = prepChat(args[1]); - let charID = Number(args[2]); - const showname = args[3] || ""; - const looping = Boolean(args[4]); - const channel = Number(args[5]) || 0; - // const fading = Number(args[6]) || 0; // unused in web - - const music = viewport.music[channel]; - let musicname; - music.pause(); - if(track.startsWith("http")) { - music.src = track; - } else { - music.src = AO_HOST + "sounds/music/" + encodeURI(track.toLowerCase()); - } - music.loop = looping; - music.play(); - - try { - musicname = this.chars[charID].name; - } catch(e) { - charID = -1; - } - - if (charID >= 0) { - musicname = this.chars[charID].name; - appendICLog(`${musicname} changed music to ${track}`); - } else { - appendICLog(`The music was changed to ${track}`); - } - - document.getElementById("client_trackstatustext").innerText = track; - } - - /** + handleMC(args) { + const track = prepChat(args[1]); + let charID = Number(args[2]); + const showname = args[3] || ''; + const looping = Boolean(args[4]); + const channel = Number(args[5]) || 0; + // const fading = Number(args[6]) || 0; // unused in web + + const music = viewport.music[channel]; + let musicname; + music.pause(); + if (track.startsWith('http')) { + music.src = track; + } else { + music.src = `${AO_HOST}sounds/music/${encodeURI(track.toLowerCase())}`; + } + music.loop = looping; + music.play(); + + try { + musicname = this.chars[charID].name; + } catch (e) { + charID = -1; + } + + if (charID >= 0) { + musicname = this.chars[charID].name; + appendICLog(`${musicname} changed music to ${track}`); + } else { + appendICLog(`The music was changed to ${track}`); + } + + document.getElementById('client_trackstatustext').innerText = track; + } + + /** * Handles a music change to an arbitrary resource, with an offset in seconds. * @param {Array} args packet arguments */ - handleRMC(args) { - viewport.music.pause(); - const music = viewport.music; - // Music offset + drift from song loading - music.totime = args[1]; - music.offset = new Date().getTime() / 1000; - music.addEventListener("loadedmetadata", function () { - music.currentTime += parseFloat(music.totime + (new Date().getTime() / 1000 - music.offset)).toFixed(3); - music.play(); - }, false); - } - - /** + handleRMC(args) { + viewport.music.pause(); + const { music } = viewport; + // Music offset + drift from song loading + music.totime = args[1]; + music.offset = new Date().getTime() / 1000; + music.addEventListener('loadedmetadata', () => { + music.currentTime += parseFloat(music.totime + (new Date().getTime() / 1000 - music.offset)).toFixed(3); + music.play(); + }, false); + } + + /** * Handles the incoming character information, and downloads the sprite + ini for it * @param {Array} chargs packet arguments * @param {Number} charid character ID */ - async handleCharacterInfo(chargs, charid) { - if (chargs[0]) { - let cini = {}; - let cswap = {}; - let icon = AO_HOST + "characters/" + encodeURI(chargs[0].toLowerCase()) + "/char_icon.png"; - let img = document.getElementById(`demo_${charid}`); - img.alt = chargs[0]; - img.src = icon; // seems like a good time to load the icon - - // If the ini doesn't exist on the server this will throw an error - try { - const cinidata = await request(AO_HOST + "characters/" + encodeURI(chargs[0].toLowerCase()) + "/char.ini"); - cini = INI.parse(cinidata); - } catch (err) { - cini = {}; - img.classList.add("noini"); - console.warn("character " + chargs[0] + " is missing from webAO"); - // If it does, give the user a visual indication that the character is unusable - } - - const mute_select = document.getElementById("mute_select"); - mute_select.add(new Option(safe_tags(chargs[0]), charid)); - const pair_select = document.getElementById("pair_select"); - pair_select.add(new Option(safe_tags(chargs[0]), charid)); - - // sometimes ini files lack important settings - const default_options = { - name: chargs[0], - showname: chargs[0], - side: "def", - blips: "male", - chat: "", - category: "" - }; - cini.options = Object.assign(default_options, cini.options); - - // sometimes ini files lack important settings - const default_emotions = { - number: 0 - }; - cini.emotions = Object.assign(default_emotions, cini.emotions); - - this.chars[charid] = { - name: safe_tags(chargs[0]), - showname: safe_tags(cini.options.showname), - desc: safe_tags(chargs[1]), - blips: safe_tags(cini.options.blips).toLowerCase(), - gender: safe_tags(cini.options.gender).toLowerCase(), - side: safe_tags(cini.options.side).toLowerCase(), - chat: (cini.options.chat==="") ? safe_tags(cini.options.chat).toLowerCase() : safe_tags(cini.options.category).toLowerCase(), - evidence: chargs[3], - icon: icon, - inifile: cini, - muted: false - }; - - if(this.chars[charid].blips === "") - this.chars[charid].blips = this.chars[charid].gender; - - const iniedit_select = document.getElementById("client_ininame"); - iniedit_select.add(new Option(safe_tags(chargs[0]))); - - } else { - console.warn("missing charid " + charid); - let img = document.getElementById(`demo_${charid}`); - img.style.display = "none"; - } - - - } - - /** + async handleCharacterInfo(chargs, charid) { + if (chargs[0]) { + let cini = {}; + const cswap = {}; + const icon = `${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char_icon.png`; + const img = document.getElementById(`demo_${charid}`); + img.alt = chargs[0]; + img.src = icon; // seems like a good time to load the icon + + // If the ini doesn't exist on the server this will throw an error + try { + const cinidata = await request(`${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char.ini`); + cini = INI.parse(cinidata); + } catch (err) { + cini = {}; + img.classList.add('noini'); + console.warn(`character ${chargs[0]} is missing from webAO`); + // If it does, give the user a visual indication that the character is unusable + } + + const mute_select = document.getElementById('mute_select'); + mute_select.add(new Option(safe_tags(chargs[0]), charid)); + const pair_select = document.getElementById('pair_select'); + pair_select.add(new Option(safe_tags(chargs[0]), charid)); + + // sometimes ini files lack important settings + const default_options = { + name: chargs[0], + showname: chargs[0], + side: 'def', + blips: 'male', + chat: '', + category: '', + }; + cini.options = Object.assign(default_options, cini.options); + + // sometimes ini files lack important settings + const default_emotions = { + number: 0, + }; + cini.emotions = Object.assign(default_emotions, cini.emotions); + + this.chars[charid] = { + name: safe_tags(chargs[0]), + showname: safe_tags(cini.options.showname), + desc: safe_tags(chargs[1]), + blips: safe_tags(cini.options.blips).toLowerCase(), + gender: safe_tags(cini.options.gender).toLowerCase(), + side: safe_tags(cini.options.side).toLowerCase(), + chat: (cini.options.chat === '') ? safe_tags(cini.options.chat).toLowerCase() : safe_tags(cini.options.category).toLowerCase(), + evidence: chargs[3], + icon, + inifile: cini, + muted: false, + }; + + if (this.chars[charid].blips === '') { this.chars[charid].blips = this.chars[charid].gender; } + + const iniedit_select = document.getElementById('client_ininame'); + iniedit_select.add(new Option(safe_tags(chargs[0]))); + } else { + console.warn(`missing charid ${charid}`); + const img = document.getElementById(`demo_${charid}`); + img.style.display = 'none'; + } + } + + /** * Handles incoming character information, bundling multiple characters * per packet. * CI#0#Phoenix&description&&&&#Miles ... * @param {Array} args packet arguments */ - handleCI(args) { - // Loop through the 10 characters that were sent - for (let i = 2; i <= args.length - 2; i++) { - if (i % 2 === 0) { - document.getElementById("client_loadingtext").innerHTML = `Loading Character ${args[1]}/${this.char_list_length}`; - const chargs = args[i].split("&"); - const charid = args[i - 1]; - setTimeout(() => this.handleCharacterInfo(chargs, charid), charid*10); - } - } - // Request the next pack - this.sendServer("AN#" + ((args[1] / 10) + 1) + "#%"); - } - - /** + handleCI(args) { + // Loop through the 10 characters that were sent + for (let i = 2; i <= args.length - 2; i++) { + if (i % 2 === 0) { + document.getElementById('client_loadingtext').innerHTML = `Loading Character ${args[1]}/${this.char_list_length}`; + const chargs = args[i].split('&'); + const charid = args[i - 1]; + setTimeout(() => this.handleCharacterInfo(chargs, charid), charid * 10); + } + } + // Request the next pack + this.sendServer(`AN#${(args[1] / 10) + 1}#%`); + } + + /** * Handles incoming character information, containing all characters * in one packet. * @param {Array} args packet arguments */ - handleSC(args) { - document.getElementById("client_loadingtext").innerHTML = "Loading Characters"; - for (let i = 1; i < args.length; i++) { - document.getElementById("client_loadingtext").innerHTML = `Loading Character ${i}/${this.char_list_length}`; - const chargs = args[i].split("&"); - const charid = i - 1; - setTimeout(() => this.handleCharacterInfo(chargs, charid), charid*10); - } - // We're done with the characters, request the music - this.sendServer("RM#%"); - } - - /** + handleSC(args) { + document.getElementById('client_loadingtext').innerHTML = 'Loading Characters'; + for (let i = 1; i < args.length; i++) { + document.getElementById('client_loadingtext').innerHTML = `Loading Character ${i}/${this.char_list_length}`; + const chargs = args[i].split('&'); + const charid = i - 1; + setTimeout(() => this.handleCharacterInfo(chargs, charid), charid * 10); + } + // We're done with the characters, request the music + this.sendServer('RM#%'); + } + + /** * Handles incoming evidence information, containing only one evidence * item per packet. - * + * * Mostly unimplemented in webAO. * @param {Array} args packet arguments */ - handleEI(args) { - document.getElementById("client_loadingtext").innerHTML = `Loading Evidence ${args[1]}/${this.evidence_list_length}`; - this.sendServer("RM#%"); - } + handleEI(args) { + document.getElementById('client_loadingtext').innerHTML = `Loading Evidence ${args[1]}/${this.evidence_list_length}`; + this.sendServer('RM#%'); + } - /** + /** * Handles incoming evidence list, all evidences at once * item per packet. - * + * * @param {Array} args packet arguments */ - handleLE(args) { - this.evidences = []; - for (let i = 1; i < args.length - 1; i++) { - const arg = args[i].split("&"); - this.evidences[i - 1] = { - name: prepChat(arg[0]), - desc: prepChat(arg[1]), - filename: safe_tags(arg[2]), - icon: AO_HOST + "evidence/" + encodeURI(arg[2].toLowerCase()) - }; - } - - const evidence_box = document.getElementById("evidences"); - evidence_box.innerHTML = ""; - for (let i = 1; i <= this.evidences.length; i++) { - evidence_box.innerHTML += `<img src="${this.evidences[i - 1].icon}" + handleLE(args) { + this.evidences = []; + for (let i = 1; i < args.length - 1; i++) { + const arg = args[i].split('&'); + this.evidences[i - 1] = { + name: prepChat(arg[0]), + desc: prepChat(arg[1]), + filename: safe_tags(arg[2]), + icon: `${AO_HOST}evidence/${encodeURI(arg[2].toLowerCase())}`, + }; + } + + const evidence_box = document.getElementById('evidences'); + evidence_box.innerHTML = ''; + for (let i = 1; i <= this.evidences.length; i++) { + evidence_box.innerHTML += `<img src="${this.evidences[i - 1].icon}" id="evi_${i}" alt="${this.evidences[i - 1].name}" class="evi_icon" onclick="pickEvidence(${i})">`; - } - } - - resetMusicList() { - this.musics = []; - document.getElementById("client_musiclist").innerHTML = ""; - } - - resetAreaList() { - this.areas = []; - document.getElementById("areas").innerHTML = ""; - - this.fetchBackgroundList(); - this.fetchEvidenceList(); - } - - async fetchBackgroundList() { - try { - const bgdata = await request(AO_HOST + "backgrounds.json"); - const bg_array = JSON.parse(bgdata); - // the try catch will fail before here when there is no file - - const bg_select = document.getElementById("bg_select"); - bg_select.innerHTML = ""; - - bg_select.add(new Option("Custom", 0)); - bg_array.forEach(background => { - bg_select.add(new Option(background)); - }); - } catch (err) { - console.warn("there was no backgrounds.json file"); - } - } - - async fetchCharacterList() { - try { - const chardata = await request(AO_HOST + "characters.json"); - const char_array = JSON.parse(chardata); - // the try catch will fail before here when there is no file - - const char_select = document.getElementById("client_ininame"); - char_select.innerHTML = ""; - - char_array.forEach(character => { - char_select.add(new Option(character)); - }); - } catch (err) { - console.warn("there was no characters.json file"); - } - } - - async fetchEvidenceList() { - try { - const evidata = await request(AO_HOST + "evidence.json"); - const evi_array = JSON.parse(evidata); - // the try catch will fail before here when there is no file - - const evi_select = document.getElementById("evi_select"); - evi_select.innerHTML = ""; - - evi_array.forEach(evi => { - evi_select.add(new Option(evi)); - }); - evidence_select.add(new Option("Custom", 0)); - - } catch (err) { - console.warn("there was no evidence.json file"); - } - } - - isAudio(trackname) { - if (trackname.endsWith(".wav") || - trackname.endsWith(".mp3") || - trackname.endsWith(".mp4") || - trackname.endsWith(".ogg") || - trackname.endsWith(".opus")) // NOT category markers - { - return true; - } else { - return false; - } - } - - addTrack(trackname) { - const newentry = document.createElement("OPTION"); - newentry.text = trackname; - document.getElementById("client_musiclist").options.add(newentry); - this.musics.push(trackname); - } - - createArea(id,name) { - const thisarea = { - name: name, - players: 0, - status: "IDLE", - cm: "", - locked: "FREE" - }; - - this.areas.push(thisarea); - - // Create area button - let newarea = document.createElement("SPAN"); - newarea.classList = "area-button area-default"; - newarea.id = "area" + id; - newarea.innerText = thisarea.name; - newarea.title = `Players: ${thisarea.players}\n` + - `Status: ${thisarea.status}\n` + - `CM: ${thisarea.cm}\n` + - `Area lock: ${thisarea.locked}`; - newarea.onclick = function () { - area_click(this); - }; - - document.getElementById("areas").appendChild(newarea); - } - - - /** + } + } + + resetMusicList() { + this.musics = []; + document.getElementById('client_musiclist').innerHTML = ''; + } + + resetAreaList() { + this.areas = []; + document.getElementById('areas').innerHTML = ''; + + this.fetchBackgroundList(); + this.fetchEvidenceList(); + } + + async fetchBackgroundList() { + try { + const bgdata = await request(`${AO_HOST}backgrounds.json`); + const bg_array = JSON.parse(bgdata); + // the try catch will fail before here when there is no file + + const bg_select = document.getElementById('bg_select'); + bg_select.innerHTML = ''; + + bg_select.add(new Option('Custom', 0)); + bg_array.forEach((background) => { + bg_select.add(new Option(background)); + }); + } catch (err) { + console.warn('there was no backgrounds.json file'); + } + } + + async fetchCharacterList() { + try { + const chardata = await request(`${AO_HOST}characters.json`); + const char_array = JSON.parse(chardata); + // the try catch will fail before here when there is no file + + const char_select = document.getElementById('client_ininame'); + char_select.innerHTML = ''; + + char_array.forEach((character) => { + char_select.add(new Option(character)); + }); + } catch (err) { + console.warn('there was no characters.json file'); + } + } + + async fetchEvidenceList() { + try { + const evidata = await request(`${AO_HOST}evidence.json`); + const evi_array = JSON.parse(evidata); + // the try catch will fail before here when there is no file + + const evi_select = document.getElementById('evi_select'); + evi_select.innerHTML = ''; + + evi_array.forEach((evi) => { + evi_select.add(new Option(evi)); + }); + evidence_select.add(new Option('Custom', 0)); + } catch (err) { + console.warn('there was no evidence.json file'); + } + } + + isAudio(trackname) { + if (trackname.endsWith('.wav') + || trackname.endsWith('.mp3') + || trackname.endsWith('.mp4') + || trackname.endsWith('.ogg') + || trackname.endsWith('.opus')) // NOT category markers + { + return true; + } + return false; + } + + addTrack(trackname) { + const newentry = document.createElement('OPTION'); + newentry.text = trackname; + document.getElementById('client_musiclist').options.add(newentry); + this.musics.push(trackname); + } + + createArea(id, name) { + const thisarea = { + name, + players: 0, + status: 'IDLE', + cm: '', + locked: 'FREE', + }; + + this.areas.push(thisarea); + + // Create area button + const newarea = document.createElement('SPAN'); + newarea.classList = 'area-button area-default'; + newarea.id = `area${id}`; + newarea.innerText = thisarea.name; + newarea.title = `Players: ${thisarea.players}\n` + + `Status: ${thisarea.status}\n` + + `CM: ${thisarea.cm}\n` + + `Area lock: ${thisarea.locked}`; + newarea.onclick = function () { + area_click(this); + }; + + document.getElementById('areas').appendChild(newarea); + } + + /** * Area list fuckery */ - fix_last_area() { - if (this.areas.length > 0) { - let malplaced = this.areas.pop().name; - const areas = document.getElementById("areas"); - areas.removeChild(areas.lastChild); - this.addTrack(malplaced); - } + fix_last_area() { + if (this.areas.length > 0) { + const malplaced = this.areas.pop().name; + const areas = document.getElementById('areas'); + areas.removeChild(areas.lastChild); + this.addTrack(malplaced); } + } - /** + /** * Handles incoming music information, containing multiple entries * per packet. * @param {Array} args packet arguments */ - handleEM(args) { - document.getElementById("client_loadingtext").innerHTML = "Loading Music"; - if(args[1] === "0") { - this.resetMusicList(); - this.resetAreaList(); - this.musics_time = false; - } - - for (let i = 2; i < args.length - 1; i++) { - if (i % 2 === 0) { - document.getElementById("client_loadingtext").innerHTML = `Loading Music ${args[1]}/${this.music_list_length}`; - const trackname = safe_tags(args[i]); - const trackindex = args[i-1]; - if (this.musics_time) { + handleEM(args) { + document.getElementById('client_loadingtext').innerHTML = 'Loading Music'; + if (args[1] === '0') { + this.resetMusicList(); + this.resetAreaList(); + this.musics_time = false; + } + + for (let i = 2; i < args.length - 1; i++) { + if (i % 2 === 0) { + document.getElementById('client_loadingtext').innerHTML = `Loading Music ${args[1]}/${this.music_list_length}`; + const trackname = safe_tags(args[i]); + const trackindex = args[i - 1]; + if (this.musics_time) { this.addTrack(trackname); } else if (this.isAudio(trackname)) { this.musics_time = true; this.fix_last_area(); this.addTrack(trackname); } else { - this.createArea(trackindex,trackname); + this.createArea(trackindex, trackname); } - } - } + } + } - // get the next batch of tracks - this.sendServer("AM#" + ((args[1] / 10) + 1) + "#%"); - } + // get the next batch of tracks + this.sendServer(`AM#${(args[1] / 10) + 1}#%`); + } - /** + /** * Handles incoming music information, containing all music in one packet. * @param {Array} args packet arguments */ - handleSM(args) { - document.getElementById("client_loadingtext").innerHTML = "Loading Music "; - this.resetMusicList(); - this.resetAreaList(); - - this.musics_time = false; - - for (let i = 1; i < args.length - 1; i++) { - // Check when found the song for the first time - const trackname = safe_tags(args[i]); - const trackindex = i-1; - document.getElementById("client_loadingtext").innerHTML = `Loading Music ${i}/${this.music_list_length}`; - if (this.musics_time) { - this.addTrack(trackname); - } else if (this.isAudio(trackname)) { - this.musics_time = true; - this.fix_last_area(); - this.addTrack(trackname); - } else { - this.createArea(trackindex,trackname); - } - } + handleSM(args) { + document.getElementById('client_loadingtext').innerHTML = 'Loading Music '; + this.resetMusicList(); + this.resetAreaList(); + + this.musics_time = false; + + for (let i = 1; i < args.length - 1; i++) { + // Check when found the song for the first time + const trackname = safe_tags(args[i]); + const trackindex = i - 1; + document.getElementById('client_loadingtext').innerHTML = `Loading Music ${i}/${this.music_list_length}`; + if (this.musics_time) { + this.addTrack(trackname); + } else if (this.isAudio(trackname)) { + this.musics_time = true; + this.fix_last_area(); + this.addTrack(trackname); + } else { + this.createArea(trackindex, trackname); + } + } - // Music done, carry on - this.sendServer("RD#%"); - } + // Music done, carry on + this.sendServer('RD#%'); + } - /** + /** * Handles updated music list * @param {Array} args packet arguments */ - handleFM(args) { - this.resetMusicList(); + handleFM(args) { + this.resetMusicList(); - for (let i = 1; i < args.length - 1; i++) { - // Check when found the song for the first time - this.addTrack(safe_tags(args[i])); - } - } + for (let i = 1; i < args.length - 1; i++) { + // Check when found the song for the first time + this.addTrack(safe_tags(args[i])); + } + } - /** + /** * Handles updated area list * @param {Array} args packet arguments */ - handleFA(args) { - this.resetAreaList(); + handleFA(args) { + this.resetAreaList(); - for (let i = 1; i < args.length - 1; i++) { - this.createArea(i-1,safe_tags(args[i])); - } - } + for (let i = 1; i < args.length - 1; i++) { + this.createArea(i - 1, safe_tags(args[i])); + } + } - /** + /** * Handles the "MusicMode" packet * @param {Array} args packet arguments */ - handleMM(_args) { - // It's unused nowadays, as preventing people from changing the music is now serverside - } + handleMM(_args) { + // It's unused nowadays, as preventing people from changing the music is now serverside + } - /** + /** * Handles the kicked packet * @param {String} type is it a kick or a ban * @param {String} reason why */ - handleBans(type, reason) { - document.getElementById("client_error").style.display = "flex"; - document.getElementById("client_errortext").innerHTML = type + ":<br>" + reason.replace(/\n/g, "<br />"); - document.getElementsByClassName("client_reconnect")[0].style.display = "none"; - document.getElementsByClassName("client_reconnect")[1].style.display = "none"; - } + handleBans(type, reason) { + document.getElementById('client_error').style.display = 'flex'; + document.getElementById('client_errortext').innerHTML = `${type}:<br>${reason.replace(/\n/g, '<br />')}`; + document.getElementsByClassName('client_reconnect')[0].style.display = 'none'; + document.getElementsByClassName('client_reconnect')[1].style.display = 'none'; + } - /** + /** * Handles the kicked packet * @param {Array} args kick reason */ - handleKK(args) { - this.handleBans("Kicked", safe_tags(args[1])); - } + handleKK(args) { + this.handleBans('Kicked', safe_tags(args[1])); + } - /** + /** * Handles the banned packet * this one is sent when you are kicked off the server * @param {Array} args ban reason */ - handleKB(args) { - this.handleBans("Banned", safe_tags(args[1])); - this.banned = true; - } + handleKB(args) { + this.handleBans('Banned', safe_tags(args[1])); + this.banned = true; + } - /** + /** * Handles the warning packet * on client this spawns a message box you can't close for 2 seconds * @param {Array} args ban reason */ handleBB(args) { - alert(safe_tags(args[1])); - } + alert(safe_tags(args[1])); + } - /** + /** * Handles the banned packet * this one is sent when you try to reconnect but you're banned * @param {Array} args ban reason */ - handleBD(args) { - this.handleBans("Banned", safe_tags(args[1])); - this.banned = true; - } + handleBD(args) { + this.handleBans('Banned', safe_tags(args[1])); + this.banned = true; + } - /** + /** * Handles the handshake completion packet, meaning the player * is ready to select a character. - * + * * @param {Array} args packet arguments */ - handleDONE(_args) { - document.getElementById("client_loading").style.display = "none"; - if (mode === "watch") { // Spectators don't need to pick a character - document.getElementById("client_charselect").style.display = "none"; - } else { - document.getElementById("client_charselect").style.display = "block"; - } - } + handleDONE(_args) { + document.getElementById('client_loading').style.display = 'none'; + if (mode === 'watch') { // Spectators don't need to pick a character + document.getElementById('client_charselect').style.display = 'none'; + } else { + document.getElementById('client_charselect').style.display = 'block'; + } + } - /** + /** * Handles a background change. * @param {Array} args packet arguments */ - handleBN(args) { - viewport.bgname = safe_tags(args[1]); - const bgfolder = viewport.bgFolder; - const bg_index = getIndexFromSelect("bg_select", viewport.bgname); - document.getElementById("bg_select").selectedIndex = bg_index; - updateBackgroundPreview(); - if (bg_index === 0) { - document.getElementById("bg_filename").value = viewport.bgname; - } - document.getElementById("bg_preview").src = AO_HOST + "background/" + encodeURI(args[1].toLowerCase()) + "/defenseempty.png"; - - document.getElementById("client_def_bench").src = bgfolder + "defensedesk.png" - document.getElementById("client_wit_bench").src = bgfolder + "stand.png" - document.getElementById("client_pro_bench").src = bgfolder + "prosecutiondesk.png" - - document.getElementById("client_court").src = bgfolder + "full.png" - - document.getElementById("client_court_def").src = bgfolder + "defenseempty.png" - document.getElementById("client_court_deft").src = bgfolder + "transition_def.png" - document.getElementById("client_court_wit").src = bgfolder + "witnessempty.png" - document.getElementById("client_court_prot").src = bgfolder + "transition_pro.png" - document.getElementById("client_court_pro").src = bgfolder + "prosecutorempty.png" - - if (this.charID === -1) { - viewport.changeBackground("jud"); - } else { - viewport.changeBackground(this.chars[this.charID].side); - } - - } - - /** + handleBN(args) { + viewport.bgname = safe_tags(args[1]); + const bgfolder = viewport.bgFolder; + const bg_index = getIndexFromSelect('bg_select', viewport.bgname); + document.getElementById('bg_select').selectedIndex = bg_index; + updateBackgroundPreview(); + if (bg_index === 0) { + document.getElementById('bg_filename').value = viewport.bgname; + } + document.getElementById('bg_preview').src = `${AO_HOST}background/${encodeURI(args[1].toLowerCase())}/defenseempty.png`; + + document.getElementById('client_def_bench').src = `${bgfolder}defensedesk.png`; + document.getElementById('client_wit_bench').src = `${bgfolder}stand.png`; + document.getElementById('client_pro_bench').src = `${bgfolder}prosecutiondesk.png`; + + document.getElementById('client_court').src = `${bgfolder}full.png`; + + document.getElementById('client_court_def').src = `${bgfolder}defenseempty.png`; + document.getElementById('client_court_deft').src = `${bgfolder}transition_def.png`; + document.getElementById('client_court_wit').src = `${bgfolder}witnessempty.png`; + document.getElementById('client_court_prot').src = `${bgfolder}transition_pro.png`; + document.getElementById('client_court_pro').src = `${bgfolder}prosecutorempty.png`; + + if (this.charID === -1) { + viewport.changeBackground('jud'); + } else { + viewport.changeBackground(this.chars[this.charID].side); + } + } + + /** * Handles a change in the health bars' states. * @param {Array} args packet arguments */ - handleHP(args) { - const percent_hp = Number(args[2]) * 10; - let healthbox; - if (args[1] === "1") { - // Def hp - this.hp[0] = args[2]; - healthbox = document.getElementById("client_defense_hp"); - } else { - // Pro hp - this.hp[1] = args[2]; - healthbox = document.getElementById("client_prosecutor_hp"); - } - healthbox.getElementsByClassName("health-bar")[0].style.width = percent_hp + "%"; - } - - /** + handleHP(args) { + const percent_hp = Number(args[2]) * 10; + let healthbox; + if (args[1] === '1') { + // Def hp + this.hp[0] = args[2]; + healthbox = document.getElementById('client_defense_hp'); + } else { + // Pro hp + this.hp[1] = args[2]; + healthbox = document.getElementById('client_prosecutor_hp'); + } + healthbox.getElementsByClassName('health-bar')[0].style.width = `${percent_hp}%`; + } + + /** * Handles a testimony states. * @param {Array} args packet arguments */ - handleRT(args) { - const judgeid = Number(args[2]); - switch (args[1]) { - case "testimony1": - this.testimonyID = 1; - break; - case "testimony2": - //Cross Examination - this.testimonyID = 2; - break; - case "judgeruling": - this.testimonyID = 3 + judgeid; - break; - default: - console.warn("Invalid testimony"); - } - viewport.initTestimonyUpdater(); - } - - /** + handleRT(args) { + const judgeid = Number(args[2]); + switch (args[1]) { + case 'testimony1': + this.testimonyID = 1; + break; + case 'testimony2': + // Cross Examination + this.testimonyID = 2; + break; + case 'judgeruling': + this.testimonyID = 3 + judgeid; + break; + default: + console.warn('Invalid testimony'); + } + viewport.initTestimonyUpdater(); + } + + /** * Handles a timer update * @param {Array} args packet arguments */ - handleTI(args) { - const timerid = Number(args[1]); - const type = Number(args[2]); - const timer_value = Number(args[3]); - switch (type) { - case 0: - // - case 1: - document.getElementById("client_timer"+timerid).innerText = timer_value; - case 2: - document.getElementById("client_timer"+timerid).style.display = ""; - case 3: - document.getElementById("client_timer"+timerid).style.display = "none"; - } - } + handleTI(args) { + const timerid = Number(args[1]); + const type = Number(args[2]); + const timer_value = Number(args[3]); + switch (type) { + case 0: + // + case 1: + document.getElementById(`client_timer${timerid}`).innerText = timer_value; + case 2: + document.getElementById(`client_timer${timerid}`).style.display = ''; + case 3: + document.getElementById(`client_timer${timerid}`).style.display = 'none'; + } + } - /** + /** * Handles a modcall * @param {Array} args packet arguments */ - handleZZ(args) { - const oocLog = document.getElementById("client_ooclog"); - oocLog.innerHTML += `$Alert: ${prepChat(args[1])}\r\n`; - if (oocLog.scrollTop > oocLog.scrollHeight - 60) { - oocLog.scrollTop = oocLog.scrollHeight; - } - viewport.sfxaudio.pause(); - const oldvolume = viewport.sfxaudio.volume; - viewport.sfxaudio.volume = 1; - viewport.sfxaudio.src = AO_HOST + "sounds/general/sfx-gallery.opus"; - viewport.sfxaudio.play(); - viewport.sfxaudio.volume = oldvolume; - } - - /** + handleZZ(args) { + const oocLog = document.getElementById('client_ooclog'); + oocLog.innerHTML += `$Alert: ${prepChat(args[1])}\r\n`; + if (oocLog.scrollTop > oocLog.scrollHeight - 60) { + oocLog.scrollTop = oocLog.scrollHeight; + } + viewport.sfxaudio.pause(); + const oldvolume = viewport.sfxaudio.volume; + viewport.sfxaudio.volume = 1; + viewport.sfxaudio.src = `${AO_HOST}sounds/general/sfx-gallery.opus`; + viewport.sfxaudio.play(); + viewport.sfxaudio.volume = oldvolume; + } + + /** * Handle the player * @param {Array} args packet arguments */ - handleHI(args) { - this.sendSelf("ID#1#webAO#" + version + "#%"); - this.sendSelf("FL#fastloading#yellowtext#cccc_ic_support#flipping#looping_sfx#effects#%"); - } + handleHI(args) { + this.sendSelf(`ID#1#webAO#${version}#%`); + this.sendSelf('FL#fastloading#yellowtext#cccc_ic_support#flipping#looping_sfx#effects#%'); + } - /** + /** * Identifies the server and issues a playerID * @param {Array} args packet arguments */ - handleID(args) { - this.playerID = Number(args[1]); - this.serverSoftware = args[2].split("&")[0]; - if (this.serverSoftware === "serverD") - this.serverVersion = args[2].split("&")[1]; - else if (this.serverSoftware === "webAO") { - oldLoading = false; - this.sendSelf("PN#0#1#%"); - } else - this.serverVersion = args[3]; - - if (this.serverSoftware === "serverD" && this.serverVersion === "1377.152") - oldLoading = true; // bugged version - } - - /** + handleID(args) { + this.playerID = Number(args[1]); + this.serverSoftware = args[2].split('&')[0]; + if (this.serverSoftware === 'serverD') { this.serverVersion = args[2].split('&')[1]; } else if (this.serverSoftware === 'webAO') { + oldLoading = false; + this.sendSelf('PN#0#1#%'); + } else { this.serverVersion = args[3]; } + + if (this.serverSoftware === 'serverD' && this.serverVersion === '1377.152') { oldLoading = true; } // bugged version + } + + /** * Indicates how many users are on this server * @param {Array} args packet arguments */ - handlePN(_args) { - this.sendServer("askchaa#%"); - } + handlePN(_args) { + this.sendServer('askchaa#%'); + } - /** + /** * What? you want a character?? * @param {Array} args packet arguments */ - handleCC(args) { - this.sendSelf("PV#1#CID#" + args[2] + "#%"); - } + handleCC(args) { + this.sendSelf(`PV#1#CID#${args[2]}#%`); + } - /** + /** * What? you want a character list from me?? * @param {Array} args packet arguments */ - handleaskchaa(_args) { - this.sendSelf("SI#" + vanilla_character_arr.length + "#0#0#%"); - } + handleaskchaa(_args) { + this.sendSelf(`SI#${vanilla_character_arr.length}#0#0#%`); + } - /** + /** * Handle the change of players in an area. * @param {Array} args packet arguments */ - handleARUP(args) { - args = args.slice(1); - for (let i = 0; i < args.length - 2; i++) { - if (this.areas[i]) { // the server sends us ARUP before we even get the area list - const thisarea = document.getElementById("area" + i); - switch (Number(args[0])) { - case 0: // playercount - this.areas[i].players = Number(args[i+1]); - break; - case 1: // status - this.areas[i].status = safe_tags(args[i+1]); - break; - case 2: - this.areas[i].cm = safe_tags(args[i+1]); - break; - case 3: - this.areas[i].locked = safe_tags(args[i+1]); - break; - } - - thisarea.classList = "area-button area-" + this.areas[i].status.toLowerCase(); - - thisarea.innerText = `${this.areas[i].name} (${this.areas[i].players}) [${this.areas[i].status}]`; - - thisarea.title = `Players: ${this.areas[i].players}\n` + - `Status: ${this.areas[i].status}\n` + - `CM: ${this.areas[i].cm}\n` + - `Area lock: ${this.areas[i].locked}`; - } - } - } - - /** + handleARUP(args) { + args = args.slice(1); + for (let i = 0; i < args.length - 2; i++) { + if (this.areas[i]) { // the server sends us ARUP before we even get the area list + const thisarea = document.getElementById(`area${i}`); + switch (Number(args[0])) { + case 0: // playercount + this.areas[i].players = Number(args[i + 1]); + break; + case 1: // status + this.areas[i].status = safe_tags(args[i + 1]); + break; + case 2: + this.areas[i].cm = safe_tags(args[i + 1]); + break; + case 3: + this.areas[i].locked = safe_tags(args[i + 1]); + break; + } + + thisarea.classList = `area-button area-${this.areas[i].status.toLowerCase()}`; + + thisarea.innerText = `${this.areas[i].name} (${this.areas[i].players}) [${this.areas[i].status}]`; + + thisarea.title = `Players: ${this.areas[i].players}\n` + + `Status: ${this.areas[i].status}\n` + + `CM: ${this.areas[i].cm}\n` + + `Area lock: ${this.areas[i].locked}`; + } + } + } + + /** * With this the server tells us which features it supports * @param {Array} args list of features */ - handleFL(args) { - console.info("Server-supported features:"); - console.info(args); - extrafeatures = args; + handleFL(args) { + console.info('Server-supported features:'); + console.info(args); + extrafeatures = args; - if (args.includes("yellowtext")) { - let colorselect = document.getElementById("textcolor"); + if (args.includes('yellowtext')) { + const colorselect = document.getElementById('textcolor'); - colorselect.options[colorselect.options.length] = new Option("Yellow", 5); - colorselect.options[colorselect.options.length] = new Option("Grey", 6); - colorselect.options[colorselect.options.length] = new Option("Pink", 7); - colorselect.options[colorselect.options.length] = new Option("Cyan", 8); - } + colorselect.options[colorselect.options.length] = new Option('Yellow', 5); + colorselect.options[colorselect.options.length] = new Option('Grey', 6); + colorselect.options[colorselect.options.length] = new Option('Pink', 7); + colorselect.options[colorselect.options.length] = new Option('Cyan', 8); + } - if (args.includes("cccc_ic_support")) { - document.getElementById("cccc").style.display = ""; - document.getElementById("pairing").style.display = ""; - } + if (args.includes('cccc_ic_support')) { + document.getElementById('cccc').style.display = ''; + document.getElementById('pairing').style.display = ''; + } - if (args.includes("flipping")) { - document.getElementById("button_flip").style.display = ""; - } + if (args.includes('flipping')) { + document.getElementById('button_flip').style.display = ''; + } - if (args.includes("looping_sfx")) { - document.getElementById("button_shake").style.display = ""; - document.getElementById("2.7").style.display = ""; - } + if (args.includes('looping_sfx')) { + document.getElementById('button_shake').style.display = ''; + document.getElementById('2.7').style.display = ''; + } - if (args.includes("effects")) { - document.getElementById("2.8").style.display = ""; - } + if (args.includes('effects')) { + document.getElementById('2.8').style.display = ''; + } - if (args.includes("y_offset")) { - document.getElementById("y_offset").style.display = ""; - } - } + if (args.includes('y_offset')) { + document.getElementById('y_offset').style.display = ''; + } + } - /** + /** * Received when the server announces its server info, * but we use it as a cue to begin retrieving characters. * @param {Array} args packet arguments */ - handleSI(args) { - this.char_list_length = Number(args[1]); - this.char_list_length += 1; // some servers count starting from 0 some from 1... - this.evidence_list_length = Number(args[2]); - this.music_list_length = Number(args[3]); + handleSI(args) { + this.char_list_length = Number(args[1]); + this.char_list_length += 1; // some servers count starting from 0 some from 1... + this.evidence_list_length = Number(args[2]); + this.music_list_length = Number(args[3]); - // create the charselect grid, to be filled by the character loader - document.getElementById("client_chartable").innerHTML = ""; + // create the charselect grid, to be filled by the character loader + document.getElementById('client_chartable').innerHTML = ''; - for (let i = 0; i < this.char_list_length; i++) { - const demothing = document.createElement("img"); + for (let i = 0; i < this.char_list_length; i++) { + const demothing = document.createElement('img'); - demothing.className = "demothing"; - demothing.id = `demo_${i}`; - const demoonclick = document.createAttribute("onclick"); - demoonclick.value = `pickChar(${i})`; - demothing.setAttributeNode(demoonclick); + demothing.className = 'demothing'; + demothing.id = `demo_${i}`; + const demoonclick = document.createAttribute('onclick'); + demoonclick.value = `pickChar(${i})`; + demothing.setAttributeNode(demoonclick); - document.getElementById("client_chartable").appendChild(demothing); - } + document.getElementById('client_chartable').appendChild(demothing); + } - // this is determined at the top of this file - if (!oldLoading && extrafeatures.includes("fastloading")) { - this.sendServer("RC#%"); - } else { - this.sendServer("askchar2#%"); - } - } + // this is determined at the top of this file + if (!oldLoading && extrafeatures.includes('fastloading')) { + this.sendServer('RC#%'); + } else { + this.sendServer('askchar2#%'); + } + } - /** + /** * Handles the list of all used and vacant characters. * @param {Array} args list of all characters represented as a 0 for free or a -1 for taken */ - handleCharsCheck(args) { - for (let i = 0; i < this.char_list_length; i++) { - let img = document.getElementById(`demo_${i}`); + handleCharsCheck(args) { + for (let i = 0; i < this.char_list_length; i++) { + const img = document.getElementById(`demo_${i}`); - if (args[i + 1] === "-1") - img.style.opacity = 0.25; - else if (args[i + 1] === "0") - img.style.opacity = 1; - } - } + if (args[i + 1] === '-1') { img.style.opacity = 0.25; } else if (args[i + 1] === '0') { img.style.opacity = 1; } + } + } - /** + /** * Handles the server's assignment of a character for the player to use. * PV # playerID (unused) # CID # character ID * @param {Array} args packet arguments */ - async handlePV(args) { - this.charID = Number(args[3]); - document.getElementById("client_charselect").style.display = "none"; - - const me = this.character; - this.selectedEmote = -1; - const emotes = this.emotes; - const emotesList = document.getElementById("client_emo"); - emotesList.style.display = ""; - emotesList.innerHTML = ""; // Clear emote box - const ini = me.inifile; - me.side = ini.options.side; - updateActionCommands(me.side); - if(ini.emotions.number === 0) { - emotesList.innerHTML = - `<span + async handlePV(args) { + this.charID = Number(args[3]); + document.getElementById('client_charselect').style.display = 'none'; + + const me = this.character; + this.selectedEmote = -1; + const { emotes } = this; + const emotesList = document.getElementById('client_emo'); + emotesList.style.display = ''; + emotesList.innerHTML = ''; // Clear emote box + const ini = me.inifile; + me.side = ini.options.side; + updateActionCommands(me.side); + if (ini.emotions.number === 0) { + emotesList.innerHTML = `<span id="emo_0" alt="unavailable" class="emote_button">No emotes available</span>`; - }else{ - for (let i = 1; i <= ini.emotions.number; i++) { - try { - const emoteinfo = ini.emotions[i].split("#"); - let esfx; - let esfxd; - try { - esfx = ini.soundn[i] || "0"; - esfxd = Number(ini.soundt[i]) || 0; - } catch (e) { - console.warn("ini sound is completly missing"); - esfx = "0"; - esfxd = 0; - } - // Make sure the asset server is case insensitive, or that everything on it is lowercase - emotes[i] = { - desc: emoteinfo[0].toLowerCase(), - preanim: emoteinfo[1].toLowerCase(), - emote: emoteinfo[2].toLowerCase(), - zoom: Number(emoteinfo[3]) || 0, - sfx: esfx.toLowerCase(), - sfxdelay: esfxd, - frame_screenshake: "", - frame_realization: "", - frame_sfx: "", - button: AO_HOST + `characters/${encodeURI(me.name.toLowerCase())}/emotions/button${i}_off.png` - }; - emotesList.innerHTML += - `<img src=${emotes[i].button} + } else { + for (let i = 1; i <= ini.emotions.number; i++) { + try { + const emoteinfo = ini.emotions[i].split('#'); + let esfx; + let esfxd; + try { + esfx = ini.soundn[i] || '0'; + esfxd = Number(ini.soundt[i]) || 0; + } catch (e) { + console.warn('ini sound is completly missing'); + esfx = '0'; + esfxd = 0; + } + // Make sure the asset server is case insensitive, or that everything on it is lowercase + emotes[i] = { + desc: emoteinfo[0].toLowerCase(), + preanim: emoteinfo[1].toLowerCase(), + emote: emoteinfo[2].toLowerCase(), + zoom: Number(emoteinfo[3]) || 0, + sfx: esfx.toLowerCase(), + sfxdelay: esfxd, + frame_screenshake: '', + frame_realization: '', + frame_sfx: '', + button: `${AO_HOST}characters/${encodeURI(me.name.toLowerCase())}/emotions/button${i}_off.png`, + }; + emotesList.innerHTML + += `<img src=${emotes[i].button} id="emo_${i}" alt="${emotes[i].desc}" class="emote_button" onclick="pickEmotion(${i})">`; + } catch (e) { + console.error(`missing emote ${i}`); + } + } + pickEmotion(1); + } - } catch (e) { - console.error("missing emote " + i); - } - } - pickEmotion(1); - } - - if(await fileExists(AO_HOST + "characters/" + encodeURI(me.name.toLowerCase()) + "/custom.gif")) - document.getElementById("button_4").style.display = ""; - else - document.getElementById("button_4").style.display = "none"; - - const iniedit_select = document.getElementById("client_ininame"); - - // Load iniswaps if there are any - try { - const cswapdata = await request(AO_HOST + "characters/" + encodeURI(me.name.toLowerCase()) + "/iniswaps.ini"); - const cswap = cswapdata.split("\n"); - - // most iniswaps don't list their original char - if (cswap.length > 0) { - iniedit_select.innerHTML = ""; - - function addIniswap(value) { - iniedit_select.add(new Option(safe_tags(value))); - } - - addIniswap(me.name); - cswap.forEach(addIniswap); - } - } catch (err) { - console.info("character doesn't have iniswaps"); - this.fetchCharacterList(); - } - } - - /** + if (await fileExists(`${AO_HOST}characters/${encodeURI(me.name.toLowerCase())}/custom.gif`)) { document.getElementById('button_4').style.display = ''; } else { document.getElementById('button_4').style.display = 'none'; } + + const iniedit_select = document.getElementById('client_ininame'); + + // Load iniswaps if there are any + try { + const cswapdata = await request(`${AO_HOST}characters/${encodeURI(me.name.toLowerCase())}/iniswaps.ini`); + const cswap = cswapdata.split('\n'); + + // most iniswaps don't list their original char + if (cswap.length > 0) { + iniedit_select.innerHTML = ''; + + function addIniswap(value) { + iniedit_select.add(new Option(safe_tags(value))); + } + + addIniswap(me.name); + cswap.forEach(addIniswap); + } + } catch (err) { + console.info("character doesn't have iniswaps"); + this.fetchCharacterList(); + } + } + + /** * new asset url!! * @param {Array} args packet arguments */ handleASS(args) { - AO_HOST = args[1]; - } + AO_HOST = args[1]; + } - /** + /** * we are asking ourselves what characters there are * @param {Array} args packet arguments */ - handleRC(_args) { - this.sendSelf("SC#" + vanilla_character_arr.join("#") + "#%"); - } + handleRC(_args) { + this.sendSelf(`SC#${vanilla_character_arr.join('#')}#%`); + } - /** + /** * we are asking ourselves what characters there are * @param {Array} args packet arguments */ - handleRM(_args) { - this.sendSelf("SM#" + vanilla_music_arr.join("#") + "#%"); - } + handleRM(_args) { + this.sendSelf(`SM#${vanilla_music_arr.join('#')}#%`); + } - /** + /** * we are asking ourselves what characters there are * @param {Array} args packet arguments */ - handleRD(_args) { - this.sendSelf("BN#gs4#%"); - this.sendSelf("DONE#%"); - const ooclog = document.getElementById("client_ooclog"); - ooclog.value = ""; - ooclog.readOnly = false; + handleRD(_args) { + this.sendSelf('BN#gs4#%'); + this.sendSelf('DONE#%'); + const ooclog = document.getElementById('client_ooclog'); + ooclog.value = ''; + ooclog.readOnly = false; - document.getElementById("client_oocinput").style.display = "none"; - document.getElementById("client_replaycontrols").style.display = "inline-block"; - } + document.getElementById('client_oocinput').style.display = 'none'; + document.getElementById('client_replaycontrols').style.display = 'inline-block'; + } } class Viewport { - constructor() { - this.textnow = ""; - this.chatmsg = { - "content": "", - "objection": 0, - "sound": "", - "startpreanim": true, - "startspeaking": false, - "side": null, - "color": 0, - "snddelay": 0, - "preanimdelay": 0 - }; - - this.shouts = [ - undefined, - "holdit", - "objection", - "takethat", - "custom" - ]; - - this.colors = [ - "white", - "green", - "red", - "orange", - "blue", - "yellow", - "pink", - "cyan", - "grey" - ]; - - // Allocate multiple blip audio channels to make blips less jittery - - this.blipChannels = new Array( new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus"), - new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus"), - new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus"), - new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus"), - new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus"), - new Audio(AO_HOST + "sounds/general/sfx-blipmale.opus")); - this.blipChannels.forEach(channel => channel.volume = 0.5); - this.blipChannels.forEach(channel => channel.onerror = opusCheck(channel)); - this.currentBlipChannel = 0; - - this.sfxaudio = document.getElementById("client_sfxaudio"); - this.sfxaudio.src = `${AO_HOST}sounds/general/sfx-realization.opus`; - - this.sfxplayed = 0; - - this.shoutaudio = document.getElementById("client_shoutaudio"); - this.shoutaudio.src = `${AO_HOST}misc/default/objection.opus`; - - this.testimonyAudio = document.getElementById("client_testimonyaudio"); - this.testimonyAudio.src = `${AO_HOST}sounds/general/sfx-guilty.opus`; - - this.music = new Array( new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`)); - this.music.forEach(channel => channel.volume = 0.5); - this.music.forEach(channel => channel.onerror = opusCheck(channel)); - - this.updater = null; - this.testimonyUpdater = null; - - this.bgname = "gs4"; - - this.lastChar = ""; - this.lastEvi = 0; - - this.testimonyTimer = 0; - this.shoutTimer = 0; - this.textTimer = 0; - - this._animating = false; - } - - /** + constructor() { + this.textnow = ''; + this.chatmsg = { + content: '', + objection: 0, + sound: '', + startpreanim: true, + startspeaking: false, + side: null, + color: 0, + snddelay: 0, + preanimdelay: 0, + }; + + this.shouts = [ + undefined, + 'holdit', + 'objection', + 'takethat', + 'custom', + ]; + + this.colors = [ + 'white', + 'green', + 'red', + 'orange', + 'blue', + 'yellow', + 'pink', + 'cyan', + 'grey', + ]; + + // Allocate multiple blip audio channels to make blips less jittery + + this.blipChannels = new Array( + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), + ); + this.blipChannels.forEach((channel) => channel.volume = 0.5); + this.blipChannels.forEach((channel) => channel.onerror = opusCheck(channel)); + this.currentBlipChannel = 0; + + this.sfxaudio = document.getElementById('client_sfxaudio'); + this.sfxaudio.src = `${AO_HOST}sounds/general/sfx-realization.opus`; + + this.sfxplayed = 0; + + this.shoutaudio = document.getElementById('client_shoutaudio'); + this.shoutaudio.src = `${AO_HOST}misc/default/objection.opus`; + + this.testimonyAudio = document.getElementById('client_testimonyaudio'); + this.testimonyAudio.src = `${AO_HOST}sounds/general/sfx-guilty.opus`; + + this.music = new Array( + new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), + new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), + new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), + new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), + ); + this.music.forEach((channel) => channel.volume = 0.5); + this.music.forEach((channel) => channel.onerror = opusCheck(channel)); + + this.updater = null; + this.testimonyUpdater = null; + + this.bgname = 'gs4'; + + this.lastChar = ''; + this.lastEvi = 0; + + this.testimonyTimer = 0; + this.shoutTimer = 0; + this.textTimer = 0; + + this._animating = false; + } + + /** * Returns whether or not the viewport is busy * performing a task (animating). */ - get isAnimating() { - return this._animating; - } + get isAnimating() { + return this._animating; + } - /** + /** * Sets the volume of the blip sounds. * @param {number} volume */ - set blipVolume(volume) { - this.blipChannels.forEach(channel => channel.volume = volume); - } + set blipVolume(volume) { + this.blipChannels.forEach((channel) => channel.volume = volume); + } - /** + /** * Sets the volume of the music. * @param {number} volume */ - set musicVolume(volume) { - this.music.forEach(channel => channel.volume = volume); - } + set musicVolume(volume) { + this.music.forEach((channel) => channel.volume = volume); + } - /** + /** * Returns the path which the background is located in. */ - get bgFolder() { - return `${AO_HOST}background/${encodeURI(this.bgname.toLowerCase())}/`; - } - + get bgFolder() { + return `${AO_HOST}background/${encodeURI(this.bgname.toLowerCase())}/`; + } - /** + /** * Play any SFX - * + * * @param {string} sfxname */ - async playSFX(sfxname, looping) { - this.sfxaudio.pause(); - this.sfxaudio.loop = looping; - this.sfxaudio.src = sfxname; - this.sfxaudio.play(); - } + async playSFX(sfxname, looping) { + this.sfxaudio.pause(); + this.sfxaudio.loop = looping; + this.sfxaudio.src = sfxname; + this.sfxaudio.play(); + } - /** + /** * Changes the viewport background based on a given position. - * + * * Valid positions: `def, pro, hld, hlp, wit, jud, jur, sea` * @param {string} position the position to change into */ -async changeBackground(position) { - const bgfolder = viewport.bgFolder; - - const view = document.getElementById("client_fullview"); - const bench = document.getElementById("client_bench_classic"); - const court = document.getElementById("client_court_classic"); - - const positions = { - def: { - bg: "defenseempty.png", - desk: { ao2: "defensedesk.png", ao1: "bancodefensa.png" }, - speedLines: "defense_speedlines.gif" - }, - pro: { - bg: "prosecutionempty.png", - desk: { ao2: "prosecutiondesk.png", ao1: "bancoacusacion.png" }, - speedLines: "prosecution_speedlines.gif" - }, - hld: { - bg: "helperstand.png", - desk: null, - speedLines: "defense_speedlines.gif" - }, - hlp: { - bg: "prohelperstand.png", - desk: null, - speedLines: "prosecution_speedlines.gif" - }, - wit: { - bg: "witnessempty.png", - desk: { ao2: "stand.png", ao1: "estrado.png" }, - speedLines: "prosecution_speedlines.gif" - }, - jud: { - bg: "judgestand.png", - desk: { ao2: "judgedesk.png", ao1: "judgedesk.gif" }, - speedLines: "prosecution_speedlines.gif" - }, - jur: { - bg: "jurystand.png", - desk: { ao2: "jurydesk.png", ao1: "estrado.png" }, - speedLines: "defense_speedlines.gif" - }, - sea: { - bg: "seancestand.png", - desk: { ao2: "seancedesk.png", ao1: "estrado.png" }, - speedLines: "prosecution_speedlines.gif" - } - }; - - let bg; - let desk; - let speedLines; - - if ( "def,pro,hld,hlp,wit,jud,jur,sea".includes(position)) { - bg = positions[position].bg; - desk = positions[position].desk; - speedLines = positions[position].speedLines; - } else { - bg = position + ".png"; - desk = { ao2: position + "_overlay.png", ao1: "_overlay.png" }; - speedLines = "defense_speedlines.gif"; - } - - if (viewport.chatmsg.type === 5) { - court.src = `${AO_HOST}themes/default/${encodeURI(speedLines)}`; - bench.style.opacity = 0; - } else { - court.src = bgfolder + bg; - if (desk) { - const deskFilename = await fileExists(bgfolder + desk.ao2) ? desk.ao2 : desk.ao1; - bench.src = bgfolder + deskFilename; - bench.style.opacity = 1; - } else { - bench.style.opacity = 0; - } - } - - if ( "def,pro,wit".includes(position)) { - bench.style.display = "none"; - view.style.display = ""; - document.getElementById("client_classicview").style.display = "none"; - switch(position) { - case "def": - view.style.left = "0"; - break; - case "wit": - view.style.left = "-200%"; - break; - case "pro": - view.style.left = "-400%"; - break; - } - } else { - bench.style.display = ""; - view.style.display = "none"; - document.getElementById("client_classicview").style.display = ""; - } -} - - /** - * Intialize testimony updater - */ - initTestimonyUpdater() { - const testimonyFilenames = { - 1: "witnesstestimony", - 2: "crossexamination", - 3: "notguilty", - 4: "guilty" - }; - - const testimony = testimonyFilenames[client.testimonyID]; - if (!testimony) { - console.warn(`Invalid testimony ID ${client.testimonyID}`); - return; - } - - this.testimonyAudio.src = client.resources[testimony].sfx; - this.testimonyAudio.play(); - - const testimonyOverlay = document.getElementById("client_testimony"); - testimonyOverlay.src = client.resources[testimony].src; - testimonyOverlay.style.opacity = 1; - - this.testimonyTimer = 0; - this.testimonyUpdater = setTimeout(() => this.updateTestimony(), UPDATE_INTERVAL); - } - - /** + async changeBackground(position) { + const bgfolder = viewport.bgFolder; + + const view = document.getElementById('client_fullview'); + const bench = document.getElementById('client_bench_classic'); + const court = document.getElementById('client_court_classic'); + + const positions = { + def: { + bg: 'defenseempty.png', + desk: { ao2: 'defensedesk.png', ao1: 'bancodefensa.png' }, + speedLines: 'defense_speedlines.gif', + }, + pro: { + bg: 'prosecutionempty.png', + desk: { ao2: 'prosecutiondesk.png', ao1: 'bancoacusacion.png' }, + speedLines: 'prosecution_speedlines.gif', + }, + hld: { + bg: 'helperstand.png', + desk: null, + speedLines: 'defense_speedlines.gif', + }, + hlp: { + bg: 'prohelperstand.png', + desk: null, + speedLines: 'prosecution_speedlines.gif', + }, + wit: { + bg: 'witnessempty.png', + desk: { ao2: 'stand.png', ao1: 'estrado.png' }, + speedLines: 'prosecution_speedlines.gif', + }, + jud: { + bg: 'judgestand.png', + desk: { ao2: 'judgedesk.png', ao1: 'judgedesk.gif' }, + speedLines: 'prosecution_speedlines.gif', + }, + jur: { + bg: 'jurystand.png', + desk: { ao2: 'jurydesk.png', ao1: 'estrado.png' }, + speedLines: 'defense_speedlines.gif', + }, + sea: { + bg: 'seancestand.png', + desk: { ao2: 'seancedesk.png', ao1: 'estrado.png' }, + speedLines: 'prosecution_speedlines.gif', + }, + }; + + let bg; + let desk; + let speedLines; + + if ('def,pro,hld,hlp,wit,jud,jur,sea'.includes(position)) { + bg = positions[position].bg; + desk = positions[position].desk; + speedLines = positions[position].speedLines; + } else { + bg = `${position}.png`; + desk = { ao2: `${position}_overlay.png`, ao1: '_overlay.png' }; + speedLines = 'defense_speedlines.gif'; + } + + if (viewport.chatmsg.type === 5) { + court.src = `${AO_HOST}themes/default/${encodeURI(speedLines)}`; + bench.style.opacity = 0; + } else { + court.src = bgfolder + bg; + if (desk) { + const deskFilename = await fileExists(bgfolder + desk.ao2) ? desk.ao2 : desk.ao1; + bench.src = bgfolder + deskFilename; + bench.style.opacity = 1; + } else { + bench.style.opacity = 0; + } + } + + if ('def,pro,wit'.includes(position)) { + bench.style.display = 'none'; + view.style.display = ''; + document.getElementById('client_classicview').style.display = 'none'; + switch (position) { + case 'def': + view.style.left = '0'; + break; + case 'wit': + view.style.left = '-200%'; + break; + case 'pro': + view.style.left = '-400%'; + break; + } + } else { + bench.style.display = ''; + view.style.display = 'none'; + document.getElementById('client_classicview').style.display = ''; + } + } + + /** + * Intialize testimony updater + */ + initTestimonyUpdater() { + const testimonyFilenames = { + 1: 'witnesstestimony', + 2: 'crossexamination', + 3: 'notguilty', + 4: 'guilty', + }; + + const testimony = testimonyFilenames[client.testimonyID]; + if (!testimony) { + console.warn(`Invalid testimony ID ${client.testimonyID}`); + return; + } + + this.testimonyAudio.src = client.resources[testimony].sfx; + this.testimonyAudio.play(); + + const testimonyOverlay = document.getElementById('client_testimony'); + testimonyOverlay.src = client.resources[testimony].src; + testimonyOverlay.style.opacity = 1; + + this.testimonyTimer = 0; + this.testimonyUpdater = setTimeout(() => this.updateTestimony(), UPDATE_INTERVAL); + } + + /** * Gets animation length. If the animation cannot be found, it will * silently fail and return 0 instead. * @param {string} filename the animation file name */ - async getAnimLength(filename) { - try { - const file = await requestBuffer(filename); - return this.calculateGifLength(file); - } catch (err) { - return 0; - } - } - - oneSuccess(promises){ - return Promise.all(promises.map(p => { - // If a request fails, count that as a resolution so it will keep - // waiting for other possible successes. If a request succeeds, - // treat it as a rejection so Promise.all immediately bails out. - return p.then( - val => Promise.reject(val), - err => Promise.resolve(err) - ); - })).then( - // If '.all' resolved, we've just got an array of errors. - errors => Promise.reject(errors), - // If '.all' rejected, we've got the result we wanted. - val => Promise.resolve(val) - ); - } - - rejectOnError(f) { - return new Promise((resolve, reject) => - f.then((res) => { - if (res.ok) resolve(f); - else reject(f); - }) - ); - } - - /** + async getAnimLength(filename) { + try { + const file = await requestBuffer(filename); + return this.calculateGifLength(file); + } catch (err) { + return 0; + } + } + + oneSuccess(promises) { + return Promise.all(promises.map((p) => + // If a request fails, count that as a resolution so it will keep + // waiting for other possible successes. If a request succeeds, + // treat it as a rejection so Promise.all immediately bails out. + p.then( + (val) => Promise.reject(val), + (err) => Promise.resolve(err), + ))).then( + // If '.all' resolved, we've just got an array of errors. + (errors) => Promise.reject(errors), + // If '.all' rejected, we've got the result we wanted. + (val) => Promise.resolve(val), + ); + } + + rejectOnError(f) { + return new Promise((resolve, reject) => f.then((res) => { + if (res.ok) resolve(f); + else reject(f); + })); + } + + /** * Adds up the frame delays to find out how long a GIF is * I totally didn't steal this * @param {data} gifFile the GIF data */ - calculateGifLength(gifFile) { - let d = new Uint8Array(gifFile); - // Thanks to http://justinsomnia.org/2006/10/gif-animation-duration-calculation/ - // And http://www.w3.org/Graphics/GIF/spec-gif89a.txt - let duration = 0; - for (var i = 0; i < d.length; i++) { - // Find a Graphic Control Extension hex(21F904__ ____ __00) - if (d[i] === 0x21 + calculateGifLength(gifFile) { + const d = new Uint8Array(gifFile); + // Thanks to http://justinsomnia.org/2006/10/gif-animation-duration-calculation/ + // And http://www.w3.org/Graphics/GIF/spec-gif89a.txt + let duration = 0; + for (let i = 0; i < d.length; i++) { + // Find a Graphic Control Extension hex(21F904__ ____ __00) + if (d[i] === 0x21 && d[i + 1] === 0xF9 && d[i + 2] === 0x04 && d[i + 7] === 0x00) { - // Swap 5th and 6th bytes to get the delay per frame - let delay = (d[i + 5] << 8) | (d[i + 4] & 0xFF); - - // Should be aware browsers have a minimum frame delay - // e.g. 6ms for IE, 2ms modern browsers (50fps) - duration += delay < 2 ? 10 : delay; - } - } - return duration * 10; - } - - /** + // Swap 5th and 6th bytes to get the delay per frame + const delay = (d[i + 5] << 8) | (d[i + 4] & 0xFF); + + // Should be aware browsers have a minimum frame delay + // e.g. 6ms for IE, 2ms modern browsers (50fps) + duration += delay < 2 ? 10 : delay; + } + } + return duration * 10; + } + + /** * Updates the testimony overaly */ - updateTestimony() { - const testimonyFilenames = { - 1: "witnesstestimony", - 2: "crossexamination", - 3: "notguilty", - 4: "guilty" - }; - - // Update timer - this.testimonyTimer = this.testimonyTimer + UPDATE_INTERVAL; - - const testimony = testimonyFilenames[client.testimonyID]; - const resource = client.resources[testimony]; - if (!resource) { - this.disposeTestimony(); - return; - } - - if (this.testimonyTimer >= resource.duration) { - this.disposeTestimony(); - } else { - this.testimonyUpdater = setTimeout(() => this.updateTestimony(), UPDATE_INTERVAL); - } - } - - /** + updateTestimony() { + const testimonyFilenames = { + 1: 'witnesstestimony', + 2: 'crossexamination', + 3: 'notguilty', + 4: 'guilty', + }; + + // Update timer + this.testimonyTimer += UPDATE_INTERVAL; + + const testimony = testimonyFilenames[client.testimonyID]; + const resource = client.resources[testimony]; + if (!resource) { + this.disposeTestimony(); + return; + } + + if (this.testimonyTimer >= resource.duration) { + this.disposeTestimony(); + } else { + this.testimonyUpdater = setTimeout(() => this.updateTestimony(), UPDATE_INTERVAL); + } + } + + /** * Dispose the testimony overlay */ - disposeTestimony() { - client.testimonyID = 0; - this.testimonyTimer = 0; - document.getElementById("client_testimony").style.opacity = 0; - clearTimeout(this.testimonyUpdater); - } + disposeTestimony() { + client.testimonyID = 0; + this.testimonyTimer = 0; + document.getElementById('client_testimony').style.opacity = 0; + clearTimeout(this.testimonyUpdater); + } - /** + /** * Sets all the img tags to the right sources - * @param {*} chatmsg - */ - setEmote(charactername, emotename, prefix, pair, side) { - const pairID = pair ? "pair" : "char"; - const characterFolder = AO_HOST + "characters/"; - const position = "def,pro,wit".includes(side) ? side+"_" : "" - - const gif_s = document.getElementById("client_" + position + pairID + "_gif"); - const png_s = document.getElementById("client_" + position + pairID + "_png"); - const apng_s = document.getElementById("client_" + position + pairID +"_apng"); - const webp_s = document.getElementById("client_" + position + pairID +"_webp"); - - if (this.lastChar !== this.chatmsg.name) { - //hide the last sprite - gif_s.src = transparentPNG; - png_s.src = transparentPNG; - apng_s.src = transparentPNG; - webp_s.src = transparentPNG; - } - - gif_s.src = characterFolder + `${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.gif`; - png_s.src = characterFolder + `${encodeURI(charactername)}/${encodeURI(emotename)}.png`; - apng_s.src = characterFolder + `${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.apng`; - webp_s.src = characterFolder + `${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.webp`; - } - - /** + * @param {*} chatmsg + */ + setEmote(charactername, emotename, prefix, pair, side) { + const pairID = pair ? 'pair' : 'char'; + const characterFolder = `${AO_HOST}characters/`; + const position = 'def,pro,wit'.includes(side) ? `${side}_` : ''; + + const gif_s = document.getElementById(`client_${position}${pairID}_gif`); + const png_s = document.getElementById(`client_${position}${pairID}_png`); + const apng_s = document.getElementById(`client_${position}${pairID}_apng`); + const webp_s = document.getElementById(`client_${position}${pairID}_webp`); + + if (this.lastChar !== this.chatmsg.name) { + // hide the last sprite + gif_s.src = transparentPNG; + png_s.src = transparentPNG; + apng_s.src = transparentPNG; + webp_s.src = transparentPNG; + } + + gif_s.src = `${characterFolder}${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.gif`; + png_s.src = `${characterFolder}${encodeURI(charactername)}/${encodeURI(emotename)}.png`; + apng_s.src = `${characterFolder}${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.apng`; + webp_s.src = `${characterFolder}${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}.webp`; + } + + /** * Sets a new emote. * This sets up everything before the tick() loops starts * a lot of things can probably be moved here, like starting the shout animation if there is one * TODO: the preanim logic, on the other hand, should probably be moved to tick() * @param {object} chatmsg the new chat message */ - async say(chatmsg) { - this.chatmsg = chatmsg; - this.textnow = ""; - this.sfxplayed = 0; - this.textTimer = 0; - this._animating = true; - let charLayers = document.getElementById("client_char"); - let pairLayers = document.getElementById("client_pair_char"); - - // stop updater - clearTimeout(this.updater); - - // stop last sfx from looping any longer - this.sfxaudio.loop = false; - - const fg = document.getElementById("client_fg"); - const gamewindow = document.getElementById("client_gamewindow"); - const waitingBox = document.getElementById("client_chatwaiting"); - - // Reset CSS animation - gamewindow.style.animation = ""; - waitingBox.style.opacity = 0; - - const eviBox = document.getElementById("client_evi"); - - if (this.lastEvi !== this.chatmsg.evidence) { - eviBox.style.opacity = "0"; - eviBox.style.height = "0%"; - } - this.lastEvi = this.chatmsg.evidence; - - if ( "def,pro,wit".includes(this.chatmsg.side)) { - charLayers = document.getElementById("client_"+this.chatmsg.side+"_char"); - pairLayers = document.getElementById("client_"+this.chatmsg.side+"_pair_char"); - } - - const chatContainerBox = document.getElementById("client_chatcontainer"); - const nameBoxInner = document.getElementById("client_inner_name"); - const chatBoxInner = document.getElementById("client_inner_chat"); - - const displayname = (document.getElementById("showname").checked && this.chatmsg.showname !== "") ? this.chatmsg.showname : this.chatmsg.nameplate; - - //Clear out the last message - chatBoxInner.innerText = this.textnow; - nameBoxInner.innerText = displayname; - - if (this.lastChar !== this.chatmsg.name) { - charLayers.style.opacity = 0; - pairLayers.style.opacity = 0; - } - this.lastChar = this.chatmsg.name; - - appendICLog(this.chatmsg.content, this.chatmsg.showname, this.chatmsg.nameplate); - - checkCallword(this.chatmsg.content); - - this.setEmote(this.chatmsg.name.toLowerCase(), this.chatmsg.sprite, "(a)", false, this.chatmsg.side); - - if (this.chatmsg.other_name) { - this.setEmote(this.chatmsg.other_name.toLowerCase(), this.chatmsg.other_emote, "(a)", false, this.chatmsg.side); - } - - // gets which shout shall played - const shoutSprite = document.getElementById("client_shout"); - const shout = this.shouts[this.chatmsg.objection]; - if (shout) { - // Hide message box - chatContainerBox.style.opacity = 0; - if (this.chatmsg.objection === 4) { - shoutSprite.src = `${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/custom.gif`; - } else { - shoutSprite.src = client.resources[shout]["src"]; - shoutSprite.style.animation = "bubble 700ms steps(10, jump-both)"; - } - shoutSprite.style.opacity = 1; - - - this.shoutaudio.src = `${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${shout}.opus`; - this.shoutaudio.play(); - this.shoutTimer = client.resources[shout]["duration"]; - } else { - this.shoutTimer = 0; - } - - this.chatmsg.startpreanim = true; - let gifLength = 0; - switch (this.chatmsg.type) { - // case 0: - // normal emote, no preanim - case 1: - // play preanim - // Hide message box - chatContainerBox.style.opacity = 0; - // If preanim existed then determine the length - gifLength = await this.getAnimLength(`${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${encodeURI(this.chatmsg.preanim)}.gif`); - this.chatmsg.startspeaking = false; - break; - // case 5: - // zoom - default: - this.chatmsg.startspeaking = true; - break; - } - this.chatmsg.preanimdelay = parseInt(gifLength); - - this.changeBackground(chatmsg.side); - - setChatbox(chatmsg.chatbox); - resizeChatbox(); - - // Flip the character - if (this.chatmsg.flip === 1) { - charLayers.style.transform = "scaleX(-1)"; - } else { - charLayers.style.transform = "scaleX(1)"; - } - - // Shift by the horizontal offset - switch(this.chatmsg.side) { - case "wit": - pairLayers.style.left = (200+Number(this.chatmsg.other_offset[0])) + "%"; - charLayers.style.left = (200+Number(this.chatmsg.self_offset[0])) + "%"; - break; - case "pro": - pairLayers.style.left = (400+Number(this.chatmsg.other_offset[0])) + "%"; - charLayers.style.left = (400+Number(this.chatmsg.self_offset[0])) + "%"; - break; - default: - pairLayers.style.left = Number(this.chatmsg.other_offset[0]) + "%"; - charLayers.style.left = Number(this.chatmsg.self_offset[0]) + "%"; - break; - } - - // New vertical offsets - pairLayers.style.top = Number(this.chatmsg.other_offset[1]) + "%"; - charLayers.style.top = Number(this.chatmsg.self_offset[1]) + "%"; - - // flip the paired character - if (this.chatmsg.other_flip === 1) { - pairLayers.style.transform = "scaleX(-1)"; - } else { - pairLayers.style.transform = "scaleX(1)"; - } - - this.blipChannels.forEach(channel => channel.src = `${AO_HOST}sounds/general/sfx-blip${encodeURI(this.chatmsg.blips.toLowerCase())}.opus`); - - // process markup - if(this.chatmsg.content.startsWith("~~")) { - chatBoxInner.style.textAlign = "center"; - this.chatmsg.content = this.chatmsg.content.substring(2, this.chatmsg.content.length); - } else { - chatBoxInner.style.textAlign = "inherit"; - } - - // apply effects - fg.style.animation = ""; - - if (this.chatmsg.effects[0] && this.chatmsg.effects[0] !== "-") - fg.src = `${AO_HOST}themes/default/effects/${encodeURI(this.chatmsg.effects[0].toLowerCase())}.webp`; - else - fg.src = transparentPNG; - - if (this.chatmsg.sound === "0" || this.chatmsg.sound === "1" || this.chatmsg.sound === "" || this.chatmsg.sound === undefined) - this.chatmsg.sound = this.chatmsg.effects[2]; - - this.tick(); - } - - /** + async say(chatmsg) { + this.chatmsg = chatmsg; + this.textnow = ''; + this.sfxplayed = 0; + this.textTimer = 0; + this._animating = true; + let charLayers = document.getElementById('client_char'); + let pairLayers = document.getElementById('client_pair_char'); + + // stop updater + clearTimeout(this.updater); + + // stop last sfx from looping any longer + this.sfxaudio.loop = false; + + const fg = document.getElementById('client_fg'); + const gamewindow = document.getElementById('client_gamewindow'); + const waitingBox = document.getElementById('client_chatwaiting'); + + // Reset CSS animation + gamewindow.style.animation = ''; + waitingBox.style.opacity = 0; + + const eviBox = document.getElementById('client_evi'); + + if (this.lastEvi !== this.chatmsg.evidence) { + eviBox.style.opacity = '0'; + eviBox.style.height = '0%'; + } + this.lastEvi = this.chatmsg.evidence; + + if ('def,pro,wit'.includes(this.chatmsg.side)) { + charLayers = document.getElementById(`client_${this.chatmsg.side}_char`); + pairLayers = document.getElementById(`client_${this.chatmsg.side}_pair_char`); + } + + const chatContainerBox = document.getElementById('client_chatcontainer'); + const nameBoxInner = document.getElementById('client_inner_name'); + const chatBoxInner = document.getElementById('client_inner_chat'); + + const displayname = (document.getElementById('showname').checked && this.chatmsg.showname !== '') ? this.chatmsg.showname : this.chatmsg.nameplate; + + // Clear out the last message + chatBoxInner.innerText = this.textnow; + nameBoxInner.innerText = displayname; + + if (this.lastChar !== this.chatmsg.name) { + charLayers.style.opacity = 0; + pairLayers.style.opacity = 0; + } + this.lastChar = this.chatmsg.name; + + appendICLog(this.chatmsg.content, this.chatmsg.showname, this.chatmsg.nameplate); + + checkCallword(this.chatmsg.content); + + this.setEmote(this.chatmsg.name.toLowerCase(), this.chatmsg.sprite, '(a)', false, this.chatmsg.side); + + if (this.chatmsg.other_name) { + this.setEmote(this.chatmsg.other_name.toLowerCase(), this.chatmsg.other_emote, '(a)', false, this.chatmsg.side); + } + + // gets which shout shall played + const shoutSprite = document.getElementById('client_shout'); + const shout = this.shouts[this.chatmsg.objection]; + if (shout) { + // Hide message box + chatContainerBox.style.opacity = 0; + if (this.chatmsg.objection === 4) { + shoutSprite.src = `${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/custom.gif`; + } else { + shoutSprite.src = client.resources[shout].src; + shoutSprite.style.animation = 'bubble 700ms steps(10, jump-both)'; + } + shoutSprite.style.opacity = 1; + + this.shoutaudio.src = `${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${shout}.opus`; + this.shoutaudio.play(); + this.shoutTimer = client.resources[shout].duration; + } else { + this.shoutTimer = 0; + } + + this.chatmsg.startpreanim = true; + let gifLength = 0; + switch (this.chatmsg.type) { + // case 0: + // normal emote, no preanim + case 1: + // play preanim + // Hide message box + chatContainerBox.style.opacity = 0; + // If preanim existed then determine the length + gifLength = await this.getAnimLength(`${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${encodeURI(this.chatmsg.preanim)}.gif`); + this.chatmsg.startspeaking = false; + break; + // case 5: + // zoom + default: + this.chatmsg.startspeaking = true; + break; + } + this.chatmsg.preanimdelay = parseInt(gifLength); + + this.changeBackground(chatmsg.side); + + setChatbox(chatmsg.chatbox); + resizeChatbox(); + + // Flip the character + if (this.chatmsg.flip === 1) { + charLayers.style.transform = 'scaleX(-1)'; + } else { + charLayers.style.transform = 'scaleX(1)'; + } + + // Shift by the horizontal offset + switch (this.chatmsg.side) { + case 'wit': + pairLayers.style.left = `${200 + Number(this.chatmsg.other_offset[0])}%`; + charLayers.style.left = `${200 + Number(this.chatmsg.self_offset[0])}%`; + break; + case 'pro': + pairLayers.style.left = `${400 + Number(this.chatmsg.other_offset[0])}%`; + charLayers.style.left = `${400 + Number(this.chatmsg.self_offset[0])}%`; + break; + default: + pairLayers.style.left = `${Number(this.chatmsg.other_offset[0])}%`; + charLayers.style.left = `${Number(this.chatmsg.self_offset[0])}%`; + break; + } + + // New vertical offsets + pairLayers.style.top = `${Number(this.chatmsg.other_offset[1])}%`; + charLayers.style.top = `${Number(this.chatmsg.self_offset[1])}%`; + + // flip the paired character + if (this.chatmsg.other_flip === 1) { + pairLayers.style.transform = 'scaleX(-1)'; + } else { + pairLayers.style.transform = 'scaleX(1)'; + } + + this.blipChannels.forEach((channel) => channel.src = `${AO_HOST}sounds/general/sfx-blip${encodeURI(this.chatmsg.blips.toLowerCase())}.opus`); + + // process markup + if (this.chatmsg.content.startsWith('~~')) { + chatBoxInner.style.textAlign = 'center'; + this.chatmsg.content = this.chatmsg.content.substring(2, this.chatmsg.content.length); + } else { + chatBoxInner.style.textAlign = 'inherit'; + } + + // apply effects + fg.style.animation = ''; + + if (this.chatmsg.effects[0] && this.chatmsg.effects[0] !== '-') { fg.src = `${AO_HOST}themes/default/effects/${encodeURI(this.chatmsg.effects[0].toLowerCase())}.webp`; } else { fg.src = transparentPNG; } + + if (this.chatmsg.sound === '0' || this.chatmsg.sound === '1' || this.chatmsg.sound === '' || this.chatmsg.sound === undefined) { this.chatmsg.sound = this.chatmsg.effects[2]; } + + this.tick(); + } + + /** * Updates the chatbox based on the given text. - * + * * OK, here's the documentation on how this works: - * + * * 1 _animating * If we're not done with this characters animation, i.e. his text isn't fully there, set a timeout for the next tick/step to happen - * + * * 2 startpreanim * If the shout timer is over it starts with the preanim * The first thing it checks for is the shake effect (TODO on client this is handled by the @ symbol and not a flag ) @@ -2258,200 +2252,198 @@ async changeBackground(position) { * After that, the shout image set to be transparent * and the main characters preanim gif is loaded * If pairing is supported the paired character will just stand around with his idle sprite - * + * * 3 preanimdelay over * this animates the evidence popup and finally shows the character name and message box * it sets the text color and the character speaking sprite - * + * * 4 textnow != content * this adds a character to the textbox and stops the animations if the entire message is present in the textbox - * + * * 5 sfx * independent of the stuff above, this will play any sound effects specified by the emote the character sent. * happens after the shout delay + an sfx delay that comes with the message packet - * + * * XXX: This relies on a global variable `this.chatmsg`! */ - tick() { - if (this._animating) { - this.updater = setTimeout(() => this.tick(), UPDATE_INTERVAL); - } - - const gamewindow = document.getElementById("client_gamewindow"); - const waitingBox = document.getElementById("client_chatwaiting"); - const eviBox = document.getElementById("client_evi"); - const shoutSprite = document.getElementById("client_shout"); - const chatBoxInner = document.getElementById("client_inner_chat"); - const chatBox = document.getElementById("client_chat"); - const effectlayer = document.getElementById("client_fg"); - let charLayers = document.getElementById("client_char"); - let pairLayers = document.getElementById("client_pair_char"); - - if ( "def,pro,wit".includes(this.chatmsg.side)) { - charLayers = document.getElementById("client_"+this.chatmsg.side+"_char"); - pairLayers = document.getElementById("client_"+this.chatmsg.side+"_pair_char"); - } - - const charName = this.chatmsg.name.toLowerCase(); - const charEmote = this.chatmsg.sprite.toLowerCase(); - - const pairName = this.chatmsg.other_name.toLowerCase(); - const pairEmote = this.chatmsg.other_emote.toLowerCase(); - - // TODO: preanims sometimes play when they're not supposed to - if (this.textTimer >= this.shoutTimer && this.chatmsg.startpreanim) { - // Effect stuff - if (this.chatmsg.screenshake === 1) { - // Shake screen - this.playSFX(AO_HOST + "sounds/general/sfx-stab.opus", false); - gamewindow.style.animation = "shake 0.2s 1"; - } - if (this.chatmsg.flash === 1) { - // Flash screen - this.playSFX(AO_HOST + "sounds/general/sfx-realization.opus", false); - effectlayer.style.animation = "flash 0.4s 1"; - } - - // Pre-animation stuff - if (this.chatmsg.preanimdelay > 0) { - shoutSprite.style.opacity = 0; - shoutSprite.style.animation = ""; - const preanim = this.chatmsg.preanim.toLowerCase(); - this.setEmote(charName,preanim,"",false,this.chatmsg.side); - charLayers.style.opacity = 1; - } - - if (this.chatmsg.other_name) { - pairLayers.style.opacity = 1; - } else { - pairLayers.style.opacity = 0; - } - - this.chatmsg.startpreanim = false; - this.chatmsg.startspeaking = true; - } else if (this.textTimer >= this.shoutTimer + this.chatmsg.preanimdelay && !this.chatmsg.startpreanim) { - if (this.chatmsg.startspeaking) { - if (this.chatmsg.evidence > 0) { - // Prepare evidence - eviBox.src = safe_tags(client.evidences[this.chatmsg.evidence - 1].icon); - - eviBox.style.width = "auto"; - eviBox.style.height = "36.5%"; - eviBox.style.opacity = 1; - - this.testimonyAudio.src = AO_HOST + "sounds/general/sfx-evidenceshoop.opus"; - this.testimonyAudio.play(); - - if (this.chatmsg.side === "def") { - // Only def show evidence on right - eviBox.style.right = "1em"; - eviBox.style.left = "initial"; - } else { - eviBox.style.right = "initial"; - eviBox.style.left = "1em"; - } - } - - resizeChatbox(); - - const chatContainerBox = document.getElementById("client_chatcontainer"); - chatContainerBox.style.opacity = 1; - - chatBoxInner.className = "text_" + this.colors[this.chatmsg.color]; - - this.chatmsg.startspeaking = false; - - if (this.chatmsg.preanimdelay === 0) { - shoutSprite.style.opacity = 0; - shoutSprite.style.animation = ""; - } - - if (this.chatmsg.other_name) { - this.setEmote(pairName,pairEmote,"(a)",true,this.chatmsg.side); - pairLayers.style.opacity = 1; - } else { - pairLayers.style.opacity = 0; - } - - this.setEmote(charName,charEmote,"(b)",false,this.chatmsg.side); - charLayers.style.opacity = 1; - - if (this.textnow === this.chatmsg.content) { - this.setEmote(charName,charEmote,"(a)",false,this.chatmsg.side); - charLayers.style.opacity = 1; - waitingBox.style.opacity = 1; - this._animating = false; - clearTimeout(this.updater); - } - } else { - if (this.textnow !== this.chatmsg.content) { - if (this.chatmsg.content.charAt(this.textnow.length) !== " ") { - this.blipChannels[this.currentBlipChannel].play(); - this.currentBlipChannel++; - this.currentBlipChannel %= this.blipChannels.length; - } - this.textnow = this.chatmsg.content.substring(0, this.textnow.length + 1); - - chatBoxInner.innerText = this.textnow; - - // scroll to bottom - chatBox.scrollTop = chatBox.scrollHeight; - - if (this.textnow === this.chatmsg.content) { - this._animating = false; - this.setEmote(charName,charEmote,"(a)",false,this.chatmsg.side); - charLayers.style.opacity = 1; - waitingBox.style.opacity = 1; - clearTimeout(this.updater); - } - } - } - } - - if (!this.sfxplayed && this.chatmsg.snddelay + this.shoutTimer >= this.textTimer) { - this.sfxplayed = 1; - if (this.chatmsg.sound !== "0" && this.chatmsg.sound !== "1" && this.chatmsg.sound !== "" && this.chatmsg.sound !== undefined && (this.chatmsg.type == 1 || this.chatmsg.type == 2 || this.chatmsg.type == 6)) { - this.playSFX(AO_HOST + "sounds/general/" + encodeURI(this.chatmsg.sound.toLowerCase()) + ".opus", this.chatmsg.looping_sfx); - } - } - this.textTimer = this.textTimer + UPDATE_INTERVAL; - } + tick() { + if (this._animating) { + this.updater = setTimeout(() => this.tick(), UPDATE_INTERVAL); + } + + const gamewindow = document.getElementById('client_gamewindow'); + const waitingBox = document.getElementById('client_chatwaiting'); + const eviBox = document.getElementById('client_evi'); + const shoutSprite = document.getElementById('client_shout'); + const chatBoxInner = document.getElementById('client_inner_chat'); + const chatBox = document.getElementById('client_chat'); + const effectlayer = document.getElementById('client_fg'); + let charLayers = document.getElementById('client_char'); + let pairLayers = document.getElementById('client_pair_char'); + + if ('def,pro,wit'.includes(this.chatmsg.side)) { + charLayers = document.getElementById(`client_${this.chatmsg.side}_char`); + pairLayers = document.getElementById(`client_${this.chatmsg.side}_pair_char`); + } + + const charName = this.chatmsg.name.toLowerCase(); + const charEmote = this.chatmsg.sprite.toLowerCase(); + + const pairName = this.chatmsg.other_name.toLowerCase(); + const pairEmote = this.chatmsg.other_emote.toLowerCase(); + + // TODO: preanims sometimes play when they're not supposed to + if (this.textTimer >= this.shoutTimer && this.chatmsg.startpreanim) { + // Effect stuff + if (this.chatmsg.screenshake === 1) { + // Shake screen + this.playSFX(`${AO_HOST}sounds/general/sfx-stab.opus`, false); + gamewindow.style.animation = 'shake 0.2s 1'; + } + if (this.chatmsg.flash === 1) { + // Flash screen + this.playSFX(`${AO_HOST}sounds/general/sfx-realization.opus`, false); + effectlayer.style.animation = 'flash 0.4s 1'; + } + + // Pre-animation stuff + if (this.chatmsg.preanimdelay > 0) { + shoutSprite.style.opacity = 0; + shoutSprite.style.animation = ''; + const preanim = this.chatmsg.preanim.toLowerCase(); + this.setEmote(charName, preanim, '', false, this.chatmsg.side); + charLayers.style.opacity = 1; + } + + if (this.chatmsg.other_name) { + pairLayers.style.opacity = 1; + } else { + pairLayers.style.opacity = 0; + } + + this.chatmsg.startpreanim = false; + this.chatmsg.startspeaking = true; + } else if (this.textTimer >= this.shoutTimer + this.chatmsg.preanimdelay && !this.chatmsg.startpreanim) { + if (this.chatmsg.startspeaking) { + if (this.chatmsg.evidence > 0) { + // Prepare evidence + eviBox.src = safe_tags(client.evidences[this.chatmsg.evidence - 1].icon); + + eviBox.style.width = 'auto'; + eviBox.style.height = '36.5%'; + eviBox.style.opacity = 1; + + this.testimonyAudio.src = `${AO_HOST}sounds/general/sfx-evidenceshoop.opus`; + this.testimonyAudio.play(); + + if (this.chatmsg.side === 'def') { + // Only def show evidence on right + eviBox.style.right = '1em'; + eviBox.style.left = 'initial'; + } else { + eviBox.style.right = 'initial'; + eviBox.style.left = '1em'; + } + } + + resizeChatbox(); + + const chatContainerBox = document.getElementById('client_chatcontainer'); + chatContainerBox.style.opacity = 1; + + chatBoxInner.className = `text_${this.colors[this.chatmsg.color]}`; + + this.chatmsg.startspeaking = false; + + if (this.chatmsg.preanimdelay === 0) { + shoutSprite.style.opacity = 0; + shoutSprite.style.animation = ''; + } + + if (this.chatmsg.other_name) { + this.setEmote(pairName, pairEmote, '(a)', true, this.chatmsg.side); + pairLayers.style.opacity = 1; + } else { + pairLayers.style.opacity = 0; + } + + this.setEmote(charName, charEmote, '(b)', false, this.chatmsg.side); + charLayers.style.opacity = 1; + + if (this.textnow === this.chatmsg.content) { + this.setEmote(charName, charEmote, '(a)', false, this.chatmsg.side); + charLayers.style.opacity = 1; + waitingBox.style.opacity = 1; + this._animating = false; + clearTimeout(this.updater); + } + } else if (this.textnow !== this.chatmsg.content) { + if (this.chatmsg.content.charAt(this.textnow.length) !== ' ') { + this.blipChannels[this.currentBlipChannel].play(); + this.currentBlipChannel++; + this.currentBlipChannel %= this.blipChannels.length; + } + this.textnow = this.chatmsg.content.substring(0, this.textnow.length + 1); + + chatBoxInner.innerText = this.textnow; + + // scroll to bottom + chatBox.scrollTop = chatBox.scrollHeight; + + if (this.textnow === this.chatmsg.content) { + this._animating = false; + this.setEmote(charName, charEmote, '(a)', false, this.chatmsg.side); + charLayers.style.opacity = 1; + waitingBox.style.opacity = 1; + clearTimeout(this.updater); + } + } + } + + if (!this.sfxplayed && this.chatmsg.snddelay + this.shoutTimer >= this.textTimer) { + this.sfxplayed = 1; + if (this.chatmsg.sound !== '0' && this.chatmsg.sound !== '1' && this.chatmsg.sound !== '' && this.chatmsg.sound !== undefined && (this.chatmsg.type == 1 || this.chatmsg.type == 2 || this.chatmsg.type == 6)) { + this.playSFX(`${AO_HOST}sounds/general/${encodeURI(this.chatmsg.sound.toLowerCase())}.opus`, this.chatmsg.looping_sfx); + } + } + this.textTimer += UPDATE_INTERVAL; + } } class INI { - static parse(data) { - const regex = { - section: /^\s*\[\s*([^\]]*)\s*\]\s*$/, - param: /^\s*([\w.\-_]+)\s*=\s*(.*?)\s*$/, - comment: /^\s*;.*$/ - }; - const value = {}; - const lines = data.split(/\r\n|\r|\n/); - let section; - lines.forEach(function (line) { - if (regex.comment.test(line)) { - return; - } else if (line.length === 0) { - return; - } else if (regex.param.test(line)) { - const match = line.match(regex.param); - if (section) { - if (match[1].toLowerCase() === "showname") { //don't lowercase the showname - value[section]["showname"] = match[2]; - } else { - value[section][match[1].toLowerCase()] = match[2].toLowerCase(); - } - //} else { // we don't care about attributes without a section - // value[match[1]] = match[2]; - } - } else if (regex.section.test(line)) { - const match = line.match(regex.section); - value[match[1].toLowerCase()] = {}; //lowercase everything else - section = match[1].toLowerCase(); - } - }); - return value; - } + static parse(data) { + const regex = { + section: /^\s*\[\s*([^\]]*)\s*\]\s*$/, + param: /^\s*([\w.\-_]+)\s*=\s*(.*?)\s*$/, + comment: /^\s*;.*$/, + }; + const value = {}; + const lines = data.split(/\r\n|\r|\n/); + let section; + lines.forEach((line) => { + if (regex.comment.test(line)) { + + } else if (line.length === 0) { + + } else if (regex.param.test(line)) { + const match = line.match(regex.param); + if (section) { + if (match[1].toLowerCase() === 'showname') { // don't lowercase the showname + value[section].showname = match[2]; + } else { + value[section][match[1].toLowerCase()] = match[2].toLowerCase(); + } + // } else { // we don't care about attributes without a section + // value[match[1]] = match[2]; + } + } else if (regex.section.test(line)) { + const match = line.match(regex.section); + value[match[1].toLowerCase()] = {}; // lowercase everything else + section = match[1].toLowerCase(); + } + }); + return value; + } } /** @@ -2461,23 +2453,23 @@ class INI { * @param {String} cname The name of the cookie to return */ function getCookie(cname) { - try { - const name = cname + "="; - const decodedCookie = decodeURIComponent(document.cookie); - const ca = decodedCookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) === ' ') { - c = c.substring(1); - } - if (c.indexOf(name) === 0) { - return c.substring(name.length, c.length); - } - } - return ""; - } catch (error) { - return ""; - } + try { + const name = `${cname}=`; + const decodedCookie = decodeURIComponent(document.cookie); + const ca = decodedCookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ''; + } catch (error) { + return ''; + } } /** @@ -2487,7 +2479,7 @@ function getCookie(cname) { * @param {String} value The value of that cookie option */ function setCookie(cname, value) { - document.cookie = cname + "=" + value; + document.cookie = `${cname}=${value}`; } /** @@ -2495,10 +2487,10 @@ function setCookie(cname, value) { * @param {KeyboardEvent} event */ export function onOOCEnter(event) { - if (event.keyCode === 13) { - client.sendOOC(document.getElementById("client_oocinputbox").value); - document.getElementById("client_oocinputbox").value = ""; - } + if (event.keyCode === 13) { + client.sendOOC(document.getElementById('client_oocinputbox').value); + document.getElementById('client_oocinputbox').value = ''; + } } window.onOOCEnter = onOOCEnter; @@ -2507,7 +2499,7 @@ window.onOOCEnter = onOOCEnter; * @param {KeyboardEvent} event */ export function onReplayGo(_event) { - client.handleReplay(); + client.handleReplay(); } window.onReplayGo = onReplayGo; @@ -2516,45 +2508,67 @@ window.onReplayGo = onReplayGo; * @param {KeyboardEvent} event */ export function onEnter(event) { - if (event.keyCode === 13) { - const mychar = client.character; - const myemo = client.emote; - const evi = client.evidence; - const flip = ((document.getElementById("button_flip").classList.contains("dark")) ? 1 : 0); - const flash = ((document.getElementById("button_flash").classList.contains("dark")) ? 1 : 0); - const screenshake = ((document.getElementById("button_shake").classList.contains("dark")) ? 1 : 0); - const noninterrupting_preanim = ((document.getElementById("check_nonint").checked) ? 1 : 0); - const looping_sfx = ((document.getElementById("check_loopsfx").checked) ? 1 : 0); - const color = document.getElementById("textcolor").value; - const showname = document.getElementById("ic_chat_name").value; - const text = document.getElementById("client_inputbox").value; - const pairchar = document.getElementById("pair_select").value; - const pairoffset = document.getElementById("pair_offset").value; - const pairyoffset = document.getElementById("pair_y_offset").value; - const myrole = document.getElementById("role_select").value ? document.getElementById("role_select").value : mychar.side; - const additive = ((document.getElementById("check_additive").checked) ? 1 : 0); - const effect = document.getElementById("effect_select").value; - - let sfxname = "0"; - let sfxdelay = 0; - let emote_mod = myemo.zoom; - if (document.getElementById("sendsfx").checked) { - sfxname = myemo.sfx; - sfxdelay = myemo.sfxdelay; - } - - // not to overwrite a 5 from the ini or anything else - if (document.getElementById("sendpreanim").checked) { - if (emote_mod === 0) - emote_mod = 1; - } else if (emote_mod === 1) - emote_mod = 0; - - client.sendIC("chat", myemo.preanim, mychar.name, myemo.emote, - text, myrole, - sfxname, emote_mod, sfxdelay, selectedShout, evi, flip, - flash, color, showname, pairchar, pairoffset, pairyoffset, noninterrupting_preanim, looping_sfx, screenshake, "-", "-", "-", additive, effect); - } + if (event.keyCode === 13) { + const mychar = client.character; + const myemo = client.emote; + const evi = client.evidence; + const flip = ((document.getElementById('button_flip').classList.contains('dark')) ? 1 : 0); + const flash = ((document.getElementById('button_flash').classList.contains('dark')) ? 1 : 0); + const screenshake = ((document.getElementById('button_shake').classList.contains('dark')) ? 1 : 0); + const noninterrupting_preanim = ((document.getElementById('check_nonint').checked) ? 1 : 0); + const looping_sfx = ((document.getElementById('check_loopsfx').checked) ? 1 : 0); + const color = document.getElementById('textcolor').value; + const showname = document.getElementById('ic_chat_name').value; + const text = document.getElementById('client_inputbox').value; + const pairchar = document.getElementById('pair_select').value; + const pairoffset = document.getElementById('pair_offset').value; + const pairyoffset = document.getElementById('pair_y_offset').value; + const myrole = document.getElementById('role_select').value ? document.getElementById('role_select').value : mychar.side; + const additive = ((document.getElementById('check_additive').checked) ? 1 : 0); + const effect = document.getElementById('effect_select').value; + + let sfxname = '0'; + let sfxdelay = 0; + let emote_mod = myemo.zoom; + if (document.getElementById('sendsfx').checked) { + sfxname = myemo.sfx; + sfxdelay = myemo.sfxdelay; + } + + // not to overwrite a 5 from the ini or anything else + if (document.getElementById('sendpreanim').checked) { + if (emote_mod === 0) { emote_mod = 1; } + } else if (emote_mod === 1) { emote_mod = 0; } + + client.sendIC( + 'chat', + myemo.preanim, + mychar.name, + myemo.emote, + text, + myrole, + sfxname, + emote_mod, + sfxdelay, + selectedShout, + evi, + flip, + flash, + color, + showname, + pairchar, + pairoffset, + pairyoffset, + noninterrupting_preanim, + looping_sfx, + screenshake, + '-', + '-', + '-', + additive, + effect, + ); + } } window.onEnter = onEnter; @@ -2564,21 +2578,21 @@ window.onEnter = onEnter; * was successfully sent/presented. */ function resetICParams() { - document.getElementById("client_inputbox").value = ""; - document.getElementById("button_flash").className = "client_button"; - document.getElementById("button_shake").className = "client_button"; + document.getElementById('client_inputbox').value = ''; + document.getElementById('button_flash').className = 'client_button'; + document.getElementById('button_shake').className = 'client_button'; - document.getElementById("sendpreanim").checked = false; + document.getElementById('sendpreanim').checked = false; - if (selectedShout) { - document.getElementById("button_" + selectedShout).className = "client_button"; - selectedShout = 0; - } + if (selectedShout) { + document.getElementById(`button_${selectedShout}`).className = 'client_button'; + selectedShout = 0; + } } export function resetOffset(_event) { - document.getElementById("pair_offset").value = 0; - document.getElementById("pair_y_offset").value = 0; + document.getElementById('pair_offset').value = 0; + document.getElementById('pair_y_offset').value = 0; } window.resetOffset = resetOffset; @@ -2587,18 +2601,18 @@ window.resetOffset = resetOffset; * @param {MouseEvent} event */ export function musiclist_filter(_event) { - const musiclist_element = document.getElementById("client_musiclist"); - const searchname = document.getElementById("client_musicsearch").value; + const musiclist_element = document.getElementById('client_musiclist'); + const searchname = document.getElementById('client_musicsearch').value; - musiclist_element.innerHTML = ""; + musiclist_element.innerHTML = ''; - for (const trackname of client.musics){ - if (trackname.toLowerCase().indexOf(searchname.toLowerCase()) !== -1) { - const newentry = document.createElement("OPTION"); - newentry.text = trackname; - musiclist_element.options.add(newentry); - } - } + for (const trackname of client.musics) { + if (trackname.toLowerCase().indexOf(searchname.toLowerCase()) !== -1) { + const newentry = document.createElement('OPTION'); + newentry.text = trackname; + musiclist_element.options.add(newentry); + } + } } window.musiclist_filter = musiclist_filter; @@ -2607,15 +2621,15 @@ window.musiclist_filter = musiclist_filter; * @param {MouseEvent} event */ export function musiclist_click(_event) { - const playtrack = document.getElementById("client_musiclist").value; - client.sendMusicChange(playtrack); + const playtrack = document.getElementById('client_musiclist').value; + client.sendMusicChange(playtrack); - // This is here so you can't actually select multiple tracks, - // even though the select tag has the multiple option to render differently - let musiclist_elements = document.getElementById("client_musiclist").selectedOptions; - for (let i = 0; i < musiclist_elements.length; i++) { - musiclist_elements[i].selected = false; - } + // This is here so you can't actually select multiple tracks, + // even though the select tag has the multiple option to render differently + const musiclist_elements = document.getElementById('client_musiclist').selectedOptions; + for (let i = 0; i < musiclist_elements.length; i++) { + musiclist_elements[i].selected = false; + } } window.musiclist_click = musiclist_click; @@ -2624,17 +2638,17 @@ window.musiclist_click = musiclist_click; * @param {MouseEvent} event */ export function mutelist_click(_event) { - const mutelist = document.getElementById("mute_select"); - const selected_character = mutelist.options[mutelist.selectedIndex]; - - if (client.chars[selected_character.value].muted === false) { - client.chars[selected_character.value].muted = true; - selected_character.text = client.chars[selected_character.value].name + " (muted)"; - console.info("muted " + client.chars[selected_character.value].name); - } else { - client.chars[selected_character.value].muted = false; - selected_character.text = client.chars[selected_character.value].name; - } + const mutelist = document.getElementById('mute_select'); + const selected_character = mutelist.options[mutelist.selectedIndex]; + + if (client.chars[selected_character.value].muted === false) { + client.chars[selected_character.value].muted = true; + selected_character.text = `${client.chars[selected_character.value].name} (muted)`; + console.info(`muted ${client.chars[selected_character.value].name}`); + } else { + client.chars[selected_character.value].muted = false; + selected_character.text = client.chars[selected_character.value].name; + } } window.mutelist_click = mutelist_click; @@ -2643,15 +2657,12 @@ window.mutelist_click = mutelist_click; * @param {MouseEvent} event */ export function showname_click(_event) { - setCookie("showname", document.getElementById("showname").checked); - setCookie("ic_chat_name", document.getElementById("ic_chat_name").value); + setCookie('showname', document.getElementById('showname').checked); + setCookie('ic_chat_name', document.getElementById('ic_chat_name').value); - const css_s = document.getElementById("nameplate_setting"); + const css_s = document.getElementById('nameplate_setting'); - if (document.getElementById("showname").checked) - css_s.href = "styles/shownames.css"; - else - css_s.href = "styles/nameplates.css"; + if (document.getElementById('showname').checked) { css_s.href = 'styles/shownames.css'; } else { css_s.href = 'styles/nameplates.css'; } } window.showname_click = showname_click; @@ -2660,13 +2671,13 @@ window.showname_click = showname_click; * @param {MouseEvent} event */ export function area_click(el) { - const area = client.areas[el.id.substr(4)].name; - client.sendMusicChange(area); + const area = client.areas[el.id.substr(4)].name; + client.sendMusicChange(area); - const areaHr = document.createElement("div"); - areaHr.className = "hrtext"; - areaHr.textContent = `switched to ${el.textContent}`; - document.getElementById("client_log").appendChild(areaHr); + const areaHr = document.createElement('div'); + areaHr.className = 'hrtext'; + areaHr.textContent = `switched to ${el.textContent}`; + document.getElementById('client_log').appendChild(areaHr); } window.area_click = area_click; @@ -2674,8 +2685,8 @@ window.area_click = area_click; * Triggered by the music volume slider. */ export function changeMusicVolume() { - viewport.musicVolume = document.getElementById("client_mvolume").value; - setCookie("musicVolume", document.getElementById("client_mvolume").value); + viewport.musicVolume = document.getElementById('client_mvolume').value; + setCookie('musicVolume', document.getElementById('client_mvolume').value); } window.changeMusicVolume = changeMusicVolume; @@ -2683,7 +2694,7 @@ window.changeMusicVolume = changeMusicVolume; * Triggered by the sound effect volume slider. */ export function changeSFXVolume() { - setCookie("sfxVolume", document.getElementById("client_sfxaudio").volume); + setCookie('sfxVolume', document.getElementById('client_sfxaudio').volume); } window.changeSFXVolume = changeSFXVolume; @@ -2691,7 +2702,7 @@ window.changeSFXVolume = changeSFXVolume; * Triggered by the shout volume slider. */ export function changeShoutVolume() { - setCookie("shoutVolume", document.getElementById("client_shoutaudio").volume); + setCookie('shoutVolume', document.getElementById('client_shoutaudio').volume); } window.changeShoutVolume = changeShoutVolume; @@ -2699,7 +2710,7 @@ window.changeShoutVolume = changeShoutVolume; * Triggered by the testimony volume slider. */ export function changeTestimonyVolume() { - setCookie("testimonyVolume", document.getElementById("client_testimonyaudio").volume); + setCookie('testimonyVolume', document.getElementById('client_testimonyaudio').volume); } window.changeTestimonyVolume = changeTestimonyVolume; @@ -2707,8 +2718,8 @@ window.changeTestimonyVolume = changeTestimonyVolume; * Triggered by the blip volume slider. */ export function changeBlipVolume() { - viewport.blipVolume = document.getElementById("client_bvolume").value; - setCookie("blipVolume", document.getElementById("client_bvolume").value); + viewport.blipVolume = document.getElementById('client_bvolume').value; + setCookie('blipVolume', document.getElementById('client_bvolume').value); } window.changeBlipVolume = changeBlipVolume; @@ -2716,9 +2727,9 @@ window.changeBlipVolume = changeBlipVolume; * Triggered by the theme selector. */ export function reloadTheme() { - viewport.theme = document.getElementById("client_themeselect").value; - setCookie("theme", viewport.theme); - document.getElementById("client_theme").href = "styles/" + viewport.theme + ".css"; + viewport.theme = document.getElementById('client_themeselect').value; + setCookie('theme', viewport.theme); + document.getElementById('client_theme').href = `styles/${viewport.theme}.css`; } window.reloadTheme = reloadTheme; @@ -2726,8 +2737,8 @@ window.reloadTheme = reloadTheme; * Triggered by a changed callword list */ export function changeCallwords() { - client.callwords = document.getElementById("client_callwords").value.split('\n'); - setCookie("callwords",client.callwords); + client.callwords = document.getElementById('client_callwords').value.split('\n'); + setCookie('callwords', client.callwords); } window.changeCallwords = changeCallwords; @@ -2735,7 +2746,7 @@ window.changeCallwords = changeCallwords; * Triggered by the modcall sfx dropdown */ export function modcall_test() { - client.handleZZ("test#test".split("#")); + client.handleZZ('test#test'.split('#')); } window.modcall_test = modcall_test; @@ -2743,28 +2754,28 @@ window.modcall_test = modcall_test; * Triggered by the ini button. */ export async function iniedit() { - const ininame = document.getElementById("client_ininame").value; - const inicharID = client.charID; - await client.handleCharacterInfo(ininame.split("&"), inicharID); - client.handlePV(("PV#0#CID#" + inicharID).split("#")); + const ininame = document.getElementById('client_ininame').value; + const inicharID = client.charID; + await client.handleCharacterInfo(ininame.split('&'), inicharID); + client.handlePV((`PV#0#CID#${inicharID}`).split('#')); } window.iniedit = iniedit; /** * Triggered by the pantilt checkbox */ - export async function switchPanTilt(addcheck) { - const background = document.getElementById("client_fullview"); - if (addcheck === 1) { - document.getElementById("client_pantilt").checked = true; - } else if (addcheck === 2) { - document.getElementById("client_pantilt").checked = false; - } - if(document.getElementById("client_pantilt").checked) { - background.style.transition = "0.5s ease-in-out"; - } else { - background.style.transition = "none" - } +export async function switchPanTilt(addcheck) { + const background = document.getElementById('client_fullview'); + if (addcheck === 1) { + document.getElementById('client_pantilt').checked = true; + } else if (addcheck === 2) { + document.getElementById('client_pantilt').checked = false; + } + if (document.getElementById('client_pantilt').checked) { + background.style.transition = '0.5s ease-in-out'; + } else { + background.style.transition = 'none'; + } } window.switchPanTilt = switchPanTilt; @@ -2772,15 +2783,15 @@ window.switchPanTilt = switchPanTilt; * Triggered by the change aspect ratio checkbox */ export async function switchAspectRatio() { - const background = document.getElementById("client_background"); - const offsetCheck = document.getElementById("client_hdviewport_offset"); - if(document.getElementById("client_hdviewport").checked) { - background.style.paddingBottom = "56.25%"; - offsetCheck.disabled = false; - } else { - background.style.paddingBottom = "75%"; - offsetCheck.disabled = true; - } + const background = document.getElementById('client_background'); + const offsetCheck = document.getElementById('client_hdviewport_offset'); + if (document.getElementById('client_hdviewport').checked) { + background.style.paddingBottom = '56.25%'; + offsetCheck.disabled = false; + } else { + background.style.paddingBottom = '75%'; + offsetCheck.disabled = true; + } } window.switchAspectRatio = switchAspectRatio; @@ -2788,14 +2799,14 @@ window.switchAspectRatio = switchAspectRatio; * Triggered by the change aspect ratio checkbox */ export async function switchChatOffset() { - const container = document.getElementById("client_chatcontainer"); - if(document.getElementById("client_hdviewport_offset").checked) { - container.style.width = "80%"; - container.style.left = "10%"; - } else { - container.style.width = "100%"; - container.style.left = 0; - } + const container = document.getElementById('client_chatcontainer'); + if (document.getElementById('client_hdviewport_offset').checked) { + container.style.width = '80%'; + container.style.left = '10%'; + } else { + container.style.width = '100%'; + container.style.left = 0; + } } window.switchChatOffset = switchChatOffset; @@ -2804,8 +2815,8 @@ window.switchChatOffset = switchChatOffset; * @param {MouseEvent} event */ export function changeCharacter(_event) { - document.getElementById("client_charselect").style.display = "block"; - document.getElementById("client_emo").innerHTML = ""; + document.getElementById('client_charselect').style.display = 'block'; + document.getElementById('client_emo').innerHTML = ''; } window.changeCharacter = changeCharacter; @@ -2814,9 +2825,9 @@ window.changeCharacter = changeCharacter; * @param {HTMLImageElement} image the element containing the missing image */ export function charError(image) { - console.warn(image.src + " is missing from webAO"); - image.src = transparentPNG; - return true; + console.warn(`${image.src} is missing from webAO`); + image.src = transparentPNG; + return true; } window.charError = charError; @@ -2825,9 +2836,9 @@ window.charError = charError; * @param {HTMLImageElement} image the element containing the missing image */ export function imgError(image) { - image.onerror = ""; - image.src = ""; //unload so the old sprite doesn't persist - return true; + image.onerror = ''; + image.src = ''; // unload so the old sprite doesn't persist + return true; } window.imgError = imgError; @@ -2835,16 +2846,16 @@ window.imgError = imgError; * Triggered when there was an error loading a sound * @param {HTMLImageElement} image the element containing the missing sound */ - export function opusCheck(channel) { - console.info(channel) - console.info("failed to load sound "+channel.src) - let oldsrc = "" - oldsrc = channel.src - if(!oldsrc.endsWith(".opus")) { - newsrc = oldsrc.replace(".mp3",".opus") - newsrc = newsrc.replace(".wav",".opus") - channel.src = newsrc; //unload so the old sprite doesn't persist - } +export function opusCheck(channel) { + console.info(channel); + console.info(`failed to load sound ${channel.src}`); + let oldsrc = ''; + oldsrc = channel.src; + if (!oldsrc.endsWith('.opus')) { + newsrc = oldsrc.replace('.mp3', '.opus'); + newsrc = newsrc.replace('.wav', '.opus'); + channel.src = newsrc; // unload so the old sprite doesn't persist + } } window.opusCheck = opusCheck; @@ -2855,31 +2866,31 @@ window.opusCheck = opusCheck; * @throws {Error} if status code is not 2xx, or a network error occurs */ async function requestBuffer(url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.responseType = "arraybuffer"; - xhr.addEventListener("error", () => { - const err = new Error(`Request for ${url} failed: ${xhr.statusText}`); - err.code = xhr.status; - reject(err); - }); - xhr.addEventListener("abort", () => { - const err = new Error(`Request for ${url} was aborted!`); - err.code = xhr.status; - reject(err); - }); - xhr.addEventListener("load", () => { - if (xhr.status < 200 || xhr.status >= 300) { - const err = new Error(`Request for ${url} failed with status code ${xhr.status}`); - err.code = xhr.status; - reject(err); - } else { - resolve(xhr.response); - } - }); - xhr.open("GET", url, true); - xhr.send(); - }); + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.responseType = 'arraybuffer'; + xhr.addEventListener('error', () => { + const err = new Error(`Request for ${url} failed: ${xhr.statusText}`); + err.code = xhr.status; + reject(err); + }); + xhr.addEventListener('abort', () => { + const err = new Error(`Request for ${url} was aborted!`); + err.code = xhr.status; + reject(err); + }); + xhr.addEventListener('load', () => { + if (xhr.status < 200 || xhr.status >= 300) { + const err = new Error(`Request for ${url} failed with status code ${xhr.status}`); + err.code = xhr.status; + reject(err); + } else { + resolve(xhr.response); + } + }); + xhr.open('GET', url, true); + xhr.send(); + }); } /** @@ -2889,31 +2900,31 @@ async function requestBuffer(url) { * @throws {Error} if status code is not 2xx, or a network error occurs */ async function request(url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.responseType = "text"; - xhr.addEventListener("error", () => { - const err = new Error(`Request for ${url} failed: ${xhr.statusText}`); - err.code = xhr.status; - reject(err); - }); - xhr.addEventListener("abort", () => { - const err = new Error(`Request for ${url} was aborted!`); - err.code = xhr.status; - reject(err); - }); - xhr.addEventListener("load", () => { - if (xhr.status < 200 || xhr.status >= 300) { - const err = new Error(`Request for ${url} failed with status code ${xhr.status}`); - err.code = xhr.status; - reject(err); - } else { - resolve(xhr.response); - } - }); - xhr.open("GET", url, true); - xhr.send(); - }); + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.responseType = 'text'; + xhr.addEventListener('error', () => { + const err = new Error(`Request for ${url} failed: ${xhr.statusText}`); + err.code = xhr.status; + reject(err); + }); + xhr.addEventListener('abort', () => { + const err = new Error(`Request for ${url} was aborted!`); + err.code = xhr.status; + reject(err); + }); + xhr.addEventListener('load', () => { + if (xhr.status < 200 || xhr.status >= 300) { + const err = new Error(`Request for ${url} failed with status code ${xhr.status}`); + err.code = xhr.status; + reject(err); + } else { + resolve(xhr.response); + } + }); + xhr.open('GET', url, true); + xhr.send(); + }); } /** @@ -2921,26 +2932,25 @@ async function request(url) { * @param {string} url the URI to be checked */ async function fileExists(url) { - try { - await request(url); - return true; - } catch (err) { - return false; - } + try { + await request(url); + return true; + } catch (err) { + return false; + } } /** * Triggered when the reconnect button is pushed. */ export function ReconnectButton() { - client.cleanup(); - client = new Client(serverIP); - if (client) { - mode = "join"; // HACK: see client.onOpen + client.cleanup(); + client = new Client(serverIP); + if (client) { + mode = 'join'; // HACK: see client.onOpen - document.getElementById("client_error").style.display = "none"; - - } + document.getElementById('client_error').style.display = 'none'; + } } window.ReconnectButton = ReconnectButton; @@ -2949,47 +2959,44 @@ window.ReconnectButton = ReconnectButton; * @param {string} msg the string to be added * @param {string} name the name of the sender */ -function appendICLog(msg, showname = "", nameplate = "", time = new Date()) { - const entry = document.createElement("p"); - const shownameField = document.createElement("span"); - const nameplateField = document.createElement("span"); - const textField = document.createElement("span"); - nameplateField.classList = "iclog_name iclog_nameplate"; - nameplateField.appendChild(document.createTextNode(nameplate)); - - shownameField.classList = "iclog_name iclog_showname"; - if (showname === "" || !showname) - shownameField.appendChild(document.createTextNode(nameplate)); - else - shownameField.appendChild(document.createTextNode(showname)); - - textField.className = "iclog_text"; - textField.appendChild(document.createTextNode(msg)); - - entry.appendChild(shownameField); - entry.appendChild(nameplateField); - entry.appendChild(textField); - - // Only put a timestamp if the minute has changed. - if (lastICMessageTime.getMinutes() !== time.getMinutes()) { - const timeStamp = document.createElement("span"); - timeStamp.className = "iclog_time"; - timeStamp.innerText = time.toLocaleTimeString(undefined, { - hour: "numeric", - minute: "2-digit" - }); - entry.appendChild(timeStamp); - } - - const clientLog = document.getElementById("client_log"); - clientLog.appendChild(entry); - - /* This is a little buggy - some troubleshooting might be desirable */ - if (clientLog.scrollTop > clientLog.scrollHeight - 800) { - clientLog.scrollTop = clientLog.scrollHeight; - } - - lastICMessageTime = new Date(); +function appendICLog(msg, showname = '', nameplate = '', time = new Date()) { + const entry = document.createElement('p'); + const shownameField = document.createElement('span'); + const nameplateField = document.createElement('span'); + const textField = document.createElement('span'); + nameplateField.classList = 'iclog_name iclog_nameplate'; + nameplateField.appendChild(document.createTextNode(nameplate)); + + shownameField.classList = 'iclog_name iclog_showname'; + if (showname === '' || !showname) { shownameField.appendChild(document.createTextNode(nameplate)); } else { shownameField.appendChild(document.createTextNode(showname)); } + + textField.className = 'iclog_text'; + textField.appendChild(document.createTextNode(msg)); + + entry.appendChild(shownameField); + entry.appendChild(nameplateField); + entry.appendChild(textField); + + // Only put a timestamp if the minute has changed. + if (lastICMessageTime.getMinutes() !== time.getMinutes()) { + const timeStamp = document.createElement('span'); + timeStamp.className = 'iclog_time'; + timeStamp.innerText = time.toLocaleTimeString(undefined, { + hour: 'numeric', + minute: '2-digit', + }); + entry.appendChild(timeStamp); + } + + const clientLog = document.getElementById('client_log'); + clientLog.appendChild(entry); + + /* This is a little buggy - some troubleshooting might be desirable */ + if (clientLog.scrollTop > clientLog.scrollHeight - 800) { + clientLog.scrollTop = clientLog.scrollHeight; + } + + lastICMessageTime = new Date(); } /** @@ -2997,36 +3004,32 @@ function appendICLog(msg, showname = "", nameplate = "", time = new Date()) { * @param {String} message */ export function checkCallword(message) { - client.callwords.forEach(testCallword); + client.callwords.forEach(testCallword); - function testCallword(item) - { - if(item !== "" && message.toLowerCase().includes(item.toLowerCase())) - { - viewport.sfxaudio.pause(); - viewport.sfxaudio.src = AO_HOST + "sounds/general/sfx-gallery.opus"; - viewport.sfxaudio.play(); - } - } + function testCallword(item) { + if (item !== '' && message.toLowerCase().includes(item.toLowerCase())) { + viewport.sfxaudio.pause(); + viewport.sfxaudio.src = `${AO_HOST}sounds/general/sfx-gallery.opus`; + viewport.sfxaudio.play(); + } + } } - - /** * Triggered when the music search bar is changed * @param {MouseEvent} event */ export function chartable_filter(_event) { - const searchname = document.getElementById("client_charactersearch").value; - - client.chars.forEach(function (character, charid) { - const demothing = document.getElementById(`demo_${charid}`); - if (character.name.toLowerCase().indexOf(searchname.toLowerCase()) === -1) { - demothing.style.display = "none"; - } else { - demothing.style.display = "inline-block"; - } - }); + const searchname = document.getElementById('client_charactersearch').value; + + client.chars.forEach((character, charid) => { + const demothing = document.getElementById(`demo_${charid}`); + if (character.name.toLowerCase().indexOf(searchname.toLowerCase()) === -1) { + demothing.style.display = 'none'; + } else { + demothing.style.display = 'inline-block'; + } + }); } window.chartable_filter = chartable_filter; @@ -3036,12 +3039,12 @@ window.chartable_filter = chartable_filter; * then spectator is chosen instead. */ export function pickChar(ccharacter) { - if (ccharacter===-1) { - // Spectator - document.getElementById("client_charselect").style.display = "none"; - } else { - client.sendCharacter(ccharacter); - } + if (ccharacter === -1) { + // Spectator + document.getElementById('client_charselect').style.display = 'none'; + } else { + client.sendCharacter(ccharacter); + } } window.pickChar = pickChar; @@ -3050,20 +3053,19 @@ window.pickChar = pickChar; * @param {string} emo the new emotion to be selected */ export function pickEmotion(emo) { - try { - if (client.selectedEmote !== -1) { - document.getElementById("emo_" + client.selectedEmote).classList="emote_button"; - } - } catch (err) { - // do nothing - } - client.selectedEmote = emo; - document.getElementById("emo_" + emo).classList="emote_button dark"; - - document.getElementById("sendsfx").checked = (client.emote.sfx.length > 1) ? true : false; + try { + if (client.selectedEmote !== -1) { + document.getElementById(`emo_${client.selectedEmote}`).classList = 'emote_button'; + } + } catch (err) { + // do nothing + } + client.selectedEmote = emo; + document.getElementById(`emo_${emo}`).classList = 'emote_button dark'; - document.getElementById("sendpreanim").checked = (client.emote.zoom == 1) ? true : false; + document.getElementById('sendsfx').checked = (client.emote.sfx.length > 1); + document.getElementById('sendpreanim').checked = (client.emote.zoom == 1); } window.pickEmotion = pickEmotion; @@ -3072,35 +3074,35 @@ window.pickEmotion = pickEmotion; * @param {string} evidence the evidence to be presented */ export function pickEvidence(evidenceID) { - const evidence = Number(evidenceID); - if (client.selectedEvidence !== evidence) { - //Update selected evidence - if (client.selectedEvidence > 0) { - document.getElementById("evi_" + client.selectedEvidence).className = "evi_icon"; - } - document.getElementById("evi_" + evidence).className = "evi_icon dark"; - client.selectedEvidence = evidence; - - // Show evidence on information window - document.getElementById("evi_name").value = client.evidences[evidence - 1].name; - document.getElementById("evi_desc").value = client.evidences[evidence - 1].desc; - - // Update icon - const icon_id = getIndexFromSelect("evi_select", client.evidences[evidence - 1].filename); - document.getElementById("evi_select").selectedIndex = icon_id; - if (icon_id === 0) { - document.getElementById("evi_filename").value = client.evidences[evidence - 1].filename; - } - updateEvidenceIcon(); - - // Update button - document.getElementById("evi_add").className = "client_button hover_button inactive"; - document.getElementById("evi_edit").className = "client_button hover_button"; - document.getElementById("evi_cancel").className = "client_button hover_button"; - document.getElementById("evi_del").className = "client_button hover_button"; - } else { - cancelEvidence(); - } + const evidence = Number(evidenceID); + if (client.selectedEvidence !== evidence) { + // Update selected evidence + if (client.selectedEvidence > 0) { + document.getElementById(`evi_${client.selectedEvidence}`).className = 'evi_icon'; + } + document.getElementById(`evi_${evidence}`).className = 'evi_icon dark'; + client.selectedEvidence = evidence; + + // Show evidence on information window + document.getElementById('evi_name').value = client.evidences[evidence - 1].name; + document.getElementById('evi_desc').value = client.evidences[evidence - 1].desc; + + // Update icon + const icon_id = getIndexFromSelect('evi_select', client.evidences[evidence - 1].filename); + document.getElementById('evi_select').selectedIndex = icon_id; + if (icon_id === 0) { + document.getElementById('evi_filename').value = client.evidences[evidence - 1].filename; + } + updateEvidenceIcon(); + + // Update button + document.getElementById('evi_add').className = 'client_button hover_button inactive'; + document.getElementById('evi_edit').className = 'client_button hover_button'; + document.getElementById('evi_cancel').className = 'client_button hover_button'; + document.getElementById('evi_del').className = 'client_button hover_button'; + } else { + cancelEvidence(); + } } window.pickEvidence = pickEvidence; @@ -3108,14 +3110,15 @@ window.pickEvidence = pickEvidence; * Add evidence. */ export function addEvidence() { - const evidence_select = document.getElementById("evi_select"); - client.sendPE(document.getElementById("evi_name").value, - document.getElementById("evi_desc").value, - evidence_select.selectedIndex === 0 ? - document.getElementById("evi_filename").value : - evidence_select.options[evidence_select.selectedIndex].text - ); - cancelEvidence(); + const evidence_select = document.getElementById('evi_select'); + client.sendPE( + document.getElementById('evi_name').value, + document.getElementById('evi_desc').value, + evidence_select.selectedIndex === 0 + ? document.getElementById('evi_filename').value + : evidence_select.options[evidence_select.selectedIndex].text, + ); + cancelEvidence(); } window.addEvidence = addEvidence; @@ -3123,16 +3126,17 @@ window.addEvidence = addEvidence; * Edit selected evidence. */ export function editEvidence() { - const evidence_select = document.getElementById("evi_select"); - const id = parseInt(client.selectedEvidence) - 1; - client.sendEE(id, - document.getElementById("evi_name").value, - document.getElementById("evi_desc").value, - evidence_select.selectedIndex === 0 ? - document.getElementById("evi_filename").value : - evidence_select.options[evidence_select.selectedIndex].text - ); - cancelEvidence(); + const evidence_select = document.getElementById('evi_select'); + const id = parseInt(client.selectedEvidence) - 1; + client.sendEE( + id, + document.getElementById('evi_name').value, + document.getElementById('evi_desc').value, + evidence_select.selectedIndex === 0 + ? document.getElementById('evi_filename').value + : evidence_select.options[evidence_select.selectedIndex].text, + ); + cancelEvidence(); } window.editEvidence = editEvidence; @@ -3140,9 +3144,9 @@ window.editEvidence = editEvidence; * Delete selected evidence. */ export function deleteEvidence() { - const id = parseInt(client.selectedEvidence) - 1; - client.sendDE(id); - cancelEvidence(); + const id = parseInt(client.selectedEvidence) - 1; + client.sendDE(id); + cancelEvidence(); } window.deleteEvidence = deleteEvidence; @@ -3150,25 +3154,25 @@ window.deleteEvidence = deleteEvidence; * Cancel evidence selection. */ export function cancelEvidence() { - //Clear evidence data - if (client.selectedEvidence > 0) { - document.getElementById("evi_" + client.selectedEvidence).className = "evi_icon"; - } - client.selectedEvidence = 0; - - // Clear evidence on information window - document.getElementById("evi_select").selectedIndex = 0; - updateEvidenceIcon(); // Update icon widget - document.getElementById("evi_filename").value = ""; - document.getElementById("evi_name").value = ""; - document.getElementById("evi_desc").value = ""; - document.getElementById("evi_preview").src = AO_HOST + "misc/empty.png"; //Clear icon - - // Update button - document.getElementById("evi_add").className = "client_button hover_button"; - document.getElementById("evi_edit").className = "client_button hover_button inactive"; - document.getElementById("evi_cancel").className = "client_button hover_button inactive"; - document.getElementById("evi_del").className = "client_button hover_button inactive"; + // Clear evidence data + if (client.selectedEvidence > 0) { + document.getElementById(`evi_${client.selectedEvidence}`).className = 'evi_icon'; + } + client.selectedEvidence = 0; + + // Clear evidence on information window + document.getElementById('evi_select').selectedIndex = 0; + updateEvidenceIcon(); // Update icon widget + document.getElementById('evi_filename').value = ''; + document.getElementById('evi_name').value = ''; + document.getElementById('evi_desc').value = ''; + document.getElementById('evi_preview').src = `${AO_HOST}misc/empty.png`; // Clear icon + + // Update button + document.getElementById('evi_add').className = 'client_button hover_button'; + document.getElementById('evi_edit').className = 'client_button hover_button inactive'; + document.getElementById('evi_cancel').className = 'client_button hover_button inactive'; + document.getElementById('evi_del').className = 'client_button hover_button inactive'; } window.cancelEvidence = cancelEvidence; @@ -3178,14 +3182,14 @@ window.cancelEvidence = cancelEvidence; * @param {string} value the value that need to be compared */ export function getIndexFromSelect(select_box, value) { - //Find if icon alraedy existed in select box - const select_element = document.getElementById(select_box); - for (let i = 1; i < select_element.length; ++i) { - if (select_element.options[i].value === value) { - return i; - } - } - return 0; + // Find if icon alraedy existed in select box + const select_element = document.getElementById(select_box); + for (let i = 1; i < select_element.length; ++i) { + if (select_element.options[i].value === value) { + return i; + } + } + return 0; } window.getIndexFromSelect = getIndexFromSelect; @@ -3193,18 +3197,18 @@ window.getIndexFromSelect = getIndexFromSelect; * Set the style of the chatbox */ export function setChatbox(style) { - const chatbox_theme = document.getElementById("chatbox_theme"); - const selected_theme = document.getElementById("client_chatboxselect").value; - setCookie("chatbox", selected_theme); - if(selected_theme === "dynamic") { - if (chatbox_arr.includes(style)) { - chatbox_theme.href = "styles/chatbox/" + style + ".css"; - } else { - chatbox_theme.href = "styles/chatbox/aa.css"; - } - } else { - chatbox_theme.href = "styles/chatbox/" + selected_theme + ".css"; - } + const chatbox_theme = document.getElementById('chatbox_theme'); + const selected_theme = document.getElementById('client_chatboxselect').value; + setCookie('chatbox', selected_theme); + if (selected_theme === 'dynamic') { + if (chatbox_arr.includes(style)) { + chatbox_theme.href = `styles/chatbox/${style}.css`; + } else { + chatbox_theme.href = 'styles/chatbox/aa.css'; + } + } else { + chatbox_theme.href = `styles/chatbox/${selected_theme}.css`; + } } window.setChatbox = setChatbox; @@ -3212,10 +3216,10 @@ window.setChatbox = setChatbox; * Set the font size for the chatbox */ export function resizeChatbox() { - const chatContainerBox = document.getElementById("client_chatcontainer"); - const gameHeight = document.getElementById("client_background").offsetHeight; - - chatContainerBox.style.fontSize = (gameHeight * 0.0521).toFixed(1) + "px"; + const chatContainerBox = document.getElementById('client_chatcontainer'); + const gameHeight = document.getElementById('client_background').offsetHeight; + + chatContainerBox.style.fontSize = `${(gameHeight * 0.0521).toFixed(1)}px`; } window.resizeChatbox = resizeChatbox; @@ -3223,17 +3227,17 @@ window.resizeChatbox = resizeChatbox; * Update evidence icon. */ export function updateEvidenceIcon() { - const evidence_select = document.getElementById("evi_select"); - const evidence_filename = document.getElementById("evi_filename"); - const evidence_iconbox = document.getElementById("evi_preview"); - - if (evidence_select.selectedIndex === 0) { - evidence_filename.style.display = "initial"; - evidence_iconbox.src = AO_HOST + "evidence/" + encodeURI(evidence_filename.value.toLowerCase()); - } else { - evidence_filename.style.display = "none"; - evidence_iconbox.src = AO_HOST + "evidence/" + encodeURI(evidence_select.value.toLowerCase()); - } + const evidence_select = document.getElementById('evi_select'); + const evidence_filename = document.getElementById('evi_filename'); + const evidence_iconbox = document.getElementById('evi_preview'); + + if (evidence_select.selectedIndex === 0) { + evidence_filename.style.display = 'initial'; + evidence_iconbox.src = `${AO_HOST}evidence/${encodeURI(evidence_filename.value.toLowerCase())}`; + } else { + evidence_filename.style.display = 'none'; + evidence_iconbox.src = `${AO_HOST}evidence/${encodeURI(evidence_select.value.toLowerCase())}`; + } } window.updateEvidenceIcon = updateEvidenceIcon; @@ -3241,21 +3245,21 @@ window.updateEvidenceIcon = updateEvidenceIcon; * Update evidence icon. */ export function updateActionCommands(side) { - if (side === "jud") { - document.getElementById("judge_action").style.display = "inline-table"; - document.getElementById("no_action").style.display = "none"; - } else { - document.getElementById("judge_action").style.display = "none"; - document.getElementById("no_action").style.display = "inline-table"; - } - - // Update role selector - for (let i = 0, role_select = document.getElementById("role_select").options; i < role_select.length; i++) { - if (side === role_select[i].value) { - role_select.selectedIndex = i; - return; - } - } + if (side === 'jud') { + document.getElementById('judge_action').style.display = 'inline-table'; + document.getElementById('no_action').style.display = 'none'; + } else { + document.getElementById('judge_action').style.display = 'none'; + document.getElementById('no_action').style.display = 'inline-table'; + } + + // Update role selector + for (let i = 0, role_select = document.getElementById('role_select').options; i < role_select.length; i++) { + if (side === role_select[i].value) { + role_select.selectedIndex = i; + return; + } + } } window.updateActionCommands = updateActionCommands; @@ -3263,21 +3267,18 @@ window.updateActionCommands = updateActionCommands; * Change background via OOC. */ export function changeBackgroundOOC() { - const selectedBG = document.getElementById("bg_select"); - const changeBGCommand = document.getElementById("bg_command").value; - const bgFilename = document.getElementById("bg_filename"); - - let filename = ""; - if (selectedBG.selectedIndex === 0) { - filename = bgFilename.value; - } else { - filename = selectedBG.value; - } - - if (mode==="join") - client.sendOOC("/" + changeBGCommand.replace("$1", filename)); - else if (mode==="replay") - client.sendSelf("BN#" + filename + "#%"); + const selectedBG = document.getElementById('bg_select'); + const changeBGCommand = document.getElementById('bg_command').value; + const bgFilename = document.getElementById('bg_filename'); + + let filename = ''; + if (selectedBG.selectedIndex === 0) { + filename = bgFilename.value; + } else { + filename = selectedBG.value; + } + + if (mode === 'join') { client.sendOOC(`/${changeBGCommand.replace('$1', filename)}`); } else if (mode === 'replay') { client.sendSelf(`BN#${filename}#%`); } } window.changeBackgroundOOC = changeBackgroundOOC; @@ -3285,11 +3286,11 @@ window.changeBackgroundOOC = changeBackgroundOOC; * Change role via OOC. */ export function changeRoleOOC() { - const new_role = document.getElementById("role_select").value; + const new_role = document.getElementById('role_select').value; - client.sendOOC("/pos " + new_role); - client.sendServer("SP#" + new_role + "#%"); - updateActionCommands(new_role); + client.sendOOC(`/pos ${new_role}`); + client.sendServer(`SP#${new_role}#%`); + updateActionCommands(new_role); } window.changeRoleOOC = changeRoleOOC; @@ -3297,7 +3298,7 @@ window.changeRoleOOC = changeRoleOOC; * Random character via OOC. */ export function randomCharacterOOC() { - client.sendOOC("/" + document.getElementById("randomchar_command").value); + client.sendOOC(`/${document.getElementById('randomchar_command').value}`); } window.randomCharacterOOC = randomCharacterOOC; @@ -3305,15 +3306,15 @@ window.randomCharacterOOC = randomCharacterOOC; * Call mod. */ export function callMod() { - let modcall; - if (extrafeatures.includes("modcall_reason")) { - modcall = prompt("Please enter the reason for the modcall", ""); - } - if (modcall == null || modcall === "") { - // cancel - } else { - client.sendZZ(modcall); - } + let modcall; + if (extrafeatures.includes('modcall_reason')) { + modcall = prompt('Please enter the reason for the modcall', ''); + } + if (modcall == null || modcall === '') { + // cancel + } else { + client.sendZZ(modcall); + } } window.callMod = callMod; @@ -3321,7 +3322,7 @@ window.callMod = callMod; * Declare witness testimony. */ export function initWT() { - client.sendRT("testimony1"); + client.sendRT('testimony1'); } window.initWT = initWT; @@ -3329,7 +3330,7 @@ window.initWT = initWT; * Declare cross examination. */ export function initCE() { - client.sendRT("testimony2"); + client.sendRT('testimony2'); } window.initCE = initCE; @@ -3337,7 +3338,7 @@ window.initCE = initCE; * Declare the defendant not guilty */ export function notguilty() { - client.sendRT("judgeruling#0"); + client.sendRT('judgeruling#0'); } window.notguilty = notguilty; @@ -3345,7 +3346,7 @@ window.notguilty = notguilty; * Declare the defendant not guilty */ export function guilty() { - client.sendRT("judgeruling#1"); + client.sendRT('judgeruling#1'); } window.guilty = guilty; @@ -3353,7 +3354,7 @@ window.guilty = guilty; * Increment defense health point. */ export function addHPD() { - client.sendHP(1, String(parseInt(client.hp[0]) + 1)); + client.sendHP(1, String(parseInt(client.hp[0]) + 1)); } window.addHPD = addHPD; @@ -3361,7 +3362,7 @@ window.addHPD = addHPD; * Decrement defense health point. */ export function redHPD() { - client.sendHP(1, String(parseInt(client.hp[0]) - 1)); + client.sendHP(1, String(parseInt(client.hp[0]) - 1)); } window.redHPD = redHPD; @@ -3369,7 +3370,7 @@ window.redHPD = redHPD; * Increment prosecution health point. */ export function addHPP() { - client.sendHP(2, String(parseInt(client.hp[1]) + 1)); + client.sendHP(2, String(parseInt(client.hp[1]) + 1)); } window.addHPP = addHPP; @@ -3377,7 +3378,7 @@ window.addHPP = addHPP; * Decrement prosecution health point. */ export function redHPP() { - client.sendHP(2, String(parseInt(client.hp[1]) - 1)); + client.sendHP(2, String(parseInt(client.hp[1]) - 1)); } window.redHPP = redHPP; @@ -3385,17 +3386,17 @@ window.redHPP = redHPP; * Update background preview. */ export function updateBackgroundPreview() { - const background_select = document.getElementById("bg_select"); - const background_filename = document.getElementById("bg_filename"); - const background_preview = document.getElementById("bg_preview"); - - if (background_select.selectedIndex === 0) { - background_filename.style.display = "initial"; - background_preview.src = AO_HOST + "background/" + encodeURI(background_filename.value.toLowerCase()) + "/defenseempty.png"; - } else { - background_filename.style.display = "none"; - background_preview.src = AO_HOST + "background/" + encodeURI(background_select.value.toLowerCase()) + "/defenseempty.png"; - } + const background_select = document.getElementById('bg_select'); + const background_filename = document.getElementById('bg_filename'); + const background_preview = document.getElementById('bg_preview'); + + if (background_select.selectedIndex === 0) { + background_filename.style.display = 'initial'; + background_preview.src = `${AO_HOST}background/${encodeURI(background_filename.value.toLowerCase())}/defenseempty.png`; + } else { + background_filename.style.display = 'none'; + background_preview.src = `${AO_HOST}background/${encodeURI(background_select.value.toLowerCase())}/defenseempty.png`; + } } window.updateBackgroundPreview = updateBackgroundPreview; @@ -3405,11 +3406,11 @@ window.updateBackgroundPreview = updateBackgroundPreview; * @param {string} effect the new effect to be selected */ export function toggleEffect(button) { - if (button.classList.contains("dark")) { - button.className = "client_button"; - } else { - button.className = "client_button dark"; - } + if (button.classList.contains('dark')) { + button.className = 'client_button'; + } else { + button.className = 'client_button dark'; + } } window.toggleEffect = toggleEffect; @@ -3418,13 +3419,13 @@ window.toggleEffect = toggleEffect; * @param {string} menu the menu to be selected */ export function toggleMenu(menu) { - if (menu !== selectedMenu) { - document.getElementById("menu_" + menu).className = "menu_button active"; - document.getElementById("content_" + menu).className = "menu_content active"; - document.getElementById("menu_" + selectedMenu).className = "menu_button"; - document.getElementById("content_" + selectedMenu).className = "menu_content"; - selectedMenu = menu; - } + if (menu !== selectedMenu) { + document.getElementById(`menu_${menu}`).className = 'menu_button active'; + document.getElementById(`content_${menu}`).className = 'menu_content active'; + document.getElementById(`menu_${selectedMenu}`).className = 'menu_button'; + document.getElementById(`content_${selectedMenu}`).className = 'menu_content'; + selectedMenu = menu; + } } window.toggleMenu = toggleMenu; @@ -3434,15 +3435,15 @@ window.toggleMenu = toggleMenu; * @param {string} shout the new shout to be selected */ export function toggleShout(shout) { - if (shout === selectedShout) { - document.getElementById("button_" + shout).className = "client_button"; - selectedShout = 0; - } else { - document.getElementById("button_" + shout).className = "client_button dark"; - if (selectedShout) { - document.getElementById("button_" + selectedShout).className = "client_button"; - } - selectedShout = shout; - } + if (shout === selectedShout) { + document.getElementById(`button_${shout}`).className = 'client_button'; + selectedShout = 0; + } else { + document.getElementById(`button_${shout}`).className = 'client_button dark'; + if (selectedShout) { + document.getElementById(`button_${selectedShout}`).className = 'client_button'; + } + selectedShout = shout; + } } window.toggleShout = toggleShout; diff --git a/webAO/encoding.js b/webAO/encoding.js index 04a44e7..21b5aa7 100644 --- a/webAO/encoding.js +++ b/webAO/encoding.js @@ -3,11 +3,11 @@ * @param {string} estring the string to be escaped */ export function escapeChat(estring) { - return estring - .replace(/#/g, "<num>") - .replace(/&/g, "<and>") - .replace(/%/g, "<percent>") - .replace(/\$/g, "<dollar>"); + return estring + .replace(/#/g, '<num>') + .replace(/&/g, '<and>') + .replace(/%/g, '<percent>') + .replace(/\$/g, '<dollar>'); } /** @@ -15,27 +15,26 @@ export function escapeChat(estring) { * @param {string} estring the string to be unescaped */ export function unescapeChat(estring) { - return estring - .replace(/<num>/g, "#") - .replace(/<and>/g, "&") - .replace(/<percent>/g, "%") - .replace(/<dollar>/g, "$"); + return estring + .replace(/<num>/g, '#') + .replace(/<and>/g, '&') + .replace(/<percent>/g, '%') + .replace(/<dollar>/g, '$'); } /** * Escapes a string to be HTML-safe. - * + * * XXX: This is unnecessary if we use `createTextNode` instead! * @param {string} unsafe an unsanitized string */ export function safe_tags(unsafe) { - if (unsafe) { - return unsafe - .replace(/>/g, '>') - .replace(/</g, '<'); - } else { - return ""; - } + if (unsafe) { + return unsafe + .replace(/>/g, '>') + .replace(/</g, '<'); + } + return ''; } /** @@ -43,24 +42,21 @@ export function safe_tags(unsafe) { * @param {string} estring the string to be encoded */ export function encodeChat(estring) { - const selectedEncoding = document.getElementById("client_encoding").value; - if (selectedEncoding === "unicode") { - // This approach works by escaping all special characters to Unicode escape sequences. - // Source: https://gist.github.com/mathiasbynens/1243213 - return estring.replace(/[^\0-~]/g, function (ch) { - return "\\u" + ("000" + ch.charCodeAt().toString(16)).slice(-4); - }); - } else if (selectedEncoding === "utf16") { - // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String - const buffer = new ArrayBuffer(estring.length * 2); - const result = new Uint16Array(buffer); - for (let i = 0, strLen = estring.length; i < strLen; i++) { - result[i] = estring.charCodeAt(i); - } - return String(result); - } else { - return estring; - } + const selectedEncoding = document.getElementById('client_encoding').value; + if (selectedEncoding === 'unicode') { + // This approach works by escaping all special characters to Unicode escape sequences. + // Source: https://gist.github.com/mathiasbynens/1243213 + return estring.replace(/[^\0-~]/g, (ch) => `\\u${(`000${ch.charCodeAt().toString(16)}`).slice(-4)}`); + } if (selectedEncoding === 'utf16') { + // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String + const buffer = new ArrayBuffer(estring.length * 2); + const result = new Uint16Array(buffer); + for (let i = 0, strLen = estring.length; i < strLen; i++) { + result[i] = estring.charCodeAt(i); + } + return String(result); + } + return estring; } /** @@ -68,25 +64,22 @@ export function encodeChat(estring) { * @param {string} estring the string to be decoded */ export function decodeChat(estring) { - const selectedDecoding = document.getElementById("client_decoding").value; - if (selectedDecoding === "unicode") { - // Source: https://stackoverflow.com/questions/7885096/how-do-i-decode-a-string-with-escaped-unicode - return estring.replace(/\\u([\d\w]{1,})/gi, function (match, group) { - return String.fromCharCode(parseInt(group, 16)); - }); - } else if (selectedDecoding === "utf16") { - // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String - return String.fromCharCode.apply(null, new Uint16Array(estring.split(","))); - } else { - return estring; - } + const selectedDecoding = document.getElementById('client_decoding').value; + if (selectedDecoding === 'unicode') { + // Source: https://stackoverflow.com/questions/7885096/how-do-i-decode-a-string-with-escaped-unicode + return estring.replace(/\\u([\d\w]{1,})/gi, (match, group) => String.fromCharCode(parseInt(group, 16))); + } if (selectedDecoding === 'utf16') { + // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String + return String.fromCharCode.apply(null, new Uint16Array(estring.split(','))); + } + return estring; } /** * XXX: a nasty hack made by gameboyprinter. - * @param {string} msg chat message to prepare for display + * @param {string} msg chat message to prepare for display */ export function prepChat(msg) { - // TODO: make this less awful - return unescapeChat(decodeChat(msg)); -}
\ No newline at end of file + // TODO: make this less awful + return unescapeChat(decodeChat(msg)); +} diff --git a/webAO/evidence.js b/webAO/evidence.js index 99896c8..900455e 100644 --- a/webAO/evidence.js +++ b/webAO/evidence.js @@ -1,10 +1,10 @@ export default [ - "1.png", - "2.png", - "3.png", - "4.png", - "5.png", - "6.png", - "empty.png", - "lawyerbadge.png" -];
\ No newline at end of file + '1.png', + '2.png', + '3.png', + '4.png', + '5.png', + '6.png', + 'empty.png', + 'lawyerbadge.png', +]; diff --git a/webAO/lib/gify.min.js b/webAO/lib/gify.min.js index 8656d4a..7afe02c 100644 --- a/webAO/lib/gify.min.js +++ b/webAO/lib/gify.min.js @@ -1 +1,11 @@ -var gify=function(){"use strict";function t(t){return 3*Math.pow(2,1+a(t.slice(5,8)))}function e(t){for(var e=[],i=7;i>=0;i--)e.push(t&1<<i?1:0);return e}function i(t){return t/100*1e3}function a(t){return t.reduce(function(t,e){return 2*t+e},0)}function r(t,e,i){for(var a={data:"",size:0};;){var r=t.getUint8(e+a.size,!0);if(0===r){a.size++;break}i&&(a.data+=t.getString(r,e+a.size+1)),a.size+=r+1}return a}function n(){return{identifier:"0",localPalette:!1,localPaletteSize:0,interlace:!1,comments:[],text:"",left:0,top:0,width:0,height:0,delay:0,disposal:0}}function o(a,o){var u=0,g=0,s={valid:!1,globalPalette:!1,globalPaletteSize:0,globalPaletteColorsRGB:[],loopCount:0,height:0,width:0,animated:!1,images:[],isBrowserDuration:!1,duration:0,durationIE:0,durationSafari:0,durationFirefox:0,durationChrome:0,durationOpera:0},d=new jDataView(a);if(a.byteLength<10)return s;if(18249!=d.getUint16(0)||17976!=d.getUint16(2))return s;s.width=d.getUint16(6,!0),s.height=d.getUint16(8,!0),s.valid=!0;var f=e(d.getUint8(10,!0));if(f[0]){var c=t(f);s.globalPalette=!0,s.globalPaletteSize=c/3,u+=c;for(var h=0;h<s.globalPaletteSize;h++){var v=13+3*h,U=d.getUint8(v,!0),b=d.getUint8(v+1,!0),m=d.getUint8(v+2,!0);s.globalPaletteColorsRGB.push({r:U,g:b,b:m})}}u+=13;for(var p=n();;){try{var w=d.getUint8(u,!0);switch(w){case 33:var z=d.getUint8(u+1,!0);if(249===z){var P=d.getUint8(u+2);if(4===P){var S=i(d.getUint16(u+4,!0));60>S&&!s.isBrowserDuration&&(s.isBrowserDuration=!0),p.delay=S,s.duration+=S,s.durationIE+=60>S?l:S,s.durationSafari+=20>S?l:S,s.durationChrome+=20>S?l:S,s.durationFirefox+=20>S?l:S,s.durationOpera+=20>S?l:S;var f=e(d.getUint8(u+3)),C=f.slice(3,6).join("");p.disposal=parseInt(C,2),u+=8}else u++}else{u+=2;var k=r(d,u,!0);switch(z){case 255:var y=d.getString(8,u+1);"NETSCAPE"===y&&(s.loopCount=d.getUint8(u+14,!0));break;case 206:p.identifier=k.data;break;case 254:p.comments.push(k.data);break;case 1:p.text=k.data}u+=k.size}break;case 44:p.left=d.getUint16(u+1,!0),p.top=d.getUint16(u+3,!0),p.width=d.getUint16(u+5,!0),p.height=d.getUint16(u+7,!0);var f=e(d.getUint8(u+9,!0));if(f[0]){var B=t(f);p.localPalette=!0,p.localPaletteSize=B/3,u+=B}if(f[1]&&(p.interlace=!0),s.images.push(p),g++,p=n(),p.identifier=g.toString(),s.images.length>1&&!s.animated&&(s.animated=!0,o))return s;u+=11;var k=r(d,u,!1);u+=k.size;break;case 59:return s;default:u++}}catch(x){return s.valid=!1,s}if(u>=a.byteLength)return s}return s}var l=100;return{isAnimated:function(t){var e=o(t,!0);return e.animated},getInfo:function(t){return o(t,!1)}}}();
\ No newline at end of file +const gify = (function () { + function t(t) { return 3 * 2 ** (1 + a(t.slice(5, 8))); } function e(t) { for (var e = [], i = 7; i >= 0; i--)e.push(t & 1 << i ? 1 : 0); return e; } function i(t) { return t / 100 * 1e3; } function a(t) { return t.reduce((t, e) => 2 * t + e, 0); } function r(t, e, i) { for (var a = { data: '', size: 0 }; ;) { const r = t.getUint8(e + a.size, !0); if (r === 0) { a.size++; break; }i && (a.data += t.getString(r, e + a.size + 1)), a.size += r + 1; } return a; } function n() { + return { + identifier: '0', localPalette: !1, localPaletteSize: 0, interlace: !1, comments: [], text: '', left: 0, top: 0, width: 0, height: 0, delay: 0, disposal: 0, + }; + } function o(a, o) { + let u = 0; let g = 0; const s = { + valid: !1, globalPalette: !1, globalPaletteSize: 0, globalPaletteColorsRGB: [], loopCount: 0, height: 0, width: 0, animated: !1, images: [], isBrowserDuration: !1, duration: 0, durationIE: 0, durationSafari: 0, durationFirefox: 0, durationChrome: 0, durationOpera: 0, + }; const d = new jDataView(a); if (a.byteLength < 10) return s; if (d.getUint16(0) != 18249 || d.getUint16(2) != 17976) return s; s.width = d.getUint16(6, !0), s.height = d.getUint16(8, !0), s.valid = !0; var f = e(d.getUint8(10, !0)); if (f[0]) { const c = t(f); s.globalPalette = !0, s.globalPaletteSize = c / 3, u += c; for (let h = 0; h < s.globalPaletteSize; h++) { const v = 13 + 3 * h; const U = d.getUint8(v, !0); const b = d.getUint8(v + 1, !0); const m = d.getUint8(v + 2, !0); s.globalPaletteColorsRGB.push({ r: U, g: b, b: m }); } }u += 13; for (let p = n(); ;) { try { const w = d.getUint8(u, !0); switch (w) { case 33: var z = d.getUint8(u + 1, !0); if (z === 249) { const P = d.getUint8(u + 2); if (P === 4) { const S = i(d.getUint16(u + 4, !0)); S < 60 && !s.isBrowserDuration && (s.isBrowserDuration = !0), p.delay = S, s.duration += S, s.durationIE += S < 60 ? l : S, s.durationSafari += S < 20 ? l : S, s.durationChrome += S < 20 ? l : S, s.durationFirefox += S < 20 ? l : S, s.durationOpera += S < 20 ? l : S; var f = e(d.getUint8(u + 3)); const C = f.slice(3, 6).join(''); p.disposal = parseInt(C, 2), u += 8; } else u++; } else { u += 2; var k = r(d, u, !0); switch (z) { case 255: var y = d.getString(8, u + 1); y === 'NETSCAPE' && (s.loopCount = d.getUint8(u + 14, !0)); break; case 206: p.identifier = k.data; break; case 254: p.comments.push(k.data); break; case 1: p.text = k.data; }u += k.size; } break; case 44: p.left = d.getUint16(u + 1, !0), p.top = d.getUint16(u + 3, !0), p.width = d.getUint16(u + 5, !0), p.height = d.getUint16(u + 7, !0); var f = e(d.getUint8(u + 9, !0)); if (f[0]) { const B = t(f); p.localPalette = !0, p.localPaletteSize = B / 3, u += B; } if (f[1] && (p.interlace = !0), s.images.push(p), g++, p = n(), p.identifier = g.toString(), s.images.length > 1 && !s.animated && (s.animated = !0, o)) return s; u += 11; var k = r(d, u, !1); u += k.size; break; case 59: return s; default: u++; } } catch (x) { return s.valid = !1, s; } if (u >= a.byteLength) return s; } return s; + } var l = 100; return { isAnimated(t) { const e = o(t, !0); return e.animated; }, getInfo(t) { return o(t, !1); } }; +}()); diff --git a/webAO/lib/jdataview.min.js b/webAO/lib/jdataview.min.js index 38e31b9..86f8794 100644 --- a/webAO/lib/jdataview.min.js +++ b/webAO/lib/jdataview.min.js @@ -1,50 +1,118 @@ -(function(global){var compatibility={ArrayBuffer:typeof ArrayBuffer!=='undefined',DataView:typeof DataView!=='undefined'&&('getFloat64'in DataView.prototype||'getFloat64'in new DataView(new ArrayBuffer(1))),NodeBuffer:typeof Buffer!=='undefined'&&'readInt16LE'in Buffer.prototype};var dataTypes={'Int8':1,'Int16':2,'Int32':4,'Uint8':1,'Uint16':2,'Uint32':4,'Float32':4,'Float64':8};var nodeNaming={'Int8':'Int8','Int16':'Int16','Int32':'Int32','Uint8':'UInt8','Uint16':'UInt16','Uint32':'UInt32','Float32':'Float','Float64':'Double'};var jDataView=function(buffer,byteOffset,byteLength,littleEndian){if(!(this instanceof jDataView)){throw new Error("jDataView constructor may not be called as a function");} -this.buffer=buffer;if(!(compatibility.NodeBuffer&&buffer instanceof Buffer)&&!(compatibility.ArrayBuffer&&buffer instanceof ArrayBuffer)&&typeof buffer!=='string'){throw new TypeError('jDataView buffer has an incompatible type');} -this._isArrayBuffer=compatibility.ArrayBuffer&&buffer instanceof ArrayBuffer;this._isDataView=compatibility.DataView&&this._isArrayBuffer;this._isNodeBuffer=compatibility.NodeBuffer&&buffer instanceof Buffer;this._littleEndian=littleEndian===undefined?false:littleEndian;var bufferLength=this._isArrayBuffer?buffer.byteLength:buffer.length;if(byteOffset===undefined){byteOffset=0;} -this.byteOffset=byteOffset;if(byteLength===undefined){byteLength=bufferLength-byteOffset;} -this.byteLength=byteLength;if(!this._isDataView){if(typeof byteOffset!=='number'){throw new TypeError('jDataView byteOffset is not a number');} -if(typeof byteLength!=='number'){throw new TypeError('jDataView byteLength is not a number');} -if(byteOffset<0){throw new Error('jDataView byteOffset is negative');} -if(byteLength<0){throw new Error('jDataView byteLength is negative');}} -if(this._isDataView){this._view=new DataView(buffer,byteOffset,byteLength);this._start=0;} -this._start=byteOffset;if(byteOffset+byteLength>bufferLength){throw new Error("jDataView (byteOffset + byteLength) value is out of bounds");} -this._offset=0;if(this._isDataView){for(var type in dataTypes){if(!dataTypes.hasOwnProperty(type)){continue;} -(function(type,view){var size=dataTypes[type];view['get'+type]=function(byteOffset,littleEndian){if(littleEndian===undefined){littleEndian=view._littleEndian;} -if(byteOffset===undefined){byteOffset=view._offset;} -view._offset=byteOffset+size;return view._view['get'+type](byteOffset,littleEndian);}})(type,this);}}else if(this._isNodeBuffer&&compatibility.NodeBuffer){for(var type in dataTypes){if(!dataTypes.hasOwnProperty(type)){continue;} -var name;if(type==='Int8'||type==='Uint8'){name='read'+nodeNaming[type];}else if(littleEndian){name='read'+nodeNaming[type]+'LE';}else{name='read'+nodeNaming[type]+'BE';} -(function(type,view,name){var size=dataTypes[type];view['get'+type]=function(byteOffset,littleEndian){if(littleEndian===undefined){littleEndian=view._littleEndian;} -if(byteOffset===undefined){byteOffset=view._offset;} -view._offset=byteOffset+size;return view.buffer[name](view._start+byteOffset);}})(type,this,name);}}else{for(var type in dataTypes){if(!dataTypes.hasOwnProperty(type)){continue;} -(function(type,view){var size=dataTypes[type];view['get'+type]=function(byteOffset,littleEndian){if(littleEndian===undefined){littleEndian=view._littleEndian;} -if(byteOffset===undefined){byteOffset=view._offset;} -view._offset=byteOffset+size;if(view._isArrayBuffer&&(view._start+byteOffset)%size===0&&(size===1||littleEndian)){return new global[type+'Array'](view.buffer,view._start+byteOffset,1)[0];}else{if(typeof byteOffset!=='number'){throw new TypeError('jDataView byteOffset is not a number');} -if(byteOffset+size>view.byteLength){throw new Error('jDataView (byteOffset + size) value is out of bounds');} -return view['_get'+type](view._start+byteOffset,littleEndian);}}})(type,this);}}};if(compatibility.NodeBuffer){jDataView.createBuffer=function(){var buffer=new Buffer(arguments.length);for(var i=0;i<arguments.length;++i){buffer[i]=arguments[i];} -return buffer;}}else if(compatibility.ArrayBuffer){jDataView.createBuffer=function(){var buffer=new ArrayBuffer(arguments.length);var view=new Int8Array(buffer);for(var i=0;i<arguments.length;++i){view[i]=arguments[i];} -return buffer;}}else{jDataView.createBuffer=function(){return String.fromCharCode.apply(null,arguments);}} -jDataView.prototype={compatibility:compatibility,getString:function(length,byteOffset){var value;if(byteOffset===undefined){byteOffset=this._offset;} -if(typeof byteOffset!=='number'){throw new TypeError('jDataView byteOffset is not a number');} -if(length<0||byteOffset+length>this.byteLength){throw new Error('jDataView length or (byteOffset+length) value is out of bounds');} -if(this._isNodeBuffer){value=this.buffer.toString('ascii',this._start+byteOffset,this._start+byteOffset+length);} -else{value='';for(var i=0;i<length;++i){var char=this.getUint8(byteOffset+i);value+=String.fromCharCode(char>127?65533:char);}} -this._offset=byteOffset+length;return value;},getChar:function(byteOffset){return this.getString(1,byteOffset);},tell:function(){return this._offset;},seek:function(byteOffset){if(typeof byteOffset!=='number'){throw new TypeError('jDataView byteOffset is not a number');} -if(byteOffset<0||byteOffset>this.byteLength){throw new Error('jDataView byteOffset value is out of bounds');} -return this._offset=byteOffset;},_endianness:function(byteOffset,pos,max,littleEndian){return byteOffset+(littleEndian?max-pos-1:pos);},_getFloat64:function(byteOffset,littleEndian){var b0=this._getUint8(this._endianness(byteOffset,0,8,littleEndian)),b1=this._getUint8(this._endianness(byteOffset,1,8,littleEndian)),b2=this._getUint8(this._endianness(byteOffset,2,8,littleEndian)),b3=this._getUint8(this._endianness(byteOffset,3,8,littleEndian)),b4=this._getUint8(this._endianness(byteOffset,4,8,littleEndian)),b5=this._getUint8(this._endianness(byteOffset,5,8,littleEndian)),b6=this._getUint8(this._endianness(byteOffset,6,8,littleEndian)),b7=this._getUint8(this._endianness(byteOffset,7,8,littleEndian)),sign=1-(2*(b0>>7)),exponent=((((b0<<1)&0xff)<<3)|(b1>>4))-(Math.pow(2,10)-1),mantissa=((b1&0x0f)*Math.pow(2,48))+(b2*Math.pow(2,40))+(b3*Math.pow(2,32))+ -(b4*Math.pow(2,24))+(b5*Math.pow(2,16))+(b6*Math.pow(2,8))+b7;if(exponent===1024){if(mantissa!==0){return NaN;}else{return sign*Infinity;}} -if(exponent===-1023){return sign*mantissa*Math.pow(2,-1022-52);} -return sign*(1+mantissa*Math.pow(2,-52))*Math.pow(2,exponent);},_getFloat32:function(byteOffset,littleEndian){var b0=this._getUint8(this._endianness(byteOffset,0,4,littleEndian)),b1=this._getUint8(this._endianness(byteOffset,1,4,littleEndian)),b2=this._getUint8(this._endianness(byteOffset,2,4,littleEndian)),b3=this._getUint8(this._endianness(byteOffset,3,4,littleEndian)),sign=1-(2*(b0>>7)),exponent=(((b0<<1)&0xff)|(b1>>7))-127,mantissa=((b1&0x7f)<<16)|(b2<<8)|b3;if(exponent===128){if(mantissa!==0){return NaN;}else{return sign*Infinity;}} -if(exponent===-127){return sign*mantissa*Math.pow(2,-126-23);} -return sign*(1+mantissa*Math.pow(2,-23))*Math.pow(2,exponent);},_getInt32:function(byteOffset,littleEndian){var b=this._getUint32(byteOffset,littleEndian);return b>Math.pow(2,31)-1?b-Math.pow(2,32):b;},_getUint32:function(byteOffset,littleEndian){var b3=this._getUint8(this._endianness(byteOffset,0,4,littleEndian)),b2=this._getUint8(this._endianness(byteOffset,1,4,littleEndian)),b1=this._getUint8(this._endianness(byteOffset,2,4,littleEndian)),b0=this._getUint8(this._endianness(byteOffset,3,4,littleEndian));return(b3*Math.pow(2,24))+(b2<<16)+(b1<<8)+b0;},_getInt16:function(byteOffset,littleEndian){var b=this._getUint16(byteOffset,littleEndian);return b>Math.pow(2,15)-1?b-Math.pow(2,16):b;},_getUint16:function(byteOffset,littleEndian){var b1=this._getUint8(this._endianness(byteOffset,0,2,littleEndian)),b0=this._getUint8(this._endianness(byteOffset,1,2,littleEndian));return(b1<<8)+b0;},_getInt8:function(byteOffset){var b=this._getUint8(byteOffset);return b>Math.pow(2,7)-1?b-Math.pow(2,8):b;},_getUint8:function(byteOffset){if(this._isArrayBuffer){return new Uint8Array(this.buffer,byteOffset,1)[0];} -else if(this._isNodeBuffer){return this.buffer[byteOffset];}else{return this.buffer.charCodeAt(byteOffset)&0xff;}}};if(typeof jQuery!=='undefined'&&jQuery.fn.jquery>="1.6.2"){var convertResponseBodyToText=function(byteArray){var scrambledStr;try{scrambledStr=IEBinaryToArray_ByteStr(byteArray);}catch(e){var IEBinaryToArray_ByteStr_Script="Function IEBinaryToArray_ByteStr(Binary)\r\n"+" IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+"End Function\r\n"+"Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+" Dim lastIndex\r\n"+" lastIndex = LenB(Binary)\r\n"+" if lastIndex mod 2 Then\r\n"+" IEBinaryToArray_ByteStr_Last = AscB( MidB( Binary, lastIndex, 1 ) )\r\n"+" Else\r\n"+" IEBinaryToArray_ByteStr_Last = -1\r\n"+" End If\r\n"+"End Function\r\n";window.execScript(IEBinaryToArray_ByteStr_Script,'vbscript');scrambledStr=IEBinaryToArray_ByteStr(byteArray);} -var lastChr=IEBinaryToArray_ByteStr_Last(byteArray),result="",i=0,l=scrambledStr.length%8,thischar;while(i<l){thischar=scrambledStr.charCodeAt(i++);result+=String.fromCharCode(thischar&0xff,thischar>>8);} -l=scrambledStr.length -while(i<l){result+=String.fromCharCode((thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8,(thischar=scrambledStr.charCodeAt(i++),thischar&0xff),thischar>>8);} -if(lastChr>-1){result+=String.fromCharCode(lastChr);} -return result;};jQuery.ajaxSetup({converters:{'* dataview':function(data){return new jDataView(data);}},accepts:{dataview:"text/plain; charset=x-user-defined"},responseHandler:{dataview:function(responses,options,xhr){if('mozResponseArrayBuffer'in xhr){responses.text=xhr.mozResponseArrayBuffer;} -else if('responseType'in xhr&&xhr.responseType==='arraybuffer'&&xhr.response){responses.text=xhr.response;} -else if('responseBody'in xhr){responses.text=convertResponseBodyToText(xhr.responseBody);} -else{responses.text=xhr.responseText;}}}});jQuery.ajaxPrefilter('dataview',function(options,originalOptions,jqXHR){if(jQuery.support.ajaxResponseType){if(!options.hasOwnProperty('xhrFields')){options.xhrFields={};} -options.xhrFields.responseType='arraybuffer';} -options.mimeType='text/plain; charset=x-user-defined';});} -global.jDataView=(global.module||{}).exports=jDataView;if(typeof module!=='undefined'){module.exports=jDataView;}})(this);
\ No newline at end of file +(function (global) { + const compatibility = { ArrayBuffer: typeof ArrayBuffer !== 'undefined', DataView: typeof DataView !== 'undefined' && ('getFloat64' in DataView.prototype || 'getFloat64' in new DataView(new ArrayBuffer(1))), NodeBuffer: typeof Buffer !== 'undefined' && 'readInt16LE' in Buffer.prototype }; const dataTypes = { + Int8: 1, Int16: 2, Int32: 4, Uint8: 1, Uint16: 2, Uint32: 4, Float32: 4, Float64: 8, + }; const nodeNaming = { + Int8: 'Int8', Int16: 'Int16', Int32: 'Int32', Uint8: 'UInt8', Uint16: 'UInt16', Uint32: 'UInt32', Float32: 'Float', Float64: 'Double', + }; var jDataView = function (buffer, byteOffset, byteLength, littleEndian) { + if (!(this instanceof jDataView)) { throw new Error('jDataView constructor may not be called as a function'); } + this.buffer = buffer; if (!(compatibility.NodeBuffer && buffer instanceof Buffer) && !(compatibility.ArrayBuffer && buffer instanceof ArrayBuffer) && typeof buffer !== 'string') { throw new TypeError('jDataView buffer has an incompatible type'); } + this._isArrayBuffer = compatibility.ArrayBuffer && buffer instanceof ArrayBuffer; this._isDataView = compatibility.DataView && this._isArrayBuffer; this._isNodeBuffer = compatibility.NodeBuffer && buffer instanceof Buffer; this._littleEndian = littleEndian === undefined ? false : littleEndian; const bufferLength = this._isArrayBuffer ? buffer.byteLength : buffer.length; if (byteOffset === undefined) { byteOffset = 0; } + this.byteOffset = byteOffset; if (byteLength === undefined) { byteLength = bufferLength - byteOffset; } + this.byteLength = byteLength; if (!this._isDataView) { + if (typeof byteOffset !== 'number') { throw new TypeError('jDataView byteOffset is not a number'); } + if (typeof byteLength !== 'number') { throw new TypeError('jDataView byteLength is not a number'); } + if (byteOffset < 0) { throw new Error('jDataView byteOffset is negative'); } + if (byteLength < 0) { throw new Error('jDataView byteLength is negative'); } + } + if (this._isDataView) { this._view = new DataView(buffer, byteOffset, byteLength); this._start = 0; } + this._start = byteOffset; if (byteOffset + byteLength > bufferLength) { throw new Error('jDataView (byteOffset + byteLength) value is out of bounds'); } + this._offset = 0; if (this._isDataView) { + for (var type in dataTypes) { + if (!dataTypes.hasOwnProperty(type)) { continue; } + (function (type, view) { + const size = dataTypes[type]; view[`get${type}`] = function (byteOffset, littleEndian) { + if (littleEndian === undefined) { littleEndian = view._littleEndian; } + if (byteOffset === undefined) { byteOffset = view._offset; } + view._offset = byteOffset + size; return view._view[`get${type}`](byteOffset, littleEndian); + }; + }(type, this)); + } + } else if (this._isNodeBuffer && compatibility.NodeBuffer) { + for (var type in dataTypes) { + if (!dataTypes.hasOwnProperty(type)) { continue; } + var name; if (type === 'Int8' || type === 'Uint8') { name = `read${nodeNaming[type]}`; } else if (littleEndian) { name = `read${nodeNaming[type]}LE`; } else { name = `read${nodeNaming[type]}BE`; } + (function (type, view, name) { + const size = dataTypes[type]; view[`get${type}`] = function (byteOffset, littleEndian) { + if (littleEndian === undefined) { littleEndian = view._littleEndian; } + if (byteOffset === undefined) { byteOffset = view._offset; } + view._offset = byteOffset + size; return view.buffer[name](view._start + byteOffset); + }; + }(type, this, name)); + } + } else { + for (var type in dataTypes) { + if (!dataTypes.hasOwnProperty(type)) { continue; } + (function (type, view) { + const size = dataTypes[type]; view[`get${type}`] = function (byteOffset, littleEndian) { + if (littleEndian === undefined) { littleEndian = view._littleEndian; } + if (byteOffset === undefined) { byteOffset = view._offset; } + view._offset = byteOffset + size; if (view._isArrayBuffer && (view._start + byteOffset) % size === 0 && (size === 1 || littleEndian)) { return new global[`${type}Array`](view.buffer, view._start + byteOffset, 1)[0]; } if (typeof byteOffset !== 'number') { throw new TypeError('jDataView byteOffset is not a number'); } + if (byteOffset + size > view.byteLength) { throw new Error('jDataView (byteOffset + size) value is out of bounds'); } + return view[`_get${type}`](view._start + byteOffset, littleEndian); + }; + }(type, this)); + } + } + }; if (compatibility.NodeBuffer) { + jDataView.createBuffer = function () { + const buffer = new Buffer(arguments.length); for (let i = 0; i < arguments.length; ++i) { buffer[i] = arguments[i]; } + return buffer; + }; + } else if (compatibility.ArrayBuffer) { + jDataView.createBuffer = function () { + const buffer = new ArrayBuffer(arguments.length); const view = new Int8Array(buffer); for (let i = 0; i < arguments.length; ++i) { view[i] = arguments[i]; } + return buffer; + }; + } else { jDataView.createBuffer = function () { return String.fromCharCode.apply(null, arguments); }; } + jDataView.prototype = { + compatibility, + getString(length, byteOffset) { + let value; if (byteOffset === undefined) { byteOffset = this._offset; } + if (typeof byteOffset !== 'number') { throw new TypeError('jDataView byteOffset is not a number'); } + if (length < 0 || byteOffset + length > this.byteLength) { throw new Error('jDataView length or (byteOffset+length) value is out of bounds'); } + if (this._isNodeBuffer) { value = this.buffer.toString('ascii', this._start + byteOffset, this._start + byteOffset + length); } else { value = ''; for (let i = 0; i < length; ++i) { const char = this.getUint8(byteOffset + i); value += String.fromCharCode(char > 127 ? 65533 : char); } } + this._offset = byteOffset + length; return value; + }, + getChar(byteOffset) { return this.getString(1, byteOffset); }, + tell() { return this._offset; }, + seek(byteOffset) { + if (typeof byteOffset !== 'number') { throw new TypeError('jDataView byteOffset is not a number'); } + if (byteOffset < 0 || byteOffset > this.byteLength) { throw new Error('jDataView byteOffset value is out of bounds'); } + return this._offset = byteOffset; + }, + _endianness(byteOffset, pos, max, littleEndian) { return byteOffset + (littleEndian ? max - pos - 1 : pos); }, + _getFloat64(byteOffset, littleEndian) { + const b0 = this._getUint8(this._endianness(byteOffset, 0, 8, littleEndian)); const b1 = this._getUint8(this._endianness(byteOffset, 1, 8, littleEndian)); const b2 = this._getUint8(this._endianness(byteOffset, 2, 8, littleEndian)); const b3 = this._getUint8(this._endianness(byteOffset, 3, 8, littleEndian)); const b4 = this._getUint8(this._endianness(byteOffset, 4, 8, littleEndian)); const b5 = this._getUint8(this._endianness(byteOffset, 5, 8, littleEndian)); const b6 = this._getUint8(this._endianness(byteOffset, 6, 8, littleEndian)); const b7 = this._getUint8(this._endianness(byteOffset, 7, 8, littleEndian)); const sign = 1 - (2 * (b0 >> 7)); const exponent = ((((b0 << 1) & 0xff) << 3) | (b1 >> 4)) - (2 ** 10 - 1); const mantissa = ((b1 & 0x0f) * 2 ** 48) + (b2 * 2 ** 40) + (b3 * 2 ** 32) ++ (b4 * 2 ** 24) + (b5 * 2 ** 16) + (b6 * 2 ** 8) + b7; if (exponent === 1024) { if (mantissa !== 0) { return NaN; } return sign * Infinity; } + if (exponent === -1023) { return sign * mantissa * 2 ** (-1022 - 52); } + return sign * (1 + mantissa * 2 ** -52) * 2 ** exponent; + }, + _getFloat32(byteOffset, littleEndian) { + const b0 = this._getUint8(this._endianness(byteOffset, 0, 4, littleEndian)); const b1 = this._getUint8(this._endianness(byteOffset, 1, 4, littleEndian)); const b2 = this._getUint8(this._endianness(byteOffset, 2, 4, littleEndian)); const b3 = this._getUint8(this._endianness(byteOffset, 3, 4, littleEndian)); const sign = 1 - (2 * (b0 >> 7)); const exponent = (((b0 << 1) & 0xff) | (b1 >> 7)) - 127; const mantissa = ((b1 & 0x7f) << 16) | (b2 << 8) | b3; if (exponent === 128) { if (mantissa !== 0) { return NaN; } return sign * Infinity; } + if (exponent === -127) { return sign * mantissa * 2 ** (-126 - 23); } + return sign * (1 + mantissa * 2 ** -23) * 2 ** exponent; + }, + _getInt32(byteOffset, littleEndian) { const b = this._getUint32(byteOffset, littleEndian); return b > 2 ** 31 - 1 ? b - 2 ** 32 : b; }, + _getUint32(byteOffset, littleEndian) { const b3 = this._getUint8(this._endianness(byteOffset, 0, 4, littleEndian)); const b2 = this._getUint8(this._endianness(byteOffset, 1, 4, littleEndian)); const b1 = this._getUint8(this._endianness(byteOffset, 2, 4, littleEndian)); const b0 = this._getUint8(this._endianness(byteOffset, 3, 4, littleEndian)); return (b3 * 2 ** 24) + (b2 << 16) + (b1 << 8) + b0; }, + _getInt16(byteOffset, littleEndian) { const b = this._getUint16(byteOffset, littleEndian); return b > 2 ** 15 - 1 ? b - 2 ** 16 : b; }, + _getUint16(byteOffset, littleEndian) { const b1 = this._getUint8(this._endianness(byteOffset, 0, 2, littleEndian)); const b0 = this._getUint8(this._endianness(byteOffset, 1, 2, littleEndian)); return (b1 << 8) + b0; }, + _getInt8(byteOffset) { const b = this._getUint8(byteOffset); return b > 2 ** 7 - 1 ? b - 2 ** 8 : b; }, + _getUint8(byteOffset) { if (this._isArrayBuffer) { return new Uint8Array(this.buffer, byteOffset, 1)[0]; } if (this._isNodeBuffer) { return this.buffer[byteOffset]; } return this.buffer.charCodeAt(byteOffset) & 0xff; }, + }; if (typeof jQuery !== 'undefined' && jQuery.fn.jquery >= '1.6.2') { + const convertResponseBodyToText = function (byteArray) { + let scrambledStr; try { scrambledStr = IEBinaryToArray_ByteStr(byteArray); } catch (e) { const IEBinaryToArray_ByteStr_Script = 'Function IEBinaryToArray_ByteStr(Binary)\r\n' + ' IEBinaryToArray_ByteStr = CStr(Binary)\r\n' + 'End Function\r\n' + 'Function IEBinaryToArray_ByteStr_Last(Binary)\r\n' + ' Dim lastIndex\r\n' + ' lastIndex = LenB(Binary)\r\n' + ' if lastIndex mod 2 Then\r\n' + ' IEBinaryToArray_ByteStr_Last = AscB( MidB( Binary, lastIndex, 1 ) )\r\n' + ' Else\r\n' + ' IEBinaryToArray_ByteStr_Last = -1\r\n' + ' End If\r\n' + 'End Function\r\n'; window.execScript(IEBinaryToArray_ByteStr_Script, 'vbscript'); scrambledStr = IEBinaryToArray_ByteStr(byteArray); } + const lastChr = IEBinaryToArray_ByteStr_Last(byteArray); let result = ''; let i = 0; let l = scrambledStr.length % 8; let thischar; while (i < l) { thischar = scrambledStr.charCodeAt(i++); result += String.fromCharCode(thischar & 0xff, thischar >> 8); } + l = scrambledStr.length; + while (i < l) { result += String.fromCharCode((thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8, (thischar = scrambledStr.charCodeAt(i++), thischar & 0xff), thischar >> 8); } + if (lastChr > -1) { result += String.fromCharCode(lastChr); } + return result; + }; jQuery.ajaxSetup({ converters: { '* dataview': function (data) { return new jDataView(data); } }, accepts: { dataview: 'text/plain; charset=x-user-defined' }, responseHandler: { dataview(responses, options, xhr) { if ('mozResponseArrayBuffer' in xhr) { responses.text = xhr.mozResponseArrayBuffer; } else if ('responseType' in xhr && xhr.responseType === 'arraybuffer' && xhr.response) { responses.text = xhr.response; } else if ('responseBody' in xhr) { responses.text = convertResponseBodyToText(xhr.responseBody); } else { responses.text = xhr.responseText; } } } }); jQuery.ajaxPrefilter('dataview', (options, originalOptions, jqXHR) => { + if (jQuery.support.ajaxResponseType) { + if (!options.hasOwnProperty('xhrFields')) { options.xhrFields = {}; } + options.xhrFields.responseType = 'arraybuffer'; + } + options.mimeType = 'text/plain; charset=x-user-defined'; + }); + } + global.jDataView = (global.module || {}).exports = jDataView; if (typeof module !== 'undefined') { module.exports = jDataView; } +}(this)); diff --git a/webAO/lib/jquery.ui.touch-punch.min.js b/webAO/lib/jquery.ui.touch-punch.min.js index 31272ce..d572ab6 100644 --- a/webAO/lib/jquery.ui.touch-punch.min.js +++ b/webAO/lib/jquery.ui.touch-punch.min.js @@ -8,4 +8,4 @@ * jquery.ui.widget.js * jquery.ui.mouse.js */ -!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
\ No newline at end of file +!(function (a) { function f(a, b) { if (!(a.originalEvent.touches.length > 1)) { a.preventDefault(); const c = a.originalEvent.changedTouches[0]; const d = document.createEvent('MouseEvents'); d.initMouseEvent(b, !0, !0, window, 1, c.screenX, c.screenY, c.clientX, c.clientY, !1, !1, !1, !1, 0, null), a.target.dispatchEvent(d); } } if (a.support.touch = 'ontouchend' in document, a.support.touch) { let e; const b = a.ui.mouse.prototype; const c = b._mouseInit; const d = b._mouseDestroy; b._touchStart = function (a) { const b = this; !e && b._mouseCapture(a.originalEvent.changedTouches[0]) && (e = !0, b._touchMoved = !1, f(a, 'mouseover'), f(a, 'mousemove'), f(a, 'mousedown')); }, b._touchMove = function (a) { e && (this._touchMoved = !0, f(a, 'mousemove')); }, b._touchEnd = function (a) { e && (f(a, 'mouseup'), f(a, 'mouseout'), this._touchMoved || f(a, 'click'), e = !1); }, b._mouseInit = function () { const b = this; b.element.bind({ touchstart: a.proxy(b, '_touchStart'), touchmove: a.proxy(b, '_touchMove'), touchend: a.proxy(b, '_touchEnd') }), c.call(b); }, b._mouseDestroy = function () { const b = this; b.element.unbind({ touchstart: a.proxy(b, '_touchStart'), touchmove: a.proxy(b, '_touchMove'), touchend: a.proxy(b, '_touchEnd') }), d.call(b); }; } }(jQuery)); diff --git a/webAO/master.js b/webAO/master.js index afa7b0d..ad0a577 100644 --- a/webAO/master.js +++ b/webAO/master.js @@ -1,188 +1,183 @@ -const MASTERSERVER_IP = "master.aceattorneyonline.com:27014"; +import Fingerprint2 from 'fingerprintjs2'; const version = process.env.npm_package_version -import Fingerprint2 from 'fingerprintjs2'; -import { unescapeChat } from './encoding.js'; -import { safe_tags } from './encoding.js'; +import { unescapeChat, safe_tags } from './encoding.js'; + +const MASTERSERVER_IP = 'master.aceattorneyonline.com:27014'; let masterserver; let hdid; -const options = { fonts: { extendedJsFonts: true, userDefinedFonts: ["Ace Attorney", "8bitoperator", "DINEngschrift"] }, excludes: { userAgent: true, enumerateDevices: true } }; +const options = { fonts: { extendedJsFonts: true, userDefinedFonts: ['Ace Attorney', '8bitoperator', 'DINEngschrift'] }, excludes: { userAgent: true, enumerateDevices: true } }; let selectedServer = -1; -let servers = []; -servers[-2] = { name: "Singleplayer", description: "Build cases, try out new things", ip: "127.0.0.1", port: 50001, assets: "", online: "" }; -servers[-1] = { name: "Localhost", description: "This is your computer on port 50001", ip: "127.0.0.1", port: 50001, assets: "", online: "Online: ?/?" }; +const servers = []; +servers[-2] = { + name: 'Singleplayer', description: 'Build cases, try out new things', ip: '127.0.0.1', port: 50001, assets: '', online: '', +}; +servers[-1] = { + name: 'Localhost', description: 'This is your computer on port 50001', ip: '127.0.0.1', port: 50001, assets: '', online: 'Online: ?/?', +}; if (window.requestIdleCallback) { - requestIdleCallback(function () { - Fingerprint2.get(options, function (components) { - hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); + requestIdleCallback(() => { + Fingerprint2.get(options, (components) => { + hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); - check_https(); + check_https(); - masterserver = new WebSocket("ws://" + MASTERSERVER_IP); - masterserver.onopen = (evt) => onOpen(evt); - masterserver.onerror = (evt) => onError(evt); - masterserver.onmessage = (evt) => onMessage(evt); + masterserver = new WebSocket(`ws://${MASTERSERVER_IP}`); + masterserver.onopen = (evt) => onOpen(evt); + masterserver.onerror = (evt) => onError(evt); + masterserver.onmessage = (evt) => onMessage(evt); - // i don't need the ms to play alone - setTimeout(() => checkOnline(-1, "127.0.0.1:50001"), 0); - }); - }); + // i don't need the ms to play alone + setTimeout(() => checkOnline(-1, '127.0.0.1:50001'), 0); + }); + }); } else { - setTimeout(function () { - Fingerprint2.get(options, function (components) { - hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); + setTimeout(() => { + Fingerprint2.get(options, (components) => { + hdid = Fingerprint2.x64hash128(components.reduce((a, b) => `${a.value || a}, ${b.value}`), 31); - check_https(); + check_https(); - masterserver = new WebSocket("ws://" + MASTERSERVER_IP); - masterserver.onopen = (evt) => onOpen(evt); - masterserver.onerror = (evt) => onError(evt); - masterserver.onmessage = (evt) => onMessage(evt); + masterserver = new WebSocket(`ws://${MASTERSERVER_IP}`); + masterserver.onopen = (evt) => onOpen(evt); + masterserver.onerror = (evt) => onError(evt); + masterserver.onmessage = (evt) => onMessage(evt); - // i don't need the ms to play alone - setTimeout(() => checkOnline(-1, "127.0.0.1:50001"), 0); - }); - }, 500); + // i don't need the ms to play alone + setTimeout(() => checkOnline(-1, '127.0.0.1:50001'), 0); + }); + }, 500); } export function check_https() { - if (document.location.protocol === "https:") { - document.getElementById("https_error").style.display = ""; - } + if (document.location.protocol === 'https:') { + document.getElementById('https_error').style.display = ''; + } } export function setServ(ID) { - selectedServer = ID; + selectedServer = ID; - if (document.getElementById(`server${ID}`).className === "") - checkOnline(ID, servers[ID].ip + ":" + servers[ID].port); + if (document.getElementById(`server${ID}`).className === '') { checkOnline(ID, `${servers[ID].ip}:${servers[ID].port}`); } - if (servers[ID].description !== undefined) { - document.getElementById("serverdescription_content").innerHTML = "<b>" + servers[ID].online + "</b><br>" + safe_tags(servers[ID].description); - } - else { - document.getElementById("serverdescription_content").innerHTML = ""; - } + if (servers[ID].description !== undefined) { + document.getElementById('serverdescription_content').innerHTML = `<b>${servers[ID].online}</b><br>${safe_tags(servers[ID].description)}`; + } else { + document.getElementById('serverdescription_content').innerHTML = ''; + } } window.setServ = setServ; function onOpen(_e) { - console.log(`Your emulated HDID is ${hdid}`); - masterserver.send(`ID#webAO#webAO#%`); + console.log(`Your emulated HDID is ${hdid}`); + masterserver.send('ID#webAO#webAO#%'); - masterserver.send("ALL#%"); - masterserver.send("VC#%"); + masterserver.send('ALL#%'); + masterserver.send('VC#%'); } /** * Triggered when an network error occurs. - * @param {ErrorEvent} e + * @param {ErrorEvent} e */ function onError(evt) { - document.getElementById("ms_error").style.display = "block"; - document.getElementById("ms_error_code").innerText = `A network error occurred: ${evt.reason} (${evt.code})`; - return; + document.getElementById('ms_error').style.display = 'block'; + document.getElementById('ms_error_code').innerText = `A network error occurred: ${evt.reason} (${evt.code})`; } function checkOnline(serverID, coIP) { - let oserv; - if (serverID !== -2) { - try { - oserv = new WebSocket("ws://" + coIP); - } catch (SecurityError) { - document.getElementById(`server${serverID}`).className = "unavailable"; - return; - } - - } - - // define what the callbacks do - function onCOOpen(_e) { - document.getElementById(`server${serverID}`).className = "available"; - oserv.send(`HI#${hdid}#%`); - oserv.send(`ID#webAO#webAO#%`); - } - - function onCOMessage(e) { - const comsg = e.data; - const coheader = comsg.split("#", 2)[0]; - const coarguments = comsg.split("#").slice(1); - if (coheader === "PN") { - servers[serverID].online = `Online: ${Number(coarguments[0])}/${Number(coarguments[1])}`; - oserv.close(); - return; - } - else if (coheader === "BD") { - servers[serverID].online = "Banned"; - servers[serverID].description = coarguments[0]; - oserv.close(); - return; - } - if (serverID === selectedServer) - document.getElementById("serverdescription_content").innerHTML = "<b>" + servers[serverID].online + "</b><br>" + safe_tags(servers[serverID].description); - } - - // assign the callbacks - oserv.onopen = function (evt) { - onCOOpen(evt); - }; - - oserv.onmessage = function (evt) { - onCOMessage(evt); - }; - - oserv.onerror = function (_evt) { - console.warn(coIP + " threw an error."); - document.getElementById(`server${serverID}`).className = "unavailable"; - return; - }; - + let oserv; + if (serverID !== -2) { + try { + oserv = new WebSocket(`ws://${coIP}`); + } catch (SecurityError) { + document.getElementById(`server${serverID}`).className = 'unavailable'; + return; + } + } + + // define what the callbacks do + function onCOOpen(_e) { + document.getElementById(`server${serverID}`).className = 'available'; + oserv.send(`HI#${hdid}#%`); + oserv.send('ID#webAO#webAO#%'); + } + + function onCOMessage(e) { + const comsg = e.data; + const coheader = comsg.split('#', 2)[0]; + const coarguments = comsg.split('#').slice(1); + if (coheader === 'PN') { + servers[serverID].online = `Online: ${Number(coarguments[0])}/${Number(coarguments[1])}`; + oserv.close(); + return; + } + if (coheader === 'BD') { + servers[serverID].online = 'Banned'; + servers[serverID].description = coarguments[0]; + oserv.close(); + return; + } + if (serverID === selectedServer) { document.getElementById('serverdescription_content').innerHTML = `<b>${servers[serverID].online}</b><br>${safe_tags(servers[serverID].description)}`; } + } + + // assign the callbacks + oserv.onopen = function (evt) { + onCOOpen(evt); + }; + + oserv.onmessage = function (evt) { + onCOMessage(evt); + }; + + oserv.onerror = function (_evt) { + console.warn(`${coIP} threw an error.`); + document.getElementById(`server${serverID}`).className = 'unavailable'; + }; } function onMessage(e) { - const msg = e.data; - const header = msg.split("#", 2)[0]; - console.debug(msg); - - if (header === "ALL") { - const allservers = msg.split("#").slice(1); - for (let i = 0; i < allservers.length - 1; i++) { - const serverEntry = allservers[i]; - const args = serverEntry.split("&"); - - let thisserver = { name: args[0], description: args[1], ip: args[2], port: Number(args[3]), assets: args[4], online: "Online: ?/?" }; - servers[i] = thisserver; - - const ipport = args[2] + ":" + args[3]; - const asset = args[4] ? `&asset=${args[4]}` : ""; - - document.getElementById("masterlist").innerHTML += - `<li id="server${i}" onmouseover="setServ(${i})"><p>${safe_tags(servers[i].name)}</p>` + const msg = e.data; + const header = msg.split('#', 2)[0]; + console.debug(msg); + + if (header === 'ALL') { + const allservers = msg.split('#').slice(1); + for (let i = 0; i < allservers.length - 1; i++) { + const serverEntry = allservers[i]; + const args = serverEntry.split('&'); + + const thisserver = { + name: args[0], description: args[1], ip: args[2], port: Number(args[3]), assets: args[4], online: 'Online: ?/?', + }; + servers[i] = thisserver; + + const ipport = `${args[2]}:${args[3]}`; + const asset = args[4] ? `&asset=${args[4]}` : ''; + + document.getElementById('masterlist').innerHTML + += `<li id="server${i}" onmouseover="setServ(${i})"><p>${safe_tags(servers[i].name)}</p>` + `<a class="button" href="client.html?mode=watch&ip=${ipport}${asset}">Watch</a>` - + `<a class="button" href="client.html?mode=join&ip=${ipport}${asset}">Join</a></li>`; - } - masterserver.close(); - return; - } - else if (header === "servercheok") { - const args = msg.split("#").slice(1); - document.getElementById("clientinfo").innerHTML = `Client version: ${version} expected: ${args[0]}`; - } - else if (header === "SV") { - const args = msg.split("#").slice(1); - document.getElementById("serverinfo").innerHTML = `Master server version: ${args[0]}`; - } - else if (header === "CT") { - const args = msg.split("#").slice(1); - const msChat = document.getElementById("masterchat"); - msChat.innerHTML += `${unescapeChat(args[0])}: ${unescapeChat(args[1])}\r\n`; - if (msChat.scrollTop > msChat.scrollHeight - 600) { - msChat.scrollTop = msChat.scrollHeight; - } - } + + `<a class="button" href="client.html?mode=join&ip=${ipport}${asset}">Join</a></li>`; + } + masterserver.close(); + } else if (header === 'servercheok') { + const args = msg.split('#').slice(1); + document.getElementById('clientinfo').innerHTML = `Client version: ${version} expected: ${args[0]}`; + } else if (header === 'SV') { + const args = msg.split('#').slice(1); + document.getElementById('serverinfo').innerHTML = `Master server version: ${args[0]}`; + } else if (header === 'CT') { + const args = msg.split('#').slice(1); + const msChat = document.getElementById('masterchat'); + msChat.innerHTML += `${unescapeChat(args[0])}: ${unescapeChat(args[1])}\r\n`; + if (msChat.scrollTop > msChat.scrollHeight - 600) { + msChat.scrollTop = msChat.scrollHeight; + } + } } diff --git a/webAO/music.js b/webAO/music.js index 23c034a..09d830b 100644 --- a/webAO/music.js +++ b/webAO/music.js @@ -1,51 +1,51 @@ -export default [ - "Announce The Truth (AA).opus", - "Announce The Truth (AJ).opus", - "Announce The Truth (JFA).opus", - "Announce The Truth (Miles).opus", - "Announce The Truth (T&T).opus", - "Confrontation ~ Presto 2009.opus", - "Crises of Fate.opus", - "Forgotten Legend.opus", - "Godot - The Fragrance of Dark Coffee.opus", - "Great Revival ~ Franziska von Karma.opus", - "Great Revival ~ Miles Edgeworth.opus", - "Hotline of Fate.opus", - "Interesting People.opus", - "Logic and Trick.opus", - "Luke Atmey ~ I Just Want Love.opus", - "Noisy People.opus", - "OBJECTION (AA).opus", - "Objection (AJ).opus", - "OBJECTION (JFA).opus", - "Objection (Miles).opus", - "OBJECTION (T&T).opus", - "Others ~ Guilty love.opus", - "Prelude (AA).opus", - "Prelude (AJ).opus", - "Prologue (AA).opus", - "Pursuit (AA) - variation.opus", - "Pursuit (AA).opus", - "Pursuit (AJ).opus", - "Pursuit (DS).opus", - "Pursuit (JFA) - variation.opus", - "Pursuit (JFA).opus", - "Pursuit (Miles).opus", - "Pursuit (T&T) - variation.opus", - "Pursuit (T&T).opus", - "Pursuit ~ I Want to Find the Truth (Orchestra).opus", - "Questioning AA (Allegro).opus", - "Questioning AA (Moderato).opus", - "Questioning AJ (Allegro).opus", - "Questioning AJ (Moderato).opus", - "Questioning JFA (Allegro).opus", - "Questioning JFA (Moderato).opus", - "Questioning T&T (Allegro).opus", - "Questioning T&T (Moderato).opus", - "Speak up Pup.opus", - "Suspense (AA).opus", - "The Great Truth Burglar.opus", - "Trial (AA).opus", - "Trial (AJ).opus", - "Trial (Miles).opus" -] +export default [ + 'Announce The Truth (AA).opus', + 'Announce The Truth (AJ).opus', + 'Announce The Truth (JFA).opus', + 'Announce The Truth (Miles).opus', + 'Announce The Truth (T&T).opus', + 'Confrontation ~ Presto 2009.opus', + 'Crises of Fate.opus', + 'Forgotten Legend.opus', + 'Godot - The Fragrance of Dark Coffee.opus', + 'Great Revival ~ Franziska von Karma.opus', + 'Great Revival ~ Miles Edgeworth.opus', + 'Hotline of Fate.opus', + 'Interesting People.opus', + 'Logic and Trick.opus', + 'Luke Atmey ~ I Just Want Love.opus', + 'Noisy People.opus', + 'OBJECTION (AA).opus', + 'Objection (AJ).opus', + 'OBJECTION (JFA).opus', + 'Objection (Miles).opus', + 'OBJECTION (T&T).opus', + 'Others ~ Guilty love.opus', + 'Prelude (AA).opus', + 'Prelude (AJ).opus', + 'Prologue (AA).opus', + 'Pursuit (AA) - variation.opus', + 'Pursuit (AA).opus', + 'Pursuit (AJ).opus', + 'Pursuit (DS).opus', + 'Pursuit (JFA) - variation.opus', + 'Pursuit (JFA).opus', + 'Pursuit (Miles).opus', + 'Pursuit (T&T) - variation.opus', + 'Pursuit (T&T).opus', + 'Pursuit ~ I Want to Find the Truth (Orchestra).opus', + 'Questioning AA (Allegro).opus', + 'Questioning AA (Moderato).opus', + 'Questioning AJ (Allegro).opus', + 'Questioning AJ (Moderato).opus', + 'Questioning JFA (Allegro).opus', + 'Questioning JFA (Moderato).opus', + 'Questioning T&T (Allegro).opus', + 'Questioning T&T (Moderato).opus', + 'Speak up Pup.opus', + 'Suspense (AA).opus', + 'The Great Truth Burglar.opus', + 'Trial (AA).opus', + 'Trial (AJ).opus', + 'Trial (Miles).opus', +]; diff --git a/webAO/sounds.js b/webAO/sounds.js index 67a7bb8..0b7c8a7 100644 --- a/webAO/sounds.js +++ b/webAO/sounds.js @@ -1,132 +1,132 @@ -export default [ - "sfx-anotherpuzzle.wav", - "sfx-answeris.wav", - "sfx-ashamed.wav", - "sfx-badum.wav", - "sfx-bang.wav", - "sfx-bip.wav", - "sfx-bip2.wav", - "sfx-bip3.wav", - "sfx-bleep.wav", - "sfx-bling2.wav", - "sfx-blink.wav", - "sfx-blipfemale.wav", - "sfx-bliplayton.wav", - "sfx-blipmale.wav", - "sfx-bvvt.wav", - "sfx-cancel.wav", - "sfx-cello.wav", - "sfx-chocolatemilk.wav", - "sfx-chug.wav", - "sfx-crackle.wav", - "sfx-crowdgoeswhile.wav", - "sfx-damage1.wav", - "sfx-damage2.wav", - "sfx-deskslam.wav", - "sfx-dink.wav", - "sfx-dog bark.wav", - "sfx-dooropens.wav", - "sfx-dramapound.wav", - "sfx-everypuzzle.wav", - "sfx-evidenceshoop.wav", - "sfx-explosion.wav", - "sfx-explosive.wav", - "sfx-fan.wav", - "sfx-furio.wav", - "sfx-fwashing.wav", - "sfx-fwasshing.wav", - "sfx-gallery.wav", - "sfx-gallerycheer.wav", - "sfx-gavel.wav", - "sfx-grinding.wav", - "sfx-grinding2.wav", - "sfx-guilty.wav", - "sfx-guitar.wav", - "sfx-guitar2.wav", - "sfx-gunshot.wav", - "sfx-gunshot2.wav", - "sfx-gunshot3.wav", - "sfx-gunshot4.wav", - "sfx-happyping.wav", - "sfx-hint.wav", - "sfx-incomingpuzzle.wav", - "sfx-lightbang.wav", - "sfx-lightbulb.wav", - "sfx-lock.wav", - "sfx-locksbreak.wav", - "sfx-longwoosh.wav", - "sfx-losepuzzle.wav", - "sfx-loudbang.wav", - "sfx-maaagical.wav", - "sfx-maaagical2.wav", - "sfx-maaagical3.wav", - "sfx-meow.wav", - "sfx-nosale.wav", - "sfx-objection.wav", - "sfx-pageturn.wav", - "sfx-peep.wav", - "sfx-peep2.wav", - "sfx-phone1.wav", - "sfx-phone2.wav", - "sfx-phone3.wav", - "sfx-phone4.wav", - "sfx-phone5.wav", - "sfx-phonebeep.wav", - "sfx-photosnap.wav", - "sfx-pichoop.wav", - "sfx-powder.wav", - "sfx-psyche1.wav", - "sfx-realization.wav", - "sfx-roar.wav", - "sfx-saveblip.wav", - "sfx-scenechange.wav", - "sfx-scroll.wav", - "sfx-selectblip.wav", - "sfx-selectblip2.wav", - "sfx-selectjingle.wav", - "sfx-shattering.wav", - "sfx-shock.wav", - "sfx-shock2.wav", - "sfx-shook.wav", - "sfx-shook2.wav", - "sfx-shoomp.wav", - "sfx-shooop.wav", - "sfx-sirens.wav", - "sfx-smack.wav", - "sfx-spritz.wav", - "sfx-squee.wav", - "sfx-stab.wav", - "sfx-stab2.wav", - "sfx-supershock.wav", - "sfx-swing.wav", - "sfx-swoop.wav", - "sfx-swoop2.wav", - "sfx-tap.wav", - "sfx-tap2.wav", - "sfx-tap3.wav", - "sfx-testimony.wav", - "sfx-testimony2.wav", - "sfx-thud.wav", - "sfx-thud2.wav", - "sfx-thud3.wav", - "sfx-thud4.wav", - "sfx-thump.wav", - "sfx-thump2.wav", - "sfx-thump3.wav", - "sfx-thwap.wav", - "sfx-tong.wav", - "sfx-triplegavel.wav", - "sfx-typwriter.wav", - "sfx-weakgunshot.wav", - "sfx-whack.wav", - "sfx-wham.wav", - "sfx-whimper.wav", - "sfx-whip.wav", - "sfx-whoops.wav", - "sfx-winpuzzle.wav", - "sfx-wipe.wav", - "sfx-wubs.wav", - "sfx-yep.wav", - "sfx-yip.wav", - "sfx-zooma.wav" +export default [ + 'sfx-anotherpuzzle.wav', + 'sfx-answeris.wav', + 'sfx-ashamed.wav', + 'sfx-badum.wav', + 'sfx-bang.wav', + 'sfx-bip.wav', + 'sfx-bip2.wav', + 'sfx-bip3.wav', + 'sfx-bleep.wav', + 'sfx-bling2.wav', + 'sfx-blink.wav', + 'sfx-blipfemale.wav', + 'sfx-bliplayton.wav', + 'sfx-blipmale.wav', + 'sfx-bvvt.wav', + 'sfx-cancel.wav', + 'sfx-cello.wav', + 'sfx-chocolatemilk.wav', + 'sfx-chug.wav', + 'sfx-crackle.wav', + 'sfx-crowdgoeswhile.wav', + 'sfx-damage1.wav', + 'sfx-damage2.wav', + 'sfx-deskslam.wav', + 'sfx-dink.wav', + 'sfx-dog bark.wav', + 'sfx-dooropens.wav', + 'sfx-dramapound.wav', + 'sfx-everypuzzle.wav', + 'sfx-evidenceshoop.wav', + 'sfx-explosion.wav', + 'sfx-explosive.wav', + 'sfx-fan.wav', + 'sfx-furio.wav', + 'sfx-fwashing.wav', + 'sfx-fwasshing.wav', + 'sfx-gallery.wav', + 'sfx-gallerycheer.wav', + 'sfx-gavel.wav', + 'sfx-grinding.wav', + 'sfx-grinding2.wav', + 'sfx-guilty.wav', + 'sfx-guitar.wav', + 'sfx-guitar2.wav', + 'sfx-gunshot.wav', + 'sfx-gunshot2.wav', + 'sfx-gunshot3.wav', + 'sfx-gunshot4.wav', + 'sfx-happyping.wav', + 'sfx-hint.wav', + 'sfx-incomingpuzzle.wav', + 'sfx-lightbang.wav', + 'sfx-lightbulb.wav', + 'sfx-lock.wav', + 'sfx-locksbreak.wav', + 'sfx-longwoosh.wav', + 'sfx-losepuzzle.wav', + 'sfx-loudbang.wav', + 'sfx-maaagical.wav', + 'sfx-maaagical2.wav', + 'sfx-maaagical3.wav', + 'sfx-meow.wav', + 'sfx-nosale.wav', + 'sfx-objection.wav', + 'sfx-pageturn.wav', + 'sfx-peep.wav', + 'sfx-peep2.wav', + 'sfx-phone1.wav', + 'sfx-phone2.wav', + 'sfx-phone3.wav', + 'sfx-phone4.wav', + 'sfx-phone5.wav', + 'sfx-phonebeep.wav', + 'sfx-photosnap.wav', + 'sfx-pichoop.wav', + 'sfx-powder.wav', + 'sfx-psyche1.wav', + 'sfx-realization.wav', + 'sfx-roar.wav', + 'sfx-saveblip.wav', + 'sfx-scenechange.wav', + 'sfx-scroll.wav', + 'sfx-selectblip.wav', + 'sfx-selectblip2.wav', + 'sfx-selectjingle.wav', + 'sfx-shattering.wav', + 'sfx-shock.wav', + 'sfx-shock2.wav', + 'sfx-shook.wav', + 'sfx-shook2.wav', + 'sfx-shoomp.wav', + 'sfx-shooop.wav', + 'sfx-sirens.wav', + 'sfx-smack.wav', + 'sfx-spritz.wav', + 'sfx-squee.wav', + 'sfx-stab.wav', + 'sfx-stab2.wav', + 'sfx-supershock.wav', + 'sfx-swing.wav', + 'sfx-swoop.wav', + 'sfx-swoop2.wav', + 'sfx-tap.wav', + 'sfx-tap2.wav', + 'sfx-tap3.wav', + 'sfx-testimony.wav', + 'sfx-testimony2.wav', + 'sfx-thud.wav', + 'sfx-thud2.wav', + 'sfx-thud3.wav', + 'sfx-thud4.wav', + 'sfx-thump.wav', + 'sfx-thump2.wav', + 'sfx-thump3.wav', + 'sfx-thwap.wav', + 'sfx-tong.wav', + 'sfx-triplegavel.wav', + 'sfx-typwriter.wav', + 'sfx-weakgunshot.wav', + 'sfx-whack.wav', + 'sfx-wham.wav', + 'sfx-whimper.wav', + 'sfx-whip.wav', + 'sfx-whoops.wav', + 'sfx-winpuzzle.wav', + 'sfx-wipe.wav', + 'sfx-wubs.wav', + 'sfx-yep.wav', + 'sfx-yip.wav', + 'sfx-zooma.wav', ]; diff --git a/webAO/styles/chatbox/chatboxes.js b/webAO/styles/chatbox/chatboxes.js index 2774860..0e0367f 100644 --- a/webAO/styles/chatbox/chatboxes.js +++ b/webAO/styles/chatbox/chatboxes.js @@ -1,27 +1,27 @@ export default [ - "aa", - "acww", - "chatdd", - "dgs", - "chatplvsaa", - "trilogy", - "chatfuture", - "legacy", - "ddlc", - "dr1", - "chatdr2", - "drv3", - "drae", - "chatp3", - "p4", - "p5", - "chat999", - "halla", - "homestuck", - "key", - "yakuza", - "yttd", - "whentheycry", - "n64zelda", - "papermario" -];
\ No newline at end of file + 'aa', + 'acww', + 'chatdd', + 'dgs', + 'chatplvsaa', + 'trilogy', + 'chatfuture', + 'legacy', + 'ddlc', + 'dr1', + 'chatdr2', + 'drv3', + 'drae', + 'chatp3', + 'p4', + 'p5', + 'chat999', + 'halla', + 'homestuck', + 'key', + 'yakuza', + 'yttd', + 'whentheycry', + 'n64zelda', + 'papermario', +]; diff --git a/webAO/ui.js b/webAO/ui.js index 7bd7ab6..9e95be9 100644 --- a/webAO/ui.js +++ b/webAO/ui.js @@ -1,78 +1,78 @@ /* eslint indent: ["error", 2] */ // import GoldenLayout from "./golden/js/goldenlayout.js"; -import GoldenLayout from "golden-layout"; +import GoldenLayout from 'golden-layout'; const config = { settings: { showPopoutIcon: false, - showCloseIcon: false + showCloseIcon: false, }, dimensions: { - minItemHeight: 40 + minItemHeight: 40, }, content: [{ - type: "row", + type: 'row', content: [{ - type: "column", + type: 'column', width: 40, content: [{ - type: "component", + type: 'component', isClosable: false, - componentName: "template", - title: "Game", - componentState: { id: "client_wrapper" } - }] + componentName: 'template', + title: 'Game', + componentState: { id: 'client_wrapper' }, + }], }, { - type: "column", + type: 'column', content: [{ - type: "row", + type: 'row', height: 65, content: [{ - type: "stack", + type: 'stack', content: [{ - type: "component", + type: 'component', isClosable: false, - title: "Main", - componentName: "template", - componentState: { id: "mainmenu" } + title: 'Main', + componentName: 'template', + componentState: { id: 'mainmenu' }, }, { - type: "component", + type: 'component', isClosable: false, - title: "Log", - componentName: "template", - componentState: { id: "log" } - }] + title: 'Log', + componentName: 'template', + componentState: { id: 'log' }, + }], }, { - type: "component", - title: "Music", + type: 'component', + title: 'Music', width: 30, - componentName: "template", - componentState: { id: "music" } - }] + componentName: 'template', + componentState: { id: 'music' }, + }], }, { - type: "row", + type: 'row', content: [{ - type: "component", - title: "Server chat", - componentName: "template", - componentState: { id: "ooc" } - }] - }] - }] - }] + type: 'component', + title: 'Server chat', + componentName: 'template', + componentState: { id: 'ooc' }, + }], + }], + }], + }], }; const golden = new GoldenLayout(config); -golden.registerComponent("template", function (container, componentState) { +golden.registerComponent('template', (container, componentState) => { const template = document.querySelector(`#${componentState.id}`); container.getElement().html(template.content); // TODO: support multiple locales // container.setTitle(document.querySelector(`#${componentState.id} meta[name='frame-title']`).getAttribute("content")); }); -golden.init();
\ No newline at end of file +golden.init(); diff --git a/webpack.config.js b/webpack.config.js index ae56719..f692749 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,17 +11,12 @@ module.exports = { entry: { ui: './webAO/ui.js', client: './webAO/client.js', - master: './webAO/master.js' + master: './webAO/master.js', }, - devtool: 'source-map', - devServer: { - static: { - directory: path.join(__dirname, 'webAO'), - }, - compress: true, - port: 8080, + output: { + path: path.resolve(__dirname, 'webAO'), + filename: '[name].b.js', }, - mode: 'production', module: { rules: [ { @@ -35,23 +30,19 @@ module.exports = { '@babel/preset-env', { useBuiltIns: 'usage', targets: [ - "defaults", - "Safari > 3", - "Opera > 8", - "Android > 3" + 'defaults', + 'Safari > 3', + 'Opera > 8', + 'Android > 3', ], - corejs: 3 - } - ] - ] - } - } - } - ] - }, - output: { - path: path.resolve(__dirname, 'webAO'), - filename: '[name].b.js' + corejs: 3, + }, + ], + ], + }, + }, + }, + ], }, performance: { hints: false, @@ -63,5 +54,6 @@ module.exports = { 'process.env': JSON.stringify(process.env) }) ], - -};
\ No newline at end of file + devtool: 'source-map', + mode: 'production', +}; |
