From e4f85415202d52912ff3c6e4dad6573ff018e147 Mon Sep 17 00:00:00 2001 From: sD Date: Sun, 22 Dec 2019 20:26:45 +0100 Subject: add rainbow text --- webAO/client.css | 19 +++++++++++++++++++ webAO/client.js | 33 +++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 12 deletions(-) (limited to 'webAO') diff --git a/webAO/client.css b/webAO/client.css index 04d7bb3..8c77a90 100644 --- a/webAO/client.css +++ b/webAO/client.css @@ -250,6 +250,25 @@ img { color: white; } +.rainbow-text { + background-image: repeating-linear-gradient(to right, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange); + background-size: 200% 200%; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: rainbow_alt 1s linear infinite; + } + + @keyframes rainbow { + 0%,100% {background-position: 0 0; } + 50% {background-position: 100% 0; } + } + + @keyframes rainbow_alt { + 0% {background-position: 0 0; } + 100% { background-position: 100% 0; } + } + #client_inputbox { font-size: 21px; padding: 2px 10px; diff --git a/webAO/client.js b/webAO/client.js index 846259e..6082637 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -899,6 +899,7 @@ class Client extends EventEmitter { let colorselect = document.getElementById("textcolor"); colorselect.options[colorselect.options.length] = new Option("Yellow", 5); + colorselect.options[colorselect.options.length] = new Option("Rainbow", 6); colorselect.options[colorselect.options.length] = new Option("Pink", 7); colorselect.options[colorselect.options.length] = new Option("Cyan", 8); } @@ -1033,6 +1034,19 @@ class Viewport { "snddelay": 0, "preanimdelay": 0 }; + + this.colors = { + "0": "#ffffff", // white + "1": "#00ff00", // green + "2": "#ff0000", // red + "3": "#ffa500", // orange + "4": "#4596ff", // blue + "5": "#ffff00", // yellow + "6": "#fedcba", // 6 is rainbow. + "7": "#aac0cb", // pink + "8": "#00ffff" // cyan + }; + this.blip = new Audio(AO_HOST + "sounds/general/sfx-blipmale.wav"); this.blip.volume = 0.5; @@ -1262,6 +1276,7 @@ class Viewport { // Hide message and evidence window nameBox.style.display = "none"; chatBox.style.display = "none"; + chatBoxInner.className = ""; eviBox.style.opacity = "0"; eviBox.style.height = "0%"; const shouts = { @@ -1368,18 +1383,12 @@ class Viewport { chatBox.style.display = "block"; chatBox.style.fontSize = (chatBox.offsetHeight * 0.25) + "px"; - let colors = { - "0": "#ffffff", // white - "1": "#00ff00", // green - "2": "#ff0000", // red - "3": "#ffa500", // orange - "4": "#4596ff", // blue - "5": "#ffff00", // yellow - "6": "#fedcba", // 6 is rainbow. - "7": "#aac0cb", // pink - "8": "#00ffff" // cyan - }; - chatBoxInner.style.color = colors[this.chatmsg.color] || "#ffffff"; + if (this.chatmsg.color === "6") + chatBoxInner.className = "rainbow-text"; + else { + chatBoxInner.className = ""; + chatBoxInner.style.color = this.colors[this.chatmsg.color] || "#ffffff"; + } this.chatmsg.startspeaking = false; if (this.chatmsg.preanimdelay === 0) { -- cgit From 82b74bb94f89ccc46edbe689cf5da3f6422638b3 Mon Sep 17 00:00:00 2001 From: sD Date: Sun, 22 Dec 2019 20:42:46 +0100 Subject: adjust animation timing to loop --- webAO/client.css | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'webAO') diff --git a/webAO/client.css b/webAO/client.css index 8c77a90..4199cf9 100644 --- a/webAO/client.css +++ b/webAO/client.css @@ -251,22 +251,26 @@ img { } .rainbow-text { - background-image: repeating-linear-gradient(to right, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange, yellow, green, blue, red, orange); - background-size: 200% 200%; + background-color: rgb(255, 255, 255); + background-image: repeating-linear-gradient(to right, + red 0% 8%, orange 8% 16%, yellow 16% 24%, green 24% 32%, blue 32% 40%, + red 40% 48%, orange 48% 56%, yellow 56% 64%, green 64% 72%, blue 72% 80%, + red 80% 88%, orange 88% 96%, yellow 96% 100% ); + background-size: 40% 40%; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; - animation: rainbow_alt 1s linear infinite; + animation: rainbow 4s linear infinite; } - @keyframes rainbow { - 0%,100% {background-position: 0 0; } - 50% {background-position: 100% 0; } + @keyframes rainbow_alt { + 0%,100% {background-position: 0 0; } + 50% {background-position: 400% 0; } } - @keyframes rainbow_alt { - 0% {background-position: 0 0; } - 100% { background-position: 100% 0; } + @keyframes rainbow { + 0% {background-position: 0 0; } + 100% {background-position: 400% 0; } } #client_inputbox { -- cgit From 1e3988772431a0dcc19a27dab083ada0adfe3779 Mon Sep 17 00:00:00 2001 From: sD Date: Sun, 22 Dec 2019 21:06:27 +0100 Subject: pink was grey --- webAO/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 6082637..5187515 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1043,7 +1043,7 @@ class Viewport { "4": "#4596ff", // blue "5": "#ffff00", // yellow "6": "#fedcba", // 6 is rainbow. - "7": "#aac0cb", // pink + "7": "#ffc0cb", // pink "8": "#00ffff" // cyan }; -- cgit From 79ce937f0d14b810603a443b1e4f82de756cefab Mon Sep 17 00:00:00 2001 From: sD Date: Mon, 23 Dec 2019 19:20:15 +0100 Subject: fix CI packet --- webAO/client.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 5187515..4fe9d25 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -601,6 +601,7 @@ class Client extends EventEmitter { /** * Handles incoming character information, bundling multiple characters * per packet. + * CI#0#Phoenix&description&&&&#Miles ... * @param {Array} args packet arguments */ handleCI(args) { @@ -610,7 +611,7 @@ class Client extends EventEmitter { if (i % 2 === 0) { document.getElementById("client_loadingtext").innerHTML = `Loading Character ${i}/${this.char_list_length}`; const chargs = args[i].split("&"); - this.handleCharacterInfo(chargs, i-1); + this.handleCharacterInfo(chargs, args[i-1]); } } // Request the next pack -- cgit From 72d52accc10f4dee36656ade1b076e482ed52623 Mon Sep 17 00:00:00 2001 From: sD Date: Mon, 23 Dec 2019 19:44:49 +0100 Subject: hide empty chars, off by one in CI, replace escapeHTML --- webAO/client.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 4fe9d25..5794de8 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -57,11 +57,6 @@ console.info(`Your emulated HDID is ${hdid}`); let lastICMessageTime = new Date(0); -function safe_tags(str) { - if (str) - return str.replace(/&/g,'&').replace(//g,'>') ; -} - class Client extends EventEmitter { constructor(address) { super(); @@ -456,7 +451,7 @@ class Client extends EventEmitter { } let chatmsg = { - deskmod: safe_tags(args[1]).toLowerCase(), + deskmod: safe_tags(args[1]).toLowerCase(), preanim: safe_tags(args[2]).toLowerCase(), // get preanim nameplate: msg_nameplate, // TODO: there's a new feature that let's people choose the name that's displayed name: safe_tags(args[3]), @@ -555,6 +550,7 @@ class Client extends EventEmitter { * @param {Number} charid character ID */ async handleCharacterInfo(chargs, charid) { + if (chargs[0]) { let cini = {}; let icon = AO_HOST + "characters/" + encodeURI(chargs[0].toLowerCase()) + "/char_icon.png"; let img = document.getElementById(`demo_${charid}`); @@ -594,6 +590,10 @@ class Client extends EventEmitter { icon: icon, inifile: cini }; + } else { + let img = document.getElementById(`demo_${charid}`); + img.style.display = "none"; + } } @@ -607,7 +607,7 @@ class Client extends EventEmitter { handleCI(args) { document.getElementById("client_loadingtext").innerHTML = "Loading Character " + args[1]; // Loop through the 10 characters that were sent - for (let i = 2; i < args.length - 1; i++) { + for (let i = 2; i <= args.length - 1; i++) { if (i % 2 === 0) { document.getElementById("client_loadingtext").innerHTML = `Loading Character ${i}/${this.char_list_length}`; const chargs = args[i].split("&"); @@ -625,7 +625,7 @@ class Client extends EventEmitter { */ handleSC(args) { document.getElementById("client_loadingtext").innerHTML = "Loading Characters"; - for (let i = 1; i < args.length - 1; i++) { + 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("&"); this.handleCharacterInfo(chargs, i-1); @@ -745,7 +745,7 @@ class Client extends EventEmitter { * Handles the "MusicMode" packet * @param {Array} args packet arguments */ - handleMM(args) { + handleMM(_args) { // It's unused nowadays, as preventing people from changing the music is now serverside } @@ -924,7 +924,7 @@ class Client extends EventEmitter { // create the charselect grid, to be filled by the character loader document.getElementById("client_chartable").innerHTML = ""; let tr; - for (let i = 0; i < this.char_list_length; i++) { + for (let i = 0; i <= this.char_list_length; i++) { if (i % CHAR_SELECT_WIDTH === 0) { tr = document.createElement("TR"); } @@ -2306,8 +2306,9 @@ window.toggleShout = toggleShout; * XXX: This is unnecessary if we use `createTextNode` instead! * @param {string} unsafe an unsanitized string */ -function escapeHtml(unsafe) { - return unsafe +function safe_tags(unsafe) { + if (unsafe) + return unsafe .replace(/&/g, "&") .replace(//g, ">") -- cgit From 944737c560b155448f67bdf80f56fa65652a3c25 Mon Sep 17 00:00:00 2001 From: sD Date: Mon, 23 Dec 2019 20:08:39 +0100 Subject: ability to log outgoing packets and server version detection --- webAO/client.js | 65 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 24 deletions(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 5794de8..82a440c 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -177,13 +177,22 @@ class Client extends EventEmitter { return this.presentable ? this.selectedEvidence : 0; } + /** + * Hook for sending messages to the server + * @param {string} message the message to send + */ + sendServer(message) { + // console.log(message); + this.serv.send(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.serv.send(`CT#${escapeChat(encodeChat(document.getElementById("OOC_name").value))}#${escapeChat(encodeChat(message))}#%`); + this.sendServer(`CT#${escapeChat(encodeChat(document.getElementById("OOC_name").value))}#${escapeChat(encodeChat(message))}#%`); } /** @@ -217,7 +226,7 @@ class Client extends EventEmitter { `#${escapeChat(encodeChat(message))}#${side}#${sfx_name}#${emote_modifier}` + `#${this.charID}#${sfx_delay}#${objection_modifier}#${evidence}#${flip}#${realization}#${text_color}#${extra_cccc}%` ); - this.serv.send( + this.sendServer( `MS#${deskmod}#${speaking}#${name}#${silent}` + `#${escapeChat(encodeChat(message))}#${side}#${sfx_name}#${emote_modifier}` + `#${this.charID}#${sfx_delay}#${objection_modifier}#${evidence}#${flip}#${realization}#${text_color}#${extra_cccc}%` @@ -231,7 +240,7 @@ class Client extends EventEmitter { * @param {string} evidence image filename */ sendPE(name, desc, img) { - this.serv.send(`PE#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); + this.sendServer(`PE#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); } /** @@ -242,7 +251,7 @@ class Client extends EventEmitter { * @param {string} evidence image filename */ sendEE(id, name, desc, img) { - this.serv.send(`EE#${id}#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); + this.sendServer(`EE#${id}#${escapeChat(encodeChat(name))}#${escapeChat(encodeChat(desc))}#${img}#%`); } /** @@ -250,7 +259,7 @@ class Client extends EventEmitter { * @param {number} evidence id */ sendDE(id) { - this.serv.send(`DE#${id}#%`); + this.sendServer(`DE#${id}#%`); } /** @@ -259,7 +268,7 @@ class Client extends EventEmitter { * @param {number} hp the health point */ sendHP(side, hp) { - this.serv.send(`HP#${side}#${hp}#%`); + this.sendServer(`HP#${side}#${hp}#%`); } /** @@ -267,7 +276,7 @@ class Client extends EventEmitter { * @param {string} message to mod */ sendZZ(msg) { - this.serv.send(`ZZ#${msg}#%`); + this.sendServer(`ZZ#${msg}#%`); } /** @@ -276,7 +285,7 @@ class Client extends EventEmitter { */ sendRT(testimony) { if (this.chars[this.charID].side === "jud") { - this.serv.send(`RT#${testimony}#%`); + this.sendServer(`RT#${testimony}#%`); } } @@ -285,7 +294,7 @@ class Client extends EventEmitter { * @param {string} track the track ID */ sendMusicChange(track) { - this.serv.send(`MC#${track}#${this.charID}#%`); + this.sendServer(`MC#${track}#${this.charID}#%`); } /** @@ -295,7 +304,7 @@ class Client extends EventEmitter { * either the AO2 client or tsuserver. */ sendLeaveRoom() { - this.serv.send("FC#%"); + this.sendServer("FC#%"); } /** @@ -303,8 +312,8 @@ class Client extends EventEmitter { * to the server. */ joinServer() { - this.serv.send(`HI#${hdid}#%`); - this.serv.send("ID#webAO#2.3#%"); + this.sendServer(`HI#${hdid}#%`); + this.sendServer("ID#webAO#2.3#%"); this.checkUpdater = setInterval(() => this.sendCheck(), 5000); } @@ -349,7 +358,7 @@ class Client extends EventEmitter { */ sendCharacter(character) { if (this.chars[character].name) - this.serv.send(`CC#${this.playerID}#${character}#web#%`); + this.sendServer(`CC#${this.playerID}#${character}#web#%`); } /** @@ -357,14 +366,14 @@ class Client extends EventEmitter { * @param {number?} song the song to be played */ sendMusic(song) { - this.serv.send(`MC#${song}`); + this.sendServer(`MC#${song}`); } /** * Sends a keepalive packet. */ sendCheck() { - this.serv.send(`CH#${this.charID}#%`); + this.sendServer(`CH#${this.charID}#%`); } /** @@ -615,7 +624,7 @@ class Client extends EventEmitter { } } // Request the next pack - this.serv.send("AN#" + ((args[1] / 10) + 1) + "#%"); + this.sendServer("AN#" + ((args[1] / 10) + 1) + "#%"); } /** @@ -631,7 +640,7 @@ class Client extends EventEmitter { this.handleCharacterInfo(chargs, i-1); } // We're done with the characters, request the music - this.serv.send("RM#%"); + this.sendServer("RM#%"); } /** @@ -643,7 +652,7 @@ class Client extends EventEmitter { */ handleEI(args) { document.getElementById("client_loadingtext").innerHTML = `Loading Evidence ${args[1]}/${this.evidence_list_length}`; - this.serv.send("RM#%"); + this.sendServer("RM#%"); } /** @@ -682,7 +691,7 @@ class Client extends EventEmitter { */ handleEM(args) { document.getElementById("client_loadingtext").innerHTML = "Loading Music " + args[1]; - this.serv.send("AM#" + ((args[1] / 10) + 1) + "#%"); + this.sendServer("AM#" + ((args[1] / 10) + 1) + "#%"); const hmusiclist = document.getElementById("client_musiclist"); for (let i = 2; i < args.length - 1; i++) { if (i % 2 === 0) { @@ -738,7 +747,7 @@ class Client extends EventEmitter { } // Music done, carry on - this.serv.send("RD#%"); + this.sendServer("RD#%"); } /** @@ -868,6 +877,14 @@ class Client extends EventEmitter { */ handleID(args) { this.playerID = args[1]; + this.serverSoftware = args[2].split("&")[0]; + if (this.serverSoftware === "serverD") + this.serverVersion = args[2].split("&")[1]; + else + this.serverVersion = args[3]; + + if (this.serverSoftware === "serverD" && this.serverVersion === "1377.152") + oldLoading = true; // bugged version } /** @@ -875,7 +892,7 @@ class Client extends EventEmitter { * @param {Array} args packet arguments */ handlePN(_args) { - this.serv.send("askchaa#%"); + this.sendServer("askchaa#%"); } /** @@ -939,10 +956,10 @@ class Client extends EventEmitter { } // this is determined at the top of this file - if (oldLoading) { - this.serv.send("askchar2#%"); + if (!oldLoading && extrafeatures.includes("fastloading")) { + this.sendServer("RC#%"); } else { - this.serv.send("RC#%"); + this.sendServer("askchar2#%"); } } -- cgit From 0672207c0fc926f062a937ddd5828fa2999aed60 Mon Sep 17 00:00:00 2001 From: sD Date: Mon, 23 Dec 2019 20:36:26 +0100 Subject: how hard can it be to add a number --- webAO/client.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 82a440c..2346041 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -600,6 +600,7 @@ class Client extends EventEmitter { inifile: cini }; } else { + console.warn("missing charid "+charid); let img = document.getElementById(`demo_${charid}`); img.style.display = "none"; } @@ -616,7 +617,7 @@ class Client extends EventEmitter { handleCI(args) { document.getElementById("client_loadingtext").innerHTML = "Loading Character " + args[1]; // Loop through the 10 characters that were sent - for (let i = 2; i <= args.length - 1; i++) { + for (let i = 2; i <= args.length - 2; i++) { if (i % 2 === 0) { document.getElementById("client_loadingtext").innerHTML = `Loading Character ${i}/${this.char_list_length}`; const chargs = args[i].split("&"); @@ -934,14 +935,15 @@ class Client extends EventEmitter { * @param {Array} args packet arguments */ handleSI(args) { - this.char_list_length = args[1]; + 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 = args[2]; this.music_list_length = args[3]; // create the charselect grid, to be filled by the character loader document.getElementById("client_chartable").innerHTML = ""; let tr; - for (let i = 0; i <= this.char_list_length; i++) { + for (let i = 0; i < this.char_list_length; i++) { if (i % CHAR_SELECT_WIDTH === 0) { tr = document.createElement("TR"); } -- cgit From 7e4b235a28788cd7c30df263e957aecea6172f2c Mon Sep 17 00:00:00 2001 From: sD Date: Mon, 23 Dec 2019 21:09:34 +0100 Subject: document tick() part1 --- webAO/client.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 2346041..4a1d743 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1258,6 +1258,32 @@ class Viewport { /** * Updates the chatbox based on the given text. * + * OK, here's the documentation on how this works: + * + * 1 flip + * For whatever reason it starts off by checking if the character is flipped, every time this is called + * This is probably a TODO to move this somewhere else + * + * 2 flip + * If the server supports it, the same is done for the paired character + * Both of these should probably be moved to say() + * + * 3 _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 + * + * 4 isnew + * This is run once for every new message + * The chatbox and evidence is hidden (TODO even if there is no shout) + * and if there is a shout it's audio starts playing + * + * 5 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 ) + * Then is the flash/realization effect + * After that, the shout image is set to a transparent placeholder gif (TODO just hide it with CSS) + * and the main characters preanim gif is loaded + * If pairing is supported the paired character will just stand around with his idle sprite + * * XXX: This relies on a global variable `this.chatmsg`! */ tick() { -- cgit From adc037aafbb19fc597b0d69bb52cacf8d40e533e Mon Sep 17 00:00:00 2001 From: sD Date: Tue, 24 Dec 2019 03:27:19 +0100 Subject: document tick() part 2 --- webAO/client.js | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 4a1d743..96c420b 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1284,6 +1284,17 @@ class Viewport { * and the main characters preanim gif is loaded * If pairing is supported the paired character will just stand around with his idle sprite * + * 6 preanimdelay over + * this animates the evidence popup and finally shows the character name and message box + * it sets the text color , changes the background (again TODO) and sets the character speaking sprite + * + * 7 textnow != content + * this adds a character to the textbox and stops the animations if the entire message is present in the textbox + * + * 8 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() { -- cgit From 062411adf06e3cf1383db541f4009e18347fccd2 Mon Sep 17 00:00:00 2001 From: sD Date: Tue, 24 Dec 2019 04:01:37 +0100 Subject: say() TODOs --- webAO/client.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 96c420b..3d9d926 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1122,6 +1122,10 @@ class Viewport { /** * Sets a new emote. + * TODO: merge this and initUpdater + * 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) { -- cgit