Last active
March 27, 2020 22:54
-
-
Save nabbynz/765e80b42b075e35acb1 to your computer and use it in GitHub Desktop.
TagPro Chat Scroller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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+'">👀</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,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')).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 👀)' : ' | 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 👀)' : ' | 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 👀)' : ' | 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 👀)' : ' | 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 👀)' : ' | 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 👀)' : ' | 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'); | |
} | |
}; | |
This script broke, but it's easily fixed by replacing all ...timer.hasOwnProperty('text')
with ...timer.hasOwnProperty('_text')
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
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.