Skip to content

Instantly share code, notes, and snippets.

@nabbynz
Last active March 27, 2020 22:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nabbynz/765e80b42b075e35acb1 to your computer and use it in GitHub Desktop.
Save nabbynz/765e80b42b075e35acb1 to your computer and use it in GitHub Desktop.
TagPro Chat Scroller
// ==UserScript==
// @name TagPro Chat Scroller
// @description Changes the default chat into a scrollable, whole-game chat. Optionally shows last-game chat between games.
// @version 0.7.0
// - v0.7.0: General update to make it work again.
// - v0.6.3: Fix the 'serverHost' bug.
// - v0.6.2: Added 'bwep' sound on all chat messages option. Fixed a teamcount bug.
// - v0.6.0: Added caps timeline.
// - Made compatible with new TagPro site design.
// - Added team totals to chat log scoreboard.
// - Added score when player joins/leaves the games.
// - Added click name in chat to report.
// - Added player join/left sounds.
// @include https://tagpro.koalabeast.com*
// @include http://*.newcompte.fr:*
// @include http://tangent.jukejuice.com*
// @author nabby
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @require http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js
// @resource jqUI_CSS http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css
// @updateURL https://gist.github.com/nabbynz/765e80b42b075e35acb1/raw/TagPro_Chat_Scroller.user.js
// @downloadURL https://gist.github.com/nabbynz/765e80b42b075e35acb1/raw/TagPro_Chat_Scroller.user.js
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_addStyle
// ==/UserScript==
console.log('START: ' + GM_info.script.name + ' (v' + GM_info.script.version + ' by ' + GM_info.script.author + ')');
var $uHome = $('#userscript-home');
var $uTop = $('#userscript-top');
var $uBottom = $('#userscript-bottom');
tagpro.ready(function() {
/*************************************/
/* Options */
/*************************************/
const showTime = true; //show the countdown timer time in chat log window [Default: true]
const hideTimeOnSystemChat = true; //hides the time on system chat messages (like "Since there aren't many players in this game yet") [Default: true]
const showPlayerAuthTick = true; //put a green tick next to authenticated player names [Default: true]
const showCaps = true; //shows when a cap was made [Default: true]
const showScoreOnJoinLeft = true; //shows the score & team counts when a player joins or leaves the game [Default: true]
const playSoundOnJoin = true; //plays a "dink" sound when a player joins the game [Default: true]
const playSoundOnLeft = true; //plays a "donk" sound when a player leaves the game [Default: true]
const playSoundOnMessage = false; //plays a "bwep" sound on all chat messages [Default: false]
const ignoreMuteSoundIcon = true; //will play sounds even if the tagpro sounds are off [Default: true]
const showBorder = true; //show a dashed border around the chat window [Default: true]
const showScollBar = true; //show a scrollbar on the chat window [Default: true]
const showLastGameOnHome = false; //shows the last game's chat log on the server home page [Default: false]
const showLastGameOnJoiner = true; //shows the last game's chat log on the joining page [Default: true]
const showScoreboardOnHome = true; //shows the last game's scoreboard at the end of the chat log on the server/joiner pages [Default: true]
const showScoreboardOnEOG = true; //shows the current game's scoreboard at the end of the chat log when the game ends [Default: true]
const showTeamTotals = true; //shows the totals for Red/Blue stats on the scoreboard [Default: true]
const showSummaryOnHome = true; //shows the game summary & caps timeline at the end of the chat log on the server/joiner pages [Default: true]
const showSummaryOnEOG = true; //shows the current game's summary (& caps timeline) at the end of the chat log when the game ends [Default: true]
const showTimelineOnSummary = true; //shows a timeline of the game caps (`showCaps` must also be `true`) [Default: true]
const showLJSOnTimeline = false; //shows all leavers, joiners & switchers on the game summary timeline (`showTimelineOnSummary` must also be `true`) [Default: false]
const hideNormalChat = true; //hide the normal chat window (good for testing) [Default: true]
//Colors...
const redTextColor = '#F8B0B8'; //Default: #F8B0B8
const blueTextColor = '#C9C9F8'; //Default: #C9C9F8
const timeColor = '#FFA500'; //Default: #FFA500
const defaultBorder = '1px dashed gray'; //Default: 1px dashed gray
const defaultBackground = 'rgba(100,100,100,0.8)'; //Default: rgba(100,100,100,0.05) (grey with 0.8 transparency)
/*************************************/
GM_addStyle('.CS_Red { color:'+redTextColor+'; }');
GM_addStyle('.CS_Blue { color:'+blueTextColor+'; }');
GM_addStyle('.CS_Font7 { font-size:7px; }');
GM_addStyle('.CS_Font9 { font-size:9px; }');
GM_addStyle('.CS_Bold { font-weight:bold; }');
GM_addStyle('.CS_Underline { text-decoration:underline; }');
GM_addStyle('.CS_Auth { color:#77ff00; }');
GM_addStyle('.CS_Cap { color:#333; background:#3D0; border-radius:4px; text-shadow:none; font-weight:bold; font-size:10px; padding:0 2px; margin-right:2px; }');
let $CS_ChatHistory, $CS_ChatHistory_Container;
let PageLoc = WhichPageAreWeOn();
function addToPage() {
if (PageLoc === 'ingame') {
$('body').append('<div id="CS_ChatHistory_Container" style="position:absolute; padding:5px 0; height:'+GM_getValue('size', {height:310}).height+'px; width:'+GM_getValue('size', {width:310}).width+'px; left:'+GM_getValue('position', {left:5}).left+'px; top:'+GM_getValue('position', {top:430}).top+'px;'+(showBorder ? ' border:'+defaultBorder+'; ' : '')+' font:11px Arial; text-shadow:1px 1px 1px black; background:'+defaultBackground+'; overflow-x:hidden; overflow-y:auto;"><div id="CS_ChatHistory"></div></div>');
} else {
$uBottom.find('.row').append('<div id="CS_ChatHistory_Container" style="position:absolute; padding:5px 0; height:'+GM_getValue('size', {height:310}).height+'px; width:'+GM_getValue('size', {width:310}).width+'px; left:'+GM_getValue('position', {left:5}).left+'px; top:'+GM_getValue('position', {top:430}).top+'px;'+(showBorder ? ' border:'+defaultBorder+'; ' : '')+' font:11px Arial; text-shadow:1px 1px 1px black; background:#333; overflow-x:hidden; overflow-y:auto;"><div id="CS_ChatHistory"></div></div>');
$uBottom.removeClass('hidden');
}
$CS_ChatHistory = $('#CS_ChatHistory');
$CS_ChatHistory_Container = $('#CS_ChatHistory_Container');
GM_addStyle('#CS_ChatHistory_Container::-webkit-scrollbar { width:'+(showScollBar?'2px':'0px')+' }');
GM_addStyle('#CS_ChatHistory_Container::-webkit-scrollbar-thumb { background:#b0b; }');
GM_addStyle('#CS_ChatHistory_Container::-webkit-scrollbar-track { background:#ddd; }');
GM_addStyle('.CS_Link { text-decoration:underline; color:palegoldenrod !important }');
}
function showLastGameLog() {
let lastChatLog = $.parseHTML( GM_getValue('lastChatLog', '') );
if (lastChatLog) {
if ($(lastChatLog).find('.CS_Kickable').length) {
$(lastChatLog).find('.CS_Kickable').removeData('kickid').removeAttr('data-kickid').removeAttr('title').removeClass();
$CS_ChatHistory.append(lastChatLog);
GM_setValue('lastChatLog', $CS_ChatHistory.html());
} else {
$CS_ChatHistory.append(lastChatLog);
}
$CS_ChatHistory.prepend('<div style="text-align:center; margin-bottom:5px; text-decoration:underline">Last Game Chat Log...</div>');
}
}
function showSummary() {
let scoreboard = '';
if ( ( (PageLoc !== 'ingame' && showScoreboardOnHome) || (PageLoc === 'ingame' && showScoreboardOnEOG) || (PageLoc !== 'ingame' && showSummaryOnHome) || (PageLoc === 'ingame' && showSummaryOnEOG) ) && GM_getValue('gameData') ) {
let stats = [ 'score', 'tags', 'pops', 'grabs', 'drops', 'hold', 'captures', 'prevent', 'returns', 'support', 'powerups', 'points' ];
let rStats = { score:0, tags:0, pops:0, grabs:0, drops:0, hold:0, captures:0, prevent:0, returns:0, support:0, powerups:0, points:0 };
let bStats = { score:0, tags:0, pops:0, grabs:0, drops:0, hold:0, captures:0, prevent:0, returns:0, support:0, powerups:0, points:0 };
let game = GM_getValue('gameData');
let playedFor = (game.timePlayed / game.fullGameLength * 100).toFixed(2);
if (playedFor > 100) playedFor = 100;
$CS_ChatHistory_Container.append('<div id="CS_GameSummary" style="border-top:1px solid white; border-bottom:1px solid white; margin:20px 1px 5px 1px"></div>');
if ((PageLoc !== 'ingame' && showScoreboardOnHome) || (PageLoc === 'ingame' && showScoreboardOnEOG)) {
scoreboard = '<table id="CS_Scoreboard"><tr id="CS_Scoreboard_Header"><td></td><td>Sc</td><td>Ta</td><td>Po</td><td>Gr</td><td>Dr</td><td>Ho</td><td>Ca</td><td>Pr</td><td>Re</td><td>Su</td><td>PU</td><td>Pt</td></tr>';
$.each(game.playersData, function(key, value) {
scoreboard += '<tr'+(value.self === true ? ' class="CS_SB_HighlightSelf"' : '')+' data-team="'+value.team+'"><td style="color:'+(value.team === 1 ? redTextColor : blueTextColor)+'">'+(value.auth ? '<span class="CS_Auth CS_Font7">✔</span>' : '')+value.name+'</td><td data-raw="'+value.score+'">'+value.score+'</td><td data-raw="'+value.tags+'">'+value.tags+'</td><td data-raw="'+value.pops+'">'+value.pops+'</td><td data-raw="'+value.grabs+'">'+value.grabs+'</td><td data-raw="'+value.drops+'">'+value.drops+'</td><td data-raw="'+value.hold+'">'+secondsToHMS(value.hold)+'</td><td data-raw="'+value.captures+'">'+value.captures+'</td><td data-raw="'+value.prevent+'">'+secondsToHMS(value.prevent)+'</td><td data-raw="'+value.returns+'">'+value.returns+'</td><td data-raw="'+value.support+'">'+value.support+'</td><td data-raw="'+value.powerups+'">'+value.powerups+'</td><td data-raw="'+value.points+'">'+(value.points ? value.points : '-')+'</td></tr>';
if (showTeamTotals) {
$.each(stats, function(k, v) {
if (value.team === 1) {
rStats[v] += value[v];
} else {
bStats[v] += value[v];
}
});
}
});
scoreboard += '</table>';
setTimeout(function() {
let $table = $('#CS_Scoreboard'), $column, prevMax;
for (let i=2; i<=13; i++) {
$column = $('#CS_Scoreboard tr:gt(0) td:nth-child('+i+')');
prevMax = 0;
$( $column ).each(function(k, v) {
if ($(this).data('raw') > prevMax) {
$($column).removeClass('CS_Max');
$(this).addClass('CS_Max');
prevMax = $(this).data('raw');
} else if ($(this).data('raw') === prevMax) {
$(this).addClass('CS_Max');
}
});
}
if (showTeamTotals) {
$('#CS_Scoreboard').append('<tr style="background:#777"><td colspan="13" style="border:3px solid transparent;"></td></tr>');
$('#CS_Scoreboard').append('<tr style="background:rgba(255,0,0,0.2)"><td style="color:'+redTextColor+'; text-align:right">Red Total:</td><td'+(rStats.score>bStats.score?' class="CS_Max_Red"':'')+'>'+rStats.score+'</td><td'+(rStats.tags>bStats.tags?' class="CS_Max_Red"':'')+'>'+rStats.tags+'</td><td'+(rStats.pops>bStats.pops?' class="CS_Max_Red"':'')+'>'+rStats.pops+'</td><td'+(rStats.grabs>bStats.grabs?' class="CS_Max_Red"':'')+'>'+rStats.grabs+'</td><td'+(rStats.drops>bStats.drops?' class="CS_Max_Red"':'')+'>'+rStats.drops+'</td><td'+(rStats.hold>bStats.hold?' class="CS_Max_Red"':'')+'>'+secondsToHMS(rStats.hold)+'</td><td'+(rStats.captures>bStats.captures?' class="CS_Max_Red"':'')+'>'+rStats.captures+'</td><td'+(rStats.prevent>bStats.prevent?' class="CS_Max_Red"':'')+'>'+secondsToHMS(rStats.prevent)+'</td><td'+(rStats.returns>bStats.returns?' class="CS_Max_Red"':'')+'>'+rStats.returns+'</td><td'+(rStats.support>bStats.support?' class="CS_Max_Red"':'')+'>'+rStats.support+'</td><td'+(rStats.powerups>bStats.powerups?' class="CS_Max_Red"':'')+'>'+rStats.powerups+'</td><td'+(rStats.points>bStats.points?' class="CS_Max_Red"':'')+'>'+(rStats.points ? rStats.points : '-')+'</td></tr>');
$('#CS_Scoreboard').append('<tr style="background:rgba(0,0,255,0.2)"><td style="color:'+blueTextColor+'; text-align:right">Blue Total:</td><td'+(bStats.score>rStats.score?' class="CS_Max_Blue"':'')+'>'+bStats.score+'</td><td'+(bStats.tags>rStats.tags?' class="CS_Max_Blue"':'')+'>'+bStats.tags+'</td><td'+(bStats.pops>rStats.pops?' class="CS_Max_Blue"':'')+'>'+bStats.pops+'</td><td'+(bStats.grabs>rStats.grabs?' class="CS_Max_Blue"':'')+'>'+bStats.grabs+'</td><td'+(bStats.drops>rStats.drops?' class="CS_Max_Blue"':'')+'>'+bStats.drops+'</td><td'+(bStats.hold>rStats.hold?' class="CS_Max_Blue"':'')+'>'+secondsToHMS(bStats.hold)+'</td><td'+(bStats.captures>rStats.captures?' class="CS_Max_Blue"':'')+'>'+bStats.captures+'</td><td'+(bStats.prevent>rStats.prevent?' class="CS_Max_Blue"':'')+'>'+secondsToHMS(bStats.prevent)+'</td><td'+(bStats.returns>rStats.returns?' class="CS_Max_Blue"':'')+'>'+bStats.returns+'</td><td'+(bStats.support>rStats.support?' class="CS_Max_Blue"':'')+'>'+bStats.support+'</td><td'+(bStats.powerups>rStats.powerups?' class="CS_Max_Blue"':'')+'>'+bStats.powerups+'</td><td'+(bStats.points>rStats.points?' class="CS_Max_Blue"':'')+'>'+(bStats.points ? bStats.points : '-')+'</td></tr>');
}
}, 100);
GM_addStyle('#CS_Scoreboard { margin:5px 0; font-size:10px; color:#bbb; line-height:8px; width:100%; text-align:center; border-collapse:collapse; border-spacing:1px; }');
GM_addStyle('#CS_Scoreboard_Header { color:#fff; }');
GM_addStyle('#CS_Scoreboard td { border:1px solid #555; }');
GM_addStyle("#CS_Scoreboard tr.CS_SB_HighlightSelf { background:rgba(50,200,50,0.2) }");
GM_addStyle('#CS_Scoreboard .CS_Max { color:gold }');
GM_addStyle('#CS_Scoreboard .CS_Max_Red { color:white; background:rgba(220,0,0,0.6) }');
GM_addStyle('#CS_Scoreboard .CS_Max_Blue { color:white; background:rgba(0,0,240,0.7) }');
$('#CS_GameSummary').append(scoreboard);
}
if ((PageLoc !== 'ingame' && showSummaryOnHome) || (PageLoc === 'ingame' && showSummaryOnEOG)) {
$('#CS_GameSummary').prepend('<div id="CS_GameSummary_Header" style="margin:2px 10px; border:1px solid #bbb; border-radius:7px; box-shadow:1px 1px 1px #999;"></div>');
$('#CS_GameSummary_Header').append('<div style="text-align:center; color:#ccc; font-size:11px; font-weight:bold;">' + (game.spectator ? '<span style="background:' + (game.spectatorTeam === 1 ? 'red' : game.spectatorTeam === 2 ? '#46F' : 'none') + '; display:inline-block; border-radius:50%; width:15px; height:13px; line-height:10px;" title="You were watching: '+game.spectator+'">&#128064;</span> ' : '') + '<span style="text-decoration:underline;">' + game.mapName + ' by ' + game.mapAuthor + ' (' + game.gameMode + ')</span></div>');
$('#CS_GameSummary_Header').append('<div style="text-align:center; color:#bbb; font-size:10px">' + new Date(parseInt(Date.parse(game.played))).toLocaleTimeString() + ' (' + new Date(parseInt(Date.parse(game.played))).toDateString() + (game.serverName ? ') on ' + game.serverName : ')') + '</div>');
$('#CS_GameSummary_Header').append('<div style="text-align:center; color:#bbb; font-size:10px; font-style:italic">You '+(game.spectator ? 'watched' : 'played')+' for ' + secondsToHMS(game.timePlayed) + ' of ' + secondsToHMS(game.fullGameLength) + ' ('+ playedFor + '%)</div>');
if (game.allCaps.length && showTimelineOnSummary) {
let timePlayed = game.timePlayed*1000;
let gameLength = game.fullGameLength*1000;
if (gameLength > 360000) gameLength = 360000;
let startTime = Date.parse(game.played);
let joinTime = startTime + gameLength - timePlayed;
let endTime = startTime + gameLength;
let fullTime = startTime + 360000;
let joinPoint = 100 - ((fullTime - joinTime) / 360000) * 100;
let endPoint = 100 - ((fullTime - endTime) / 360000) * 100;
let gameWidth = endPoint - joinPoint;
let endWidth = 100 - endPoint;
$('#CS_GameSummary').append('<div id="CS_TL_Outer"></div>');
$('#CS_TL_Outer').append('<div id="CS_TL"></div>');
if (joinPoint > 0) $('#CS_TL').append('<div id="CS_TL_Pre" style="width:'+joinPoint+'%"></div>');
$('#CS_TL').append('<div id="CS_TL_Game" style="left:'+joinPoint+'%; width:'+gameWidth+'%;"></div>');
if (endPoint < 100) $('#CS_TL').append('<div id="CS_TL_Post" style="left:'+endPoint+'%; width:'+endWidth+'%;"></div>');
let resultClass='CS_TL_MyTeam', title='';
$('#CS_TL_Outer').append('<div id="CS_TL_RedLabel">'+game.redScore+'</div>');
$('#CS_TL_Outer').append('<div id="CS_TL_BlueLabel">'+game.blueScore+'</div>');
if (game.result === 'Win') {
if (game.team === 1) $('#CS_TL_RedLabel').attr('title', 'We (Red) Won '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeamWin');
else $('#CS_TL_BlueLabel').attr('title', 'We (Blue) Won '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeamWin');
} else if (game.result === 'Loss') {
if (game.team === 1) $('#CS_TL_RedLabel').attr('title', 'We (Red) Lost '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeamLoss');
else $('#CS_TL_BlueLabel').attr('title', 'We (Blue) Lost '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeamLoss');
} else if (game.result === 'Tie') {
if (game.team === 1) $('#CS_TL_RedLabel').attr('title', 'Game Tied '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeam');
else $('#CS_TL_BlueLabel').attr('title', 'Game Tied '+game.redScore+':'+game.blueScore).addClass('CS_TL_MyTeam');
}
$.each(game.allCaps, function(key, value) {
let thisPoint = joinPoint + (100 - ((fullTime - value.time) / 360000) * 100);
if (!value.hasOwnProperty('what') || value.what === 'cap') {
$('#CS_TL').append('<div class="'+(value.team===1?'CS_TL_CapRed':'CS_TL_CapBlue')+'" style="left:'+thisPoint+'%;" title="Cap: '+value.name+'\nHold: '+value.holdTime+'\nTimer: '+value.timer+'\nTeams: '+value.redCount+'v'+value.blueCount+'\nScore: '+value.redScore+':'+value.blueScore+'"></div>');
} else if (value.what === 'left') {
$('#CS_TL').append('<div class="'+(value.team===1?'CS_TL_Left_Red':'CS_TL_Left_Blue')+'" style="left:'+thisPoint+'%;" title="Left: '+value.name+'\nTimer: '+value.timer+'\nTeams: '+value.redCount+'v'+value.blueCount+'\nScore: '+value.redScore+':'+value.blueScore+'"></div>');
} else if (value.what === 'joined') {
$('#CS_TL').append('<div class="'+(value.team===1?'CS_TL_Joined_Red':'CS_TL_Joined_Blue')+'" style="left:'+thisPoint+'%;" title="Joined: '+value.name+'\nTimer: '+value.timer+'\nTeams: '+value.redCount+'v'+value.blueCount+'\nScore: '+value.redScore+':'+value.blueScore+'"></div>');
} else if (value.what === 'switched') {
$('#CS_TL').append('<div class="'+(value.team===1?'CS_TL_Switched_Red':'CS_TL_Switched_Blue')+'" style="left:'+thisPoint+'%;" title="Switched: '+value.name+'\nTimer: '+value.timer+'\nTeams: '+value.redCount+'v'+value.blueCount+'\nScore: '+value.redScore+':'+value.blueScore+'"></div>');
}
});
GM_addStyle('#CS_TL_Outer { position:relative; margin:0 6px 0 20px; padding:16px 0 20px 0; text-align:left; }');
GM_addStyle('#CS_TL { position:absolute; display:inline-block; width:100%; }');
GM_addStyle('#CS_TL_Pre { position:absolute; display:inline-block; left:0px; border-bottom:1px dotted #666; }');
GM_addStyle('#CS_TL_Game { position:absolute; display:inline-block; border-bottom:1px solid #ddd; }');
GM_addStyle('#CS_TL_Post { position:absolute; display:inline-block; border-bottom:1px dashed #a33; }');
GM_addStyle('.CS_TL_CapRed { position:absolute; display:inline-block; margin-top:-2px; width:2px; height:5px; background:#f33 }');
GM_addStyle('.CS_TL_CapBlue { position:absolute; display:inline-block; margin-top:-2px; width:2px; height:5px; background:deepskyblue }');
GM_addStyle('.CS_TL_Left_Red { position:absolute; display:inline-block; margin-top:-4px; width:1px; height:2px; background:#ff65f2 }');
GM_addStyle('.CS_TL_Joined_Red { position:absolute; display:inline-block; margin-top:-4px; width:1px; height:2px; background:limegreen }');
GM_addStyle('.CS_TL_Switched_Red { position:absolute; display:inline-block; margin-top:-4px; width:1px; height:2px; background:yellow }');
GM_addStyle('.CS_TL_Left_Blue { position:absolute; display:inline-block; margin-top:3px; width:1px; height:2px; background:#ff65f2 }');
GM_addStyle('.CS_TL_Joined_Blue { position:absolute; display:inline-block; margin-top:3px; width:1px; height:2px; background:limegreen }');
GM_addStyle('.CS_TL_Switched_Blue { position:absolute; display:inline-block; margin-top:3px; width:1px; height:2px; background:yellow }');
GM_addStyle('#CS_TL_RedLabel { position:absolute; display:inline-block; width:16px; height:17px; text-align:center; color:#f33; font:14px Arial; margin:-17px -18px; cursor:default; }');
GM_addStyle('#CS_TL_BlueLabel { position:absolute; display:inline-block; width:16px; height:17px; text-align:center; color:deepskyblue; font:14px Arial; margin:2px -18px; cursor:default; }');
GM_addStyle('.CS_TL_MyTeam { border:1px dashed #fff; border-radius:50%; }');
GM_addStyle('.CS_TL_MyTeamWin { border:1px dashed #0d0; border-radius:50%; }');
GM_addStyle('.CS_TL_MyTeamLoss { border:1px dashed #e00; border-radius:50%; }');
}
}
setTimeout(function() {
window.requestAnimationFrame(function() {
$CS_ChatHistory_Container.animate({scrollTop: $CS_ChatHistory_Container.get(0).scrollHeight}, 500);
});
}, 600);
}
}
if (showLastGameOnHome && PageLoc === 'server') {
addToPage();
showLastGameLog();
showSummary();
} else if (showLastGameOnJoiner && PageLoc === 'joining') {
addToPage();
showLastGameLog();
showSummary();
} else if (PageLoc === 'ingame') {
let joinTime;
let gameData = {};
let mapName='', mapAuthor='', mapType='';
let pupsCount = 0;
let escape = document.createElement('textarea');
let allCaps = [];
let teamCounts = { Red:0, Blue:0 };
let jqUI_CssSrc = GM_getResourceText("jqUI_CSS"); //so we can drag/resize the chat window
GM_addStyle(jqUI_CssSrc);
let updateChatHistory = function(from, message, to, c, mod) {
let playerId = null;
let playerName = '';
let playerAuth = false;
let showTimer = showTime;
let name = '';
let playerColor = '#ffffff', messageColor = '#ffffff';
let timerText = '--:--';
let messageStyle = '';
if (!message) return;
if (/[<>&"]/.test(message)) {
escape.textContent = message;
message = escape.innerHTML;
}
message = linkify(message);
if ((tagpro.ui.sprites.hasOwnProperty('timer')) && (tagpro.ui.sprites.timer.hasOwnProperty('text'))) {
timerText = tagpro.ui.sprites.timer.text;
if (timerText.includes(':-')) timerText = '00:00'; //timer has gone into negatives (after end of game)
}
if ($.isNumeric(from)) {
playerId = from;
playerName = tagpro.players[from].name;
if (tagpro.players[from].auth && showPlayerAuthTick) playerAuth = true;
if (tagpro.players[from].team === 1) playerColor = redTextColor;
else playerColor = blueTextColor;
if (to === 'team') {
if (tagpro.players[from].team === 1) messageColor = redTextColor;
else messageColor = blueTextColor;
}
} else if ($.type(from) === 'string') {
playerName = from;
playerColor = '#e7e700';
messageColor = '#e7e700';
} else if (from === null) {
let hasLeft = message.indexOf('has left the ');
let hasJoined = message.indexOf('has joined the');
let hasSwitched = message.indexOf('has switched to');
let teamColor = 'Red';
messageStyle = '; font-style:italic';
if (hasLeft >= 0 || hasJoined >= 0 || hasSwitched >= 0) {
if (message.indexOf('Blue') > 10) teamColor = 'Blue';
if (hasLeft >= 0) {
name = message.substr(1, hasLeft - 3);
message = message.replace(teamColor, '<span class="CS_Underline">'+teamColor+'</span>').replace(name, '<span class="CS_Underline">'+name+'</span>').replace('left', '<span class="CS_Underline">left</span>');
teamCounts[teamColor]--;
} else if (hasJoined >= 0) {
name = message.substr(1, hasJoined - 3);
message = message.replace(teamColor, '<span class="CS_Underline">'+teamColor+'</span>').replace(name, '<span class="CS_Underline">'+name+'</span>').replace('joined', '<span class="CS_Underline">joined</span>');
teamCounts[teamColor]++;
} else if (hasSwitched >= 0) {
name = message.substr(1, hasSwitched - 3);
message = message.replace(teamColor, '<span class="CS_Underline">'+teamColor+'</span>').replace(name, '<span class="CS_Underline">'+name+'</span>').replace('switched', '<span class="CS_Underline">switched</span>');
teamCounts[teamColor]++;
if (teamColor === 'Red') teamCounts.Blue--;
else teamCounts.Red--;
}
if ((tagpro.state === 1)) { // || (tagpro.state === 3)
if ((teamCounts.Red < 1) || (teamCounts.Red > 4) || (teamCounts.Blue < 1) || (teamCounts.Blue > 4)) { //sometimes happens when we join a game
getTeamCounts();
}
if (showScoreOnJoinLeft) message += ' [' + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red + 'v' + teamCounts.Blue + ']';
if (tagpro.state === 1) {
if (playSoundOnJoin && (tagpro.sound || ignoreMuteSoundIcon) && (hasJoined >= 0 || hasSwitched >= 0)) {
(new Audio('data:audio/wav;base64,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Xa0lrXnW5iq7oijh0o0xjpZkRk3p/////13/9da9rot9TFf+tH3cz+/2oSRPc6GMjVRsur6ndEKPz5oZmQAAd6cAmAPdWwd4dwZWiYw9IQAgb+JfmbJ4uWttS5KlcqGaZbP///0yv//3oRlLYpUu7JhkUP/7gMTogBYuQRnuCNuh5sYkPA4JLZuj0VqornMV9VNO76uORLnq1iojbf/////r6bU6zNstVRCz+u2lvSXZlU6IzS7zC7UKRWRrozWbshSiSRfoRdmVAAAGoAWAOBGge8h9tFX2WVGSZhtwajk7sua6/0ttCQRTf//9cF////q7ciuqOZ3c6PSpXozGU5SkY+ik87F90e6TI//////9XdDGZLqy2KkwtZlkc2jmexkc7o7OyaNWynnRTEOpZSKjaGK7MYg7qp7sax1KwJlxDMwAFTdgUyBx/YHrPm4YZWnIW7MAOrtwEPgzoNxpbaZa/UttN////0//T/v3Yx0e8IDouNWfSw0InhusUOScUDwSmEXu//6K7lEDTTxE6fFQqUb1/7PS3uqShenfoeoACquwCwAAv1D////1nhm/jD0hCz5jHU7sGTQU1WcvdqUyrH/+k971VUUx5iplarGQhLlIYWiikLZlD6OzlImz//tQxP8ADhInI+BsRanXROQ8DYi1lbL//////tsdE6JRzlyESOU+79f78eqtPZ3duAE0BxtoHhTu4xNHztKYOoeM/NrFiTuxqy9y////r//9vX6v32u/U+hksWeZGcMUHU7WBc3FU3f//sofdaDy2i4EBkGf//2dbnouYsWrgagAAJvAWqA4/0D7qVvoreXsAI2pAZBZMscQ1caWrqd2HrL6////r//83ZK5cpEZw52fIjEVyotY4uJAdAjWAsomEiO+r///2QEDqnuIFBEGCP/7YMTpAA8+MR/gbEkpdJblPA0ItP9n+3VqufVflNyWBAACYqgCg9gf9ComxlBC4YgAFBlwcsDBMQdQfOqWr703mOyqz1diMio5TuzSnSVTIdGKjTo7pr0dk0VDbW/////9G+yl+8HZFmDKFIKLt6Ovu3ENegUkUdA9MleLKoiImEABa/2MgAoMZEDBTiMQOB4ADEWuasB7jpoCPLjpOA5CwZf40KIB56gfL3Qh1360OM9QGL7X+uR5V3w0xCUssaOtdgDmLngZdkOrEglx4AgR95G7EVZwaFlED0yCgREnRB0ysQm6M9mZGPuYXTZ72W942PV16aaYusft4+tn9NOOzd8f+v/7UMT1ggttnSnsgFMhPp1lPAyJJO253+f//vuf//vv//fP8//7f43btXY2N+XcN+VvP1RubMfZqMfd2vymOOl+6kKJlmS0SfqXaETEbIokEH7p5CbUxo8yzQG+hLKRAjvfMJa7QrsIAD/6pAAGOzkY5GJlAdiMhGnygY8UICNpicjGZw2Z9TBjUUmeD6IAMYbBgiDZhwKgUzGx4QasO4OHBhMJF8zDAVkF8mEncMmklgryad8HSzfRzMEjesgafNobAiM1Akw6QOdGQQiSAy7/+1DE/YCLiNsp4GhHYW+zZP1ACmRoBAzLEUXwERHQQYKCwMeAgkEqMCAWHpEs8TqYStVaTQlbYHVK7Cxpt+Y9FojPQzRQ1Tw7MQ9Qz0RnYatxmpGqGHpuM0Euq2Ka6LROJPh2nXJyT4ck3lquWruRyt9bWkcJLmKZJ0Wp2r0+VT5WVv/nK9efXn/ubP7HS2motpFRqLPLEtlyMmo5TzVHU852NI5VaCgGAUAwSS9EgYjKOU5qMSRkijjmkdyq9EgEFEQCRmZlGaqnIolJVUxB//ugxP6AGsZBF+xszaSQR+G9zRo8TUUzLjk5LjVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjk5LjVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sQxNYDwAAB/gAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU=')).play();
} else if (playSoundOnLeft && (tagpro.sound || ignoreMuteSoundIcon) && hasLeft >= 0) {
(new Audio('data:audio/wav;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAATAAAdigAaGhoaGjAwMDAwQ0NDQ0NVVVVVVVVkZGRkZHNzc3NzgoKCgoKRkZGRkZGenp6enqqqqqqqtbW1tbW+vr6+vr7JycnJydPT09PT3Nzc3Nzj4+Pj4+Pr6+vr6/r6+vr6//////8AAABkTEFNRTMuOTlyBN0AAAAAAAAAADUgJATtQQAB9AAAHYoFHEY8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//vAxAAAC3wDNaCAACoJoCR+sLAE21kICku++34AAAABAefnHTh+b8wAQAACoeHh48AAAAARh4eHh4AAAAAjDw8/wAAAAADDw8PDwAAAABWOH///gZn4/////ccPDx6nAAARh4eP/////////83/A/szd1MgrPdvs4xVjMMw611yXJay7MNU2VPDe8JYIlAiAfD2b0sda1znOc5zra1rWta1sOc5znOva1rWtbw5ztzr5qprqnw63Nh0RdTXPP/c39Mr4iJj+I4pyUwoUXeTbTe9u7sZ+ztxaoXqv05hbCdhgqyWmBZ5RRgeLSoqotUkQtE6VQAAACAGRIJEigIAgEAiIB4taZ944ZjxGrGGqdUZyYWZgNgDgYGMzOhpjQZLlMS0B8w7RNjAMAMEIJxjbiJmGSCiYMIKBgogsD207Z0kwb82GACJhQK26a8AG5FhvbOa2nmDBqVSRTqKWQHA51KSeFTHLRBuBYX+cFrq5WnxyKPxNnFuptLCaeNm0KxpiMypryt0Mxm3L6mFJmDhQxUNMLCQwHMMBjAgJwaa1Esf7b/HD9pqFo0H1roAExGSR3KlqYRrvcOYY5569FNY7T0wF2Oosdnb97s2dU1NVpaXfe/hhlf/PS6HIgRl7/xdrj+RRx43lTU1WrKa1NTVaX+f+WGru57GkkspiMvdyMTj909uHKSxP188dUs1WlV6lpa1NKqtLZiEuu4SGU0FqjlcGxSUyjKIY6gOlgF255p7YoVAE2+0zzXO3u4162qucqlF67uX1qDXKebnqkOSbKzjVyyrY445ZVsatXWVNjy7pNFAAAB+n+tyIBgAg2GGmIQYMo5py33nGMqRAaE5ipi9C4mZYzaZlgc5hghhGCGDKEAamCMBiPAauIWyV1Aw5YuUTcGJh3GY5Iypdc1PChRSKJFhcQrYlQXEZYgRNOXSKkVcxLpdNZkXi8ySSSVjxqdFzILWZlMY8Qb/+7DE84At6jctue2iC+PE47e9IAUX03STuiaoImpiqgZHE3UbpmRVJobTIGCBQHwRczTqUqkk1NGgrXoGyjMfZUQQdMzHyTyCKJV///qMhWFppO6iaIi1S2q9+jW1anYyEZDeQMEWOizBkTHe2jfZJFaWu6aSZ83mp6XzFDunWZougdUZLUtSM2TSRZSSaKaZwEWW1kqqAAAE+3gbJABgCYAUYCGANGBbAFppYiMWYIYBWGKdBKxgT4HUYFgMqGKDAURgRQDgYIYATGArgBYQAHIKoaBgAvL2L4ratTF+lzx/fLoiABldO87TKmHJ6oHS7Luv////WiRwvSdLpdJ0mRyRJ0E0HVs3uv1oUlGxHEFPmTuZJDMG5spFFNkUp16KZjVSN1m1EZ0kkknY+UCJnkFGj9qWr+yTnBGQojqOJIiVkgknRV6kZ1VA6mg6jZzE6OIQ2YnWLoTg711kpbqq1fJdrWLXjmTqZdqlrZkjNyV8m9bKVA6xU8oqiDyFJqaxgUSNiiqJMnklJ+cmFkYePO/z7togBH0wCYA9MCbAMDQiTEwwUkA8MRDBCDArAK8w4cYdMUaASTATAQYwBMCADgHwEgAhfsvMEAAiwU4/DSaGtb7aq4ctRFebmQ9uAZI7gkAGv9N2KOluZrmqTzhsig89MXTpYuPQsPt7RHgSDtdNObF036t/dbO1JYNw8KXNOEMlmUadKVB5rIa3mGNjU0nmRuy7lofihzYNf5pze7/3TD7bAIYcmr9l1Z6X1jPpb43mttWzu3zTVYInZiySvJIRzGvX2tJam658PWfrWIm56eerXfMr/G389X9Pnc3llf/7oMTtgh8+QRWvxTnj8Mgi9fW/NPPtxX0bbjXd3PC9CiT2ritWGr61n0eLA9IcugAADfd6JGQAIQAUKgERgQABOaBcSomB4AHphrQSGYD2A+mHRCd5hVQDiPAIxgEQFOYAYAGmAIgAidDV0kU92qOA38qluf/+tUlVDCWw3Rtwii2Eoql7e/5///dIwNxCnzA0J5Li4FzZ1M2pSS0a009ak9FMd44TQ6bpGBNJi3sip2dFFdmQqWy0l47B7IIoLTLxdSUo27P9Vv2RCjHibpoMcHoPJBJ3UtSLrcuNXeo4kkgeOgPq0FOZogxkcxunPKQ1m76/jUUSmfCdk4vD0MJEaqzbVjv1pk1VDttIEiWAQkEINBI/GlwknJullp4tAAAAIgI/+rJAIgIjA+ARMEEHw9jVrjC7BGMhEnowKArDEpKQMl4CYqhBGC0AgYFIABgKACqw12VOTIos3tu3//9JXrQQCgB5PI6tWVTZWAVAlJzPPP1ppvQQQqQatMzWYCbhPDQ8ZJE0ZwchLlNE0QPUFqUt33Z6Cqjo/mCaNZwqIZule6tK6DKd1tWYLMkBoMU0qRmNZcVm7Vv//tTEeQrXULJ73Q6lIHXutbJrQOrTSEBGXOHFLB5IBpuN/G5R+7lNr0fGnZmY26SLmDzWbD5xKPiT4TPv7O0RqpTO5komUgR5EI21GKwAAP/7oMTtAB3aQRevtNnjpUgjPeabPE7f7/RkAA4DEwIwODBWCPPJgz8wtgYTEUJ1MEAGcxJ0TzJaA9AIQRBQboACvbhgkS71vdLjruVru8pVDSSFrLVatESg63S0tnmsmt3Ova13LW1BsShtAPNW01EeQbck53NXf1U3dzFvprWom77dTjYsPRtmObiXdbKj/tznFlx8ol7dsc9ffP/z/tlYa21tg2MncbY4qq3Vwt1bjrG47Ako6bshBLbXVEzfNNXe65vOTdOzjZju30w2s0/ROnlKncquoyH2eiUt810YKQq1iaqKh2pUAAFuMYBoDRgeARmBiF0epIUhhdgsGA+UMPBhmRoPOYnQHJgAgGGAcC3JDASARFgBntLVNZl0cgez////ny2v+EUd6nnJANACSOx3DvO//vsZoEoJgPMoG5obkoMAeTbRNE1qXqPJJO5x1pubFwwNE588UzNl0a0qmdLRQdqLUXQJ5igt7kgbLUtav//8TQlk1JswxzVnUnqtdNFboWU51KVGQaC1qzp4GA0S8/3XvU8ThkYyGt91gK3mNAxJWySWjrYS20uLW1n3UtZB4hZRQ+U0dPkxeucRRWowAAM4Zp//jJASAMAMFIwQgdzpsIUNBDk0jvzHgcOdtw7kEAIPjEQOMCh8AdAfYcwFOJ7HWfXtZMvnimJvBel83UYID4CzZv/7kMT7gNqyPRmvZWnraEei0eabPcXDRk001pp1IVptTTdA0MExXBUzA0Z5YHeeppug1bM9GhUyKTm6zhGH6aKkSyaIOyLvS9Sk3eymqyPNUXQN1lhM3UzL1rX/0+6huKsvI1Kt0/7IJugyTMqyKQrB7TSNBniXOqQtutNFSCkVumq7qdSU6gua0kkFIGyRqjqSL7GaUspsmcM1ujUxqiYWnlqYuGRROuZMwAFv99xoyADAPAqMAgEEwKQhjk/N/MHMDYw5hKjAjAxMAcvExJANQKBU0wwIACyICZBCmS1qBpbKseb/9d3l2urFfywxy2hBFbPcsv3/71XQuQAdHDXapBByrlajaJjWb6XtqukE10sXAjtFR0sK9ojwnf9OmNH93FSOqY+fifn///6EINffkCfiKmv+E7giehkQ0oHQIJcOQD4jDk2REdkmTx6naucyLL3TD6HdMiiymwOc8dUGEsQOllkssyZtIVEsbdmueIAxTFRVUAAAeHB/xo0ADAcAfMD0FgwDgiTf2RoMFIAMw7wmwgBww/gJzCCANU+YDf/7kMTpgBt+QRnvciLjLUejNeUjDAB7tAgAEGgADQCLlqpxjDPHL//9/jcWLUl2fLEApr0uOWX////eaVBuPHqHOIEQ5E7M6PqZ2WyTrFJUiIh8ho8GQ8djnus8sax22zufqh7HTpWvvN+v/uMySyYlIud9DERFNZnc92VhHE0nnHKGJIV707rl4eszbxuhL2/Ljy8wQX1YguM5TqZUXM+5ZqpLINSNlTO2rKo0pzzSgzAAF9Hv2iIABIABgIAkmACE0b0a2pgbgdGIMAIYCICxh/gbgIcAwBAFDAKAWU5Q3FgCbTytOv5c7z//8KlePLDXu83y8j5G7lW1ezwUt2TQWpmTUtJnQMxpE9Nka0jw5DRaUxc6pTKq3ptetNR0usynW6ZcRd0Dt6a6WvXekpZUZLdSCj1fsv9W37oCzMb8vHmU61spbLRZ6NTKapFZmH08mcQLiJIkY/2fzmbkyz58Kst2r+7vJI0CDSkRElG1eVeRyI92KIz8cqkpwK+kmJJHhYNZuIpFakAAAnhgjcWNEAwDAFRCCMMgzmmElEYBQP/7kMTbgBjmQRnvKNnjXkgi9eabPB5hUgoFQAswSBkTBiALLvBYBGDANaCxkERHSFLqK/2usPhTTTdMoCCZut/////8OkpEQgR0/qNZ/jmrt57r3Fj3uZEMdXY+5b0ett/mpSIQYu2iCQfff3/x////4lOqE5EOvr7/naEmZaOPSQdD+biyQMMbbmI5qLblIuLI6lV4S1e5q4mVF6geVEni0P9GDJE7IzVBbiq2zNbwkD5HKAAZvDhP4+iIBgCDwVCskD47P6EKgAYsCilUYZAwNEAYDgOAhFdswMAdlEScqlrLS/rRKw2jZJTVhzG///66Jwf0UUbJDwWgg6FB0fkqlpyO6Hqi53qqtPv9PI56o+ZEa3///yD/iL/f7690z0KDXKYwUZfSjNqeiPIqVNopZFKqS7ij1IhFOKCyM5TqzudmaQivlYWNLWAABogAjcexEAwEAFx0GIRgpmU8lUFwBzBDCCX0YOIPZEFahwGQQC5oBFASwTkQMnjX/pLLorJo95iKDNVH2U6//5ppWHDoBg+p7JCNpqIeKleJ2pKi/f/7kMTSABbGQRvvSQviWkcj/daV/R7GQu7IMpN66m4LnruXpL+bcQZpK8tE4r/nv////xI386PH/P//CXd1ysXYSDyp6SxGn3jdK56eE4rMPH0o6zuraUql0grW51uxw6ildxyPKWlwedLOQNgkg0hRsACfwH3GjJAUaIQJRECAYzaQICCDEHNhZomuZgEo5ggNZwEFydL/LT/0MBhj0ZSUCQ1+n//3Q8XnGLQ0ePu+1terqudPQ9dXSYddknd0PRWNWrmsYeiu7mkZrvX7//8XNXlH9UsffrYyzHu8SjHPYu4ljw+lF6HtZTjjnOU5XMcss09zCkxTpg65kgZTyZTsncxTSlWNscUIDnkB7EQ/AhiAATGGAI/HkRACwAmDQlBUJzHTtAcB4MExMYwADQaCF5hYCXeAwYr2flF/9jCAJ7upx5AC2Tn+n//zCMWGM6CyfnWludrNe4cR6KNVSlcx61VGay3RasZ+iPf0p//8bfM300mp56kuaGGmvCiFW7lR2ZTItzI8ppFqtYIE6Iis7kRUCprMHAxiuIBCzJOQOf/7gMTxgBZuPxvvSQvigkcjde2oZYjHC5OragBA1lQCB0AjCsSQYDxkJtpgwABhGJ6nBhGL4sUiDAiBBK0EgE2Kqv/0uAJ+Ag5HORP/9DknDov/Edn96Tq0srWMgVyJqovKZm87K5GZG6GdLLRDJk///8G3eDbu6rT+rHX1BjazBERbchmdqOyrCrKZXMgVTnMzkRzO5kOcjVK5IQKzVOSAsKQ6MrGDMQ4sK9VgEHSWAI/FkRALVmAgOAUEzSHGAEIZhYFCm5hIJpgqEZg2BIGIyIZZEMIGkv/rzpA0HRSROjrQf///9nbnO/7NvymRnZLlZit0I72OVkNk/XbIYje6lq16b//438v/+fXnd6hFjG3Ehc9fn0pVXZHRZyo5WmVyIQ5J2KuVyIkxq0QeI3jxacphJWxGIDqAhVZcAgcSEQQmI4pgwCDYSvzDQADEED0vDAUFjBQAFaQZAWkFgkiPy2X/6CyCfkYyb2////twxPOA0povHe6oTepBx+O504m8/0f6k9Hkmd5FWdFIQ6mIKUyVJOjEjOVEW6Uye1VfkOWzV///1f9//uinns9y1DnQxmVzk90TW3W6upziTPByI65COjZLrRzKRTtsTEZT4QqOiRYQoCCJhwCPhZEgDBUBzEALkE5sXCQQKY0MMNhUNTG4HQgGgOBAv2MYaUX//km9EVA////+X6Ht79W9ylS9XRb9W3/fZqyLOzIVUpar3///+j/T+nt+t9GYVKWgOTzPLK73R57Os7oeVqmOtgTHLfIwoyqNsdh2oxwjOrlUSqMM7IEMTDAEfj2NACwVCBWnQeq34aYcZEmNBcPzQDnA+n7H7Xp//QMMZ2LCD////ZRJytmJ8tqJ6ra0+4w2PFBMYhrM2Yoks5yq/dGKNdnsV7f////7cMTygFGaPR3uwKnqIMdjvdmJPfp/b7/pR205IhoRXUoizvbo1zls6qqFQzFO5Umd6uhTLkZ3IqEZmO6sIOjOzoV2OMJI5RIVapAlp5CAjcW1oAMEQGLi4z3NoFxzUTWseKxgAKHGIMpNuE9V6PP+rgzeoX////Vdlz2VFcuz3SxpBpToUgjXmKc21klXOqrJ1ZJKorUR0T///0/X/r9Wqr9kRVrv/0VTWVqaMvXbspHKtlXYgiphVUF2ZHqKsREQeNN9J3CAIJmAAHHFcRAAQGgoTk1TkJcSlwz4pSQ1gIEWEDCFWwxZz//1Av4SInf///MzdSKnTpnRpFLIiTUdUagkjXQsjGcQ2oa6q1keQ/ZEtTr//7fX7f1po9mtRCFOLFEJzNehqqpnRrHqzy5lKR53uVTuKMX/+2DE+gAP1jMf7sxJahvII/3MlGQqM4xlE2cXKPVBBBgccayAx5RSwqNHEE2qsFZ5gACfxdWwTDIEMdBtnR3NUDZIwzVWs3AsaloczEBWqR+13/8hVA1Og3////X0nlPIt3Kndl1PfQ0pfV0K+d3Idkc6WKzMpUYlaqzv///9f7/r/tZU3nZlFlG7NTWXvrl7Uur8x73S5Ey5x5L4j74GQnbPQNeC0CI0TLxH41rQBhIImKxEpieUO4HVBqS7ya8xAkf8oVAkQhx/IcnHYhBBCVIxAFp6wT////oT6ELfQyWKqHLQroyOUqEzPJUGV2cxtEK7+WuaiIqVelv//+r/T/7pzo7/+3DE7wAPgicf7mSjKilII33clGRaEVHVis91QxP1kq72r3ZSOyHKVnMFOdXe1x3VpEVjmPaZClMdD1BSNaOaoFerqZihxrYgTBIIMQClaR0UOA41KMApwWCfqrXMBQgrku7LeVqals48/LLK1v60S/Cv////P/22lTtVFaqGU0mQqIoQjMV2FFcWUT12bfq8miNr//////+2pnKQxbnL1KoMV7P9/9rW567nfvVXCUnoDZaxfv0JHTGkX4t1UDZEDj7SBAABMJFG4ntAAGTVrAYZTWvaxyvQL+b///+rfVv597ZWVlNkOcrFJI9lcqEKR66KRHY5XXKhUe1iJ////+v1+7fQh0XBKHVFQuxm/9sWlVARLCBRMNOfMemAzQnTwJuZAACBwPrAzBwwxIteI6chNPFC3qKT//tgxP2ADwYFIe5ooyomxiP9zIhtXcscsfT8v/////PkvV0vuyfPLVm0oDqupbuRikMran7kd3Vn2P/////77aWyqytZKIq0MEDCjf0bE1OFPVzk7LJcNQWSV5bAq4gcDaMIwgRMRNm6nTIRsBeYGAISWtY9531/N/////9OiUkVURZlkOt5d0dmQ9kZT2lK1OrZEa23XX/////+lqpenY9iIx6FcgfrX0vMO/aKnyjoeSXvYoaAjD1jAKVVwKx4AACBwPpAjAw4wY1bscWpmglgIAS3TIdc7z0/L////9e9HuQrq1dXaVZ1Zy22dm3V7SXs2RSoVlVjOcjoZiu1v////T/b//tgxPSBD8WfIe5gRemLMiS9sAlcar1O5uioCcE5Meaq/Md4HsKQ3NPE9dkaEg1PuuFCxawupgcDasMGAQqebCe64bR+FRDMYKr953z/m//////3fZK2nJsjKxkQ5GYzuikmnRUU/69WvIyqRP/////6SXVHSREVD2KshxTKcGgNgj+WXbsYl19CiACY8+0NE4N2IQ0sFGBouqAAAcD2MIw4MyZ0qADq6SFOb1KAl6B4CGISGlv/F//////+X////9VnUzKzlozst6dj1NlU6nIdlcqqjJedT5FrQxyk+yUJ/////37/5bEIig6yFOxTqwS3GtUmmycWw+PixPiCJg0guA2J//tQxPwBC+GbJ+2ASuGBNCS9sAlccJTC0CpAEwASoQwQgOw9FQZBAAABKNzHoKBBzM7CQzdFTqUXMNhfzMQlMQg8zIYhIWf5UDhigEHBxsa2E+BIWBwYG2nWBkFmcA4CAFCQLXwMHmMJjkDIQW8aZHCzQ5cDRI/AzqTAMyF0DE5U+F7xcBFxH41AMSk4DBo9AxYPAGBoAMevyIEsbEQGQJsFASBgQEgPAwIQOGcg2Mf3rNyugmFswuqC4EMvBa8H5hdD/pqZqBonIIKkMQQVE//7UMT5gQzplyXtgErhizNkvaAJXHC/GdFyCg//7vv4yQnUc4QmF+KQIoNsbAskWd//2b1vdPZQ1RnRlBc47hkRzhZw/jkEYO8dguUgX9f1+ulWjbqdNFpktRfUzXSU7mKSVI4cUOkckgA55bKhExcws0U4uEDGwREZogIxpACBkeOATkLmFIjkD6HeQioBN6uUlUoH//6rO0sMsaUGNRtUhtDbDZxpSpgGoQlFp85JIk9q1bXLatW2ZWu5b6rbWtMzZcu5pdba40udy3zta9v/+5DE8gAOXaMj9aEAJLlIJf85UFBa9n6yt8SuiU9ljwNPg07zuCt2d6b6j39Z3r/xF/+s7/Ue//Ev+mpMQU1FMy45OS41qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+zDE5wPNCKULnYYAAAAANIAAAASqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=')).play();
}
}
if (showLJSOnTimeline) {
let what = '';
if (hasLeft >= 0) what = 'left';
else if (hasJoined >= 0) what = 'joined';
else if (hasSwitched >= 0) what = 'switched';
allCaps.push( { what:what, time:Date.now(), name:name, team:(teamColor==='Red'?1:2), timer:timerText, redScore:tagpro.score.r, blueScore:tagpro.score.b, redCount:teamCounts.Red, blueCount:teamCounts.Blue } );
}
}
} else {
//let joinedAsSpec = message.indexOf('joined a game as a spectator');
let isSaveAttempt = message.startsWith('This is a save attempt!');
let youHaveReported = message.startsWith('You have reported');
let hasVotedYou = message.startsWith('Someone has voted');
let hasBanned = message.includes('(mod) has banned');
let joinedAsSBFromSpec = message.startsWith("Hi! You're currently");
if (isSaveAttempt) {
c = '#ff77ff';
} else if ((youHaveReported) || (hasVotedYou) || (hasBanned)) {
c = '#ff5599';
} else if (joinedAsSBFromSpec) {
let oldTCR = teamCounts.Red;
let oldTCB = teamCounts.Blue;
getTeamCounts(); //sometimes happens when we join a game from spec (as a sb?)
message = 'Was:' + oldTCR + ':' + oldTCB + ' |Now:' + teamCounts.Red + ':' + teamCounts.Blue + ' || ' + message;
alert('joined from spec - check player counts!!!');
} else {
message = message.replace(/�/g, '\'').trim();
if (hideTimeOnSystemChat) showTimer = false;
}
}
}
if (mod) {
playerColor = '#00aa00';
messageColor = '#00aa00';
}
if (c) {
playerColor = c;
messageColor = c;
}
$CS_ChatHistory.append('<div>' +
(showTimer ? '<span style="color:'+timeColor+'">'+timerText+' </span>' : '') +
(playerName ? (playerAuth ? '<span class="CS_Auth CS_Font9">✔</span>' : '') + '<span'+(playerId ? ' class="CS_Kickable" data-kickid="'+playerId+'" title="Report '+playerName+'"' : '')+' style="color:'+playerColor+'">'+playerName+'</span>: ' : '') +
'<span style="color:'+messageColor+messageStyle+'">'+message + '</span>' +
'</div>');
//only autoscroll down if we're already at/near the bottom (otherwise user is reading previous chat and autoscroll is painful)...
if ($CS_ChatHistory_Container.get(0).scrollTop + 40 > $CS_ChatHistory_Container.get(0).scrollHeight - $CS_ChatHistory_Container.innerHeight()) {
window.requestAnimationFrame(function() {
$CS_ChatHistory_Container.animate({scrollTop: $CS_ChatHistory_Container.get(0).scrollHeight}, 500);
});
}
if (playSoundOnMessage && (tagpro.sound || ignoreMuteSoundIcon)) {
(new Audio('data:audio/wav;base64,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')).play();
}
GM_setValue('lastChatLog', $CS_ChatHistory.html());
};
let addToChatHistory = function(message, eog) { //this is used to add other messages to the chat history (like caps)
let timerText = '--:--';
if ((tagpro.ui.sprites.hasOwnProperty('timer')) && (tagpro.ui.sprites.timer.hasOwnProperty('text'))) {
timerText = tagpro.ui.sprites.timer.text;
if (timerText.includes(':-')) timerText = '00:00'; //timer has gone into negatives (after end of game)
}
$CS_ChatHistory.append('<div'+(eog ? ' id="CS_EOG" style="border-top:1px solid white; border-bottom:1px solid white"' : '')+'>' +
(showTime ? '<span style="color:'+timeColor+'">'+timerText+' </span>' : '') +
message +
'</div>');
window.requestAnimationFrame(function() {
$CS_ChatHistory_Container.animate({scrollTop: $CS_ChatHistory_Container.get(0).scrollHeight}, 500);
});
GM_setValue('lastChatLog', $CS_ChatHistory.html());
};
let friendlyGrabTime = 0;
let enemyGrabTime = 0;
let grabCheckFlagsDelay = 120;
let redHolder = 0;
let blueHolder = 0;
let whoHasFlags = function() {
redHolder=0;
blueHolder=0;
for (let playerId in tagpro.players) {
if (tagpro.players.hasOwnProperty(playerId)) {
if (tagpro.players[playerId].flag === 1) {
blueHolder = Number(playerId);
} else if (tagpro.players[playerId].flag === 2) {
redHolder = Number(playerId);
} else if (tagpro.players[playerId].flag === 3) {
if (tagpro.players[playerId].team === 1) {
redHolder = Number(playerId);
} else {
blueHolder = Number(playerId);
}
}
}
}
};
let getPlayerCaps = function() {
let playerCaps = {};
for (let playerId in tagpro.players) {
if (tagpro.players.hasOwnProperty(playerId)) {
playerCaps[playerId] = { caps:tagpro.players[playerId]['s-captures'], team:tagpro.players[playerId].team, name:tagpro.players[playerId].name };
}
}
return playerCaps;
};
let getTeamCounts = function() {
teamCounts.Red = 0;
teamCounts.Blue = 0;
for (let playerId in tagpro.players) {
if (tagpro.players.hasOwnProperty(playerId)) {
if (tagpro.players[playerId].team === 1) teamCounts.Red++;
else teamCounts.Blue++;
}
}
};
if (tagpro.group.socket !== null) { //save all group chat events (if we're in a group)...
tagpro.group.socket.on('chat', function(data) {
updateChatHistory(data.from, data.message, data.to, null, null);
});
}
tagpro.socket.on('chat', function(data) { //save all regular chat events...
updateChatHistory(data.from, data.message, data.to, data.c, data.mod);
});
tagpro.socket.on('spectator', function(spectator) {
if (!spectator.type) { //we joined from spec
joinTime = Date.now();
}
});
tagpro.socket.on('time', function(message) {
if (tagpro.state === 3) { //before the actual start
joinTime = Date.now();
} else if (tagpro.state === 1) { //game has started
if (joinTime) {
joinTime = Date.parse(tagpro.gameEndsAt) - 360000;
} else {
joinTime = Date.now();
whoHasFlags();
}
setTimeout(function() {
getTeamCounts();
}, 200);
} else if (tagpro.state === 5) { //overtime
if (!joinTime) { //joined in overtime
joinTime = Date.now();
}
}
});
tagpro.socket.on('map', function(data) {
if (hideNormalChat) {
setTimeout(function() {
$('#chatHistory').hide(0);
}, 1100);
}
mapName = data.info.name;
mapAuthor = data.info.author;
for (let i=0; i<tagpro.map.length; i++) { //find the flags which will tell us if it's a CTF or NF map...
for (let j=0; j<tagpro.map[i].length; j++) {
if (tagpro.map[i][j] == 16 || (tagpro.map[i][j] == 16.1)) { //yellow flag found
mapType = 'NF';
} else if ((tagpro.map[i][j] == 3) || (tagpro.map[i][j] == 3.1) || (tagpro.map[i][j] == 4) || (tagpro.map[i][j] == 4.1)) { //red or blue flag found
mapType = 'CTF';
}
}
}
addToPage();
GM_deleteValue('lastChatLog');
GM_deleteValue('gameData');
$CS_ChatHistory_Container.resizable({
delay: 50,
distance: 3,
containment: 'document',
handles: 'n, e, s, w, ne, se, sw, nw',
resize: function(event, ui) {
$CS_ChatHistory_Container.css('border', '1px dashed white');
},
stop: function(event, ui) {
GM_setValue('size', {'width':ui.size.width, 'height':ui.size.height});
GM_setValue('position', {'top':ui.position.top, 'left':ui.position.left});
if (!showBorder) $CS_ChatHistory_Container.css('border', 'none');
$CS_ChatHistory_Container.css('background', defaultBorder);
}
});
$CS_ChatHistory_Container.draggable({
delay: 50,
containment: 'window',
scroll: false,
drag: function(event, ui) {
$CS_ChatHistory_Container.css('border', '1px dashed white');
},
stop: function(event, ui) {
GM_setValue('position', {'top':ui.position.top, 'left':ui.position.left});
if (!showBorder) $CS_ChatHistory_Container.css('border', 'none');
$CS_ChatHistory_Container.css('background', defaultBorder);
}
});
$CS_ChatHistory.on('click', '.CS_Kickable', function() {
tagpro.kick.player( tagpro.players[$(this).data('kickid')] );
});
GM_addStyle('.CS_Kickable:hover { text-decoration:underline; cursor:pointer; }');
});
if (showCaps) {
tagpro.socket.on('sound', function(data) {
let capTime, capperId, capperColor, capMessage;
let playerCaps;
let timerText = '';
let holdTime;
grabCheckFlagsDelay = tagpro.ping.avg + 30;
if (isNaN(grabCheckFlagsDelay) || grabCheckFlagsDelay <= 80) grabCheckFlagsDelay = 80;
//Friendly Grab...
if ((data.s === 'friendlyalert') && (data.hasOwnProperty('v'))) {
friendlyGrabTime = Date.now();
whoHasFlags();
//Enemy Grab...
} else if ((data.s === 'alert') && (data.hasOwnProperty('v'))) {
enemyGrabTime = Date.now();
whoHasFlags();
//Friendly Cap...
} else if (data.s === 'cheering') {
capTime = Date.now();
playerCaps = getPlayerCaps();
setTimeout(function(friendlyGrabTime) {
let done = false;
for (let playerId in tagpro.players) {
if (tagpro.players.hasOwnProperty(playerId) && playerCaps.hasOwnProperty(playerId)) {
if (tagpro.players[playerId]['s-captures'] === playerCaps[playerId].caps + 1) {
playerCaps[playerId].caps++;
capperId = playerId;
if (tagpro.players[playerId].team === 1) capperColor = redTextColor;
else capperColor = blueTextColor;
done = true;
break;
}
}
}
if (!done) {
if (tagpro.players[tagpro.playerId].team === 1) {
capperId = redHolder;
capperColor = redTextColor;
} else {
capperId = blueHolder;
capperColor = blueTextColor;
}
if (capperId) {
addToChatHistory('<span style="color:#9A5">FRIENDLY -- NOT DONE: ' + playerCaps[capperId].name + ' |caps:' + playerCaps[capperId].caps + '</span>');
playerCaps[capperId].caps++;
}
}
if ((tagpro.ui.sprites.hasOwnProperty('timer')) && (tagpro.ui.sprites.timer.hasOwnProperty('text'))) timerText = tagpro.ui.sprites.timer.text;
if (capperId) {
//if (tagpro.players[capperId]['s-captures'] === 0) addToChatHistory('<span style="color:#B0B">0th! </span><span style="color:'+capperColor+'">' + tagpro.players[capperId].name + ' (' + ordinal_suffix_of(tagpro.players[capperId]['s-captures']) + ', ' + (friendlyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-friendlyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
addToChatHistory('<span class="CS_Cap">CAP!</span><span style="color:'+capperColor+'">' + tagpro.players[capperId].name + ' (' + ordinal_suffix_of(playerCaps[capperId].caps||1) + ', ' + (friendlyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-friendlyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
holdTime = secondsToHMS((capTime-friendlyGrabTime)/1000);
allCaps.push( { what:'cap', time:capTime, id:capperId, name:tagpro.players[capperId].name, team:tagpro.players[capperId].team, holdTime:holdTime, timer:timerText, redScore:tagpro.score.r, blueScore:tagpro.score.b, redCount:teamCounts.Red, blueCount:teamCounts.Blue } );
} else {
addToChatHistory('<span class="CS_Cap">CAP!</span><span style="color:'+(tagpro.players[tagpro.playerId].team === 1 ? redTextColor : blueTextColor)+'">Unknown (' + (friendlyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-friendlyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
allCaps.push( { what:'cap', time:capTime, id:0, name:'Unknown', team:(tagpro.players[tagpro.playerId].team === 1 ? 1 : 2), holdTime:0, timer:'', redScore:tagpro.score.r, blueScore:tagpro.score.b, redCount:teamCounts.Red, blueCount:teamCounts.Blue } );
}
whoHasFlags();
}, 200, friendlyGrabTime);
//Enemy Cap...
} else if (data.s === 'sigh') {
capTime = Date.now();
playerCaps = getPlayerCaps();
setTimeout(function(enemyGrabTime) {
let done = false;
for (let playerId in tagpro.players) {
if (tagpro.players.hasOwnProperty(playerId) && playerCaps.hasOwnProperty(playerId)) {
if (tagpro.players[playerId]['s-captures'] === playerCaps[playerId].caps + 1) {
playerCaps[playerId].caps++;
capperId = playerId;
if (tagpro.players[playerId].team === 1) capperColor = redTextColor;
else capperColor = blueTextColor;
done = true;
break;
}
}
}
if (!done) {
if (tagpro.players[tagpro.playerId].team === 1) {
capperId = blueHolder;
capperColor = blueTextColor;
} else {
capperId = redHolder;
capperColor = redTextColor;
}
if (capperId) {
addToChatHistory('<span style="color:#9A5">ENEMY -- NOT DONE: ' + playerCaps[capperId].name + ' |caps:' + playerCaps[capperId].caps + '</span>');
playerCaps[capperId].caps++;
}
}
if ((tagpro.ui.sprites.hasOwnProperty('timer')) && (tagpro.ui.sprites.timer.hasOwnProperty('text'))) timerText = tagpro.ui.sprites.timer.text;
if (capperId) {
//if (tagpro.players[capperId]['s-captures'] === 0) addToChatHistory('<span style="color:#B0B">0th! </span><span style="color:'+capperColor+'">' + tagpro.players[capperId].name + ' (' + ordinal_suffix_of(tagpro.players[capperId]['s-captures']) + ', ' + (enemyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-enemyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
addToChatHistory('<span class="CS_Cap">CAP!</span><span style="color:'+capperColor+'">' + (tagpro.players[capperId].name) + ' (' + ordinal_suffix_of(playerCaps[capperId].caps||1) + ', ' + (enemyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-enemyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
holdTime = secondsToHMS((capTime-enemyGrabTime)/1000);
allCaps.push( { what:'cap', time:capTime, id:capperId, name:tagpro.players[capperId].name, team:tagpro.players[capperId].team, holdTime:holdTime, timer:timerText, redScore:tagpro.score.r, blueScore:tagpro.score.b, redCount:teamCounts.Red, blueCount:teamCounts.Blue } );
} else {
addToChatHistory('<span class="CS_Cap">CAP!</span><span style="color:'+(tagpro.players[tagpro.playerId].team === 1 ? blueTextColor : redTextColor)+'">Unknown (' + (enemyGrabTime ? '<span title="Hold Time">'+secondsToHMS((capTime-enemyGrabTime)/1000)+'</span>, ' : '') + tagpro.score.r + ':' + tagpro.score.b + ', ' + teamCounts.Red+'v'+teamCounts.Blue + ')</span>');
allCaps.push( { what:'cap', time:capTime, id:0, name:'Unknown', team:(tagpro.players[tagpro.playerId].team === 1 ? 2 : 1), holdTime:0, timer:'', redScore:tagpro.score.r, blueScore:tagpro.score.b, redCount:teamCounts.Red, blueCount:teamCounts.Blue } );
}
whoHasFlags();
}, 200, enemyGrabTime);
}
});
}
tagpro.socket.on('end', function(data) {
let fullTime = Date.parse(tagpro.gameEndsAt); //expected end of game time after 6 mins
let endTime = Date.now(); //actual end of game time
let startTime = fullTime - 6 * 60 * 1000; //start of game time
let fullGameLength = (endTime-startTime)/1000; //how long the whole game lasted (with or without us)
if (fullGameLength > 360) fullGameLength = 360;
let playedGameLength = (endTime-joinTime)/1000; //how long we played for
let capTrickMessage = '';
let eogMessage = '';
let playerId;
//GM_deleteValue('lastChatLog');
//GM_deleteValue('gameData');
gameData.mapName = mapName;
gameData.mapAuthor = mapAuthor;
gameData.gameMode = mapType;
gameData.played = new Date(joinTime).toISOString();
gameData.timePlayed = playedGameLength;
gameData.fullGameLength = fullGameLength;
gameData.spectator = (tagpro.spectator ? tagpro.players[tagpro.playerId].name : false);
gameData.spectatorTeam = (tagpro.spectator ? tagpro.players[tagpro.playerId].team : false);
if (tagproConfig) {
let serverName = tagproConfig.gameSocket.substring(0, tagproConfig.gameSocket.indexOf(':')).replace('tagpro-', '').replace('.koalabeast.com', '');
} else {
gameData.serverName = document.URL;
}
//save scoreboard...
gameData.playersData = [];
for (playerId in tagpro.players) {
gameData.playersData.push({
name:tagpro.players[playerId].name,
id:tagpro.players[playerId].id,
team:tagpro.players[playerId].team,
auth:tagpro.players[playerId].auth,
self:(tagpro.playerId === tagpro.players[playerId].id && !tagpro.spectator ? true : false),
tags:tagpro.players[playerId]["s-tags"],
pops:tagpro.players[playerId]["s-pops"],
grabs:tagpro.players[playerId]["s-grabs"],
drops:tagpro.players[playerId]["s-drops"],
hold:tagpro.players[playerId]["s-hold"],
captures:tagpro.players[playerId]["s-captures"],
prevent:tagpro.players[playerId]["s-prevent"],
returns:tagpro.players[playerId]["s-returns"],
support:tagpro.players[playerId]["s-support"],
powerups:tagpro.players[playerId]["s-powerups"],
score:tagpro.players[playerId].score,
points:tagpro.players[playerId].points
});
}
gameData.playersData.sort(function(a, b) {
return (b.score - a.score ? b.score - a.score : a.id - b.id);
});
gameData.allCaps = allCaps;
//Look for Cap-Tricks...
for (playerId in tagpro.players) {
if (tagpro.players[playerId]['s-captures'] >= 3) capTrickMessage = 'CapTrick ('+tagpro.players[playerId]['s-captures']+' caps!) by ' + tagpro.players[playerId].name;
}
setTimeout(function() {
if (tagpro.score.r > tagpro.score.b) {
if (tagpro.players[tagpro.playerId].team === 1) {
eogMessage += '<span style="color:limegreen">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Red Won (Spec &#128064;)' : ' | We (Red) Won!</span>');
} else {
eogMessage += '<span style="color:#f33">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Red Won (Spec &#128064;)' : ' | We (Blue) Lost :(</span>');
}
} else if (tagpro.score.r < tagpro.score.b) {
if (tagpro.players[tagpro.playerId].team === 1) {
eogMessage += '<span style="color:#f33">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Blue Won (Spec &#128064;)' : ' | We (Red) Lost :(</span>');
} else {
eogMessage += '<span style="color:limegreen">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Blue Won (Spec &#128064;)' : ' | We (Blue) Won!</span>');
}
} else if (tagpro.score.r === tagpro.score.b) {
if (tagpro.players[tagpro.playerId].team === 1) {
eogMessage += '<span style="color:cadetblue">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Tie! (Spec &#128064;)' : ' | Tie! We were on Red</span>');
} else {
eogMessage += '<span style="color:cadetblue">End of Game | Score ' + tagpro.score.r + ':' + tagpro.score.b + (tagpro.spectator ? ' | Tie! (Spec &#128064;)' : ' | Tie! We were on Blue</span>');
}
}
gameData.eogMessage = eogMessage;
let result = '', resultText = '';
if (data.winner === 'tie') {
result = 'Tie';
resultText = 'Tie!' + (tagpro.players[tagpro.playerId].team === 1 ? ' We were on Red' : ' We were on Blue');
} else if ((data.winner === 'red') && (tagpro.players[tagpro.playerId].team === 1)) {
result = 'Win';
resultText = 'We (Red) Won!';
} else if ((data.winner === 'red') && (tagpro.players[tagpro.playerId].team === 2)) {
result = 'Loss';
resultText = 'We (Blue) Lost';
} else if ((data.winner === 'blue') && (tagpro.players[tagpro.playerId].team === 1)) {
result = 'Loss';
resultText = 'We (Red) Lost';
} else if ((data.winner === 'blue') && (tagpro.players[tagpro.playerId].team === 2)) {
result = 'Win';
resultText = 'We (Blue) Won!';
}
gameData.result = result;
gameData.redScore = tagpro.score.r;
gameData.blueScore = tagpro.score.b;
gameData.team = tagpro.players[tagpro.playerId].team;
GM_setValue('gameData', gameData);
if (capTrickMessage) eogMessage += '<div style="text-align:center; background:#0c0; color:white; width:90%; margin:2px auto; border-radius:5px;">' + capTrickMessage + '</div>';
addToChatHistory(eogMessage, true);
showSummary();
}, 250);
});
}
});
//helper functions...
function secondsToHMS(d) {
d = Number(d);
let h = Math.floor(d / 3600);
let m = Math.floor(d % 3600 / 60);
let s = Math.floor(d % 3600 % 60);
return ((h > 0 ? h + ":" : "") + (m > 0 ? (h > 0 && m < 10 ? "0" : "") + m + ":" : "0:") + (s < 10 ? "0" : "") + s);
}
function ordinal_suffix_of(i) {
let j = i % 10, k = i % 100;
if (j == 1 && k != 11) return i + "st";
if (j == 2 && k != 12) return i + "nd";
if (j == 3 && k != 13) return i + "rd";
return i + "th";
}
function capitaliseFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function linkify(string) {
let urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;
let pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
let emailAddressPattern = /[\w.]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim;
return string
.replace(urlPattern, '<a href="$&" class="CS_Link" target="_blank">$&</a>')
.replace(pseudoUrlPattern, '$1<a href="http://$2" class="CS_Link" target="_blank">$2</a>')
.replace(emailAddressPattern, '<a href="mailto:$&" class="CS_Link">$&</a>');
}
function WhichPageAreWeOn() {
if (window.location.port || window.location.href.endsWith('/game')) { //In a real game
return('ingame');
} else if (document.URL.indexOf('/games/find') > 0) { //Joining page
return('joining');
} else if ($('#userscript-home').length) { //Chosen server homepage
return('server');
} else if (document.URL.indexOf('/profile/') > 0) {
if ($('#saveSettings').length) {
return('profile'); //Profile page and logged in
} else {
return('profileNotOurs'); //Profile page, but not our one (or we're logged out)
}
} else if (document.URL.indexOf('/groups') > 0) {
return('groups');
} else if (document.URL.indexOf('/boards') > 0) {
return('boards');
} else if (document.URL.indexOf('/maps') > 0) {
return('maps');
} else if (document.URL.indexOf('/settings') > 0) {
return('settings');
}
};
@wilcooo
Copy link

wilcooo commented Oct 12, 2017

The one thing I missed was some way to know when the message disappears for other balls (after 20 secs).
So I forked this gist and implemented this. Feel free to do whatever you want with it.

@wilcooo
Copy link

wilcooo commented Nov 13, 2017

This script broke, but it's easily fixed by replacing all ...timer.hasOwnProperty('text') with ...timer.hasOwnProperty('_text')

@wilcooo
Copy link

wilcooo commented Dec 12, 2017

Found another bug: when ingame, the addToPage() function is called on receiving a map socket event (line 576). When a chat event is received before the map event, updateChatHistory() will fail because $CS_ChatHistory is yet to be defined, and no chat messages can be read during the rest of the game :/. Fix: call addToPage() directly, not on receiving a socket. I updated the fork on my account. Btw: it's a great script, can't live without it!
@nabbynz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment