// ==UserScript== // @name C&C:Online (Near) Full room notifier // @namespace https://github.com/BSG-75/C-C-Online-Website-hooks/ // @version 0.1030011 // @description A script for those game hosts who are AFK. It will play sound when the game is full or nearly full. It works by hooking some CNCOnline serverinfo.js functions. // @author [RA3Bar]Lanyi // @match https://cnc-online.net/* // @grant none // @run-at document-end // @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt // @downloadURL none // ==/UserScript== function main() { window.anyNewStagingGames = function(newStaging) { let oldGames = window.oldStagingGames; let newGames = newStaging.map(function(game) { return game.host.id + game.map + game.title; }); window.oldStagingGames = newGames; if(!oldGames) { return false; } for(let i = 0; i < newGames.length; ++i) { if(newGames[i].map.startsWith("Co-Op ")) { continue; } if(oldGames.indexOf(newGames[i]) == -1) { return true; } } return false; }; window.playersChanged = function(host, newPlayers) { let newHost = host.nickanme; let oldHost = window.previousHost; window.previousHost = newHost; let oldPlayers = window.previousPlayers; let mapped = newPlayers.map(function(player) { return player.nickname; }); window.previousPlayers = mapped; if(oldHost != newHost) { return false; } if(oldPlayers.length != mapped.length) { return true; } for(let i = 0; i < mapped.length; ++i) { if(oldPlayers[i] != mapped[i]) { return true; } } return false; }; window.myPrefix = "RA3Bar_Lanyi_CNCOLWebsiteNotifier_"; window.playerNameField = "PlayerNameField_"; window.monitorStagingGameId = window.myPrefix + "monitorStagingGame"; for (let i = 0; i < gamenames.length; ++i) { window[myPrefix + playerNameField + gamenames[i]] = null; } //from: http://s1download-universal-soundbank.com/wav/2838.wav window[myPrefix + "sound"] = new Audio("https://raw.githubusercontent.com/BSG-75/C-C-Online-Website-hooks/master/2838%5B2%5D.wav"); function notifyPlayer() { window[myPrefix + "sound"].play(); } //https://stackoverflow.com/questions/5499078/fastest-method-to-escape-html-tags-as-html-entities function escapeHTMLTags(str) { return str.replace(/&/g,'&').replace(//g,'>'); } //onfocus window[myPrefix + "onMyFieldFocus"] = function(field) { let myFieldID = field.id; if(!window[myFieldID] || window[myFieldID].length == 0) { field.innerText = ""; } }; //oninput window[myPrefix + "onMyFieldInput"] = function(field) { let myFieldID = field.id; window[myFieldID] = field.innerText.trim(); }; let originalSetUserBarInfo = setUserbarInfo; let originalGetUserSection = getUserSection; let originalHandleJSON = handleJSON; setUserbarInfo = function($parent, response) { let result = originalSetUserBarInfo($parent, response); $parent.append("← Click game name to monitor your room!"); }; getUserSection = function(response, gamename) { let myFieldID = myPrefix + playerNameField + gamename; let myFieldStyle = "background: #A00060; margin-left: 1em; padding-left: 0.5em; padding-right: 0.5em;" let myFieldDefaultValue = ""; let myFieldValue = myFieldDefaultValue; if(window[myFieldID] && window[myFieldID].length > 0) { myFieldValue = window[myFieldID]; } let attributes = "contenteditable = \"true\" id = \"" + myFieldID + "\" style = \"" + myFieldStyle + "\""; attributes += " onfocus = \"" + myPrefix + "onMyFieldFocus(this);" + "\" "; attributes += " oninput = \"" + myPrefix + "onMyFieldInput(this);" + "\" "; let myField = "" + escapeHTMLTags(myFieldValue) + ""; let result = originalGetUserSection(response, gamename); result.find("h3").append(myField); return result; }; handleJSON = function(response, textStatus, jqXHR) { let result = originalHandleJSON(response, textStatus, jqXHR); for (let i = 0; i < gamenames.length; ++i) { let gamename = gamenames[i]; let nickname = window[myPrefix + playerNameField + gamename]; let games = response[gamename].games.staging; console.log("nickname: " + nickname); if(nickname) { console.log("checking if it's in game " + gamename); for(let userNickname in response[gamename].users) { if(userNickname.toUpperCase() == nickname.toUpperCase()) { let inRoom = false; games.forEach(function(game) { if(game.players.nickname == userNickname) { console.log("player is inside a room"); inRoom = true; } }); if(!inRoom) { console.log("player in lobby"); if(window.anyNewStagingGames(games)) { console.log("new staging games, notifying player..."); notifyPlayer(); } } } } } $.each(games, function(i, game) { //if ( parseInt(game.numRealPlayers)+parseInt(game.numObservers) == parseInt(game.maxRealPlayers) ) { // $gameItem.addClass('full'); //} if (game.players != 'error') { $.each(game.players, function(j, player) { if(nickname && player.nickname) { if(player.nickname.toUpperCase() == nickname.toUpperCase()) { let realPlayers = parseInt(game.numRealPlayers); let observers = parseInt(game.numObservers); let maxPlayers = parseInt(game.maxRealPlayers); console.log("Player in room. totalPlayers = " + (realPlayers + observers)); if(realPlayers + observers >= maxPlayers * 0.5) { if(window.playersChanged(game.host, game.players)) { console.log("Players changed"); notifyPlayer(); } } } } }); } }); } return result; }; } (function() { 'use strict'; // Your code here... let mainScript = document.createElement("script"); mainScript.textContent = main.toString() + "\nmain();"; document.body.appendChild(mainScript); })();