Host Config
Host Config
/* ROOM */
var roomWebhook = ''; // this webhook is used to send the details of the room
(chat, join, leave) ; it should be in a private discord channel
var gameWebhook = ''; // this webhook is used to send the summary of the games ; it
should be in a public discord channel
var fetchRecordingVariable = true;
var timeLimit = 3;
var scoreLimit = 3;
var gameConfig = {
roomName: roomName,
maxPlayers: maxPlayers,
public: roomPublic,
noPlayer: true,
}
room.setScoreLimit(scoreLimit);
room.setTimeLimit(timeLimit);
room.setTeamsLock(true);
room.setKickRateLimit(6, 0, 0);
/* OPTIONS */
/* OBJECTS */
class Goal {
constructor(time, team, striker, assist) {
this.time = time;
this.team = team;
this.striker = striker;
this.assist = assist;
}
}
class Game {
constructor() {
this.date = Date.now();
this.scores = room.getScores();
this.playerComp = getStartingLineups();
this.goals = [];
this.rec = room.startRecording();
this.touchArray = [];
}
}
class PlayerComposition {
constructor(player, auth, timeEntry, timeExit) {
this.player = player;
this.auth = auth;
this.timeEntry = timeEntry;
this.timeExit = timeExit;
this.inactivityTicks = 0;
this.GKTicks = 0;
}
}
class MutePlayer {
constructor(name, id, auth) {
this.id = MutePlayer.incrementId();
this.name = name;
this.playerId = id;
this.auth = auth;
this.unmuteTimeout = null;
}
static incrementId() {
if (!this.latestId) this.latestId = 1
else this.latestId++
return this.latestId
}
setDuration(minutes) {
this.unmuteTimeout = setTimeout(() => {
room.sendAnnouncement(
`Has sido silenciado.`,
this.playerId,
announcementColor,
"bold",
HaxNotification.CHAT
);
this.remove();
}, minutes * 60 * 1000);
muteArray.add(this);
}
remove() {
this.unmuteTimeout = null;
muteArray.removeById(this.id);
}
}
class MuteList {
constructor() {
this.list = [];
}
add(mutePlayer) {
this.list.push(mutePlayer);
return mutePlayer;
}
getById(id) {
var index = this.list.findIndex(mutePlayer => mutePlayer.id === id);
if (index !== -1) {
return this.list[index];
}
return null;
}
getByPlayerId(id) {
var index = this.list.findIndex(mutePlayer => mutePlayer.playerId === id);
if (index !== -1) {
return this.list[index];
}
return null;
}
getByAuth(auth) {
var index = this.list.findIndex(mutePlayer => mutePlayer.auth === auth);
if (index !== -1) {
return this.list[index];
}
return null;
}
removeById(id) {
var index = this.list.findIndex(mutePlayer => mutePlayer.id === id);
if (index !== -1) {
this.list.splice(index, 1);
}
}
removeByAuth(auth) {
var index = this.list.findIndex(mutePlayer => mutePlayer.auth === auth);
if (index !== -1) {
this.list.splice(index, 1);
}
}
}
class BallTouch {
constructor(player, time, goal, position) {
this.player = player;
this.time = time;
this.goal = goal;
this.position = position;
}
}
class HaxStatistics {
constructor(playerName = '') {
this.playerName = playerName;
this.games = 0;
this.wins = 0;
this.winrate = '0.00%';
this.playtime = 0;
this.goals = 0;
this.assists = 0;
this.CS = 0;
this.ownGoals = 0;
}
}
/* PLAYERS */
/* AUTH */
/* COMMANDS */
var commands = {
help: {
aliases: ['commands'],
roles: Role.PLAYER,
desc: `
This command shows all the available commands. It also can show the
description of a command in particular.
Example: \'!help bb\' will show the description of the \'bb\' command.`,
function: helpCommand,
},
claim: {
aliases: [],
roles: Role.PLAYER,
desc: false,
function: masterCommand,
},
afk: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command makes you go AFK.
It has constraints: 1 minute minimum of AFK time, 5 minutes maximum and 10
minutes cooldown.`,
function: afkCommand,
},
afks: {
aliases: ['afklist'],
roles: Role.PLAYER,
desc: `
This command shows all the players that are AFK.`,
function: afkListCommand,
},
bb: {
aliases: ['bye', 'gn', 'cya'],
roles: Role.PLAYER,
desc: `
This command makes you leave instantly (use recommended).`,
function: leaveCommand,
},
me: {
aliases: ['stat', 'stats'],
roles: Role.PLAYER,
desc: `
This command shows your global stats in the room.`,
function: globalStatsCommand,
},
rename: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command allows you to rename yourself for the leaderboard.`,
function: renameCommand,
},
games: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most games in the room.`,
function: statsLeaderboardCommand,
},
wins: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most wins in the room.`,
function: statsLeaderboardCommand,
},
goals: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most goals in the room.`,
function: statsLeaderboardCommand,
},
assists: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most assists in the room.`,
function: statsLeaderboardCommand,
},
cs: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most CS in the room.`,
function: statsLeaderboardCommand,
},
playtime: {
aliases: [],
roles: Role.PLAYER,
desc: `
This command shows the top 5 players with the most time played in the
room.`,
function: statsLeaderboardCommand,
},
training: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command loads the classic training stadium.`,
function: stadiumCommand,
},
classic: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command loads the classic stadium.`,
function: stadiumCommand,
},
big: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command loads the big stadium.`,
function: stadiumCommand,
},
rr: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command restarts the game.`,
function: restartCommand,
},
rrs: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command swaps the teams and restarts the game.`,
function: restartSwapCommand,
},
swap: {
aliases: ['s'],
roles: Role.ADMIN_TEMP,
desc: `
This command swaps the teams when the game is stopped.`,
function: swapCommand,
},
kickred: {
aliases: ['kickr'],
roles: Role.ADMIN_TEMP,
desc: `
This command kicks all the players from the red team, including the player that
entered the command. You can give as an argument the reason of the kick.`,
function: kickTeamCommand,
},
kickblue: {
aliases: ['kickb'],
roles: Role.ADMIN_TEMP,
desc: `
This command kicks all the players from the blue team, including the player
that entered the command. You can give as an argument the reason of the kick.`,
function: kickTeamCommand,
},
kickspec: {
aliases: ['kicks'],
roles: Role.ADMIN_TEMP,
desc: `
This command kicks all the players from the spectators team, including the
player that entered the command. You can give as an argument the reason of the
kick.`,
function: kickTeamCommand,
},
mute: {
aliases: ['m'],
roles: Role.ADMIN_TEMP,
desc: `
This command allows to mute a player. He won't be able to talk for a
certain duration, and can be unmuted at any time by admins.
It takes 2 arguments:
Argument 1: #<id> where <id> is the id of the player targeted. This won't work
if the player is an admin.
Argument 2 (optional): <duration> where <duration> is the duration of the mute
in minutes. If no value is provided, the mute lasts for the default duration, $
{muteDuration} minutes.
Example: !mute #3 20 will mute the player with id 3 for 20 minutes.`,
function: muteCommand,
},
unmute: {
aliases: ['um'],
roles: Role.ADMIN_TEMP,
desc: `
This command allows to unmute someone.
It takes 1 argument:
Argument 1: #<id> where <id> is the id of the muted player.
OR
Argument 1: <number> where <number> is the number associated with the mute
given by the 'muteList' command.
Example: !unmute #300 will unmute the player with id 300,
!unmute 8 will unmute the n°8 player according to the 'muteList'
command.`,
function: unmuteCommand,
},
mutes: {
aliases: [],
roles: Role.ADMIN_TEMP,
desc: `
This command shows the list of muted players.`,
function: muteListCommand,
},
clearbans: {
aliases: [],
roles: Role.MASTER,
desc: `
This command unbans everyone. It also can unban one player in particular, by
adding his ID as an argument.`,
function: clearbansCommand,
},
bans: {
aliases: ['banlist'],
roles: Role.MASTER,
desc: `
This command shows all the players that were banned and their IDs.`,
function: banListCommand,
},
admins: {
aliases: ['adminlist'],
roles: Role.MASTER,
desc: `
This command shows all the players that are permanent admins.`,
function: adminListCommand,
},
setadmin: {
aliases: ['admin'],
roles: Role.MASTER,
desc: `
This command allows to set someone as admin. He will be able to connect as
admin, and can be removed at any time by masters.
It takes 1 argument:
Argument 1: #<id> where <id> is the id of the player targeted.
Example: !setadmin #3 will give admin to the player with id 3.`,
function: setAdminCommand,
},
removeadmin: {
aliases: ['unadmin'],
roles: Role.MASTER,
desc: `
This command allows to remove someone as admin.
It takes 1 argument:
Argument 1: #<id> where <id> is the id of the player targeted.
OR
Argument 1: <number> where <number> is the number associated with the admin given
by the 'admins' command.
Example: !removeadmin #300 will remove admin to the player with id 300,
!removeadmin 2 will remove the admin n°2 according to the 'admins'
command.`,
function: removeAdminCommand,
},
password: {
aliases: ['pw'],
roles: Role.MASTER,
desc: `
This command allows to add a password to the room.
It takes 1 argument:
Argument 1: <password> where <password> is the password you want for the room.
/* GAME */
/* COLORS */
var welcomeColor = 0xf5005f;
var announcementColor = 0xffffff;
var infoColor = 0xbebebe;
var privateMessageColor = 0x4ff1fe;
var redColor = 0xff4c4c;
var blueColor = 0x62cbff;
var warningColor = 0xffa135;
var errorColor = 0xa40000;
var successColor = 0x75ff75;
var defaultColor = null;
/* AUXILIARY */
var stopTimeout;
var startTimeout;
var unpauseTimeout;
var removingTimeout;
var insertingTimeout;
var emptyPlayer = {
id: 0,
};
stadiumCommand(emptyPlayer, "!training");
/* FUNCTIONS */
/* AUXILIARY FUNCTIONS */
function getDate() {
let d = new Date();
return d.toLocaleDateString() + ' ' + d.toLocaleTimeString();
}
/* MATH FUNCTIONS */
function getRandomInt(max) {
// returns a random number between 0 and max-1
return Math.floor(Math.random() * Math.floor(max));
}
/* TIME FUNCTIONS */
function getHoursStats(time) {
return Math.floor(time / 3600);
}
function getMinutesGame(time) {
var t = Math.floor(time / 60);
return `${Math.floor(t / 10)}${Math.floor(t % 10)}`;
}
function getMinutesReport(time) {
return Math.floor(Math.round(time) / 60);
}
function getMinutesEmbed(time) {
var t = Math.floor(Math.round(time) / 60);
return `${Math.floor(t / 10)}${Math.floor(t % 10)}`;
}
function getMinutesStats(time) {
return Math.floor(time / 60) - getHoursStats(time) * 60;
}
function getSecondsGame(time) {
var t = Math.floor(time - Math.floor(time / 60) * 60);
return `${Math.floor(t / 10)}${Math.floor(t % 10)}`;
}
function getSecondsReport(time) {
var t = Math.round(time);
return Math.floor(t - getMinutesReport(t) * 60);
}
function getSecondsEmbed(time) {
var t = Math.round(time);
var t2 = Math.floor(t - Math.floor(t / 60) * 60);
return `${Math.floor(t2 / 10)}${Math.floor(t2 % 10)}`;
}
function getTimeGame(time) {
return `[${getMinutesGame(time)}:${getSecondsGame(time)}]`;
}
function getTimeEmbed(time) {
return `[${getMinutesEmbed(time)}:${getSecondsEmbed(time)}]`;
}
function getTimeStats(time) {
if (getHoursStats(time) > 0) {
return `${getHoursStats(time)}h${getMinutesStats(time)}m`;
} else {
return `${getMinutesStats(time)}m`;
}
}
function getGoalGame() {
return game.scores.red + game.scores.blue;
}
/* REPORT FUNCTIONS */
function findFirstNumberCharString(str) {
let str_number = str[str.search(/[0-9]/g)];
return str_number === undefined ? "0" : str_number;
}
function getIdReport() {
var d = new Date();
return `${d.getFullYear() % 100}${d.getMonth() < 9 ? '0' : ''}${d.getMonth() +
1}${d.getDate() < 10 ? '0' : ''}${d.getDate()}${d.getHours() < 10 ? '0' : ''}$
{d.getHours()}${d.getMinutes() < 10 ? '0' : ''}${d.getMinutes()}${d.getSeconds() <
10 ? '0' : ''}${d.getSeconds()}${findFirstNumberCharString(roomName)}`;
}
function getRecordingName(game) {
let d = new Date();
let redCap = game.playerComp[0][0] != undefined ? game.playerComp[0]
[0].player.name : 'Red';
let blueCap = game.playerComp[1][0] != undefined ? game.playerComp[1]
[0].player.name : 'Blue';
let day = d.getDate() < 10 ? '0' + d.getDate() : d.getDate();
let month = d.getMonth() < 10 ? '0' + (d.getMonth() + 1) : (d.getMonth() + 1);
let year = d.getFullYear() % 100 < 10 ? '0' + (d.getFullYear() % 100) :
(d.getFullYear() % 100);
let hour = d.getHours() < 10 ? '0' + d.getHours() : d.getHours();
let minute = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes();
return `${day}-${month}-${year}-${hour}h${minute}-${redCap}vs${blueCap}.hbr2`;
}
function fetchRecording(game) {
if (gameWebhook != "") {
let form = new FormData();
form.append(null, new File([game.rec], getRecordingName(game), { "type":
"text/plain" }));
form.append("payload_json", JSON.stringify({
"username": roomName
}));
fetch(gameWebhook, {
method: 'POST',
body: form,
}).then((res) => res);
}
}
/* FEATURE FUNCTIONS */
function getCommand(commandStr) {
if (commands.hasOwnProperty(commandStr)) return commandStr;
for (const [key, value] of Object.entries(commands)) {
for (let alias of value.aliases) {
if (alias == commandStr) return key;
}
}
return false;
}
function getPlayerComp(player) {
if (player == null || player.id == 0) return null;
var comp = game.playerComp;
var index = comp[0].findIndex((c) => c.auth == authArray[player.id][0]);
if (index != -1) return comp[0][index];
index = comp[1].findIndex((c) => c.auth == authArray[player.id][0]);
if (index != -1) return comp[1][index];
return null;
}
room.sendAnnouncement(
messageFrom,
player.id,
privateMessageColor,
'bold',
HaxNotification.CHAT
);
room.sendAnnouncement(
messageTo,
playerTarget.id,
privateMessageColor,
'bold',
HaxNotification.CHAT
);
}
/* PHYSICS FUNCTIONS */
function calculateStadiumVariables() {
if (checkStadiumVariable && teamRed.length + teamBlue.length > 0) {
checkStadiumVariable = false;
setTimeout(() => {
let ballDisc = room.getDiscProperties(0);
let playerDisc = room.getPlayerDiscProperties(teamRed.concat(teamBlue)
[0].id);
ballRadius = ballDisc.radius;
playerRadius = playerDisc.radius;
triggerDistance = ballRadius + playerRadius + 0.01;
speedCoefficient = 100 / (5 * ballDisc.invMass * (ballDisc.damping **
60 + 1));
}, 1);
}
}
/* BUTTONS */
function topButton() {
if (teamSpec.length > 0) {
if (teamRed.length == teamBlue.length && teamSpec.length > 1) {
room.setPlayerTeam(teamSpec[0].id, Team.RED);
room.setPlayerTeam(teamSpec[1].id, Team.BLUE);
} else if (teamRed.length < teamBlue.length)
room.setPlayerTeam(teamSpec[0].id, Team.RED);
else room.setPlayerTeam(teamSpec[0].id, Team.BLUE);
}
}
function randomButton() {
if (teamSpec.length > 0) {
if (teamRed.length == teamBlue.length && teamSpec.length > 1) {
var r = getRandomInt(teamSpec.length);
room.setPlayerTeam(teamSpec[r].id, Team.RED);
teamSpec = teamSpec.filter((spec) => spec.id != teamSpec[r].id);
room.setPlayerTeam(teamSpec[getRandomInt(teamSpec.length)].id,
Team.BLUE);
} else if (teamRed.length < teamBlue.length)
room.setPlayerTeam(teamSpec[getRandomInt(teamSpec.length)].id,
Team.RED);
else
room.setPlayerTeam(teamSpec[getRandomInt(teamSpec.length)].id,
Team.BLUE);
}
}
function blueToSpecButton() {
clearTimeout(removingTimeout);
removingPlayers = true;
removingTimeout = setTimeout(() => {
removingPlayers = false;
}, 100);
for (var i = 0; i < teamBlue.length; i++) {
room.setPlayerTeam(teamBlue[teamBlue.length - 1 - i].id, Team.SPECTATORS);
}
}
function redToSpecButton() {
clearTimeout(removingTimeout);
removingPlayers = true;
removingTimeout = setTimeout(() => {
removingPlayers = false;
}, 100);
for (var i = 0; i < teamRed.length; i++) {
room.setPlayerTeam(teamRed[teamRed.length - 1 - i].id, Team.SPECTATORS);
}
}
function resetButton() {
clearTimeout(removingTimeout);
removingPlayers = true;
removingTimeout = setTimeout(() => {
removingPlayers = false;
}, 100);
for (let i = 0; i < Math.max(teamRed.length, teamBlue.length); i++) {
if (Math.max(teamRed.length, teamBlue.length) - teamRed.length - i > 0)
room.setPlayerTeam(teamBlue[teamBlue.length - 1 - i].id,
Team.SPECTATORS);
else if (Math.max(teamRed.length, teamBlue.length) - teamBlue.length - i >
0)
room.setPlayerTeam(teamRed[teamRed.length - 1 - i].id,
Team.SPECTATORS);
else break;
}
for (let i = 0; i < Math.min(teamRed.length, teamBlue.length); i++) {
room.setPlayerTeam(
teamBlue[Math.min(teamRed.length, teamBlue.length) - 1 - i].id,
Team.SPECTATORS
);
room.setPlayerTeam(
teamRed[Math.min(teamRed.length, teamBlue.length) - 1 - i].id,
Team.SPECTATORS
);
}
}
function swapButton() {
clearTimeout(removingTimeout);
removingPlayers = true;
removingTimeout = setTimeout(() => {
removingPlayers = false;
}, 100);
for (let player of teamBlue) {
room.setPlayerTeam(player.id, Team.RED);
}
for (let player of teamRed) {
room.setPlayerTeam(player.id, Team.BLUE);
}
}
/* COMMAND FUNCTIONS */
/* PLAYER COMMANDS */
/* ADMIN COMMANDS */
/* MASTER COMMANDS */
/* GAME FUNCTIONS */
function checkTime() {
const scores = room.getScores();
if (game != undefined) game.scores = scores;
if (Math.abs(scores.time - scores.timeLimit) <= 0.01 && scores.timeLimit != 0
&& playSituation == Situation.PLAY) {
if (scores.red != scores.blue) {
if (!checkTimeVariable) {
checkTimeVariable = true;
setTimeout(() => {
checkTimeVariable = false;
}, 3000);
scores.red > scores.blue ? endGame(Team.RED) : endGame(Team.BLUE);
stopTimeout = setTimeout(() => {
room.stopGame();
}, 2000);
}
return;
}
if (drawTimeLimit != 0) {
goldenGoal = true;
room.sendAnnouncement(
'⚽ Tiempo extra! Gol gana!',
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
}
}
if (Math.abs(scores.time - drawTimeLimit * 60 - scores.timeLimit) <= 0.01 &&
scores.timeLimit != 0) {
if (!checkTimeVariable) {
checkTimeVariable = true;
setTimeout(() => {
checkTimeVariable = false;
}, 10);
endGame(Team.SPECTATORS);
room.stopGame();
goldenGoal = false;
}
}
}
function instantRestart() {
room.stopGame();
startTimeout = setTimeout(() => {
room.startGame();
}, 10);
}
function resumeGame() {
startTimeout = setTimeout(() => {
room.startGame();
}, 1000);
setTimeout(() => {
room.pauseGame(false);
}, 500);
}
function endGame(winner) {
if (players.length >= 2 * teamSize - 1) activateChooseMode();
const scores = room.getScores();
game.scores = scores;
lastWinner = winner;
endGameVariable = true;
if (winner == Team.RED) {
streak++;
room.sendAnnouncement(
`✨ Red Team won ${scores.red} - ${scores.blue} ! Current streak: $
{streak}`,
null,
redColor,
'bold',
HaxNotification.CHAT
);
} else if (winner == Team.BLUE) {
streak = 1;
room.sendAnnouncement(
`✨ Blue Team won ${scores.blue} - ${scores.red} ! Current streak: $
{streak}`,
null,
blueColor,
'bold',
HaxNotification.CHAT
);
} else {
streak = 0;
room.sendAnnouncement(
'💤 Draw limit reached !',
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
}
let possessionRedPct = (possession[0] / (possession[0] + possession[1])) * 100;
let possessionBluePct = 100 - possessionRedPct;
let possessionString = `🔴 ${possessionRedPct.toFixed(0)}% - $
{possessionBluePct.toFixed(0)}% 🔵`;
let actionRedPct = (actionZoneHalf[0] / (actionZoneHalf[0] +
actionZoneHalf[1])) * 100;
let actionBluePct = 100 - actionRedPct;
let actionString = `🔴 ${actionRedPct.toFixed(0)}% - ${actionBluePct.toFixed(0)}
% 🔵`;
let CSString = getCSString(scores);
room.sendAnnouncement(
`📊 Possession: 🔴 ${possessionString}\n` +
`📊 Action Zone: 🔴 ${actionString}\n` +
`${CSString}`,
null,
announcementColor,
'bold',
HaxNotification.NONE
);
updateStats();
}
/* CHOOSING FUNCTIONS */
function activateChooseMode() {
chooseMode = true;
slowMode = chooseModeSlowMode;
room.sendAnnouncement(
`🐢 Modo lento cambiado para elegir la duración del modo de: $
{chooseModeSlowMode}s.`,
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
}
function deactivateChooseMode() {
chooseMode = false;
clearTimeout(timeOutCap);
if (slowMode != defaultSlowMode) {
slowMode = defaultSlowMode;
room.sendAnnouncement(
`🐢 Modo lento cambiado para elegir la duración del modo de: $
{defaultSlowMode}s.`,
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
}
redCaptainChoice = '';
blueCaptainChoice = '';
}
function getSpecList(player) {
if (player == null) return null;
var cstm = 'Players : ';
for (let i = 0; i < teamSpec.length; i++) {
cstm += teamSpec[i].name + `[${i + 1}], `;
}
cstm = cstm.substring(0, cstm.length - 2) + '.';
room.sendAnnouncement(
cstm,
player.id,
infoColor,
'bold',
HaxNotification.CHAT
);
}
function choosePlayer() {
clearTimeout(timeOutCap);
let captain;
if (teamRed.length <= teamBlue.length && teamRed.length != 0) {
captain = teamRed[0];
} else if (teamBlue.length < teamRed.length && teamBlue.length != 0) {
captain = teamBlue[0];
}
if (captain != null) {
room.sendAnnouncement(
"Para elegir un jugador, ingresa su número en la lista proporcionada o
usa 'top', 'random' o 'bottom'.",
captain.id,
infoColor,
'bold',
HaxNotification.MENTION
);
timeOutCap = setTimeout(
(player) => {
room.sendAnnouncement(
`Date prisa ${player.name}, solo quedan $
{Number.parseInt(String(chooseTime / 2))} segundos para elegir !`,
player.id,
warningColor,
'bold',
HaxNotification.MENTION
);
timeOutCap = setTimeout(
(player) => {
room.kickPlayer(
player.id,
"No elegiste a tiempo !",
false
);
},
chooseTime * 500,
captain
);
},
chooseTime * 1000,
captain
);
}
if (teamRed.length != 0 && teamBlue.length != 0) {
getSpecList(teamRed.length <= teamBlue.length ? teamRed[0] : teamBlue[0]);
}
}
function checkCaptainLeave(player) {
if (
(teamRed.findIndex((red) => red.id == player.id) == 0 && chooseMode &&
teamRed.length <= teamBlue.length) ||
(teamBlue.findIndex((blue) => blue.id == player.id) == 0 && chooseMode &&
teamBlue.length < teamRed.length)
) {
choosePlayer();
capLeft = true;
setTimeout(() => {
capLeft = false;
}, 10);
}
}
/* PLAYER FUNCTIONS */
function updateTeams() {
playersAll = room.getPlayerList();
players = playersAll.filter((p) => !AFKSet.has(p.id));
teamRed = players.filter((p) => p.team == Team.RED);
teamBlue = players.filter((p) => p.team == Team.BLUE);
teamSpec = players.filter((p) => p.team == Team.SPECTATORS);
}
function updateAdmins(excludedPlayerID = 0) {
if (players.length != 0 && players.filter((p) => p.admin).length < maxAdmins) {
let playerArray = players.filter((p) => p.id != excludedPlayerID && !
p.admin);
let arrayID = playerArray.map((player) => player.id);
room.setPlayerAdmin(Math.min(...arrayID), true);
}
}
function getRole(player) {
return (
!!masterList.find((a) => a == authArray[player.id][0]) * 2 +
!!adminList.find((a) => a[0] == authArray[player.id][0]) * 1 +
player.admin * 1
);
}
/* ACTIVITY FUNCTIONS */
function handleActivityPlayer(player) {
let pComp = getPlayerComp(player);
if (pComp != null) {
pComp.inactivityTicks++;
if (pComp.inactivityTicks == 60 * ((2 / 3) * afkLimit)) {
room.sendAnnouncement(
`⛔ ${player.name}, Si no te mueves ni envías un mensaje en los
próximos ${Math.floor(afkLimit / 3)} segundos, serás expulsado. !`,
player.id,
warningColor,
'bold',
HaxNotification.MENTION
);
return;
}
if (pComp.inactivityTicks >= 60 * afkLimit) {
pComp.inactivityTicks = 0;
if (game.scores.time <= afkLimit - 0.5) {
setTimeout(() => {
!chooseMode ? instantRestart() : room.stopGame();
}, 10);
}
room.kickPlayer(player.id, 'AFK', false);
}
}
}
function handleActivityPlayerTeamChange(changedPlayer) {
if (changedPlayer.team == Team.SPECTATORS) {
let pComp = getPlayerComp(changedPlayer);
if (pComp != null) pComp.inactivityTicks = 0;
}
}
function handleActivityStop() {
for (let player of players) {
let pComp = getPlayerComp(player);
if (pComp != null) pComp.inactivityTicks = 0;
}
}
function handleActivity() {
if (gameState === State.PLAY && players.length > 1) {
for (let player of teamRed) {
handleActivityPlayer(player);
}
for (let player of teamBlue) {
handleActivityPlayer(player);
}
}
}
/* LINEUP FUNCTIONS */
function getStartingLineups() {
var compositions = [[], []];
for (let player of teamRed) {
compositions[0].push(
new PlayerComposition(player, authArray[player.id][0], [0], [])
);
}
for (let player of teamBlue) {
compositions[1].push(
new PlayerComposition(player, authArray[player.id][0], [0], [])
);
}
return compositions;
}
function handleLineupChangeTeamChange(changedPlayer) {
if (gameState != State.STOP) {
var playerLineup;
if (changedPlayer.team == Team.RED) {
// player gets in red team
var redLineupAuth = game.playerComp[0].map((p) => p.auth);
var ind = redLineupAuth.findIndex((auth) => auth ==
authArray[changedPlayer.id][0]);
if (ind != -1) {
// Player goes back in
playerLineup = game.playerComp[0][ind];
if (playerLineup.timeExit.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
playerLineup.timeExit = playerLineup.timeExit.filter((t) => t !
= game.scores.time);
} else {
playerLineup.timeEntry.push(game.scores.time);
}
} else {
playerLineup = new PlayerComposition(
changedPlayer,
authArray[changedPlayer.id][0],
[game.scores.time],
[]
);
game.playerComp[0].push(playerLineup);
}
} else if (changedPlayer.team == Team.BLUE) {
// player gets in blue team
var blueLineupAuth = game.playerComp[1].map((p) => p.auth);
var ind = blueLineupAuth.findIndex((auth) => auth ==
authArray[changedPlayer.id][0]);
if (ind != -1) {
// Player goes back in
playerLineup = game.playerComp[1][ind];
if (playerLineup.timeExit.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
playerLineup.timeExit = playerLineup.timeExit.filter((t) => t !
= game.scores.time);
} else {
playerLineup.timeEntry.push(game.scores.time);
}
} else {
playerLineup = new PlayerComposition(
changedPlayer,
authArray[changedPlayer.id][0],
[game.scores.time],
[]
);
game.playerComp[1].push(playerLineup);
}
}
if (teamRed.some((r) => r.id == changedPlayer.id)) {
// player leaves red team
var redLineupAuth = game.playerComp[0].map((p) => p.auth);
var ind = redLineupAuth.findIndex((auth) => auth ==
authArray[changedPlayer.id][0]);
playerLineup = game.playerComp[0][ind];
if (playerLineup.timeEntry.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
if (game.scores.time == 0) {
game.playerComp[0].splice(ind, 1);
} else {
playerLineup.timeEntry = playerLineup.timeEntry.filter((t) => t
!= game.scores.time);
}
} else {
playerLineup.timeExit.push(game.scores.time);
}
} else if (teamBlue.some((r) => r.id == changedPlayer.id)) {
// player leaves blue team
var blueLineupAuth = game.playerComp[1].map((p) => p.auth);
var ind = blueLineupAuth.findIndex((auth) => auth ==
authArray[changedPlayer.id][0]);
playerLineup = game.playerComp[1][ind];
if (playerLineup.timeEntry.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
if (game.scores.time == 0) {
game.playerComp[1].splice(ind, 1);
} else {
playerLineup.timeEntry = playerLineup.timeEntry.filter((t) => t
!= game.scores.time);
}
} else {
playerLineup.timeExit.push(game.scores.time);
}
}
}
}
function handleLineupChangeLeave(player) {
if (playSituation != Situation.STOP) {
if (player.team == Team.RED) {
// player gets in red team
var redLineupAuth = game.playerComp[0].map((p) => p.auth);
var ind = redLineupAuth.findIndex((auth) => auth ==
authArray[player.id][0]);
var playerLineup = game.playerComp[0][ind];
if (playerLineup.timeEntry.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
if (game.scores.time == 0) {
game.playerComp[0].splice(ind, 1);
} else {
playerLineup.timeEntry = playerLineup.timeEntry.filter((t) => t
!= game.scores.time);
}
} else {
playerLineup.timeExit.push(game.scores.time);
}
} else if (player.team == Team.BLUE) {
// player gets in blue team
var blueLineupAuth = game.playerComp[1].map((p) => p.auth);
var ind = blueLineupAuth.findIndex((auth) => auth ==
authArray[player.id][0]);
var playerLineup = game.playerComp[1][ind];
if (playerLineup.timeEntry.includes(game.scores.time)) {
// gets subbed off then in at the exact same time -> no sub
if (game.scores.time == 0) {
game.playerComp[1].splice(ind, 1);
} else {
playerLineup.timeEntry = playerLineup.timeEntry.filter((t) => t
!= game.scores.time);
}
} else {
playerLineup.timeExit.push(game.scores.time);
}
}
}
}
function balanceTeams() {
if (!chooseMode) {
if (players.length == 0) {
room.stopGame();
room.setScoreLimit(scoreLimit);
room.setTimeLimit(timeLimit);
} else if (players.length == 1 && teamRed.length == 0) {
instantRestart();
setTimeout(() => {
stadiumCommand(emptyPlayer, `!training`);
}, 5);
room.setPlayerTeam(players[0].id, Team.RED);
} else if (Math.abs(teamRed.length - teamBlue.length) == teamSpec.length &&
teamSpec.length > 0) {
const n = Math.abs(teamRed.length - teamBlue.length);
if (players.length == 2) {
instantRestart();
setTimeout(() => {
stadiumCommand(emptyPlayer, `!classic`);
}, 5);
}
if (teamRed.length > teamBlue.length) {
for (var i = 0; i < n; i++) {
room.setPlayerTeam(teamSpec[i].id, Team.BLUE);
}
} else {
for (var i = 0; i < n; i++) {
room.setPlayerTeam(teamSpec[i].id, Team.RED);
}
}
} else if (Math.abs(teamRed.length - teamBlue.length) > teamSpec.length) {
const n = Math.abs(teamRed.length - teamBlue.length);
if (players.length == 1) {
instantRestart();
setTimeout(() => {
stadiumCommand(emptyPlayer, `!training`);
}, 5);
room.setPlayerTeam(players[0].id, Team.RED);
return;
} else if (teamSize > 2 && players.length == 5) {
instantRestart();
setTimeout(() => {
stadiumCommand(emptyPlayer, `!classic`);
}, 5);
}
if (players.length == teamSize * 2 - 1) {
teamRedStats = [];
teamBlueStats = [];
}
if (teamRed.length > teamBlue.length) {
for (var i = 0; i < n; i++) {
room.setPlayerTeam(
teamRed[teamRed.length - 1 - i].id,
Team.SPECTATORS
);
}
} else {
for (var i = 0; i < n; i++) {
room.setPlayerTeam(
teamBlue[teamBlue.length - 1 - i].id,
Team.SPECTATORS
);
}
}
} else if (Math.abs(teamRed.length - teamBlue.length) < teamSpec.length &&
teamRed.length != teamBlue.length) {
room.pauseGame(true);
activateChooseMode();
choosePlayer();
} else if (teamSpec.length >= 2 && teamRed.length == teamBlue.length &&
teamRed.length < teamSize) {
if (teamRed.length == 2) {
instantRestart();
setTimeout(() => {
stadiumCommand(emptyPlayer, `!big`);
}, 5);
}
topButton();
}
}
}
function handlePlayersJoin() {
if (chooseMode) {
if (teamSize > 2 && players.length == 6) {
setTimeout(() => {
stadiumCommand(emptyPlayer, `!big`);
}, 5);
}
getSpecList(teamRed.length <= teamBlue.length ? teamRed[0] : teamBlue[0]);
}
balanceTeams();
}
function handlePlayersLeave() {
if (gameState != State.STOP) {
var scores = room.getScores();
if (players.length >= 2 * teamSize && scores.time >= (5 / 6) *
game.scores.timeLimit && teamRed.length != teamBlue.length) {
var rageQuitCheck = false;
if (teamRed.length < teamBlue.length) {
if (scores.blue - scores.red == 2) {
endGame(Team.BLUE);
rageQuitCheck = true;
}
} else {
if (scores.red - scores.blue == 2) {
endGame(Team.RED);
rageQuitCheck = true;
}
}
if (rageQuitCheck) {
room.sendAnnouncement(
"Ragequit detectado, juego terminado.",
null,
infoColor,
'bold',
HaxNotification.MENTION
)
stopTimeout = setTimeout(() => {
room.stopGame();
}, 100);
return;
}
}
}
if (chooseMode) {
if (teamSize > 2 && players.length == 5) {
setTimeout(() => {
stadiumCommand(emptyPlayer, `!classic`);
}, 5);
}
if (teamRed.length == 0 || teamBlue.length == 0) {
room.setPlayerTeam(teamSpec[0].id, teamRed.length == 0 ? Team.RED :
Team.BLUE);
return;
}
if (Math.abs(teamRed.length - teamBlue.length) == teamSpec.length) {
deactivateChooseMode();
resumeGame();
var b = teamSpec.length;
if (teamRed.length > teamBlue.length) {
for (var i = 0; i < b; i++) {
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
room.setPlayerTeam(teamSpec[0].id, Team.BLUE);
}, 5 * i);
}
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 5 * b);
} else {
for (var i = 0; i < b; i++) {
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
room.setPlayerTeam(teamSpec[0].id, Team.RED);
}, 5 * i);
}
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 5 * b);
}
return;
}
if (streak == 0 && gameState == State.STOP) {
if (Math.abs(teamRed.length - teamBlue.length) == 2) {
var teamIn = teamRed.length > teamBlue.length ? teamRed : teamBlue;
room.setPlayerTeam(teamIn[teamIn.length - 1].id, Team.SPECTATORS)
}
}
if (teamRed.length == teamBlue.length && teamSpec.length < 2) {
deactivateChooseMode();
resumeGame();
return;
}
if (capLeft) {
choosePlayer();
} else {
getSpecList(teamRed.length <= teamBlue.length ? teamRed[0] :
teamBlue[0]);
}
}
balanceTeams();
}
function handlePlayersTeamChange(byPlayer) {
if (chooseMode && !removingPlayers && byPlayer == null) {
if (Math.abs(teamRed.length - teamBlue.length) == teamSpec.length) {
deactivateChooseMode();
resumeGame();
var b = teamSpec.length;
if (teamRed.length > teamBlue.length) {
for (var i = 0; i < b; i++) {
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
room.setPlayerTeam(teamSpec[0].id, Team.BLUE);
}, 5 * i);
}
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 5 * b);
} else {
for (var i = 0; i < b; i++) {
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
room.setPlayerTeam(teamSpec[0].id, Team.RED);
}, 5 * i);
}
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 5 * b);
}
return;
} else if (
(teamRed.length == teamSize && teamBlue.length == teamSize) ||
(teamRed.length == teamBlue.length && teamSpec.length < 2)
) {
deactivateChooseMode();
resumeGame();
} else if (teamRed.length <= teamBlue.length && redCaptainChoice != '') {
if (redCaptainChoice == 'top') {
room.setPlayerTeam(teamSpec[0].id, Team.RED);
} else if (redCaptainChoice == 'random') {
var r = getRandomInt(teamSpec.length);
room.setPlayerTeam(teamSpec[r].id, Team.RED);
} else {
room.setPlayerTeam(teamSpec[teamSpec.length - 1].id, Team.RED);
}
return;
} else if (teamBlue.length < teamRed.length && blueCaptainChoice != '') {
if (blueCaptainChoice == 'top') {
room.setPlayerTeam(teamSpec[0].id, Team.BLUE);
} else if (blueCaptainChoice == 'random') {
var r = getRandomInt(teamSpec.length);
room.setPlayerTeam(teamSpec[r].id, Team.BLUE);
} else {
room.setPlayerTeam(teamSpec[teamSpec.length - 1].id, Team.BLUE);
}
return;
} else {
choosePlayer();
}
}
}
function handlePlayersStop(byPlayer) {
if (byPlayer == null && endGameVariable) {
if (chooseMode) {
if (players.length == 2 * teamSize) {
chooseMode = false;
resetButton();
for (var i = 0; i < teamSize; i++) {
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
randomButton();
}, 200 * i);
}
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 200 * teamSize);
startTimeout = setTimeout(() => {
room.startGame();
}, 2000);
} else {
if (lastWinner == Team.RED) {
blueToSpecButton();
} else if (lastWinner == Team.BLUE) {
redToSpecButton();
setTimeout(() => {
swapButton();
}, 10);
} else {
resetButton();
}
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
topButton();
}, 300);
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 300);
}
} else {
if (players.length == 2) {
if (lastWinner == Team.BLUE) {
swapButton();
}
startTimeout = setTimeout(() => {
room.startGame();
}, 2000);
} else if (players.length == 3 || players.length >= 2 * teamSize + 1) {
if (lastWinner == Team.RED) {
blueToSpecButton();
} else {
redToSpecButton();
setTimeout(() => {
swapButton();
}, 5);
}
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
topButton();
}, 200);
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 300);
startTimeout = setTimeout(() => {
room.startGame();
}, 2000);
} else if (players.length == 4) {
resetButton();
clearTimeout(insertingTimeout);
insertingPlayers = true;
setTimeout(() => {
randomButton();
setTimeout(() => {
randomButton();
}, 500);
}, 500);
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 2000);
startTimeout = setTimeout(() => {
room.startGame();
}, 2000);
} else if (players.length == 5 || players.length >= 2 * teamSize + 1) {
if (lastWinner == Team.RED) {
blueToSpecButton();
} else {
redToSpecButton();
setTimeout(() => {
swapButton();
}, 5);
}
clearTimeout(insertingTimeout);
insertingPlayers = true;
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 200);
setTimeout(() => {
topButton();
}, 200);
activateChooseMode();
} else if (players.length == 6) {
resetButton();
clearTimeout(insertingTimeout);
insertingPlayers = true;
insertingTimeout = setTimeout(() => {
insertingPlayers = false;
}, 1500);
setTimeout(() => {
randomButton();
setTimeout(() => {
randomButton();
setTimeout(() => {
randomButton();
}, 500);
}, 500);
}, 500);
startTimeout = setTimeout(() => {
room.startGame();
}, 2000);
}
}
}
}
/* STATS FUNCTIONS */
/* GK FUNCTIONS */
function handleGKTeam(team) {
if (team == Team.SPECTATORS) {
return null;
}
let teamArray = team == Team.RED ? teamRed : teamBlue;
let playerGK = teamArray.reduce((prev, current) => {
if (team == Team.RED) {
return (prev?.position.x < current.position.x) ? prev : current
} else {
return (prev?.position.x > current.position.x) ? prev : current
}
}, null);
let playerCompGK = getPlayerComp(playerGK);
return playerCompGK;
}
function handleGK() {
let redGK = handleGKTeam(Team.RED);
if (redGK != null) {
redGK.GKTicks++;
}
let blueGK = handleGKTeam(Team.BLUE);
if (blueGK != null) {
blueGK.GKTicks++;
}
}
function getGK(team) {
if (team == Team.SPECTATORS) {
return null;
}
let teamArray = team == Team.RED ? game.playerComp[0] : game.playerComp[1];
let playerGK = teamArray.reduce((prev, current) => {
return (prev?.GKTicks > current.GKTicks) ? prev : current
}, null);
return playerGK;
}
function getCS(scores) {
let playersNameCS = [];
let redGK = getGK(Team.RED);
let blueGK = getGK(Team.BLUE);
if (redGK != null && scores.blue == 0) {
playersNameCS.push(redGK.player.name);
}
if (blueGK != null && scores.red == 0) {
playersNameCS.push(blueGK.player.name);
}
return playersNameCS;
}
function getCSString(scores) {
let playersCS = getCS(scores);
if (playersCS.length == 0) {
return "🥅 No CS";
} else if (playersCS.length == 1) {
return `🥅 ${playersCS[0]} had a CS.`;
} else {
return `🥅 ${playersCS[0]} and ${playersCS[1]} had a CS.`;
}
}
function getLastTouchOfTheBall() {
const ballPosition = room.getBallPosition();
updateTeams();
let playerArray = [];
for (let player of players) {
if (player.position != null) {
var distanceToBall = pointDistance(player.position, ballPosition);
if (distanceToBall < triggerDistance) {
if (playSituation == Situation.KICKOFF) playSituation =
Situation.PLAY;
playerArray.push([player, distanceToBall]);
}
}
}
if (playerArray.length != 0) {
let playerTouch = playerArray.sort((a, b) => a[1] - b[1])[0][0];
if (lastTeamTouched == playerTouch.team || lastTeamTouched ==
Team.SPECTATORS) {
if (lastTouches[0] == null || (lastTouches[0] != null &&
lastTouches[0].player.id != playerTouch.id)) {
game.touchArray.push(
new BallTouch(
playerTouch,
game.scores.time,
getGoalGame(),
ballPosition
)
);
lastTouches[0] = checkGoalKickTouch(
game.touchArray,
game.touchArray.length - 1,
getGoalGame()
);
lastTouches[1] = checkGoalKickTouch(
game.touchArray,
game.touchArray.length - 2,
getGoalGame()
);
}
}
lastTeamTouched = playerTouch.team;
}
}
function getBallSpeed() {
var ballProp = room.getDiscProperties(0);
return Math.sqrt(ballProp.xspeed ** 2 + ballProp.yspeed ** 2) *
speedCoefficient;
}
function getGameStats() {
if (playSituation == Situation.PLAY && gameState == State.PLAY) {
lastTeamTouched == Team.RED ? possession[0]++ : possession[1]++;
var ballPosition = room.getBallPosition();
ballPosition.x < 0 ? actionZoneHalf[0]++ : actionZoneHalf[1]++;
handleGK();
}
}
function getGoalAttribution(team) {
var goalAttribution = Array(2).fill(null);
if (lastTouches[0] != null) {
if (lastTouches[0].player.team == team) {
// Direct goal scored by player
if (lastTouches[1] != null && lastTouches[1].player.team == team) {
goalAttribution = [lastTouches[0].player, lastTouches[1].player];
} else {
goalAttribution = [lastTouches[0].player, null];
}
} else {
// Own goal
goalAttribution = [lastTouches[0].player, null];
}
}
return goalAttribution;
}
function getGoalString(team) {
var goalString;
var scores = game.scores;
var goalAttribution = getGoalAttribution(team);
if (goalAttribution[0] != null) {
if (goalAttribution[0].team == team) {
if (goalAttribution[1] != null && goalAttribution[1].team == team) {
goalString = `⚽ ${getTimeGame(scores.time)} Gol de $
{goalAttribution[0].name} ! con asistencia de ${goalAttribution[1].name}.`;
game.goals.push(
new Goal(
scores.time,
team,
goalAttribution[0],
goalAttribution[1]
)
);
} else {
goalString = `⚽ ${getTimeGame(scores.time)} Gol de $
{goalAttribution[0].name} ! Velocidad del gol : ${ballSpeed.toFixed(2)}km/h.`;
game.goals.push(
new Goal(scores.time, team, goalAttribution[0], null)
);
}
} else {
goalString = `😂 ${getTimeGame(scores.time)} Auto gol de $
{goalAttribution[0].name} ! tremendo meme.`;
game.goals.push(
new Goal(scores.time, team, goalAttribution[0], null)
);
}
} else {
goalString = `⚽ ${getTimeGame(scores.time)} Goal for ${team == Team.RED ?
'red' : 'blue'} team ! Goal speed : ${ballSpeed.toFixed(2)}km/h.`;
game.goals.push(
new Goal(scores.time, team, null, null)
);
}
return goalString;
}
function updateStats() {
if (
players.length >= 2 * teamSize &&
(
game.scores.time >= (5 / 6) * game.scores.timeLimit ||
game.scores.red == game.scores.scoreLimit ||
game.scores.blue == game.scores.scoreLimit
) &&
teamRedStats.length >= teamSize && teamBlueStats.length >= teamSize
) {
for (let player of teamRedStats) {
updatePlayerStats(player, Team.RED);
}
for (let player of teamBlueStats) {
updatePlayerStats(player, Team.BLUE);
}
}
}
function printRankings(statKey, id = 0) {
var leaderboard = [];
statKey = statKey == "cs" ? "CS" : statKey;
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (key.length == 43)
leaderboard.push([
JSON.parse(localStorage.getItem(key)).playerName,
JSON.parse(localStorage.getItem(key))[statKey],
]);
}
if (leaderboard.length < 5) {
if (id != 0) {
room.sendAnnouncement(
'Aún no se han jugado suficientes juegos !',
id,
errorColor,
'bold',
HaxNotification.CHAT
);
}
return;
}
leaderboard.sort(function (a, b) { return b[1] - a[1]; });
var rankingString = `${statKey.charAt(0).toUpperCase() + statKey.slice(1)}> `;
for (let i = 0; i < 5; i++) {
let playerName = leaderboard[i][0];
let playerStat = leaderboard[i][1];
if (statKey == 'playtime') playerStat = getTimeStats(playerStat);
rankingString += `#${i + 1} ${playerName} : ${playerStat}, `;
}
rankingString = rankingString.substring(0, rankingString.length - 2);
room.sendAnnouncement(
rankingString,
id,
infoColor,
'bold',
HaxNotification.CHAT
);
}
function getGamePlayerStats(player) {
var stats = new HaxStatistics(player.name);
var pComp = getPlayerComp(player);
stats.goals += getGoalsPlayer(pComp);
stats.assists += getAssistsPlayer(pComp);
stats.ownGoals += getOwnGoalsPlayer(pComp);
stats.playtime += getGametimePlayer(pComp);
stats.CS += getCSPlayer(pComp);
return stats;
}
function getGametimePlayer(pComp) {
if (pComp == null) return 0;
var timePlayer = 0;
for (let j = 0; j < pComp.timeEntry.length; j++) {
if (pComp.timeExit.length < j + 1) {
timePlayer += game.scores.time - pComp.timeEntry[j];
} else {
timePlayer += pComp.timeExit[j] - pComp.timeEntry[j];
}
}
return Math.floor(timePlayer);
}
function getGoalsPlayer(pComp) {
if (pComp == null) return 0;
var goalPlayer = 0;
for (let goal of game.goals) {
if (goal.striker != null && goal.team === pComp.player.team) {
if (authArray[goal.striker.id][0] == pComp.auth) {
goalPlayer++;
}
}
}
return goalPlayer;
}
function getOwnGoalsPlayer(pComp) {
if (pComp == null) return 0;
var goalPlayer = 0;
for (let goal of game.goals) {
if (goal.striker != null && goal.team !== pComp.player.team) {
if (authArray[goal.striker.id][0] == pComp.auth) {
goalPlayer++;
}
}
}
return goalPlayer;
}
function getAssistsPlayer(pComp) {
if (pComp == null) return 0;
var assistPlayer = 0;
for (let goal of game.goals) {
if (goal.assist != null) {
if (authArray[goal.assist.id][0] == pComp.auth) {
assistPlayer++;
}
}
}
return assistPlayer;
}
function getGKPlayer(pComp) {
if (pComp == null) return 0;
let GKRed = getGK(Team.RED);
if (pComp.auth == GKRed?.auth) {
return Team.RED;
}
let GKBlue = getGK(Team.BLUE);
if (pComp.auth == GKBlue?.auth) {
return Team.BLUE;
}
return Team.SPECTATORS;
}
function getCSPlayer(pComp) {
if (pComp == null || game.scores == null) return 0;
if (getGKPlayer(pComp) == Team.RED && game.scores.blue == 0) {
return 1;
} else if (getGKPlayer(pComp) == Team.BLUE && game.scores.red == 0) {
return 1;
}
return 0;
}
/* PRINT FUNCTIONS */
function printPlayerStats(stats) {
let statsString = '';
for (let [key, value] of Object.entries(stats)) {
if (key == 'playerName') statsString += `${value}: `;
else {
if (key == 'playtime') value = getTimeStats(value);
let reCamelCase = /([A-Z](?=[a-z]+)|[A-Z]+(?![a-z]))/g;
let statName = key.replaceAll(reCamelCase, ' $1').trim();
statsString += `${statName.charAt(0).toUpperCase() +
statName.slice(1)}: ${value}, `;
}
}
statsString = statsString.substring(0, statsString.length - 2);
return statsString;
}
/* FETCH FUNCTIONS */
function fetchGametimeReport(game) {
var fieldGametimeRed = {
name: '🔴 **RED TEAM STATS**',
value: '⌛ __**Game Time:**__\n\n',
inline: true,
};
var fieldGametimeBlue = {
name: '🔵 **BLUE TEAM STATS**',
value: '⌛ __**Game Time:**__\n\n',
inline: true,
};
var redTeamTimes = game.playerComp[0].map((p) => [p.player,
getGametimePlayer(p)]);
var blueTeamTimes = game.playerComp[1].map((p) => [p.player,
getGametimePlayer(p)]);
for (let time of redTeamTimes) {
var minutes = getMinutesReport(time[1]);
var seconds = getSecondsReport(time[1]);
fieldGametimeRed.value += `> **${time[0].name}:** ${minutes > 0 ? `$
{minutes}m` : ''}` +
`${seconds > 0 || minutes == 0 ? `${seconds}s` : ''}\n`;
}
fieldGametimeRed.value += `\n${blueTeamTimes.length - redTeamTimes.length > 0 ?
'\n'.repeat(blueTeamTimes.length - redTeamTimes.length) : ''
}`;
fieldGametimeRed.value += '=====================';
function fetchActionsSummaryReport(game) {
var fieldReportRed = {
name: '🔴 **RED TEAM STATS**',
value: '📊 __**Player Stats:**__\n\n',
inline: true,
};
var fieldReportBlue = {
name: '🔵 **BLUE TEAM STATS**',
value: '📊 __**Player Stats:**__\n\n',
inline: true,
};
var goals = [[], []];
for (let i = 0; i < game.goals.length; i++) {
goals[game.goals[i].team - 1].push([game.goals[i].striker,
game.goals[i].assist]);
}
var redActions = actionReportCountTeam(goals, Team.RED);
if (redActions.length > 0) {
for (let act of redActions) {
fieldReportRed.value += `> **${act[0].team != Team.RED ? '[OG] ' : ''}$
{act[0].name}:**` +
`${act[1] > 0 ? ` ${act[1]}G` : ''}` +
`${act[2] > 0 ? ` ${act[2]}A` : ''}` +
`${act[3] > 0 ? ` ${act[3]}CS` : ''}\n`;
}
}
var blueActions = actionReportCountTeam(goals, Team.BLUE);
if (blueActions.length > 0) {
for (let act of blueActions) {
fieldReportBlue.value += `> **${act[0].team != Team.BLUE ? '[OG] ' :
''}${act[0].name}:**` +
`${act[1] > 0 ? ` ${act[1]}G` : ''}` +
`${act[2] > 0 ? ` ${act[2]}A` : ''}` +
`${act[3] > 0 ? ` ${act[3]}CS` : ''}\n`;
}
}
function fetchSummaryEmbed(game) {
var fetchEndgame = [fetchGametimeReport, fetchActionsSummaryReport];
var logChannel = gameWebhook;
var fields = [
{
name: '🔴 **RED TEAM STATS**',
value: '=====================\n\n',
inline: true,
},
{
name: '🔵 **BLUE TEAM STATS**',
value: '=====================\n\n',
inline: true,
},
];
for (let i = 0; i < fetchEndgame.length; i++) {
var fieldsReport = fetchEndgame[i](game);
fields[0].value += fieldsReport[0].value + '\n\n';
fields[1].value += fieldsReport[1].value + '\n\n';
}
fields[0].value = fields[0].value.substring(0, fields[0].value.length - 2);
fields[1].value = fields[1].value.substring(0, fields[1].value.length - 2);
/* EVENTS */
/* PLAYER MOVEMENT */
room.sendAnnouncement(
`👋 Bienvenidx ${player.name} !\nIngresa "t" antes de tu mensaje para usar
el chat del equipo y "@@" seguido del nombre de un jugador para enviarle un mensaje
privado.`,
player.id,
welcomeColor,
'bold',
HaxNotification.CHAT
);
updateTeams();
updateAdmins();
if (masterList.findIndex((auth) => auth == player.auth) != -1) {
room.sendAnnouncement(
`Master ${player.name} se ha conectado a la sala !`,
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
room.setPlayerAdmin(player.id, true);
} else if (adminList.map((a) => a[0]).findIndex((auth) => auth ==
player.auth) != -1) {
room.sendAnnouncement(
`Admin ${player.name} se ha conectado a la sala !`,
null,
announcementColor,
'bold',
HaxNotification.CHAT
);
room.setPlayerAdmin(player.id, true);
}
var sameAuthCheck = playersAll.filter((p) => p.id != player.id &&
authArray[p.id][0] == player.auth);
if (sameAuthCheck.length > 0 && !debugMode) {
var oldPlayerArray = playersAll.filter((p) => p.id != player.id &&
authArray[p.id][0] == player.auth);
for (let oldPlayer of oldPlayerArray) {
ghostKickHandle(oldPlayer, player);
}
}
handlePlayersJoin();
};
/* PLAYER ACTIVITY */
/* GAME MANAGEMENT */
room.onPositionsReset = function () {
lastTouches = Array(2).fill(null);
lastTeamTouched = Team.SPECTATORS;
playSituation = Situation.KICKOFF;
};
/* MISCELLANEOUS */
room.onGameTick = function () {
checkTime();
getLastTouchOfTheBall();
getGameStats();
handleActivity();
};