aboutsummaryrefslogtreecommitdiff
path: root/webAO
diff options
context:
space:
mode:
authorsD <stoned@derpymail.org>2019-12-25 18:17:04 +0100
committersD <stoned@derpymail.org>2019-12-25 18:17:04 +0100
commit25bf92857171e5d81daba41676ad23ea00eb8369 (patch)
treed0e707c6d06a6754f1ab1947541332fa1208cadf /webAO
parentab5a95dcdc622bb2c7cd35e2cc29c1881c882eb2 (diff)
parent96220bf48024cf2722b45366bb176d6c1879fe7e (diff)
Merge branch 'master' into arup
Diffstat (limited to 'webAO')
-rw-r--r--webAO/client.css23
-rw-r--r--webAO/client.js169
2 files changed, 143 insertions, 49 deletions
diff --git a/webAO/client.css b/webAO/client.css
index 7a0d449..c22c0f9 100644
--- a/webAO/client.css
+++ b/webAO/client.css
@@ -246,6 +246,29 @@ img {
color: white;
}
+.rainbow-text {
+ 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 4s linear infinite;
+ }
+
+ @keyframes rainbow_alt {
+ 0%,100% {background-position: 0 0; }
+ 50% {background-position: 400% 0; }
+ }
+
+ @keyframes rainbow {
+ 0% {background-position: 0 0; }
+ 100% {background-position: 400% 0; }
+ }
+
#client_inputbox {
font-size: 21px;
padding: 2px 10px;
diff --git a/webAO/client.js b/webAO/client.js
index 817277f..b66f9cc 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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') ;
-}
-
class Client extends EventEmitter {
constructor(address) {
super();
@@ -184,12 +179,21 @@ class Client extends EventEmitter {
}
/**
+ * 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))}#%`);
}
/**
@@ -223,7 +227,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}%`
@@ -237,7 +241,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}#%`);
}
/**
@@ -248,7 +252,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}#%`);
}
/**
@@ -256,7 +260,7 @@ class Client extends EventEmitter {
* @param {number} evidence id
*/
sendDE(id) {
- this.serv.send(`DE#${id}#%`);
+ this.sendServer(`DE#${id}#%`);
}
/**
@@ -265,7 +269,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}#%`);
}
/**
@@ -273,7 +277,7 @@ class Client extends EventEmitter {
* @param {string} message to mod
*/
sendZZ(msg) {
- this.serv.send(`ZZ#${msg}#%`);
+ this.sendServer(`ZZ#${msg}#%`);
}
/**
@@ -282,7 +286,7 @@ class Client extends EventEmitter {
*/
sendRT(testimony) {
if (this.chars[this.charID].side === "jud") {
- this.serv.send(`RT#${testimony}#%`);
+ this.sendServer(`RT#${testimony}#%`);
}
}
@@ -291,7 +295,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}#%`);
}
/**
@@ -301,7 +305,7 @@ class Client extends EventEmitter {
* either the AO2 client or tsuserver.
*/
sendLeaveRoom() {
- this.serv.send("FC#%");
+ this.sendServer("FC#%");
}
/**
@@ -309,8 +313,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);
}
@@ -355,7 +359,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#%`);
}
/**
@@ -363,14 +367,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}#%`);
}
/**
@@ -457,7 +461,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]),
@@ -556,6 +560,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}`);
@@ -595,6 +600,11 @@ class Client extends EventEmitter {
icon: icon,
inifile: cini
};
+ } else {
+ console.warn("missing charid "+charid);
+ let img = document.getElementById(`demo_${charid}`);
+ img.style.display = "none";
+ }
}
@@ -602,20 +612,21 @@ class Client extends EventEmitter {
/**
* Handles incoming character information, bundling multiple characters
* per packet.
+ * CI#0#Phoenix&description&&&&&#1#Miles ...
* @param {Array} args packet arguments
*/
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("&");
- this.handleCharacterInfo(chargs, i-1);
+ this.handleCharacterInfo(chargs, args[i-1]);
}
}
// Request the next pack
- this.serv.send("AN#" + ((args[1] / 10) + 1) + "#%");
+ this.sendServer("AN#" + ((args[1] / 10) + 1) + "#%");
}
/**
@@ -625,13 +636,13 @@ 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);
}
// We're done with the characters, request the music
- this.serv.send("RM#%");
+ this.sendServer("RM#%");
}
/**
@@ -643,7 +654,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 +693,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) {
@@ -751,14 +762,14 @@ class Client extends EventEmitter {
}
// Music done, carry on
- this.serv.send("RD#%");
+ this.sendServer("RD#%");
}
/**
* 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
}
@@ -881,6 +892,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
}
/**
@@ -888,7 +907,7 @@ class Client extends EventEmitter {
* @param {Array} args packet arguments
*/
handlePN(_args) {
- this.serv.send("askchaa#%");
+ this.sendServer("askchaa#%");
}
/**
@@ -938,6 +957,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);
}
@@ -954,7 +974,8 @@ 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];
@@ -976,10 +997,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#%");
}
}
@@ -1072,6 +1093,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": "#ffc0cb", // pink
+ "8": "#00ffff" // cyan
+ };
+
this.blip = new Audio(AO_HOST + "sounds/general/sfx-blipmale.wav");
this.blip.volume = 0.5;
@@ -1127,6 +1161,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) {
@@ -1263,6 +1301,43 @@ 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
+ *
+ * 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() {
@@ -1301,6 +1376,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 = {
@@ -1407,18 +1483,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) {
@@ -2335,8 +2405,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, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")