monkeytype/src/js/tribe.js
2021-04-05 20:28:23 +01:00

2337 lines
67 KiB
JavaScript

import InputSuggestions from "./input-suggestions";
import * as MatchmakingStatus from "./tribe-mm-status";
import TribeDefaultConfigs from "./tribe-default-configs";
import * as Misc from "./misc";
import * as UI from "./ui";
import Config, * as UpdateConfig from "./config";
import * as CustomText from "./custom-text";
import * as Notifications from "./notifications";
import * as Funbox from "./funbox";
import * as ThemeColors from "./theme-colors";
import Chart from "chart.js";
import * as TestLogic from "./test-logic";
import * as TestUI from "./test-ui";
import * as Commandline from "./commandline";
import * as CommandlineLists from "./commandline-lists";
import seedrandom from "seedrandom";
export let state = -1;
export let socket = io(
window.location.hostname === "localhost"
? "http://localhost:3000"
: "https://tribe.monkeytype.com",
{
// socket: io("http://localhost:3000", {
autoConnect: false,
secure: true,
reconnectionAttempts: 1,
}
);
export let reconnectionAttempts = 0;
export let maxReconnectionAttempts = 1;
export let activePage = "preloader";
export let pageTransition = false;
export let expectedVersion = "0.9.21";
export let room = undefined;
let name = undefined;
let autoJoin = undefined;
let lastQueue = undefined;
export function setAutoJoin(code) {
autoJoin = code;
}
let shouldScrollChat = true;
let lobbySuggestions;
let resultSuggestions;
Misc.getEmojiList().then((list) => {
lobbySuggestions = new InputSuggestions(
$(".pageTribe .lobby .chat .input .emojiSuggestion"),
list,
["test", "miodec", "vastus"]
);
resultSuggestions = new InputSuggestions(
$(".pageTest #result .tribeResultChat .chat .input .emojiSuggestion"),
list,
[]
);
});
let tribeSounds = {
join: new Audio("../sound/tribe_ui/join.wav"),
leave: new Audio("../sound/tribe_ui/leave.wav"),
start: new Audio("../sound/tribe_ui/start.wav"),
chat1: new Audio("../sound/tribe_ui/chat1.wav"),
chat2: new Audio("../sound/tribe_ui/chat2.wav"),
chat_mention: new Audio("../sound/tribe_ui/chat_mention.wav"),
finish: new Audio("../sound/tribe_ui/finish.wav"),
finish_win: new Audio("../sound/tribe_ui/finish_win.wav"),
glow: new Audio("../sound/tribe_ui/glow.wav"),
cd: new Audio("../sound/tribe_ui/cd2.wav"),
cd_go: new Audio("../sound/tribe_ui/cd_go2.wav"),
};
//-1 - disconnected
//1 - connected
//6 - looking for a public game
//7 - in a public lobby waiting to fill
//8 - one second before public start
//10 - lobby
//20 - test about to start
//21 - test active
//28 - leader finished
//29 - everybody finished
export function init() {
$(".pageTribe .preloader .icon").html(
`<i class="fas fa-fw fa-spin fa-circle-notch"></i>`
);
$(".pageTribe .preloader .text").text("Connecting to Tribe");
socket.connect();
}
function changeActiveSubpage(newPage) {
if (pageTransition) return;
if (newPage === activePage) return;
pageTransition = true;
UI.swapElements(
$(`.pageTribe .${activePage}`),
$(`.pageTribe .${newPage}`),
250,
() => {
if (newPage === "prelobby") {
socket.emit("mp_get_online_stats");
}
if (newPage === "lobby") {
$(".pageTribe .lobby .chat .input input").focus();
}
pageTransition = false;
activePage = newPage;
}
);
}
function refreshUserList() {
$(".pageTribe .lobby .userlist .list").empty();
$(".pageTest #result .tribeResultChat .userlist .list").empty();
let usersArray = [];
let names = [];
Object.keys(room.users).forEach((sid) => {
let u = room.users[sid];
u.sid = sid;
if (sid !== socket.id) {
names.push(u.name);
}
usersArray.push(u);
});
lobbySuggestions.setNameList(names);
resultSuggestions.setNameList(names);
let sortedUsers = usersArray.sort((a, b) => b.points - a.points);
sortedUsers.forEach((user) => {
let icons = "";
if (user.isLeader) {
if (user.sid === socket.id) {
room.isLeader = true;
}
icons += `<div class="icon active"><i class="fas fa-fw fa-star"></i></div>`;
} else {
icons += `<div class="icon ${
user.isReady ? "active" : ""
}"><i class="fas fa-fw fa-check"></i></div>`;
}
icons += `<div class="icon ${
user.isTyping ? "active" : ""
}"><i class="fas fa-fw fa-keyboard"></i></div>`;
let pointsString;
if (user.points == undefined) {
pointsString = "";
} else {
pointsString = user.points + (user.points == 1 ? "pt" : "pts");
}
$(".pageTribe .lobby .userlist .list").append(`
<div class='user ${user.sid === socket.id ? "me" : ""}'>
<div class="nameAndIcons">
<div class='icons'>
${icons}
</div>
<div class='name'>
${user.name}
</div>
${
room.isLeader && user.sid !== socket.id
? `<div class='userSettings' sid='` +
user.sid +
`' aria-label="User settigns" data-balloon-pos="up"><div class="icon"><i class="fas fa-fw fa-cog"></i></div></div>`
: ``
}
</div>
<div class='points'>${pointsString}</div>
</div>
`);
$(".pageTest #result .tribeResultChat .userlist .list").append(`
<div class='user ${user.sid === socket.id ? "me" : ""}'>
<div class="nameAndIcons">
<div class='icons'>
${icons}
</div>
<div class='name'>
${user.name}
</div>
${
room.isLeader && user.sid !== socket.id
? `<div class='userSettings' sid='` +
user.sid +
`' aria-label="User settigns" data-balloon-pos="up"><div class="icon"><i class="fas fa-fw fa-cog"></i></div></div>`
: ``
}
</div>
<div class='points'>${pointsString}</div>
</div>
`);
});
}
function playSound(sound) {
tribeSounds[sound].currentTime = 0;
tribeSounds[sound].play();
}
function resetLobby() {
$(".pageTribe .lobby .userlist .list").empty();
$(".pageTest #result .tribeResultChat .chat .messages").empty();
$(".pageTest #result .tribeResultChat .userlist .list").empty();
$(".pageTribe .lobby .chat .messages").empty();
$(".pageTribe .lobby .inviteLink .code .text").text("");
$(".pageTribe .lobby .inviteLink .link").text("");
$(".pageTest .tribeResultChat .inviteLink .code .text").text("");
$(".pageTest .tribeResultChat .inviteLink .link").text("");
$("#tribeCountdownWrapper .faint").addClass("hidden");
$("#tribeCountdownWrapper .withbg").addClass("hidden");
}
export function resetRace() {
$(".pageTest .tribePlayers").empty().addClass("hidden");
$(".pageTribe .lobby .tribePlayers").empty().addClass("hidden");
hideCountdown();
hideResultCountdown();
// $(".pageTest #result .tribeResult").addClass("hidden");
// $(".pageTest #result .tribeResultChat").addClass("hidden");
}
function applyRoomConfig(cfg) {
UpdateConfig.setMode(cfg.mode, true, true);
if (cfg.mode === "time") {
UpdateConfig.setTimeConfig(cfg.mode2, true, true);
} else if (cfg.mode === "words") {
UpdateConfig.setWordCount(cfg.mode2, true, true);
} else if (cfg.mode === "quote") {
UpdateConfig.setQuoteLength(cfg.mode2, true, true, true);
}
UpdateConfig.setDifficulty(cfg.difficulty, true, true);
UpdateConfig.setBlindMode(cfg.blindMode, true, true);
UpdateConfig.setLanguage(cfg.language, true, true);
Funbox.activate(cfg.funbox, null, true);
UpdateConfig.setStopOnError(cfg.stopOnError, true, true);
UpdateConfig.setConfidenceMode(cfg.confidenceMode, true, true);
UpdateConfig.setPunctuation(cfg.punctuation, true, true);
UpdateConfig.setNumbers(cfg.numbers, true, true);
if (cfg.minAcc != null) {
UpdateConfig.setMinAccCustom(cfg.minAcc, true, true);
UpdateConfig.setMinAcc("custom", true, true);
} else {
UpdateConfig.setMinAcc("off", true, true);
}
if (cfg.minWpm != null) {
UpdateConfig.setMinWpmCustomSpeed(cfg.minAcc, true, true);
UpdateConfig.setMinWpm("custom", true, true);
} else {
UpdateConfig.setMinWpm("off", true, true);
}
if (cfg.customText !== null) {
CustomText.setText(cfg.customText.text);
CustomText.setIsWordRandom(cfg.customText.isWordRandom);
CustomText.setIsTimeRandom(cfg.customText.isTimeRandom);
CustomText.setTime(cfg.customText.time);
CustomText.setWord(cfg.customText.word);
}
}
export function checkIfCanChangeConfig(mp) {
if (state >= 6) {
if (state >= 20 && state < 29) {
Notifications.add("You can't change settings during the test", 0, 1);
return false;
} else if (room !== undefined && room.isLeader) {
return true;
} else {
if (mp) return true;
if (room.private) {
Notifications.add("Only the leader can change this setting", 0, 1);
return false;
} else {
Notifications.add("You can't change settings when matchmaking", 0, 1);
return false;
}
}
} else {
return true;
}
}
let syncConfigTimeout = null;
export function syncConfig() {
setSettingsLoadingIndicator(true);
if (syncConfigTimeout === null) {
syncConfigTimeout = setTimeout(() => {
setSettingsLoadingIndicator(false);
let mode2;
if (Config.mode === "time") {
mode2 = Config.time;
} else if (Config.mode === "words") {
mode2 = Config.words;
} else if (Config.mode === "quote") {
mode2 = Config.quoteLength === undefined ? "-1" : Config.quoteLength;
}
socket.emit("mp_room_config_update", {
config: {
mode: Config.mode,
mode2: mode2,
difficulty: Config.difficulty,
blindMode: Config.blindMode,
language: Config.language,
funbox: Funbox.active,
stopOnError: Config.stopOnError,
confidenceMode: Config.confidenceMode,
customText: {
text: CustomText.text,
isWordRandom: CustomText.isWordRandom,
isTimeRandom: CustomText.isTimeRandom,
word: CustomText.word,
time: CustomText.time,
},
punctuation: Config.punctuation,
numbers: Config.numbers,
minWpm: Config.minWpm === "custom" ? Config.minWpmCustomSpeed : null,
minAcc: Config.minAcc === "custom" ? Config.minAccCustom : null,
},
});
clearTimeout(syncConfigTimeout);
syncConfigTimeout = null;
}, 500);
}
}
export function joinRoomByCode(code) {
code = "room_" + code;
socket.emit("mp_room_join", { roomId: code });
$(".pageTribe .prelobby #joinByCode input").val("");
$(".pageTribe .prelobby #joinByCode .customInput").html(`
<span class="byte">--</span>
/
<span class="byte">--</span>
/
<span class="byte">--</span>
`);
}
export function startTest() {
if (syncConfigTimeout !== null) return;
if (room.newTestCooldown) return;
room.isReady = true;
socket.emit("mp_room_test_start");
}
export function sendTestProgress(wpm, raw, acc, progress) {
if (state >= 21 && state <= 28 && TestLogic.active) {
socket.emit("mp_room_test_progress_update", {
sid: socket.id,
roomId: room.id,
stats: {
wpm: wpm,
raw: raw,
acc: acc,
progress: progress,
},
});
}
}
function refreshTestUserList() {
$(".tribePlayers").empty();
Object.keys(room.users).forEach((sid) => {
if (
(room.private &&
(room.users[sid].isTyping ||
room.users[sid].isReady ||
room.users[sid].isLeader)) ||
!room.private
) {
let user = room.users[sid];
let me = "";
if (sid === socket.id) {
me = " me";
}
$(".tribePlayers").append(`
<tr class="player ${me}" sid="${sid}">
<td class="name">${user.name}</td>
<td class="progress">
<div class="barBg">
<div class="bar" style="width: 0%;"></div>
</div>
</td>
<td class="stats">
<div class="wpm">-</div>
<div class="acc">-</div>
</td>
</tr>
`);
}
});
$(".tribePlayers").removeClass("hidden");
$(".tribeResult table tbody").empty();
Object.keys(room.users).forEach((sid) => {
if (
(room.private &&
(room.users[sid].isTyping ||
room.users[sid].isReady ||
room.users[sid].isLeader)) ||
!room.private
) {
let user = room.users[sid];
let me = "";
if (sid === socket.id) {
me = " me";
}
$(".tribeResult table tbody").append(`
<tr class="player ${me}" sid="${sid}">
<td class="name">${user.name}</td>
<td class="pos"><span class="num">-</span><span class="points"></span></td>
<td class="crown"><i class="fas fa-crown" style="opacity:0"></i></td>
<td>
<div class="wpm">
<div class="text">-</div>
<div class="miniCrown"><i class="fas fa-crown"></i></div>
</div>
<div class="acc">
<div class="text">-</div>
<div class="miniCrown"><i class="fas fa-crown"></i></div>
</div>
</td>
<td>
<div class="raw">
<div class="text">-</div>
<div class="miniCrown"><i class="fas fa-crown"></i></div>
</div>
<div class="con">
<div class="text">-</div>
<div class="miniCrown"><i class="fas fa-crown"></i></div>
</div>
</td>
<td>
<div class="char">-</div>
<div class="other">-</div>
</td>
<td class="progressAndGraph">
<div class="progress">
<div class="barBg">
<div class="bar" style="width: 0%;"></div>
</div>
</div>
<div class="graph hidden" style="height: 50px">
<canvas></canvas>
</div>
</td>
</tr>
`);
}
});
$(".tribeResult").removeClass("hidden");
}
function refreshConfig() {
if (room == undefined) return;
$(".pageTribe .lobby .currentSettings .groups").empty();
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Mode" data-balloon-pos="up" commands="commandsMode">
<i class="fas fa-bars"></i>${room.config.mode}
</div>
`);
if (room.config.mode === "time") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Time" data-balloon-pos="up" commands="commandsTimeConfig">
<i class="fas fa-clock"></i>${room.config.mode2}
</div>
`);
} else if (room.config.mode === "words") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Words" data-balloon-pos="up" commands="commandsWordCount">
<i class="fas fa-font"></i>${room.config.mode2}
</div>
`);
} else if (room.config.mode === "quote") {
let qstring = "all";
let num = room.config.mode2;
if (num == 0) {
qstring = "short";
} else if (num == 1) {
qstring = "medium";
} else if (num == 2) {
qstring = "long";
} else if (num == 3) {
qstring = "thicc";
}
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Quote length" data-balloon-pos="up" commands="commandsQuoteLengthConfig">
<i class="fas fa-quote-right"></i>${qstring}
</div>
`);
} else if (room.config.mode === "custom") {
let t = "Custom settings:";
t += `\ntext length: ${CustomText.text.length}`;
if (CustomText.isTimeRandom || CustomText.isWordRandom) {
let r = "";
let n = "";
if (CustomText.isTimeRandom) {
r = "time";
n = CustomText.time;
} else if (CustomText.isWordRandom) {
r = "words";
n = CustomText.word;
}
t += `\nrandom: ${r} ${n}`;
}
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="${t}" data-balloon-pos="up" data-balloon-break commands="commandsQuoteLengthConfig">
<i class="fas fa-tools"></i>custom
</div>
`);
}
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Punctuation" data-balloon-pos="up" function="togglePunctuation()">
<span class="punc" style="font-weight: 900;
color: var(--main-color);
width: 1.25rem;
text-align: center;
display: inline-block;
margin-right: .5rem;
letter-spacing: -.1rem;">!?</span>${
room.config.punctuation ? "on" : "off"
}
</div>
`);
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Numbers" data-balloon-pos="up" function="toggleNumbers()">
<span class="numbers" style="font-weight: 900;
color: var(--main-color);
width: 1.25rem;
text-align: center;
margin-right: .1rem;
display: inline-block;
margin-right: .5rem;
letter-spacing: -.1rem;">15</span>${room.config.numbers ? "on" : "off"}
</div>
`);
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Language" data-balloon-pos="up" commands="commandsLanguages">
<i class="fas fa-globe-americas"></i>${room.config.language}
</div>
`);
if (room.config.difficulty === "normal") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Difficulty" data-balloon-pos="up" commands="commandsDifficulty">
<i class="far fa-star"></i>normal
</div>
`);
} else if (room.config.difficulty === "expert") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Difficulty" data-balloon-pos="up" commands="commandsDifficulty">
<i class="fas fa-star-half-alt"></i>expert
</div>
`);
} else if (room.config.difficulty === "master") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Difficulty" data-balloon-pos="up" commands="commandsDifficulty">
<i class="fas fa-star"></i>master
</div>
`);
}
if (room.config.blindMode) {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Blind mode" data-balloon-pos="up" function="toggleBlindMode()">
<i class="fas fa-eye-slash"></i>blind
</div>
`);
} else {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Blind mode" data-balloon-pos="up" function="toggleBlindMode()">
<i class="fas fa-eye-slash"></i>off
</div>
`);
}
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Funbox" data-balloon-pos="up" commands="commandsFunbox">
<i class="fas fa-gamepad"></i>${room.config.funbox}
</div>
`);
if (room.config.confidenceMode === "off") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Confidence mode" data-balloon-pos="up" commands="commandsConfidenceMode">
<i class="fas fa-backspace"></i>off
</div>
`);
} else if (room.config.confidenceMode === "on") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Confidence mode" data-balloon-pos="up" commands="commandsConfidenceMode">
<i class="fas fa-backspace"></i>confidence
</div>
`);
} else if (room.config.confidenceMode === "max") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Confidence mode" data-balloon-pos="up" commands="commandsConfidenceMode">
<i class="fas fa-backspace"></i>max
</div>
`);
}
if (room.config.stopOnError === "off") {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Stop on error" data-balloon-pos="up" commands="commandsStopOnError">
<i class="fas fa-hand-paper"></i>off
</div>
`);
} else {
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Stop on error" data-balloon-pos="up" commands="commandsStopOnError">
<i class="fas fa-hand-paper"></i>stop on ${room.config.stopOnError}
</div>
`);
}
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Min Wpm" data-balloon-pos="up" commands="commandsMinWpm">
<i class="fas fa-bomb"></i>${
room.config.minWpm == null ? "off" : room.config.minWpm + "wpm"
}
</div>
`);
$(".pageTribe .lobby .currentSettings .groups").append(`
<div class='group' aria-label="Min Acc" data-balloon-pos="up" commands="commandsMinAcc">
<i class="fas fa-bomb"></i>${
room.config.minAcc == null ? "off" : room.config.minAcc + "%"
}
</div>
`);
}
export function testFinished(result) {
if (state >= 21) {
socket.emit("mp_room_test_finished", { result: result });
}
}
function showCountdown(faint = false) {
if (faint) {
$("#tribeCountdownWrapper .faint").removeClass("hidden");
} else {
$("#tribeCountdownWrapper .withbg").removeClass("hidden");
}
}
function hideCountdown() {
$("#tribeCountdownWrapper .faint").addClass("hidden");
$("#tribeCountdownWrapper .withbg").addClass("hidden");
}
function updateCountdown(text) {
$("#tribeCountdownWrapper .number").text(text);
}
function fadeoutCountdown() {
$("#tribeCountdownWrapper .faint").animate(
{
opacity: 0,
},
125,
() => {
$("#tribeCountdownWrapper .faint")
.addClass("hidden")
.css("opacity", 0.075);
}
);
$("#tribeCountdownWrapper .withbg").animate(
{
opacity: 0,
},
125,
() => {
$("#tribeCountdownWrapper .withbg").addClass("hidden").css("opacity", 1);
}
);
}
function showResultCountdown() {
$("#result .tribeResult .timer").animate({ opacity: 1 }, 125);
}
function hideResultCountdown() {
$("#result .tribeResult .timer").animate({ opacity: 0 }, 125);
}
function updateResultCountdown(text) {
$("#result .tribeResult .timer").text(text);
}
export function scrollChat() {
let chatEl = $(".pageTribe .lobby .chat .messages")[0];
let chatEl2 = $(".pageTest #result .tribeResultChat .chat .messages")[0];
if (shouldScrollChat) {
chatEl.scrollTop = chatEl.scrollHeight;
chatEl2.scrollTop = chatEl2.scrollHeight;
shouldScrollChat = true;
}
}
// function updateAllGraphs(graphs, max) {
// try {
// graphs.forEach((graph) => {
// if (graph.options.scales.yAxes[0].ticks.max < Math.round(max)) {
// graph.options.scales.yAxes[0].ticks.max = Math.round(max);
// graph.options.scales.yAxes[1].ticks.max = Math.round(max);
// }
// });
// } catch (e) {
// console.error("Something went wrong while updating max graph values " + e);
// }
// }
function fillGraphDataAndUpdate(graph, result, sid) {
let labels = [];
for (let i = 1; i <= result.chartData.wpm.length; i++) {
labels.push(i);
}
let graphmaxval = Math.max(
Math.max(...result.chartData.wpm),
Math.max(...result.chartData.raw)
);
graph.data.labels = labels;
graph.data.datasets[0].data = result.chartData.wpm;
graph.data.datasets[1].data = result.chartData.raw;
graph.data.datasets[2].data = result.chartData.err;
graph.options.scales.yAxes[0].ticks.max = Math.round(graphmaxval);
graph.options.scales.yAxes[1].ticks.max = Math.round(graphmaxval);
if (sid == socket.id) {
graph.data.datasets[0].borderColor = ThemeColors.main;
graph.data.datasets[0].pointBackgroundColor = ThemeColors.main;
} else {
graph.data.datasets[0].borderColor = ThemeColors.text;
graph.data.datasets[0].pointBackgroundColor = ThemeColors.text;
}
graph.data.datasets[1].borderColor = ThemeColors.sub;
graph.data.datasets[1].pointBackgroundColor = ThemeColors.sub;
graph.update({ duration: 0 });
}
function drawMinigraph(sid, result) {
try {
let graphelem = $(`.tribeResult .player[sid='${sid}'] .graph canvas`)[0];
let graph = new Chart(graphelem, miniChartSettings);
fillGraphDataAndUpdate(graph, result, sid);
return graph;
} catch (e) {
Notifications.add("Error drawing mini graph: " + e.message, -1);
}
}
function destroyAllGraphs() {
Object.keys(room.userGraphs).forEach((sid) => {
let userGraph = room.userGraphs[sid];
userGraph.graph.clear();
userGraph.graph.destroy();
delete room.userGraphs[sid];
});
}
function setSettingsLoadingIndicator(truefalse) {
if (truefalse) {
$(".pageTribe .lobby .currentSettings .loadingIndicator").removeClass(
"hidden"
);
} else {
$(".pageTribe .lobby .currentSettings .loadingIndicator").addClass(
"hidden"
);
}
}
function userReady() {
$(".pageTribe .lobby .lobbyButtons .userReadyButton").addClass("disabled");
$(".pageTest #result .resultMpButtons .userReadyButton").addClass("disabled");
$(".pageTest #result #readyButton").addClass("disabled");
socket.emit("mp_user_ready");
}
function resetReadyButtons() {
if (room.isLeader === false && room.isReady === false) {
$(".pageTribe .lobby .lobbyButtons .userReadyButton").removeClass(
"disabled"
);
$(".pageTest #result .resultMpButtons .userReadyButton").removeClass(
"disabled"
);
$(".pageTest #result #readyButton").removeClass("disabled");
$(".pageTribe .lobby .lobbyButtons .userReadyButton").removeClass("hidden");
$(".pageTest #result .resultMpButtons .userReadyButton").removeClass(
"hidden"
);
$(".pageTest #result #readyButton").removeClass("hidden");
} else {
let cls = "disabled";
if (room.isLeader) {
cls = "hidden";
}
$(".pageTribe .lobby .lobbyButtons .userReadyButton").addClass(cls);
$(".pageTest #result .resultMpButtons .userReadyButton").addClass(cls);
$(".pageTest #result #readyButton").addClass(cls);
}
}
function resetLeaderButtons() {
if (room.isLeader) {
$(".pageTribe .lobby .lobbyButtons .startTestButton").removeClass("hidden");
$(".pageTest #result #backToLobbyButton").removeClass("hidden");
} else {
$(".pageTribe .lobby .lobbyButtons .startTestButton").addClass("hidden");
$(".pageTest #result #backToLobbyButton").addClass("hidden");
}
}
function showTribeUserSettingsPopup() {
if ($("#tribeUserSettingsPopupWrapper").hasClass("hidden")) {
$("#tribeUserSettingsPopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100);
}
}
function hideTribeUserSettingsPopup() {
if (!$("#tribeUserSettingsPopupWrapper").hasClass("hidden")) {
$("#tribeUserSettingsPopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#tribeUserSettingsPopup").attr("sid", "");
$("#tribeUserSettingsPopupWrapper").addClass("hidden");
}
);
}
}
function updateTribeUserSettingsPopup(sid) {
$("#tribeUserSettingsPopup").attr("sid", sid);
$("#tribeUserSettingsPopup .title").text(
"User settings: " + room.users[sid].name
);
}
export function setName(newname) {
name = newname;
socket.emit("mp_system_name_set", { name: newname });
}
export function sendIsTypingUpdate(truefalse) {
socket.emit("mp_room_user_istypingupdate", {
sid: socket.id,
typing: truefalse,
name: name,
});
}
function updateWhoIsTyping() {
let string = "";
let names = [];
Object.keys(room.whoIsTyping).forEach((sid) => {
if (room.whoIsTyping[sid].truefalse && sid !== socket.id) {
names.push(room.whoIsTyping[sid].name);
}
});
if (names.length > 0) {
for (let i = 0; i < names.length; i++) {
if (i === 0) {
string += `<span class="who">${names[i]}</span>`;
} else if (i === names.length - 1) {
string += ` and <span class="who">${names[i]}</span>`;
} else {
string += `, <span class="who">${names[i]}</span>`;
}
}
if (names.length == 1) {
string += " is typing...";
} else {
string += " are typing...";
}
} else {
string = " ";
}
$(".pageTribe .lobby .chat .whoIsTyping").html(string);
$(".pageTest #result .tribeResultChat .chat .whoIsTyping").html(string);
}
export function updateTribeDiff(currentSpeed) {
if (state >= 21 && state <= 28 && TestLogic.active) {
let elem = $("#tribeDiff");
elem.removeClass("ahead");
elem.removeClass("behind");
let maxwpm = 0;
Object.keys(room.userSpeeds).forEach((sid) => {
if (room.userSpeeds[sid] > maxwpm) maxwpm = room.userSpeeds[sid];
});
let diff = Math.round(maxwpm - currentSpeed);
if (diff == 0) {
elem.text("--");
} else if (diff > 0) {
elem.text("-" + diff);
elem.addClass("behind");
} else {
elem.addClass("ahead");
elem.text("+" + Math.abs(diff));
}
}
}
export function showHideTribeDiff(showhide) {
if (showhide) {
$("#tribeDiff").removeClass("hidden");
} else {
$("#tribeDiff").addClass("hidden");
}
}
function resetTribeDiff() {
let elem = $("#tribeDiff");
elem.removeClass("ahead");
elem.removeClass("behind");
elem.text("--");
}
async function insertImageEmoji(text) {
text = text.trim().split(" ");
let big = "";
if (text.length === 1) big = " big";
for (let i = 0; i < text.length; i++) {
if (/:.+:/g.test(text[i])) {
let emoji = await Misc.getEmojiList();
let result = emoji.filter((e) => e.from == text[i].replace(/:/g, ""));
if (result[0] !== undefined) {
text[
i
] = `<div class="emoji ${big}" style="background-image: url('${result[0].to}')"></div>`;
}
}
}
return text.join(" ");
}
socket.on("connect", (f) => {
UpdateConfig.setTimerStyle("mini", true);
state = 1;
reconnectionAttempts = 0;
Notifications.add("Connected to Tribe", 1);
let name = "Guest";
if (firebase.auth().currentUser !== null) {
name = firebase.auth().currentUser.displayName;
}
setName(name);
changeActiveSubpage("prelobby");
showHideTribeDiff(true);
setTimeout(() => {
if (autoJoin) {
socket.emit("mp_room_join", { roomId: autoJoin });
autoJoin = undefined;
// swapElements($(".pageTribe .preloader"), $(".pageTribe .lobby"), 250);
} else {
// swapElements($(".pageTribe .preloader"), $(".pageTribe .prelobby"), 250);
}
}, 500);
});
socket.on("mp_room_name_update", (data) => {
room.users[data.sid].name = data.name;
refreshUserList();
});
socket.on("mp_update_online_stats", (data) => {
$(".pageTribe .prelobby .welcome .stats").empty();
$(".pageTribe .prelobby .welcome .stats").append(
`<div>Online <span class="num">${data.online}</span></div>`
);
$(".pageTribe .prelobby .welcome .stats").append(
`<div>Active Races <span class="num">${data.rooms}</span></div>`
);
$(".pageTribe .prelobby .welcome .stats").append(
`<div class="small">Version ${data.version}</div>`
);
if (data.version !== expectedVersion) {
Notifications.add(
`Tribe version mismatch. Try refreshing or clearing cache. Client version: ${expectedVersion}, server version: ${data.version}`,
-1
);
socket.disconnect();
}
});
socket.on("mp_update_name", (data) => {
name = data.newName;
});
socket.on("disconnect", (f) => {
state = -1;
room = undefined;
Notifications.add("Disconnected from Tribe", 0);
resetLobby();
resetRace();
changeActiveSubpage("preloader");
showHideTribeDiff(false);
MatchmakingStatus.reset();
// $(".pageTribe .preloader div").removeClass("hidden");
// $(".pageTribe .preloader").removeClass("hidden").css("opacity", 1);
// $(".pageTribe .preloader .icon").html(`<i class="fas fa-fw fa-times"></i>`);
// $(".pageTribe .preloader .text").text(`Disconnected from Tribe`);
});
socket.on("connect_failed", (f) => {
state = -1;
changeActiveSubpage("preloader");
// $(".pageTribe .preloader div").removeClass("hidden");
// $(".pageTribe .preloader").removeClass("hidden").css("opacity", 1);
reconnectionAttempts++;
if (reconnectionAttempts >= maxReconnectionAttempts) {
$(".pageTribe .preloader .icon").html(`<i class="fas fa-fw fa-times"></i>`);
$(".pageTribe .preloader .text").text(
`Could not connect to Tribe server: ${f.message}`
);
} else {
$(".pageTribe .preloader .text").text("Connection failed. Retrying");
Notifications.add("Tribe connection error: " + f.message, -1);
}
});
socket.on("connect_error", (f) => {
state = -1;
reconnectionAttempts++;
console.error(f);
changeActiveSubpage("preloader");
// $(".pageTribe .preloader div").removeClass("hidden");
// $(".pageTribe .preloader").removeClass("hidden").css("opacity", 1);
if (reconnectionAttempts >= maxReconnectionAttempts) {
$(".pageTribe .preloader .icon").html(`<i class="fas fa-fw fa-times"></i>`);
$(".pageTribe .preloader .text").text(
`Could not connect to Tribe server: ${f.message}`
);
} else {
$(".pageTribe .preloader .text").text("Connection error. Retrying");
Notifications.add("Tribe connection error: " + f.message, -1);
}
});
socket.on("mp_room_joined", (data) => {
if (room === undefined) {
room = data.room;
} else {
room.users[data.sid] = { sid: data.sid, name: data.name };
}
if (data.room.private) {
playSound("join");
if (data.sid === socket.id) {
let user = room.users[socket.id];
if (user.isLeader) {
room.isLeader = true;
} else {
room.isLeader = false;
}
room.isReady = false;
room.isTyping = false;
}
resetReadyButtons();
refreshUserList();
if (state === 10) {
//user is already in the room and somebody joined
} else if (state === 1) {
//user is in prelobby and joined a room
applyRoomConfig(room.config);
refreshConfig();
let link = location.origin + "/tribe" + room.id.substring(4);
$(".pageTribe .lobby .inviteLink .code .text").text(room.id.substring(5));
$(".pageTribe .lobby .inviteLink .link").text(link);
$(".pageTest .tribeResultChat .inviteLink .code .text").text(
room.id.substring(5)
);
$(".pageTest .tribeResultChat .inviteLink .link").text(link);
changeActiveSubpage("lobby");
state = data.room.state;
if (state >= 20 && state < 29) {
refreshTestUserList();
}
// swapElements($(".pageTribe .prelobby"), $(".pageTribe .lobby"), 250, () => {
// state = 10;
// // $(".pageTribe .prelobby").addClass('hidden');
// });
resetReadyButtons();
resetLeaderButtons();
}
} else {
state = 7;
MatchmakingStatus.setText(
`Waiting for more players to join (${
Object.keys(room.users).length
}/5)...`
);
}
});
socket.on("mp_room_leave", () => {
let privateRoom = room.private;
state = 1;
room = undefined;
name.replace(/\(\d\)$/g, "");
resetLobby();
changeActiveSubpage("prelobby");
resetLobby();
resetRace();
$(".pageTribe .prelobby .matchmaking .leaveMatchmakingButton").addClass(
"hidden"
);
$(".pageTribe .prelobby .matchmaking .buttons .button").removeClass(
"disabled"
);
MatchmakingStatus.hide();
// swapElements($(".pageTribe .lobby"), $(".pageTribe .prelobby"), 250);
});
socket.on("mp_room_user_left", (data) => {
if (room.private) {
playSound("leave");
if (room.whoIsTyping === undefined) {
room.whoIsTyping = {};
}
room.whoIsTyping[data.sid] = { name: data.name, truefalse: false };
updateWhoIsTyping();
delete room.users[data.sid];
if (data.newLeader !== "" && data.newLeader === socket.id) {
room.isLeader = true;
room.users[socket.id].isLeader = true;
}
refreshUserList();
resetLeaderButtons();
resetReadyButtons();
} else {
delete room.users[data.sid];
if (state <= 8) {
MatchmakingStatus.setText(
`Waiting for more players to join (${
Object.keys(room.users).length
}/5)...`
);
} else if (state >= 20) {
$(`.tribePlayers .player[sid=${data.sid}]`).addClass("failed");
$(`.tribeResult .player[sid=${data.sid}]`).addClass("failed");
}
}
});
socket.on("mp_room_new_leader", (data) => {
room.isLeader = false;
Object.keys(room.users).forEach((u) => {
room.users[u].isLeader = false;
});
room.users[data.newLeader].isLeader = true;
if (data.newLeader !== "" && data.newLeader === socket.id) {
room.isLeader = true;
room.users[socket.id].isLeader = true;
}
refreshUserList();
resetLeaderButtons();
resetReadyButtons();
});
socket.on("mp_room_config_update", (data) => {
room.config = data.newConfig;
refreshConfig();
if (!room.isLeader) {
Notifications.add("Config changed", 0, 2);
applyRoomConfig(room.config);
}
Object.keys(room.users).forEach((sid) => {
room.users[sid].isReady = false;
});
room.isReady = false;
resetReadyButtons();
refreshUserList();
});
socket.on("mp_chat_message", async (data) => {
data.message = data.message.trim();
let nameregex;
if (data.isLeader) {
nameregex = new RegExp(
` @${name.replace(/[.()]/g, "\\$&")} |^@${name.replace(
/[.()]/g,
"\\$&"
)}$|ready|@everyone`,
"i"
);
} else {
nameregex = new RegExp(
` @${name.replace(/[.()]/g, "\\$&")} |^@${name.replace(
/[.()]/g,
"\\$&"
)}$`,
"i"
);
}
if (!data.isSystem && data.from.name != name) {
if (nameregex.test(data.message)) {
playSound("chat_mention");
data.message = data.message.replace(
nameregex,
"<span class='mention'>$&</span>"
);
} else {
playSound("chat2");
}
}
let cls = "message";
let author = "";
if (data.isSystem) {
cls = "systemMessage";
} else {
let me = "";
if (data.from.name == name) me = " me";
author = `<div class="author ${me}">${data.from.name}:</div>`;
}
data.message = await insertImageEmoji(data.message);
$(".pageTribe .lobby .chat .messages").append(`
<div class="${cls}">${author}<div class="text">${data.message}</div></div>
`);
$(".pageTest #result .tribeResultChat .chat .messages").append(`
<div class="${cls}">${author}<div class="text">${data.message}</div></div>
`);
scrollChat();
});
socket.on("mp_update_mm_status", (data) => {
if (data.visible) {
MatchmakingStatus.show();
} else {
MatchmakingStatus.hide();
}
if (data.text !== undefined) MatchmakingStatus.setText(data.text);
if (data.raceStarting === true) {
playSound("join");
}
});
socket.on("mp_room_user_istypingupdate", (data) => {
if (room.whoIsTyping === undefined) {
room.whoIsTyping = {};
}
room.whoIsTyping[data.sid] = { name: data.name, truefalse: data.typing };
updateWhoIsTyping();
});
$(".pageTest #result .tribeResultChat .chat .input input").keypress(() => {
setTimeout(() => {
$(".pageTribe .lobby .chat .input input").val(
$(".pageTest #result .tribeResultChat .chat .input input").val()
);
}, 1);
});
$(".pageTribe .lobby .chat .input input").keypress((e) => {
setTimeout(() => {
$(".pageTest #result .tribeResultChat .chat .input input").val(
$(".pageTribe .lobby .chat .input input").val()
);
}, 1);
});
$(".pageTribe .lobby .chat .input input").keydown((e) => {
if (e.key == "ArrowUp" || e.key == "ArrowDown" || e.key == "Tab") {
e.preventDefault();
}
});
$(".pageTribe .lobby .chat .input input").keyup((e) => {
if (e.key == "ArrowUp" || e.key == "ArrowDown" || e.key == "Tab") {
e.preventDefault();
}
if (e.key == "ArrowUp") {
lobbySuggestions.moveActiveSuggestion(false);
} else if (e.key == "ArrowDown") {
lobbySuggestions.moveActiveSuggestion(true);
} else if (e.key == "Tab") {
let active = lobbySuggestions.getActive();
if (active) {
let split = $(".pageTribe .lobby .chat .input input").val().split(" ");
if (active.type === "image") {
split[split.length - 1] = `:${active.from}:`;
} else if (active.type === "emoji") {
split[split.length - 1] = `${active.to}`;
} else {
//its a name
split[split.length - 1] = `@${active}`;
}
$(".pageTribe .lobby .chat .input input").val(split.join(" ") + " ");
lobbySuggestions.hide();
}
} else {
let split = $(".pageTribe .lobby .chat .input input").val().split(" ");
split = split[split.length - 1];
if (split.slice(0, 1) === ":") {
split = split.replace(/:/g, "");
if (split.length >= 2) {
lobbySuggestions.updateSuggestions("emoji", split);
lobbySuggestions.show();
} else {
lobbySuggestions.hide();
}
} else if (split.slice(0, 1) === "@") {
split = split.replace(/@/g, "");
if (split.length >= 0) {
lobbySuggestions.updateSuggestions("name", split);
lobbySuggestions.show();
} else {
lobbySuggestions.hide();
}
} else {
lobbySuggestions.hide();
}
}
});
$(".pageTest #result .tribeResultChat .chat .input input").keydown((e) => {
if (e.key == "ArrowUp" || e.key == "ArrowDown" || e.key == "Tab") {
e.preventDefault();
}
});
$(".pageTest #result .tribeResultChat .chat .input input").keyup((e) => {
if (e.key == "ArrowUp" || e.key == "ArrowDown" || e.key == "Tab") {
e.preventDefault();
}
if (e.key == "ArrowUp") {
resultSuggestions.moveActiveSuggestion(false);
} else if (e.key == "ArrowDown") {
resultSuggestions.moveActiveSuggestion(true);
} else if (e.key == "Tab") {
let emoji = resultSuggestions.getActive();
if (emoji) {
let split = $(".pageTest #result .tribeResultChat .chat .input input")
.val()
.split(" ");
if (emoji.type === "image") {
split[split.length - 1] = `:${emoji.from}:`;
} else if (emoji.type === "emoji") {
split[split.length - 1] = `${emoji.to}`;
}
$(".pageTest #result .tribeResultChat .chat .input input").val(
split.join(" ") + " "
);
resultSuggestions.hide();
}
} else {
let split = $(".pageTest #result .tribeResultChat .chat .input input")
.val()
.split(" ");
split = split[split.length - 1];
if (split.slice(0, 1) === ":") {
split = split.replace(/:/g, "");
if (split.length >= 2) {
resultSuggestions.updateSuggestions(split);
resultSuggestions.show();
} else {
resultSuggestions.hide();
}
} else {
resultSuggestions.hide();
}
}
});
socket.on("mp_system_message", (data) => {
Notifications.add(`${data.message}`, data.level, undefined, "Tribe");
});
socket.on("mp_room_test_start", (data) => {
if (room.private && !room.isTyping) return;
// UI.changePage('');
// mp_testCountdown();
// startTest();
setTimeout(() => {
if (!TestLogic.active) {
TestLogic.startTest();
}
}, 500);
// Notifications.add("test starting",0);
updateCountdown("");
fadeoutCountdown();
playSound("cd_go");
});
socket.on("mp_room_test_countdown", (data) => {
if (room.private && !room.isTyping) return;
TestUI.focusWords();
updateCountdown(data.val);
if (data.val <= 3) playSound("cd");
// if (data.val == 1) fadeoutCountdown()
// Notifications.add(`countdown ${data.val}`,0);
});
socket.on("mp_room_finishTimer_countdown", (data) => {
showResultCountdown();
updateResultCountdown(`Time left for everyone to finish: ${data.val}s`);
showCountdown(true);
updateCountdown(data.val);
if (data.val <= 3) playSound("cd");
});
socket.on("mp_room_finishTimer_over", (data) => {
hideResultCountdown();
if (TestLogic.active) TestLogic.finish(undefined, true);
});
socket.on("mp_room_readyResultTimer_countdown", (data) => {
showResultCountdown();
updateResultCountdown(`Waiting for everyone to get ready: ${data.val}s`);
});
socket.on("mp_room_readyResultTimer_over", (data) => {
hideResultCountdown();
if (room.isLeader) {
$(".pageTest #nextTestButton").removeClass("hidden");
$(".pageTest #backToLobbyButton").removeClass("hidden");
}
});
socket.on("mp_room_test_init", (data) => {
if (room.private && room.isReady !== true && room.isLeader !== true) {
UI.changePage("tribe");
changeActiveSubpage("lobby");
Notifications.add(
`Not joining race. isReady: ${room.isReady}, isLeader: ${room.isLeader}`,
0,
0,
"DEBUG"
);
return;
}
let delay = 0;
if ($(".page.pageTest").hasClass("active")) {
//test already visible, delay some stuff
delay = 125;
}
playSound("start");
room.userSpeeds = {};
resetTribeDiff();
room.userGraphs = {};
room.userFinished = false;
destroyAllGraphs();
seedrandom(data.seed, { global: true });
console.log(`seed: ${data.seed}`);
console.log(`random: ${Math.random()}`);
UI.changePage("", true);
$(".pageTribe .lobby .chat .input input").val("");
$(".pageTest #result .tribeResultChat .chat .input input").val("");
lobbySuggestions.hide();
resultSuggestions.hide();
MatchmakingStatus.reset();
sendIsTypingUpdate(false);
hideResultCountdown();
$(".pageTest #restartTestButton").addClass("hidden");
setTimeout(() => {
refreshTestUserList();
showCountdown();
}, delay);
});
socket.on("mp_room_state_update", (data) => {
state = data.newState;
Notifications.add(`state changed to ${data.newState}`, 0);
if (data.newState === 8) {
$(".pageTribe .prelobby .matchmaking .leaveMatchmakingButton").addClass(
"hidden"
);
}
});
socket.on("mp_room_user_test_progress_update", (data) => {
if (room.isTyping) {
if (data.sid !== socket.id) room.userSpeeds[data.sid] = data.stats.wpm;
}
$(`.tribePlayers .player[sid=${data.sid}] .wpm`).text(data.stats.wpm);
$(`.tribePlayers .player[sid=${data.sid}] .acc`).text(
Math.floor(data.stats.acc) + "%"
);
$(`.tribeResult table .player[sid=${data.sid}] .wpm .text`).text(
data.stats.wpm
);
$(`.tribeResult table .player[sid=${data.sid}] .acc .text`).text(
Math.floor(data.stats.acc) + "%"
);
$(`.tribePlayers .player[sid=${data.sid}] .bar`)
.stop(true, false)
.animate(
{
width:
Config.mode === "time"
? data.stats.wpmProgress + "%"
: data.stats.progress + "%",
},
1000,
"linear"
);
$(`.tribeResult table .player[sid=${data.sid}] .bar`)
.stop(true, false)
.animate(
{
width:
Config.mode === "time"
? data.stats.wpmProgress + "%"
: data.stats.progress + "%",
},
1000,
"linear"
);
});
let graphs = [];
socket.on("mp_room_user_finished", (data) => {
room.users[data.sid].isFinished = true;
$(`.tribeResult`).removeClass("hidden");
$(`.tribeResult table .player[sid=${data.sid}] .wpm .text`).text(
data.result.wpm
);
$(`.tribeResult table .player[sid=${data.sid}] .acc .text`).text(
data.result.acc + "%"
);
// $(`.tribeResult table .player[sid=${data.sid}] .progress`).remove();
// $(`.tribeResult table .player[sid=${data.sid}] .raw`).remove();
// $(`.tribeResult table .player[sid=${data.sid}] .con`).remove();
// $(`.tribeResult table .player[sid=${data.sid}] .char`).remove();
// $(`.tribeResult table .player[sid=${data.sid}] .acc`).after(`
// <td class="raw"></div>
// <td class="con"></div>
// <td class="char"></div>
// `);
$(`.tribeResult table .player[sid=${data.sid}] .raw .text`).text(
data.result.raw
);
let val = "-";
if (data.result.afk) {
val = "afk";
} else if (data.result.invalid) {
val = "invalid";
} else if (data.result.failed) {
val = "failed";
} else if (data.result.outOfTime) {
val = "out of time";
}
$(`.tribeResult table .player[sid=${data.sid}] .other`).text(val);
$(`.tribeResult table .player[sid=${data.sid}] .char`).text(data.result.char);
$(`.tribeResult table .player[sid=${data.sid}] .con .text`).text(
data.result.con + "%"
);
if (data.result.failed || data.result.invalid || data.result.afk) {
$(`.tribePlayers .player[sid=${data.sid}]`).addClass("failed");
$(`.tribeResult .player[sid=${data.sid}]`).addClass("failed");
}
if (room.userGraphs === undefined) room.userGraphs = {};
room.userGraphs[data.sid] = {
data: data.result,
};
UI.swapElements(
$(`.tribeResult table .player[sid=${data.sid}] .progress`),
$(`.tribeResult table .player[sid=${data.sid}] .graph`),
125
);
setTimeout(() => {
if (data.sid === socket.id) {
room.userFinished = true;
Object.keys(room.userGraphs).forEachWithCallback((sid, i, next) => {
setTimeout(() => {
let userGraph = room.userGraphs[sid];
userGraph.graph = drawMinigraph(sid, userGraph.data);
next();
}, 100);
});
} else if (room.userFinished) {
room.userGraphs[data.sid].graph = drawMinigraph(data.sid, data.result);
}
}, 250);
// $(`.tribeResult table .player[sid=${data.sid}] .progress`),
// swapElements(
// $(`.tribeResult table .player[sid=${data.sid}] .progress`),
// $(`.tribeResult table .player[sid=${data.sid}] .graph`),
// 125,
// () => {
// drawMinigraph(data.sid, data.result);
// // $(`.tribeResult table .player[sid=${data.sid}] .graph`).css('opacity',0).animate({opacity:1},125);
// }
// );
if (Config.mode !== "time" && !data.result.failed && !data.result.afk) {
$(`.tribePlayers .player[sid=${data.sid}] .bar`).stop(true, false).animate(
{
width: "100%",
},
1000,
"linear"
);
$(`.tribeResult table .player[sid=${data.sid}] .bar`)
.stop(true, false)
.animate(
{
width: "100%",
},
1000,
"linear"
);
}
});
socket.on("mp_room_winner", (data) => {
let pos = 1;
if (data.official) {
hideResultCountdown();
// updateAllGraphs(graphs, data.maxRaw);
// room.newTestCooldown = true;
// $("#result #nextTestButton").html(
// `<i class="fas fa-fw fa-spin fa-circle-notch"></i>`
// );
// $("#result #nextTestButton").attr(
// "aria-label",
// "Please wait for all players to view their result"
// );
// setTimeout(() => {
// room.newTestCooldown = false;
// $("#result #nextTestButton").html(
// `<i class="fas fa-fw fa-chevron-right"></i>`
// );
// $("#result #nextTestButton").attr("aria-label", "Next test");
// }, 5000);
}
let userwon = false;
data.sorted.forEach((sid) => {
$(`.tribeResult table [sid=${sid.sid}] .pos .num`).text(
`${pos}${Misc.getNumberSuffix(pos)}`
);
if (data.official && pos == 1) {
if (sid.sid === socket.id) {
userwon = true;
}
$(`.tribeResult table [sid=${sid.sid}] .crown .fa-crown`).animate(
{ opacity: 1 },
125
);
} else {
$(`.tribeResult table [sid=${sid.sid}] .crown .fa-crown`).css(
"opacity",
0
);
}
pos++;
});
if (userwon && data.official) {
playSound("finish_win");
} else if (!userwon && data.official) {
playSound("finish");
}
});
socket.on("mp_room_miniCrowns", (data) => {
let count = {};
Object.keys(data.crowns).forEach((c) => {
let crown = data.crowns[c];
crown.sidList.forEach((sid) => {
if (count[sid] === undefined) {
count[sid] = 1;
} else {
count[sid]++;
}
$(`.tribeResult table [sid=${sid}] .${c} .miniCrown`).animate(
{ opacity: 0.5 },
125
);
});
});
Object.keys(count).forEach((sid) => {
if (count[sid] === 4) {
$(`.tribeResult table [sid=${sid}] .crown`).append(
`<div class="glow"></div>`
);
$(`.tribeResult table [sid=${sid}] .crown`).attr(
"aria-label",
"Dominated"
);
$(`.tribeResult table [sid=${sid}] .crown`).attr(
"data-balloon-pos",
"up"
);
if (sid === socket.id) {
playSound("glow");
}
}
});
});
socket.on("mp_room_points", (data) => {
data.users.forEach((user) => {
$(`.tribeResult table [sid=${user.sid}] .pos .points`).text(
`+${user.newPoints}${user.newPoints == 1 ? "pt" : "pts"}`
);
room.users[user.sid].points = user.totalPoints;
});
refreshUserList();
});
socket.on("mp_room_back_to_lobby", (data) => {
Object.keys(room.users).forEach((sid) => {
room.users[sid].isTyping = false;
});
$(".tribePlayers").addClass("hidden");
UI.changePage("tribe");
refreshUserList();
});
socket.on("mp_room_user_info_update", (data) => {
let checkReady = false;
Object.keys(data.values).forEach((bool) => {
room.users[data.sid][bool] = data.values[bool];
if (bool === "isReady" && data.values[bool]) checkReady = true;
if (data.sid === socket.id) {
room[bool] = data.values[bool];
if (bool === "isReady" && !data.values[bool] && !room.isLeader) {
resetReadyButtons();
}
}
});
if (room.isLeader && checkReady) {
let everyoneReady = true;
Object.keys(room.users).forEach((sid) => {
if (
!room.users[sid].isReady &&
!room.users[sid].isLeader &&
(!room.users[sid].isTyping || room.users[sid].isFinished)
)
everyoneReady = false;
});
if (everyoneReady) {
playSound("chat_mention");
Notifications.add("Everyone is ready", 1, 3, "Tribe");
}
}
refreshUserList();
});
$(".pageTribe #createPrivateRoom").click((f) => {
// activateFunbox("none");
// setLanguage("english");
// setMode("quote");
let mode2;
if (Config.mode === "time") {
mode2 = Config.time;
} else if (Config.mode === "words") {
mode2 = Config.words;
} else if (Config.mode === "quote") {
mode2 = Config.quoteLength === undefined ? "-1" : Config.quoteLength;
}
socket.emit("mp_room_create", {
config: {
mode: Config.mode,
mode2: mode2,
difficulty: Config.difficulty,
blindMode: Config.blindMode,
language: Config.language,
funbox: Funbox.active,
stopOnError: Config.stopOnError,
confidenceMode: Config.confidenceMode,
customText: {
text: CustomText.text,
isWordRandom: CustomText.isWordRandom,
isTimeRandom: CustomText.isTimeRandom,
word: CustomText.word,
time: CustomText.time,
},
punctuation: Config.punctuation,
numbers: Config.numbers,
minWpm: Config.minWpm === "custom" ? Config.minWpmCustomSpeed : null,
minAcc: Config.minAcc === "custom" ? Config.minAccCustom : null,
},
});
});
$(".pageTest #result .tribeResultChat .chat .input input").keyup((e) => {
if (e.keyCode === 13) {
let msg = $(".pageTest #result .tribeResultChat .chat .input input").val();
msg = Misc.encodeHTML(msg);
if (msg === "") return;
if (msg.length > 512) {
Notifications.add("Message cannot be longer than 512 characters.", 0);
return;
}
sendIsTypingUpdate(false);
socket.emit("mp_chat_message", {
isSystem: false,
isLeader: room.isLeader,
message: msg,
from: {
id: socket.id,
name: name,
},
});
resultSuggestions.hide();
$(".pageTest #result .tribeResultChat .chat .input input").val("");
$(".pageTribe .lobby .chat .input input").val("");
}
});
$(".pageTribe .lobby .chat .input input").keyup((e) => {
if (e.keyCode === 13) {
let msg = $(".pageTribe .lobby .chat .input input").val();
msg = Misc.encodeHTML(msg);
if (msg === "") return;
if (msg.length > 512) {
Notifications.add("Message cannot be longer than 512 characters.", 0);
return;
}
sendIsTypingUpdate(false);
socket.emit("mp_chat_message", {
isSystem: false,
isLeader: room.isLeader,
message: msg,
from: {
id: socket.id,
name: name,
},
});
lobbySuggestions.hide();
$(".pageTribe .lobby .chat .input input").val("");
$(".pageTest #result .tribeResultChat .chat .input input").val("");
}
});
$(
".pageTribe .lobby .chat .input input, .pageTest #result .tribeResultChat .chat .input input"
).on("input", (e) => {
// e.currentTarget.value = emoji.emojify(e.currentTarget.value);
if (e.currentTarget.value.length === 1) {
//typing update
sendIsTypingUpdate(true);
} else if (e.currentTarget.value == "") {
//not typing update
sendIsTypingUpdate(false);
}
});
$(".pageTest #result .tribeResultChat .chat .messages").on("scroll", (e) => {
let chatEl = $(".pageTest #result .tribeResultChat .chat .messages")[0];
shouldScrollChat =
chatEl.scrollHeight - chatEl.scrollTop <= chatEl.clientHeight + 10;
});
$(".pageTribe .lobby .chat .messages").on("scroll", (e) => {
let chatEl = $(".pageTribe .lobby .chat .messages")[0];
shouldScrollChat =
chatEl.scrollHeight - chatEl.scrollTop <= chatEl.clientHeight + 10;
});
$(
".pageTribe .lobby .inviteLink .text, .pageTest .tribeResultChat .inviteLink .code .text"
).click(async (e) => {
try {
await navigator.clipboard.writeText(
$(".pageTribe .lobby .inviteLink .text").text()
);
Notifications.add("Code copied", 1);
} catch (e) {
Notifications.add("Could not copy to clipboard: " + e, -1);
}
});
$(".pageTribe .lobby .inviteLink .text").hover(async (e) => {
$(".pageTribe .lobby .inviteLink .text").css(
"color",
"#" + $(".pageTribe .lobby .inviteLink .text").text()
);
});
$(".pageTest .tribeResultChat .inviteLink .code .text").hover(async (e) => {
$(".pageTest .tribeResultChat .inviteLink .code .text").css(
"color",
"#" + $(".pageTest .tribeResultChat .inviteLink .code .text").text()
);
});
$(".pageTest .tribeResultChat .inviteLink .code .text").hover(
function () {
$(this).css("color", "#" + $(".pageTribe .lobby .inviteLink .text").text());
},
function () {
$(this).css("color", "");
}
);
$(".pageTribe .lobby .inviteLink .text").hover(
function () {
$(this).css("color", "#" + $(".pageTribe .lobby .inviteLink .text").text());
},
function () {
$(this).css("color", "");
}
);
$(
".pageTribe .lobby .inviteLink .link, .pageTest .tribeResultChat .inviteLink .link"
).click(async (e) => {
try {
await navigator.clipboard.writeText(
$(".pageTribe .lobby .inviteLink .link").text()
);
Notifications.add("Link copied", 1);
} catch (e) {
Notifications.add("Could not copy to clipboard: " + e, -1);
}
});
$(".pageTribe .prelobby #joinByCode .customInput").click((e) => {
$(".pageTribe .prelobby #joinByCode input").focus();
});
$(".pageTribe .prelobby #joinByCode input").focus((e) => {
$(".pageTribe .prelobby #joinByCode .customInput .byte").addClass("focused");
});
$(".pageTribe .prelobby #joinByCode input").focusout((e) => {
$(".pageTribe .prelobby #joinByCode .customInput .byte").removeClass(
"focused"
);
});
$(".pageTribe .prelobby .matchmaking .button").click((e) => {
if (state >= 6 && state <= 8) return;
let queue = $(e.currentTarget).attr("queue");
MatchmakingStatus.setText("Searching for a room...");
MatchmakingStatus.show();
state = 6;
lastQueue = queue;
applyRoomConfig(TribeDefaultConfigs[queue]);
$(".pageTribe .prelobby .matchmaking .buttons .button").addClass("disabled");
setTimeout(() => {
$(".pageTribe .prelobby .matchmaking .leaveMatchmakingButton").removeClass(
"hidden"
);
socket.emit("mp_room_join", { queue: queue });
}, 1000);
});
$(".pageTest #result #queueAgainButton").click((e) => {
if (state >= 6 && state <= 8) return;
MatchmakingStatus.setText("Searching for a room...");
MatchmakingStatus.show();
state = 6;
applyRoomConfig(TribeDefaultConfigs[lastQueue]);
TestLogic.restart();
$(".pageTribe .prelobby .matchmaking .buttons .button").addClass("disabled");
setTimeout(() => {
socket.emit("mp_room_join", { queue: lastQueue });
$(".pageTribe .prelobby .matchmaking .leaveMatchmakingButton").removeClass(
"hidden"
);
}, 1000);
});
$(".pageTribe .prelobby .matchmaking .leaveMatchmakingButton").click((e) => {
if (state === 7) {
socket.emit("mp_room_leave");
}
});
$(".pageTribe .prelobby #joinByCode .button").click((e) => {
let code = $(".pageTribe .prelobby #joinByCode input").val().toLowerCase();
if (code.length !== 6) {
Notifications.add("Code required", 0);
} else {
joinRoomByCode(code);
}
});
$(".pageTribe .prelobby #joinByCode input").keyup((e) => {
if (e.key === "Enter") {
let code = $(".pageTribe .prelobby #joinByCode input").val().toLowerCase();
if (code.length !== 6) {
Notifications.add("Code required", 0);
} else {
joinRoomByCode(code);
}
} else {
setTimeout((t) => {
// let t1 = "xx";
// let t2 = "xx";
// let t2 = "xx";
let v = $(".pageTribe .prelobby #joinByCode input").val();
// let text = `${v[0] == undefined ? 'x' : v[0]}`;
// let iv = 0;
// for (let i = 0; i < 8; i++){
// text[i] = v[iv] == undefined ? 'x' : v[iv];
// if(![2,5].includes(i)) iv++;
// }
let code = [];
for (let i = 0; i < 6; i++) {
let char = v[i] == undefined ? "-" : v[i];
code.push(char);
}
let text = code.join("");
$($(".pageTribe .prelobby #joinByCode .customInput .byte")[0]).text(
text.substring(0, 2)
);
$($(".pageTribe .prelobby #joinByCode .customInput .byte")[1]).text(
text.substring(2, 4)
);
$($(".pageTribe .prelobby #joinByCode .customInput .byte")[2]).text(
text.substring(4, 6)
);
}, 0);
}
});
$(
".pageTribe .lobby .lobbyButtons .leaveRoomButton, .pageTest #result .resultMpButtons .leaveRoomButton"
).click((e) => {
socket.emit("mp_room_leave");
});
$(".pageTribe .lobby .lobbyButtons .startTestButton").click((e) => {
startTest();
});
$(
`.pageTribe .lobby .lobbyButtons .userReadyButton,
.pageTest #result #readyButton,
.pageTest #result .resultMpButtons .userReadyButton`
).click((e) => {
userReady();
});
$(
`.pageTribe .lobby .lobbyButtons .userReadyButton,
.pageTest #result #readyButton,
.pageTest #result .resultMpButtons .userReadyButton`
).on("keypress", (event) => {
if (event.keyCode == 13) {
userReady();
}
});
$(document).on("keypress", (e) => {
if ((state === 10 || state === 29) && e.key === "Enter" && e.shiftKey) {
if (room.isLeader) {
startTest();
} else {
userReady();
}
}
});
$(".pageTest #result #backToLobbyButton").click((e) => {
socket.emit("mp_room_back_to_lobby");
});
$(document).on(
"click",
".pageTribe .lobby .currentSettings .groups .group",
(e) => {
if (room.isLeader) {
// let commands = eval($(e.currentTarget).attr("commands"));
let commands = CommandlineLists.getList(
$(e.currentTarget).attr("commands")
);
let func = $(e.currentTarget).attr("function");
if (commands != undefined) {
if ($(e.currentTarget).attr("commands") === "commandsTags") {
CommandlineLists.updateTagCommands();
}
CommandlineLists.pushCurrent(commands);
Commandline.show();
} else if (func != undefined) {
eval(func);
}
}
}
);
$("#tribeUserSettingsPopupWrapper").click((e) => {
if ($(e.target).attr("id") === "tribeUserSettingsPopupWrapper") {
hideTribeUserSettingsPopup();
}
});
$(document).on(
"click",
".pageTribe .lobby .userlist .user .userSettings",
(e) => {
updateTribeUserSettingsPopup($(e.currentTarget).attr("sid"));
showTribeUserSettingsPopup();
}
);
$(document).on("click", "#tribeUserSettingsPopup .buttons .leader", (e) => {
let sid = $("#tribeUserSettingsPopup").attr("sid");
socket.emit("mp_room_new_leader", { sid: sid });
hideTribeUserSettingsPopup();
});
$(document).on("click", "#tribeUserSettingsPopup .buttons .ban", (e) => {
let sid = $("#tribeUserSettingsPopup").attr("sid");
socket.emit("mp_room_ban_user", { sid: sid });
hideTribeUserSettingsPopup();
});
$(document).on("keypress", (e) => {
if (
state === 10 &&
!$(".pageTribe .lobby .chat .input input").is(":focus") &&
e.key === "/"
) {
$(".pageTribe .lobby .chat .input input").focus();
e.preventDefault();
}
if (
state >= 28 &&
!$(".pageTest #result .tribeResultChat .chat .input input").is(":focus") &&
e.key === "/"
) {
$(".pageTest #result .tribeResultChat .chat .input input").focus();
e.preventDefault();
}
});
let miniChartSettings = {
type: "line",
data: {
labels: [1, 2, 3],
datasets: [
{
label: "wpm",
data: [100, 100, 100],
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 1,
yAxisID: "wpm",
order: 2,
radius: 1,
},
{
label: "raw",
data: [110, 110, 110],
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 1,
yAxisID: "raw",
order: 3,
radius: 1,
},
{
label: "errors",
data: [1, 0, 1],
borderColor: "rgba(255, 125, 125, 1)",
pointBackgroundColor: "rgba(255, 125, 125, 1)",
borderWidth: 1,
order: 1,
yAxisID: "error",
maxBarThickness: 10,
type: "scatter",
pointStyle: "crossRot",
radius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value <= 0 ? 0 : 2;
},
pointHoverRadius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value <= 0 ? 0 : 3;
},
},
],
},
options: {
layout: {
padding: {
left: 5,
right: 5,
top: 5,
bottom: 5,
},
},
tooltips: {
titleFontFamily: "Roboto Mono",
bodyFontFamily: "Roboto Mono",
mode: "index",
intersect: false,
callbacks: {
afterLabel: function (ti, data) {
try {
//TODO bring back
// $(".wordInputAfter").remove();
// let wordsToHighlight =
// keypressPerSecond[parseInt(ti.xLabel) - 1].words;
// let unique = [...new Set(wordsToHighlight)];
// unique.forEach((wordIndex) => {
// let wordEl = $($("#resultWordsHistory .words .word")[wordIndex]);
// let input = wordEl.attr("input");
// if (input != undefined)
// wordEl.append(`<div class="wordInputAfter">${input}</div>`);
// });
} catch (e) {}
},
},
},
legend: {
display: false,
labels: {
defaultFontFamily: "Roboto Mono",
},
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
ticks: {
fontFamily: "Roboto Mono",
autoSkip: true,
autoSkipPadding: 40,
},
display: false,
scaleLabel: {
display: false,
labelString: "Seconds",
fontFamily: "Roboto Mono",
},
},
],
yAxes: [
{
id: "wpm",
display: false,
scaleLabel: {
display: true,
labelString: "Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: true,
},
},
{
id: "raw",
display: false,
scaleLabel: {
display: true,
labelString: "Raw Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
{
id: "error",
display: false,
position: "right",
scaleLabel: {
display: true,
labelString: "Errors",
fontFamily: "Roboto Mono",
},
ticks: {
precision: 0,
fontFamily: "Roboto Mono",
beginAtZero: true,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
],
},
annotation: {
annotations: [],
},
},
};