From bf094eb936a1e6005ba7116a25b59cacadeb799d Mon Sep 17 00:00:00 2001 From: borrageiros Date: Mon, 13 May 2024 20:04:35 +0200 Subject: [PATCH] =?UTF-8?q?A=C3=B1adir=20script=5Fhecho.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script_hecho.js | 7620 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 7620 insertions(+) create mode 100644 script_hecho.js diff --git a/script_hecho.js b/script_hecho.js new file mode 100644 index 0000000..9705960 --- /dev/null +++ b/script_hecho.js @@ -0,0 +1,7620 @@ +// CHANGES BY BORRAGEIROS +// +// -Momento en el que se cambia al mapa grande, changeToBigMapOn variable +// - +// CHANGES BY BORRAGEIROS + + +/* VARIABLES */ + +/* ROOM */ + +const roomName = 'πŸ‡ͺπŸ‡Έ....3οΈβƒ£πŸ†š3️⃣....⚽FUTBOL SALA⚽'; +const maxPlayers = 15; +const roomPublic = true; +const token = ""; // Insert token here + +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 = 7; +var scoreLimit = 3; + +var gameConfig = { + roomName: roomName, + maxPlayers: maxPlayers, + public: roomPublic, + noPlayer: true, +} + +if (typeof token == 'string' && token.length == 39) { + gameConfig.token = token; +} + +var room = HBInit(gameConfig); + +const trainingMap = `{ + "name": "Futsal 3x3 4x4 from HaxMaps", + "width": 755, + "height": 339, + "spawnDistance": 310, + "bg": { + "type": "hockey", + "width": 665, + "height": 290, + "kickOffRadius": 80, + "cornerRadius": 0 + }, + "vertexes": [ + { + "x": -665, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": 80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": -80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": -290, + "trait": "ballArea", + "bCoef": 1, + "cMask": [ + "ball" + ] + }, + { + "x": 665, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": 80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": -80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 0, + "y": 306, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": 80, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -80, + "trait": "line" + }, + { + "x": 0, + "y": -306, + "trait": "kickOffBarrier" + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": -693, + "y": -80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": 693, + "y": -80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": -693, + "y": 80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": 693, + "y": 80 + }, + { + "trait": "line", + "x": -665, + "y": -215 + }, + { + "trait": "line", + "x": -500, + "y": -50 + }, + { + "trait": "line", + "x": 665, + "y": -215 + }, + { + "trait": "line", + "x": 500, + "y": -50 + }, + { + "trait": "line", + "x": -665, + "y": 215 + }, + { + "trait": "line", + "x": -500, + "y": 50 + }, + { + "trait": "line", + "x": 665, + "y": 215 + }, + { + "trait": "line", + "x": 500, + "y": 50 + }, + { + "bCoef": 1, + "trait": "ballArea", + "x": 665, + "y": 290 + }, + { + "bCoef": 1, + "trait": "ballArea", + "x": 665, + "y": -290 + }, + { + "bCoef": 0, + "trait": "line", + "x": 0, + "y": 290 + }, + { + "bCoef": 0, + "trait": "line", + "x": 0, + "y": -290 + }, + { + "x": 0, + "y": 80, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -80, + "trait": "kickOffBarrier" + }, + { + "x": 674, + "y": -80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": -80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": 80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": 80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + } + ], + "segments": [ + { + "v0": 0, + "v1": 1, + "trait": "ballArea" + }, + { + "v0": 2, + "v1": 3, + "trait": "ballArea" + }, + { + "v0": 4, + "v1": 5, + "trait": "ballArea" + }, + { + "v0": 6, + "v1": 7, + "trait": "ballArea" + }, + { + "v0": 8, + "v1": 9, + "trait": "kickOffBarrier" + }, + { + "v0": 9, + "v1": 10, + "trait": "kickOffBarrier", + "curve": 180, + "cGroup": [ + "blueKO" + ] + }, + { + "v0": 9, + "v1": 10, + "trait": "kickOffBarrier", + "curve": -180, + "cGroup": [ + "redKO" + ] + }, + { + "v0": 10, + "v1": 11, + "trait": "kickOffBarrier" + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 2, + "v1": 12, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 6, + "v1": 13, + "color": "FFFFFF", + "curve": 35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 1, + "v1": 14, + "color": "FFFFFF", + "curve": 35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 5, + "v1": 15, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 12, + "v1": 14, + "x": -585, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 13, + "v1": 15, + "x": 585, + "color": "FFFFFF", + "curve": 35 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 16, + "v1": 17, + "curve": 90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 18, + "v1": 19, + "curve": -90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 20, + "v1": 21, + "curve": -90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 22, + "v1": 23, + "curve": 90 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 17, + "v1": 21, + "curve": 0 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 19, + "v1": 23, + "curve": 0 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 1, + "v1": 0, + "cMask": [ + "ball" + ], + "x": -665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 5, + "v1": 4, + "cMask": [ + "ball" + ], + "x": 665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 2, + "v1": 3, + "cMask": [ + "ball" + ], + "x": -665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 6, + "v1": 7, + "cMask": [ + "ball" + ], + "x": 665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 0, + "v1": 24, + "y": 290 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 3, + "v1": 25, + "y": -290 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 26, + "v1": 27 + }, + { + "curve": -180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 10, + "v1": 9 + }, + { + "curve": 180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 29, + "v1": 28 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 2, + "v1": 1 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 6, + "v1": 5 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 30, + "v1": 31, + "cMask": [ + "ball" + ], + "x": 614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 32, + "v1": 33, + "cMask": [ + "ball" + ], + "x": -614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 34, + "v1": 35, + "cMask": [ + "ball" + ], + "x": -614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 36, + "v1": 37, + "cMask": [ + "ball" + ], + "x": 614 + } + ], + "goals": [ + { + "p0": [ + -674, + -80 + ], + "p1": [ + -674, + 80 + ], + "team": "red" + }, + { + "p0": [ + 674, + 80 + ], + "p1": [ + 674, + -80 + ], + "team": "blue" + } + ], + "discs": [ + { + "pos": [ + -665, + 80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + -665, + -80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + 665, + 80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + 665, + -80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + } + ], + "planes": [ + { + "normal": [ + 0, + 1 + ], + "dist": -290, + "trait": "ballArea" + }, + { + "normal": [ + 0, + -1 + ], + "dist": -290, + "trait": "ballArea" + }, + { + "normal": [ + 0, + 1 + ], + "dist": -339, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 0, + -1 + ], + "dist": -339, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 1, + 0 + ], + "dist": -755, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + -1, + 0 + ], + "dist": -755, + "bCoef": 0.2, + "cMask": [ + "all" + ] + } + ], + "traits": { + "ballArea": { + "vis": false, + "bCoef": 1, + "cMask": [ + "ball" + ] + }, + "goalPost": { + "radius": 8, + "invMass": 0, + "bCoef": 1 + }, + "goalNet": { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "all" + ] + }, + "kickOffBarrier": { + "vis": false, + "bCoef": 0.1, + "cGroup": [ + "redKO", + "blueKO" + ], + "cMask": [ + "red", + "blue" + ] + }, + "line": { + "vis": true, + "bCoef": 0, + "cMask": [ + "" + ] + }, + "arco": { + "radius": 2, + "cMask": [ + "n\/d" + ], + "color": "cccccc" + } + }, + "playerPhysics": { + "acceleration": 0.11, + "kickingAcceleration": 0.1, + "kickStrength": 7 + }, + "ballPhysics": { + "radius": 6.4, + "color": "EAFF00" + } +}`; +const classicMap = `{ + "name": "Futsal 3x3 4x4 from HaxMaps", + "width": 755, + "height": 339, + "spawnDistance": 310, + "bg": { + "type": "hockey", + "width": 665, + "height": 290, + "kickOffRadius": 80, + "cornerRadius": 0 + }, + "vertexes": [ + { + "x": -665, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": 80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": -80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -665, + "y": -290, + "trait": "ballArea", + "bCoef": 1, + "cMask": [ + "ball" + ] + }, + { + "x": 665, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": 80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": -80, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 665, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 0, + "y": 306, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": 80, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -80, + "trait": "line" + }, + { + "x": 0, + "y": -306, + "trait": "kickOffBarrier" + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": -693, + "y": -80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": 693, + "y": -80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": -693, + "y": 80 + }, + { + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": 693, + "y": 80 + }, + { + "trait": "line", + "x": -665, + "y": -215 + }, + { + "trait": "line", + "x": -500, + "y": -50 + }, + { + "trait": "line", + "x": 665, + "y": -215 + }, + { + "trait": "line", + "x": 500, + "y": -50 + }, + { + "trait": "line", + "x": -665, + "y": 215 + }, + { + "trait": "line", + "x": -500, + "y": 50 + }, + { + "trait": "line", + "x": 665, + "y": 215 + }, + { + "trait": "line", + "x": 500, + "y": 50 + }, + { + "bCoef": 1, + "trait": "ballArea", + "x": 665, + "y": 290 + }, + { + "bCoef": 1, + "trait": "ballArea", + "x": 665, + "y": -290 + }, + { + "bCoef": 0, + "trait": "line", + "x": 0, + "y": 290 + }, + { + "bCoef": 0, + "trait": "line", + "x": 0, + "y": -290 + }, + { + "x": 0, + "y": 80, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -80, + "trait": "kickOffBarrier" + }, + { + "x": 674, + "y": -80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": -80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": -290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": 80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": -674, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": 80, + "trait": "line", + "cMask": [ + "ball" + ], + "bCoef": 1 + }, + { + "x": 674, + "y": 290, + "trait": "ballArea", + "cMask": [ + "ball" + ], + "bCoef": 1 + } + ], + "segments": [ + { + "v0": 0, + "v1": 1, + "trait": "ballArea" + }, + { + "v0": 2, + "v1": 3, + "trait": "ballArea" + }, + { + "v0": 4, + "v1": 5, + "trait": "ballArea" + }, + { + "v0": 6, + "v1": 7, + "trait": "ballArea" + }, + { + "v0": 8, + "v1": 9, + "trait": "kickOffBarrier" + }, + { + "v0": 9, + "v1": 10, + "trait": "kickOffBarrier", + "curve": 180, + "cGroup": [ + "blueKO" + ] + }, + { + "v0": 9, + "v1": 10, + "trait": "kickOffBarrier", + "curve": -180, + "cGroup": [ + "redKO" + ] + }, + { + "v0": 10, + "v1": 11, + "trait": "kickOffBarrier" + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 2, + "v1": 12, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 6, + "v1": 13, + "color": "FFFFFF", + "curve": 35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 1, + "v1": 14, + "color": "FFFFFF", + "curve": 35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 5, + "v1": 15, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 12, + "v1": 14, + "x": -585, + "color": "FFFFFF", + "curve": -35 + }, + { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "v0": 13, + "v1": 15, + "x": 585, + "color": "FFFFFF", + "curve": 35 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 16, + "v1": 17, + "curve": 90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 18, + "v1": 19, + "curve": -90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 20, + "v1": 21, + "curve": -90 + }, + { + "color": "FFFFFF", + "trait": "line", + "v0": 22, + "v1": 23, + "curve": 90 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 17, + "v1": 21, + "curve": 0 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 19, + "v1": 23, + "curve": 0 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 1, + "v1": 0, + "cMask": [ + "ball" + ], + "x": -665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 5, + "v1": 4, + "cMask": [ + "ball" + ], + "x": 665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 2, + "v1": 3, + "cMask": [ + "ball" + ], + "x": -665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 6, + "v1": 7, + "cMask": [ + "ball" + ], + "x": 665 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 0, + "v1": 24, + "y": 290 + }, + { + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 3, + "v1": 25, + "y": -290 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 26, + "v1": 27 + }, + { + "curve": -180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 10, + "v1": 9 + }, + { + "curve": 180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 29, + "v1": 28 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 2, + "v1": 1 + }, + { + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "v0": 6, + "v1": 5 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 30, + "v1": 31, + "cMask": [ + "ball" + ], + "x": 614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 32, + "v1": 33, + "cMask": [ + "ball" + ], + "x": -614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 34, + "v1": 35, + "cMask": [ + "ball" + ], + "x": -614 + }, + { + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "v0": 36, + "v1": 37, + "cMask": [ + "ball" + ], + "x": 614 + } + ], + "goals": [ + { + "p0": [ + -674, + -80 + ], + "p1": [ + -674, + 80 + ], + "team": "red" + }, + { + "p0": [ + 674, + 80 + ], + "p1": [ + 674, + -80 + ], + "team": "blue" + } + ], + "discs": [ + { + "pos": [ + -665, + 80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + -665, + -80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + 665, + 80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + }, + { + "pos": [ + 665, + -80 + ], + "trait": "goalPost", + "color": "FFFFFF", + "radius": 5 + } + ], + "planes": [ + { + "normal": [ + 0, + 1 + ], + "dist": -290, + "trait": "ballArea" + }, + { + "normal": [ + 0, + -1 + ], + "dist": -290, + "trait": "ballArea" + }, + { + "normal": [ + 0, + 1 + ], + "dist": -339, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 0, + -1 + ], + "dist": -339, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 1, + 0 + ], + "dist": -755, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + -1, + 0 + ], + "dist": -755, + "bCoef": 0.2, + "cMask": [ + "all" + ] + } + ], + "traits": { + "ballArea": { + "vis": false, + "bCoef": 1, + "cMask": [ + "ball" + ] + }, + "goalPost": { + "radius": 8, + "invMass": 0, + "bCoef": 1 + }, + "goalNet": { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "all" + ] + }, + "kickOffBarrier": { + "vis": false, + "bCoef": 0.1, + "cGroup": [ + "redKO", + "blueKO" + ], + "cMask": [ + "red", + "blue" + ] + }, + "line": { + "vis": true, + "bCoef": 0, + "cMask": [ + "" + ] + }, + "arco": { + "radius": 2, + "cMask": [ + "n\/d" + ], + "color": "cccccc" + } + }, + "playerPhysics": { + "acceleration": 0.11, + "kickingAcceleration": 0.1, + "kickStrength": 7 + }, + "ballPhysics": { + "radius": 6.4, + "color": "EAFF00" + } +}`; +const bigMap = `{ + "name": "Futsal x5 GLH ; By Bazinga! from HaxMaps", + "width": 1080, + "height": 532, + "spawnDistance": 310, + "bg": { + "type": "hockey", + "width": 950, + "height": 460, + "kickOffRadius": 6, + "cornerRadius": 0 + }, + "vertexes": [ + { + "x": -950, + "y": 460, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": -950, + "y": 90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0, + "color": "ffffff" + }, + { + "x": -950, + "y": -90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0, + "color": "ffffff" + }, + { + "x": -950, + "y": -460, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": 950, + "y": 456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": 950, + "y": 90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0, + "color": "ffffff" + }, + { + "x": 950, + "y": -90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0, + "color": "ffffff" + }, + { + "x": 950, + "y": -456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": 0, + "y": 508, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": 150, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -150, + "trait": "line" + }, + { + "x": 0, + "y": -508, + "trait": "kickOffBarrier" + }, + { + "x": -995, + "y": -90, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "curve": 0 + }, + { + "x": 995, + "y": -90, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "curve": 0 + }, + { + "x": -995, + "y": 90, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "curve": 0 + }, + { + "x": 995, + "y": 90, + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "curve": 0 + }, + { + "x": 951, + "y": 460, + "bCoef": 1, + "trait": "ballArea" + }, + { + "x": 951, + "y": -460, + "bCoef": 1, + "trait": "ballArea" + }, + { + "x": 0, + "y": 460, + "bCoef": 0, + "trait": "line", + "curve": 0 + }, + { + "x": 0, + "y": -460, + "bCoef": 0, + "trait": "line", + "curve": 0 + }, + { + "x": 0, + "y": 150, + "trait": "kickOffBarrier" + }, + { + "x": 0, + "y": -150, + "trait": "kickOffBarrier" + }, + { + "x": 958, + "y": -90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "line", + "curve": 0 + }, + { + "x": 958, + "y": -456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": -958, + "y": -90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "line", + "curve": 0 + }, + { + "x": -958, + "y": -456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": -958, + "y": 90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "line", + "curve": 0 + }, + { + "x": -958, + "y": 456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": 958, + "y": 90, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "line", + "curve": 0 + }, + { + "x": 958, + "y": 456, + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "curve": 0 + }, + { + "x": 0, + "y": -9, + "trait": "line", + "curve": -180 + }, + { + "x": 0, + "y": 9, + "trait": "line", + "curve": -180 + }, + { + "x": 0, + "y": -9, + "trait": "line", + "curve": 180 + }, + { + "x": 0, + "y": 9, + "trait": "line", + "curve": 180 + }, + { + "x": 634.21528583524, + "y": -109.20953737271, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 0 + }, + { + "x": 634.21528583524, + "y": 114.16613046747, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 44.336382176589 + }, + { + "x": 634.21528583524, + "y": 114.16613046747, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + }, + { + "x": 950, + "y": 324.62551819445, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + }, + { + "x": 634.21528583524, + "y": -109.20953737271, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 90 + }, + { + "x": -423.82978278939, + "y": 449, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -423.82978278939, + "y": 471, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -222.35509186163, + "y": 449, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -222.35509186163, + "y": 471, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 386.06898092163, + "y": 449, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 386.06898092163, + "y": 471, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 184.59428999387, + "y": 449, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 184.59428999387, + "y": 471, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -657.56254462949, + "y": 460, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -657.56254462949, + "y": 473, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 975, + "y": 193.91895440419, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 956, + "y": 193.91895440419, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 975, + "y": -188.96236130943, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 956, + "y": -188.96236130943, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -667.82213435646, + "y": -460, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -667.82213435646, + "y": -473, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 621.80174276174, + "y": 460, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 621.80174276174, + "y": 473, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 644.74331148229, + "y": -460, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 644.74331148229, + "y": -473, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": 634.35340467604, + "y": 4.2212921610516, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": 1.7712285482462, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": 6.6713557738571, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": -0.67883506455928, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": 0.54619674184346, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": 5.4463239674544, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": -1.2913509677606, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 634.35340467604, + "y": 7.2838716770584, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 4.2212921610516, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 1.7712285482462, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 6.6713557738571, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": -0.67883506455928, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 0.54619674184346, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 5.4463239674544, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": -1.2913509677606, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 484.86942705432, + "y": 7.2838716770584, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -975, + "y": -191.85660774843, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -956, + "y": -191.96236130943, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -975, + "y": 190.91895440419, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -956, + "y": 190.91895440419, + "bCoef": 0.1, + "trait": "line" + }, + { + "x": -950, + "y": 432.90041943973, + "bCoef": 0.1, + "trait": "line", + "curve": -90 + }, + { + "x": -926.21802170761, + "y": 460, + "bCoef": 0.1, + "trait": "line", + "curve": -90 + }, + { + "x": -950, + "y": -433.32499678239, + "bCoef": 0.1, + "trait": "line", + "curve": 90 + }, + { + "x": -925.43621788149, + "y": -460, + "bCoef": 0.1, + "trait": "line", + "curve": 90 + }, + { + "x": 950, + "y": -433.36622514797, + "bCoef": 0.1, + "trait": "line", + "curve": -90 + }, + { + "x": 927.73220749769, + "y": -460, + "bCoef": 0.1, + "trait": "line", + "curve": -90 + }, + { + "x": 950, + "y": 434.55334331787, + "bCoef": 0.1, + "trait": "line", + "curve": 90 + }, + { + "x": 925.51401132381, + "y": 460, + "bCoef": 0.1, + "trait": "line", + "curve": 90 + }, + { + "x": 950, + "y": -319.66892509968, + "bCoef": 0, + "trait": "line", + "curve": 90 + }, + { + "x": -635.67083595539, + "y": 111.16613046747, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 0 + }, + { + "x": -635.67083595539, + "y": -112.20953737271, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 44.336382176589 + }, + { + "x": -950, + "y": -322.66892509968, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + }, + { + "x": -635.82253673536, + "y": -2.314063297901, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.83851134042, + "y": 0.13595112921681, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.80656213031, + "y": -4.764077725019, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.85448594547, + "y": 2.5859655563347, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.84649864294, + "y": 1.3609583427757, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.81454943284, + "y": -3.53907051146, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.85847959673, + "y": 3.1984691631142, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -635.80256847905, + "y": -5.3765813317984, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.3415600448, + "y": -1.3935524756233, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.35753464985, + "y": 1.0564619514946, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.32558543975, + "y": -3.8435669027412, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.3735092549, + "y": 3.5064763786125, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.36552195238, + "y": 2.2814691650535, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.33357274227, + "y": -2.6185596891822, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.37750290617, + "y": 4.1189799853919, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -486.32159178848, + "y": -4.4560705095206, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -950, + "y": 321.62551819445, + "bCoef": 0, + "trait": "line", + "curve": 90 + }, + { + "x": 486.4717644406, + "y": -216.68073468914, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": 486.26181026907, + "y": -213.90354363921, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": 484.90815678836, + "y": 227.79125744183, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": 484.69820261683, + "y": 230.56844849177, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": -487.89251107699, + "y": -222.71985942166, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": -488.10246524852, + "y": -219.94266837173, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": -487.11070725087, + "y": 223.27169507557, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": -487.3206614224, + "y": 226.04888612551, + "bCoef": 0.1, + "trait": "line", + "curve": 200 + }, + { + "x": -0.077614373673782, + "y": -2.4626457981722, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.10499941090626, + "y": 2.3835365851378, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.050229336441873, + "y": -7.3088281814824, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.13238444813857, + "y": 7.2297189684479, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.11869192952281, + "y": 4.8066277767929, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.063921855057799, + "y": -4.8857369898273, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.13923070744664, + "y": 8.4412645642754, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -0.043383077133171, + "y": -8.5203737773099, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 0.77952848346911, + "y": 1.5373542018278, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 2.7521434462366, + "y": 3.3835365851378, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 0.80691352070102, + "y": -3.3088281814824, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 1.7247584090043, + "y": 2.2297189684479, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 2.73845092762, + "y": 5.8066277767929, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 0.79322100208503, + "y": -0.88573698982727, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 1.7179121496962, + "y": 3.4412645642754, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": 0.81375978000966, + "y": -4.5203737773099, + "bCoef": 0.1, + "trait": "line", + "curve": 180 + }, + { + "x": -950, + "y": -322.66892509968, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + }, + { + "x": -950, + "y": 321.62551819445, + "bCoef": 0, + "trait": "line", + "curve": 90 + }, + { + "x": -635.67083595539, + "y": 111.16613046747, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": 90 + }, + { + "x": -950, + "y": 321.62551819445, + "bCoef": 0, + "trait": "line", + "curve": 90 + }, + { + "x": -635.67083595539, + "y": -112.20953737271, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + }, + { + "x": -950, + "y": -322.66892509968, + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line", + "curve": -90 + } + ], + "segments": [ + { + "v0": 0, + "v1": 1, + "curve": 0, + "trait": "ballArea" + }, + { + "v0": 2, + "v1": 3, + "trait": "ballArea" + }, + { + "v0": 4, + "v1": 5, + "trait": "ballArea", + "x": 951 + }, + { + "v0": 6, + "v1": 7, + "trait": "ballArea", + "x": 951 + }, + { + "v0": 8, + "v1": 9, + "trait": "kickOffBarrier", + "x": 0 + }, + { + "v0": 9, + "v1": 10, + "curve": 180, + "cGroup": [ + "blueKO" + ], + "trait": "kickOffBarrier" + }, + { + "v0": 9, + "v1": 10, + "curve": -180, + "cGroup": [ + "redKO" + ], + "trait": "kickOffBarrier" + }, + { + "v0": 10, + "v1": 11, + "trait": "kickOffBarrier", + "x": 0 + }, + { + "v0": 2, + "v1": 12, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "y": -95 + }, + { + "v0": 6, + "v1": 13, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "y": -95 + }, + { + "v0": 1, + "v1": 14, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "y": 95 + }, + { + "v0": 5, + "v1": 15, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "y": 95 + }, + { + "v0": 12, + "v1": 14, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": -821 + }, + { + "v0": 13, + "v1": 15, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0.1, + "cMask": [ + "ball" + ], + "trait": "goalNet", + "x": 585 + }, + { + "v0": 1, + "v1": 0, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": -950 + }, + { + "v0": 5, + "v1": 4, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": 950 + }, + { + "v0": 2, + "v1": 3, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": -950 + }, + { + "v0": 6, + "v1": 7, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": 950 + }, + { + "v0": 0, + "v1": 16, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "y": 460 + }, + { + "v0": 3, + "v1": 17, + "vis": true, + "color": "FFFFFF", + "bCoef": 1, + "trait": "ballArea", + "y": -460 + }, + { + "v0": 18, + "v1": 19, + "curve": 0, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 10, + "v1": 9, + "curve": -180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 21, + "v1": 20, + "curve": 180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 2, + "v1": 1, + "curve": 0, + "vis": true, + "color": "ffffff", + "bCoef": 0, + "trait": "line", + "x": -950 + }, + { + "v0": 6, + "v1": 5, + "curve": 0, + "vis": true, + "color": "ffffff", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 22, + "v1": 23, + "curve": 0, + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": 958 + }, + { + "v0": 24, + "v1": 25, + "curve": 0, + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": -958 + }, + { + "v0": 26, + "v1": 27, + "curve": 0, + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": -958 + }, + { + "v0": 28, + "v1": 29, + "curve": 0, + "vis": false, + "color": "FFFFFF", + "bCoef": 1, + "cMask": [ + "ball" + ], + "trait": "ballArea", + "x": 958 + }, + { + "v0": 30, + "v1": 31, + "curve": -180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "x": 572 + }, + { + "v0": 32, + "v1": 33, + "curve": 180, + "vis": true, + "color": "FFFFFF", + "bCoef": 0, + "trait": "line", + "x": 0 + }, + { + "v0": 34, + "v1": 35, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line" + }, + { + "v0": 36, + "v1": 37, + "curve": -90, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line" + }, + { + "v0": 39, + "v1": 40, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -240 + }, + { + "v0": 41, + "v1": 42, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -120 + }, + { + "v0": 43, + "v1": 44, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 240 + }, + { + "v0": 45, + "v1": 46, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 120 + }, + { + "v0": 47, + "v1": 48, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -381 + }, + { + "v0": 49, + "v1": 50, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -240, + "y": 251.96814834 + }, + { + "v0": 51, + "v1": 52, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -240, + "y": -251.96814834 + }, + { + "v0": 53, + "v1": 54, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -381 + }, + { + "v0": 55, + "v1": 56, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 381 + }, + { + "v0": 57, + "v1": 58, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 381 + }, + { + "v0": 60, + "v1": 59, + "curve": 180.00000000015, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 59, + "v1": 60, + "curve": 180.00000000011, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 62, + "v1": 61, + "curve": 179.99999999999, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 61, + "v1": 62, + "curve": 180.00000000001, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 64, + "v1": 63, + "curve": 180.00000000006, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 63, + "v1": 64, + "curve": 180.00000000001, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 66, + "v1": 65, + "curve": 179.99999999999, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 65, + "v1": 66, + "curve": 179.99999999999, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 68, + "v1": 67, + "curve": 179.99999999994, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 67, + "v1": 68, + "curve": 180.00000000006, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 70, + "v1": 69, + "curve": 180, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 69, + "v1": 70, + "curve": 180, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 72, + "v1": 71, + "curve": 179.99999999998, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 71, + "v1": 72, + "curve": 179.99999999998, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 74, + "v1": 73, + "curve": 180, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 73, + "v1": 74, + "curve": 180, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 75, + "v1": 76, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -240, + "y": 123 + }, + { + "v0": 77, + "v1": 78, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": -240, + "y": 251.96814834 + }, + { + "v0": 80, + "v1": 79, + "curve": -91.636910923379, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 82, + "v1": 81, + "curve": 91.636910923384, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 84, + "v1": 83, + "curve": -91.636910923386, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 86, + "v1": 85, + "curve": 91.636910923367, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 38, + "v1": 87, + "curve": 90, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 88, + "v1": 89, + "curve": 0, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line" + }, + { + "v0": 92, + "v1": 91, + "curve": 180.04149903472, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 91, + "v1": 92, + "curve": 180.04149903448, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 94, + "v1": 93, + "curve": 180.04149903461, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 93, + "v1": 94, + "curve": 180.04149903457, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 96, + "v1": 95, + "curve": 180.0414990346, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 95, + "v1": 96, + "curve": 180.04149903458, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 98, + "v1": 97, + "curve": 180.04149903458, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 97, + "v1": 98, + "curve": 180.0414990346, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 375 + }, + { + "v0": 100, + "v1": 99, + "curve": 180.04149903447, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 99, + "v1": 100, + "curve": 180.04149903471, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 102, + "v1": 101, + "curve": 180.0414990346, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 101, + "v1": 102, + "curve": 180.04149903457, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 104, + "v1": 103, + "curve": 180.04149903454, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 103, + "v1": 104, + "curve": 180.04149903457, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 106, + "v1": 105, + "curve": 180.04149903458, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 105, + "v1": 106, + "curve": 180.04149903459, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 108, + "v1": 109, + "curve": -196.43548932859, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 109, + "v1": 108, + "curve": -211.97212519444, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 110, + "v1": 111, + "curve": -196.43548932841, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 111, + "v1": 110, + "curve": -211.97212519486, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 112, + "v1": 113, + "curve": -196.43548932818, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 113, + "v1": 112, + "curve": -211.97212519503, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 114, + "v1": 115, + "curve": -196.4354893283, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 115, + "v1": 114, + "curve": -211.97212519445, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line" + }, + { + "v0": 117, + "v1": 116, + "curve": 179.83332296199, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 116, + "v1": 117, + "curve": 179.8333229623, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 119, + "v1": 118, + "curve": 179.83332296215, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 118, + "v1": 119, + "curve": 179.8333229621, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 121, + "v1": 120, + "curve": 179.83332296204, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 120, + "v1": 121, + "curve": 179.83332296211, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 123, + "v1": 122, + "curve": 179.8333229621, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 122, + "v1": 123, + "curve": 179.83332296208, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 125, + "v1": 124, + "curve": 179.83332296199, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 124, + "v1": 125, + "curve": 179.8333229623, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 127, + "v1": 126, + "curve": 179.83332296215, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 126, + "v1": 127, + "curve": 179.8333229621, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 129, + "v1": 128, + "curve": 179.83332296204, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 128, + "v1": 129, + "curve": 179.83332296211, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 131, + "v1": 130, + "curve": 179.8333229621, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 130, + "v1": 131, + "curve": 179.83332296208, + "vis": true, + "color": "F8F8F8", + "bCoef": 0.1, + "trait": "line", + "x": 277.5 + }, + { + "v0": 134, + "v1": 135, + "curve": 90, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "trait": "line" + }, + { + "v0": 136, + "v1": 137, + "curve": -90, + "vis": true, + "color": "F8F8F8", + "bCoef": 0, + "cMask": [ + "" + ], + "trait": "line" + } + ], + "goals": [ + { + "p0": [ + -957.4, + -90 + ], + "p1": [ + -957.4, + 90 + ], + "team": "red" + }, + { + "p0": [ + 957.4, + 90 + ], + "p1": [ + 957.4, + -90 + ], + "team": "blue" + } + ], + "discs": [ + { + "radius": 5, + "pos": [ + -950, + 90 + ], + "color": "6666CC", + "trait": "goalPost" + }, + { + "radius": 5, + "pos": [ + -950, + -90 + ], + "color": "6666CC", + "trait": "goalPost" + }, + { + "radius": 5, + "pos": [ + 950, + 90 + ], + "color": "6666CC", + "trait": "goalPost" + }, + { + "radius": 5, + "pos": [ + 950, + -90 + ], + "color": "6666CC", + "trait": "goalPost" + }, + { + "radius": 3, + "invMass": 0, + "pos": [ + -950, + 460 + ], + "color": "FFCC00", + "bCoef": 0.1, + "trait": "line" + }, + { + "radius": 3, + "invMass": 0, + "pos": [ + -950, + -460 + ], + "color": "FFCC00", + "bCoef": 0.1, + "trait": "line" + }, + { + "radius": 3, + "invMass": 0, + "pos": [ + 950, + -460 + ], + "color": "FFCC00", + "bCoef": 0.1, + "trait": "line" + }, + { + "radius": 3, + "invMass": 0, + "pos": [ + 950, + 460 + ], + "color": "FFCC00", + "bCoef": 0.1, + "trait": "line" + } + ], + "planes": [ + { + "normal": [ + 0, + 1 + ], + "dist": -456, + "trait": "ballArea" + }, + { + "normal": [ + 0, + -1 + ], + "dist": -456, + "trait": "ballArea" + }, + { + "normal": [ + 0, + 1 + ], + "dist": -508, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 0, + -1 + ], + "dist": -508, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + 1, + 0 + ], + "dist": -1002, + "bCoef": 0.2, + "cMask": [ + "all" + ] + }, + { + "normal": [ + -1, + 0 + ], + "dist": -1002, + "bCoef": 0.2, + "cMask": [ + "all" + ] + } + ], + "traits": { + "ballArea": { + "vis": false, + "bCoef": 1, + "cMask": [ + "ball" + ] + }, + "goalPost": { + "radius": 8, + "invMass": 0, + "bCoef": 1 + }, + "goalNet": { + "vis": true, + "bCoef": 0.1, + "cMask": [ + "all" + ] + }, + "kickOffBarrier": { + "vis": false, + "bCoef": 0.1, + "cGroup": [ + "redKO", + "blueKO" + ], + "cMask": [ + "red", + "blue" + ] + }, + "line": { + "vis": true, + "bCoef": 0, + "cMask": [ + "" + ] + }, + "arco": { + "radius": 2, + "cMask": [ + "n\/d" + ], + "color": "cccccc" + } + }, + "playerPhysics": { + "bCoef": 0, + "acceleration": 0.11, + "kickingAcceleration": 0.083, + "kickStrength": 5 + }, + "ballPhysics": { + "radius": 6.4, + "bCoef": 0.4, + "invMass": 1.5, + "damping": 0.99, + "color": "FFCC00" + } +}`; + +var currentStadium = 'training'; +var bigMapObj = JSON.parse(trainingMap); + +room.setScoreLimit(scoreLimit); +room.setTimeLimit(timeLimit); +room.setTeamsLock(true); +room.setKickRateLimit(6, 0, 0); + +var masterPassword = 10000 + getRandomInt(90000); +var roomPassword = ''; + +/* OPTIONS */ + +// by borrageiros +var changeToBigMapOn = 8; +// by borrageiros + +var drawTimeLimit = Infinity; +var teamSize = 5; +var maxAdmins = 0; +var disableBans = false; +var debugMode = false; +var afkLimit = debugMode ? Infinity : 12; + +var defaultSlowMode = 0.5; +var chooseModeSlowMode = 1; +var slowMode = defaultSlowMode; +var SMSet = new Set(); + +var hideClaimMessage = true; +var mentionPlayersUnpause = true; + +/* 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( + `You have been unmuted.`, + 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 */ + +const Team = { SPECTATORS: 0, RED: 1, BLUE: 2 }; +const State = { PLAY: 0, PAUSE: 1, STOP: 2 }; +const Role = { PLAYER: 0, ADMIN_TEMP: 1, ADMIN_PERM: 2, MASTER: 3 }; +const HaxNotification = { NONE: 0, CHAT: 1, MENTION: 2 }; +const Situation = { STOP: 0, KICKOFF: 1, PLAY: 2, GOAL: 3 }; + +var gameState = State.STOP; +var playSituation = Situation.STOP; +var goldenGoal = false; + +var playersAll = []; +var players = []; +var teamRed = []; +var teamBlue = []; +var teamSpec = []; + +var teamRedStats = []; +var teamBlueStats = []; + +var banList = []; + +/* STATS */ + +var possession = [0, 0]; +var actionZoneHalf = [0, 0]; +var lastWinner = Team.SPECTATORS; +var streak = 0; + +/* AUTH */ + +var authArray = []; +var adminList = [ + ["amuZ3Vk-M6Vk8_DuphOjismmfRRo4SQ44RyUuLb9nLc", "borrageiros"], // borrageiros + ["_LSQgSnedi0Y2E86tf5-ql6fLYORVHUDsEvilNFXKA4", "xoel"] // xoel + // ['INSERT_AUTH_HERE_1', 'NICK_OF_ADMIN_1'], + // ['INSERT_AUTH_HERE_2', 'NICK_OF_ADMIN_2'], +]; +var masterList = [ + 'amuZ3Vk-M6Vk8_DuphOjismmfRRo4SQ44RyUuLb9nLc', + '_LSQgSnedi0Y2E86tf5-ql6fLYORVHUDsEvilNFXKA4' +]; + +/* 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: # where is the id of the player targeted. This won't work if the player is an admin. + Argument 2 (optional): where 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: # where is the id of the muted player. + OR + Argument 1: where 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: # where 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: # where is the id of the player targeted. +OR +Argument 1: where 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: where is the password you want for the room. + + To remove the room password, simply enter '!password'.`, + function: passwordCommand, + }, +}; + +/* GAME */ + +var lastTouches = Array(2).fill(null); +var lastTeamTouched; + +var speedCoefficient = 100 / (5 * (0.99 ** 60 + 1)); +var ballSpeed = 0; +var playerRadius = 15; +var ballRadius = 10; +var triggerDistance = playerRadius + ballRadius + 0.01; + +/* COLORS */ + +var welcomeColor = 0xc4ff65; +var announcementColor = 0xffefd6; +var infoColor = 0xbebebe; +var privateMessageColor = 0xffc933; +var redColor = 0xff4c4c; +var blueColor = 0x62cbff; +var warningColor = 0xffa135; +var errorColor = 0xa40000; +var successColor = 0x75ff75; +var defaultColor = null; + +/* AUXILIARY */ + +var checkTimeVariable = false; +var checkStadiumVariable = true; +var endGameVariable = false; +var cancelGameVariable = false; +var kickFetchVariable = false; + +var chooseMode = false; +var timeOutCap; +var capLeft = false; +var redCaptainChoice = ''; +var blueCaptainChoice = ''; +var chooseTime = 20; + +var AFKSet = new Set(); +var AFKMinSet = new Set(); +var AFKCooldownSet = new Set(); +var minAFKDuration = 0; +var maxAFKDuration = 30; +var AFKCooldown = 0; + +var muteArray = new MuteList(); +var muteDuration = 5; + +var removingPlayers = false; +var insertingPlayers = false; + +var stopTimeout; +var startTimeout; +var unpauseTimeout; +var removingTimeout; +var insertingTimeout; + +var emptyPlayer = { + id: 0, +}; +stadiumCommand(emptyPlayer, "!training"); + +var game = new Game(); + +/* FUNCTIONS */ + +/* AUXILIARY FUNCTIONS */ + +if (typeof String.prototype.replaceAll != 'function') { + String.prototype.replaceAll = function (search, replacement) { + var target = this; + return target.split(search).join(replacement); + }; +} + +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)); +} + +function pointDistance(p1, p2) { + return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); +} + +/* 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; +} + +function getTeamArray(team, includeAFK = true) { + if (team == Team.RED) return teamRed; + if (team == Team.BLUE) return teamBlue; + if (includeAFK) { + return playersAll.filter((p) => p.team === Team.SPECTATORS); + } + return teamSpec; +} + +function sendAnnouncementTeam(message, team, color, style, mention) { + for (let player of team) { + room.sendAnnouncement(message, player.id, color, style, mention); + } +} + +function teamChat(player, message) { + var msgArray = message.split(/ +/).slice(1); + var emoji = player.team == Team.RED ? 'πŸ”΄' : player.team == Team.BLUE ? 'πŸ”΅' : 'βšͺ'; + var message = `${emoji} [TEAM] ${player.name}: ${msgArray.join(' ')}`; + var team = getTeamArray(player.team, true); + var color = player.team == Team.RED ? redColor : player.team == Team.BLUE ? blueColor : null; + var style = 'bold'; + var mention = HaxNotification.CHAT; + sendAnnouncementTeam(message, team, color, style, mention); +} + +function playerChat(player, message) { + var msgArray = message.split(/ +/); + var playerTargetIndex = playersAll.findIndex( + (p) => p.name.replaceAll(' ', '_') == msgArray[0].substring(2) + ); + if (playerTargetIndex == -1) { + room.sendAnnouncement( + `Invalid player, make sure the name you entered is correct.`, + player.id, + errorColor, + 'bold', + null + ); + return false; + } + var playerTarget = playersAll[playerTargetIndex]; + if (player.id == playerTarget.id) { + room.sendAnnouncement( + `You can't send a PM to yourself!`, + player.id, + errorColor, + 'bold', + null + ); + return false; + } + var messageFrom = `πŸ“ [PM with ${playerTarget.name}] ${player.name}: ${msgArray.slice(1).join(' ')}` + + var messageTo = `πŸ“ [PM with ${player.name}] ${player.name}: ${msgArray.slice(1).join(' ')}` + + 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); + } +} + +function checkGoalKickTouch(array, index, goal) { + if (array != null && array.length >= index + 1) { + var obj = array[index]; + if (obj != null && obj.goal != null && obj.goal == goal) return obj; + } + return null; +} + +/* 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 */ + +function leaveCommand(player, message) { + room.kickPlayer(player.id, 'Bye !', false); +} + +function helpCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length == 0) { + var commandString = 'Player commands :'; + for (const [key, value] of Object.entries(commands)) { + if (value.desc && value.roles == Role.PLAYER) commandString += ` !${key},`; + } + commandString = commandString.substring(0, commandString.length - 1) + '.\n'; + if (getRole(player) >= Role.ADMIN_TEMP) { + commandString += `Admin commands :`; + for (const [key, value] of Object.entries(commands)) { + if (value.desc && value.roles == Role.ADMIN_TEMP) commandString += ` !${key},`; + } + if (commandString.slice(commandString.length - 1) == ':') + commandString += ` None,`; + commandString = commandString.substring(0, commandString.length - 1) + '.\n'; + } + if (getRole(player) >= Role.MASTER) { + commandString += `Master commands :`; + for (const [key, value] of Object.entries(commands)) { + if (value.desc && value.roles == Role.MASTER) commandString += ` !${key},`; + } + if (commandString.slice(commandString.length - 1) == ':') commandString += ` None,`; + commandString = commandString.substring(0, commandString.length - 1) + '.\n'; + } + commandString += "\nTo get information on a specific command, type ''!help '."; + room.sendAnnouncement( + commandString, + player.id, + infoColor, + 'bold', + HaxNotification.CHAT + ); + } else if (msgArray.length >= 1) { + var commandName = getCommand(msgArray[0].toLowerCase()); + if (commandName != false && commands[commandName].desc != false) + room.sendAnnouncement( + `\'${commandName}\' command :\n${commands[commandName].desc}`, + player.id, + infoColor, + 'bold', + HaxNotification.CHAT + ); + else + room.sendAnnouncement( + `The command you tried to get information on does not exist. To check all available commands, type \'!help\'`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function globalStatsCommand(player, message) { + var stats = new HaxStatistics(player.name); + if (localStorage.getItem(authArray[player.id][0])) { + stats = JSON.parse(localStorage.getItem(authArray[player.id][0])); + } + var statsString = printPlayerStats(stats); + room.sendAnnouncement( + statsString, + player.id, + infoColor, + 'bold', + HaxNotification.CHAT + ); +} + +function renameCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (localStorage.getItem(authArray[player.id][0])) { + var stats = JSON.parse(localStorage.getItem(authArray[player.id][0])); + if (msgArray.length == 0) { + stats.playerName = player.name; + } else { + stats.playerName = msgArray.join(' '); + } + localStorage.setItem(authArray[player.id][0], JSON.stringify(stats)); + room.sendAnnouncement( + `You successfully renamed yourself ${stats.playerName} !`, + player.id, + successColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `You haven't played a game in this room yet !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function statsLeaderboardCommand(player, message) { + var key = message.split(/ +/)[0].substring(1).toLowerCase(); + printRankings(key, player.id); +} + +function afkCommand(player, message) { + if (player.team == Team.SPECTATORS || players.length == 1) { + if (AFKSet.has(player.id)) { + if (AFKMinSet.has(player.id)) { + room.sendAnnouncement( + `There is a minimum of ${minAFKDuration} minute of AFK time. Don't abuse the command !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } else { + AFKSet.delete(player.id); + room.sendAnnouncement( + `πŸŒ… ${player.name} is not AFK anymore !`, + null, + announcementColor, + 'bold', + null + ); + updateTeams(); + handlePlayersJoin(); + } + } else { + if (AFKCooldownSet.has(player.id)) { + room.sendAnnouncement( + `You can only go AFK every ${AFKCooldown} minutes. Don't abuse the command !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } else { + AFKSet.add(player.id); + if (!player.admin) { + AFKMinSet.add(player.id); + AFKCooldownSet.add(player.id); + setTimeout( + (id) => { + AFKMinSet.delete(id); + }, + minAFKDuration * 60 * 1000, + player.id + ); + setTimeout( + (id) => { + AFKSet.delete(id); + }, + maxAFKDuration * 60 * 1000, + player.id + ); + setTimeout( + (id) => { + AFKCooldownSet.delete(id); + }, + AFKCooldown * 60 * 1000, + player.id + ); + } + room.setPlayerTeam(player.id, Team.SPECTATORS); + room.sendAnnouncement( + `😴 ${player.name} is now AFK !`, + null, + announcementColor, + 'bold', + null + ); + updateTeams(); + handlePlayersLeave(); + } + } + } else { + room.sendAnnouncement( + `You can't go AFK while in a team !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function afkListCommand(player, message) { + if (AFKSet.size == 0) { + room.sendAnnouncement( + "😴 There's nobody in the AFK list.", + player.id, + announcementColor, + 'bold', + null + ); + return; + } + var cstm = '😴 AFK list : '; + AFKSet.forEach((_, value) => { + var p = room.getPlayer(value); + if (p != null) cstm += p.name + `, `; + }); + cstm = cstm.substring(0, cstm.length - 2) + '.'; + room.sendAnnouncement(cstm, player.id, announcementColor, 'bold', null); +} + +function masterCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (parseInt(msgArray[0]) == masterPassword) { + if (!masterList.includes(authArray[player.id][0])) { + room.setPlayerAdmin(player.id, true); + adminList = adminList.filter((a) => a[0] != authArray[player.id][0]); + masterList.push(authArray[player.id][0]); + room.sendAnnouncement( + `${player.name} is now a room master !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `You are a master already !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } +} + +/* ADMIN COMMANDS */ + +function restartCommand(player, message) { + instantRestart(); +} + +function restartSwapCommand(player, message) { + room.stopGame(); + swapButton(); + startTimeout = setTimeout(() => { + room.startGame(); + }, 10); +} + +function swapCommand(player, message) { + if (playSituation == Situation.STOP) { + swapButton(); + room.sendAnnouncement( + 'βœ”οΈ Teams swapped !', + null, + announcementColor, + 'bold', + null + ); + } else { + room.sendAnnouncement( + `Please stop the game before swapping.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function kickTeamCommand(player, message) { + var msgArray = message.split(/ +/); + var reasonString = `Team kick by ${player.name}`; + if (msgArray.length > 1) { + reasonString = msgArray.slice(1).join(' '); + } + if (['!kickred', '!kickr'].includes(msgArray[0].toLowerCase())) { + for (let i = 0; i < teamRed.length; i++) { + setTimeout(() => { + room.kickPlayer(teamRed[0].id, reasonString, false); + }, i * 20) + } + } else if (['!kickblue', '!kickb'].includes(msgArray[0].toLowerCase())) { + for (let i = 0; i < teamBlue.length; i++) { + setTimeout(() => { + room.kickPlayer(teamBlue[0].id, reasonString, false); + }, i * 20) + } + } else if (['!kickspec', '!kicks'].includes(msgArray[0].toLowerCase())) { + for (let i = 0; i < teamSpec.length; i++) { + setTimeout(() => { + room.kickPlayer(teamSpec[0].id, reasonString, false); + }, i * 20) + } + } +} + +function stadiumCommand(player, message) { + var msgArray = message.split(/ +/); + if (gameState == State.STOP) { + if (['!classic'].includes(msgArray[0].toLowerCase())) { + if (JSON.parse(classicMap).name == 'Classic') { + room.setDefaultStadium('Classic'); + } else { + room.setCustomStadium(classicMap); + } + currentStadium = 'classic'; + } else if (['!big'].includes(msgArray[0].toLowerCase())) { + if (JSON.parse(bigMap).name == 'Big') { + room.setDefaultStadium('Big'); + } else { + room.setCustomStadium(bigMap); + } + currentStadium = 'big'; + } else if (['!training'].includes(msgArray[0].toLowerCase())) { + room.setCustomStadium(trainingMap); + currentStadium = 'training'; + } else { + room.sendAnnouncement( + `Stadium not recognized.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Please stop the game before using this command.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function muteCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length > 0) { + if (msgArray[0].length > 0 && msgArray[0][0] == '#') { + msgArray[0] = msgArray[0].substring(1, msgArray[0].length); + if (room.getPlayer(parseInt(msgArray[0])) != null) { + var playerMute = room.getPlayer(parseInt(msgArray[0])); + var minutesMute = muteDuration; + if (msgArray.length > 1 && parseInt(msgArray[1]) > 0) { + minutesMute = parseInt(msgArray[1]); + } + if (!playerMute.admin) { + var muteObj = new MutePlayer(playerMute.name, playerMute.id, authArray[playerMute.id][0]); + muteObj.setDuration(minutesMute); + room.sendAnnouncement( + `${playerMute.name} has been muted for ${minutesMute} minutes.`, + null, + announcementColor, + 'bold', + null + ); + } else { + room.sendAnnouncement( + `You can't mute an admin.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `There is no player with such ID in the room. Enter "!help mute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Incorrect format for your argument. Enter "!help mute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Wrong number of arguments. Enter "!help mute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function unmuteCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length > 0) { + if (msgArray[0].length > 0 && msgArray[0][0] == '#') { + msgArray[0] = msgArray[0].substring(1, msgArray[0].length); + if (room.getPlayer(parseInt(msgArray[0])) != null) { + var playerUnmute = room.getPlayer(parseInt(msgArray[0])); + if (muteArray.getByPlayerId(playerUnmute.id) != null) { + var muteObj = muteArray.getByPlayerId(playerUnmute.id); + muteObj.remove() + room.sendAnnouncement( + `${playerUnmute.name} has been unmuted !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `This player isn't muted !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `There is no player with such ID in the room. Enter "!help unmute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else if (msgArray[0].length > 0 && parseInt(msgArray[0]) > 0 && muteArray.getById(parseInt(msgArray[0])) != null) { + var playerUnmute = muteArray.getById(parseInt(msgArray[0])); + playerUnmute.remove(); + room.sendAnnouncement( + `${playerUnmute.name} has been unmuted !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `Incorrect format for your argument. Enter "!help unmute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Wrong number of arguments. Enter "!help unmute" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function muteListCommand(player, message) { + if (muteArray.list.length == 0) { + room.sendAnnouncement( + "πŸ”‡ There's nobody in the mute list.", + player.id, + announcementColor, + 'bold', + null + ); + return false; + } + var cstm = 'πŸ”‡ Mute list : '; + for (let mute of muteArray.list) { + cstm += mute.name + `[${mute.id}], `; + } + cstm = cstm.substring(0, cstm.length - 2) + '.'; + room.sendAnnouncement( + cstm, + player.id, + announcementColor, + 'bold', + null + ); +} + +/* MASTER COMMANDS */ + +function clearbansCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length == 0) { + room.clearBans(); + room.sendAnnouncement( + 'βœ”οΈ Bans cleared !', + null, + announcementColor, + 'bold', + null + ); + banList = []; + } else if (msgArray.length == 1) { + if (parseInt(msgArray[0]) > 0) { + var ID = parseInt(msgArray[0]); + room.clearBan(ID); + if (banList.length != banList.filter((p) => p[1] != ID).length) { + room.sendAnnouncement( + `βœ”οΈ ${banList.filter((p) => p[1] == ID)[0][0]} has been unbanned from the room !`, + null, + announcementColor, + 'bold', + null + ); + } else { + room.sendAnnouncement( + `The ID you entered doesn't have a ban associated to. Enter "!help clearbans" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + banList = banList.filter((p) => p[1] != ID); + } else { + room.sendAnnouncement( + `Invalid ID entered. Enter "!help clearbans" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Wrong number of arguments. Enter "!help clearbans" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function banListCommand(player, message) { + if (banList.length == 0) { + room.sendAnnouncement( + "πŸ“’ There's nobody in the ban list.", + player.id, + announcementColor, + 'bold', + null + ); + return false; + } + var cstm = 'πŸ“’ Ban list : '; + for (let ban of banList) { + cstm += ban[0] + `[${ban[1]}], `; + } + cstm = cstm.substring(0, cstm.length - 2) + '.'; + room.sendAnnouncement( + cstm, + player.id, + announcementColor, + 'bold', + null + ); +} + +function adminListCommand(player, message) { + if (adminList.length == 0) { + room.sendAnnouncement( + "πŸ“’ There's nobody in the admin list.", + player.id, + announcementColor, + 'bold', + null + ); + return false; + } + var cstm = 'πŸ“’ Admin list : '; + for (let i = 0; i < adminList.length; i++) { + cstm += adminList[i][1] + `[${i}], `; + } + cstm = cstm.substring(0, cstm.length - 2) + '.'; + room.sendAnnouncement( + cstm, + player.id, + announcementColor, + 'bold', + null + ); +} + +function setAdminCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length > 0) { + if (msgArray[0].length > 0 && msgArray[0][0] == '#') { + msgArray[0] = msgArray[0].substring(1, msgArray[0].length); + if (room.getPlayer(parseInt(msgArray[0])) != null) { + var playerAdmin = room.getPlayer(parseInt(msgArray[0])); + + if (!adminList.map((a) => a[0]).includes(authArray[playerAdmin.id][0])) { + if (!masterList.includes(authArray[playerAdmin.id][0])) { + room.setPlayerAdmin(playerAdmin.id, true); + adminList.push([authArray[playerAdmin.id][0], playerAdmin.name]); + room.sendAnnouncement( + `${playerAdmin.name} is now a room admin !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `This player is a master already !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `This player is a permanent admin already !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `There is no player with such ID in the room. Enter "!help setadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Incorrect format for your argument. Enter "!help setadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Wrong number of arguments. Enter "!help setadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function removeAdminCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length > 0) { + if (msgArray[0].length > 0 && msgArray[0][0] == '#') { + msgArray[0] = msgArray[0].substring(1, msgArray[0].length); + if (room.getPlayer(parseInt(msgArray[0])) != null) { + var playerAdmin = room.getPlayer(parseInt(msgArray[0])); + + if (adminList.map((a) => a[0]).includes(authArray[playerAdmin.id][0])) { + room.setPlayerAdmin(playerAdmin.id, false); + adminList = adminList.filter((a) => a[0] != authArray[playerAdmin.id][0]); + room.sendAnnouncement( + `${playerAdmin.name} is not a room admin anymore !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `This player isn't a permanent admin !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `There is no player with such ID in the room. Enter "!help removeadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else if (msgArray[0].length > 0 && parseInt(msgArray[0]) < adminList.length) { + var index = parseInt(msgArray[0]); + var playerAdmin = adminList[index]; + if (playersAll.findIndex((p) => authArray[p.id][0] == playerAdmin[0]) != -1) { + // check if there is the removed admin in the room + var indexRem = playersAll.findIndex((p) => authArray[p.id][0] == playerAdmin[0]); + room.setPlayerAdmin(playersAll[indexRem].id, false); + } + adminList.splice(index); + room.sendAnnouncement( + `${playerAdmin[1]} is not a room admin anymore !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `Incorrect format for your argument. Enter "!help removeadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } else { + room.sendAnnouncement( + `Wrong number of arguments. Enter "!help removeadmin" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } +} + +function passwordCommand(player, message) { + var msgArray = message.split(/ +/).slice(1); + if (msgArray.length > 0) { + if (msgArray.length == 1 && msgArray[0] == '') { + roomPassword = ''; + room.setPassword(null); + room.sendAnnouncement( + `The room password has been removed.`, + player.id, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } + roomPassword = msgArray.join(' '); + room.setPassword(roomPassword); + room.sendAnnouncement( + `The room password has been set to ${roomPassword}`, + player.id, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + if (roomPassword != '') { + roomPassword = ''; + room.setPassword(null); + room.sendAnnouncement( + `The room password has been removed.`, + player.id, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.sendAnnouncement( + `The room currently does not have a password. Enter "!help password" for more information.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } + } +} + +/* 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( + '⚽ First goal wins !', + 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( + `🐒 Slow mode changed to choose mode duration of: ${chooseModeSlowMode}s.`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); +} + +function deactivateChooseMode() { + chooseMode = false; + clearTimeout(timeOutCap); + if (slowMode != defaultSlowMode) { + slowMode = defaultSlowMode; + room.sendAnnouncement( + `🐒 Slow mode changed to choose mode duration of: ${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( + "To choose a player, enter his number in the list given or use 'top', 'random' or 'bottom'.", + captain.id, + infoColor, + 'bold', + HaxNotification.MENTION + ); + timeOutCap = setTimeout( + (player) => { + room.sendAnnouncement( + `Hurry up ${player.name}, only ${Number.parseInt(String(chooseTime / 2))} seconds left to choose !`, + player.id, + warningColor, + 'bold', + HaxNotification.MENTION + ); + timeOutCap = setTimeout( + (player) => { + room.kickPlayer( + player.id, + "You didn't choose in time !", + false + ); + }, + chooseTime * 500, + captain + ); + }, + chooseTime * 1000, + captain + ); + } + if (teamRed.length != 0 && teamBlue.length != 0) { + getSpecList(teamRed.length <= teamBlue.length ? teamRed[0] : teamBlue[0]); + } +} + +function chooseModeFunction(player, message) { + var msgArray = message.split(/ +/); + if (player.id == teamRed[0].id || player.id == teamBlue[0].id) { + if (teamRed.length <= teamBlue.length && player.id == teamRed[0].id) { + if (['top', 'auto'].includes(msgArray[0].toLowerCase())) { + room.setPlayerTeam(teamSpec[0].id, Team.RED); + redCaptainChoice = 'top'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Top !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (['random', 'rand'].includes(msgArray[0].toLowerCase())) { + var r = getRandomInt(teamSpec.length); + room.setPlayerTeam(teamSpec[r].id, Team.RED); + redCaptainChoice = 'random'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Random !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (['bottom', 'bot'].includes(msgArray[0].toLowerCase())) { + room.setPlayerTeam(teamSpec[teamSpec.length - 1].id, Team.RED); + redCaptainChoice = 'bottom'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Bottom !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (!Number.isNaN(Number.parseInt(msgArray[0]))) { + if (Number.parseInt(msgArray[0]) > teamSpec.length || Number.parseInt(msgArray[0]) < 1) { + room.sendAnnouncement( + `Your number is invalid !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.setPlayerTeam( + teamSpec[Number.parseInt(msgArray[0]) - 1].id, + Team.RED + ); + room.sendAnnouncement( + `${player.name} chose ${teamSpec[Number.parseInt(msgArray[0]) - 1].name} !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } + } else return false; + return true; + } + if (teamRed.length > teamBlue.length && player.id == teamBlue[0].id) { + if (['top', 'auto'].includes(msgArray[0].toLowerCase())) { + room.setPlayerTeam(teamSpec[0].id, Team.BLUE); + blueCaptainChoice = 'top'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Top !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (['random', 'rand'].includes(msgArray[0].toLowerCase())) { + room.setPlayerTeam( + teamSpec[getRandomInt(teamSpec.length)].id, + Team.BLUE + ); + blueCaptainChoice = 'random'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Random !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (['bottom', 'bot'].includes(msgArray[0].toLowerCase())) { + room.setPlayerTeam(teamSpec[teamSpec.length - 1].id, Team.BLUE); + blueCaptainChoice = 'bottom'; + clearTimeout(timeOutCap); + room.sendAnnouncement( + `${player.name} chose Bottom !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } else if (!Number.isNaN(Number.parseInt(msgArray[0]))) { + if (Number.parseInt(msgArray[0]) > teamSpec.length || Number.parseInt(msgArray[0]) < 1) { + room.sendAnnouncement( + `Your number is invalid !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + } else { + room.setPlayerTeam( + teamSpec[Number.parseInt(msgArray[0]) - 1].id, + Team.BLUE + ); + room.sendAnnouncement( + `${player.name} chose ${teamSpec[Number.parseInt(msgArray[0]) - 1].name} !`, + null, + announcementColor, + 'bold', + HaxNotification.CHAT + ); + } + } else return false; + return true; + } + } +} + +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); + } +} + +function slowModeFunction(player, message) { + if (!player.admin) { + if (!SMSet.has(player.id)) { + SMSet.add(player.id); + setTimeout( + (number) => { + SMSet.delete(number); + }, + slowMode * 1000, + player.id + ); + } else { + return true; + } + } + return false; +} + +/* 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 + ); +} + +function ghostKickHandle(oldP, newP) { + var teamArrayId = getTeamArray(oldP.team, true).map((p) => p.id); + teamArrayId.splice(teamArrayId.findIndex((id) => id == oldP.id), 1, newP.id); + + room.kickPlayer(oldP.id, 'Ghost kick', false); + room.setPlayerTeam(newP.id, oldP.team); + room.setPlayerAdmin(newP.id, oldP.admin); + room.reorderPlayers(teamArrayId, true); + + if (oldP.team != Team.SPECTATORS && playSituation != Situation.STOP) { + var discProp = room.getPlayerDiscProperties(oldP.id); + room.setPlayerDiscProperties(newP.id, discProp); + } +} + +/* 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}, if you don't move or send a message in the next ${Math.floor(afkLimit / 3)} seconds, you will be kicked !`, + 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); + } + } + } +} + +/* TEAM BALANCE FUNCTIONS */ + +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 == changeToBigMapOn) { + 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 detected, game ended.", + 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.`; + } +} + +/* GLOBAL STATS FUNCTIONS */ + +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(); + } +} + +/* GOAL ATTRIBUTION FUNCTIONS */ + +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)} Goal by ${goalAttribution[0].name} ! Assist by ${goalAttribution[1].name}. Goal speed : ${ballSpeed.toFixed(2)}km/h.`; + game.goals.push( + new Goal( + scores.time, + team, + goalAttribution[0], + goalAttribution[1] + ) + ); + } else { + goalString = `⚽ ${getTimeGame(scores.time)} Goal by ${goalAttribution[0].name} ! Goal speed : ${ballSpeed.toFixed(2)}km/h.`; + game.goals.push( + new Goal(scores.time, team, goalAttribution[0], null) + ); + } + } else { + goalString = `πŸ˜‚ ${getTimeGame(scores.time)} Own goal by ${goalAttribution[0].name} ! Goal speed : ${ballSpeed.toFixed(2)}km/h.`; + 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; +} + +/* ROOM STATS FUNCTIONS */ + +function updatePlayerStats(player, teamStats) { + var stats = new HaxStatistics(player.name); + var pComp = getPlayerComp(player); + if (localStorage.getItem(authArray[player.id][0])) { + stats = JSON.parse(localStorage.getItem(authArray[player.id][0])); + } + stats.games++; + if (lastWinner == teamStats) stats.wins++; + stats.winrate = ((100 * stats.wins) / (stats.games || 1)).toFixed(1) + `%`; + stats.goals += getGoalsPlayer(pComp); + stats.assists += getAssistsPlayer(pComp); + stats.ownGoals += getOwnGoalsPlayer(pComp); + stats.CS += getCSPlayer(pComp); + stats.playtime += getGametimePlayer(pComp); + localStorage.setItem(authArray[player.id][0], JSON.stringify(stats)); +} + +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( + 'Not enough games played yet !', + 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 + ); +} + +/* GET STATS FUNCTIONS */ + +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; +} + +function actionReportCountTeam(goals, team) { + let playerActionSummaryTeam = []; + let indexTeam = team == Team.RED ? 0 : 1; + let indexOtherTeam = team == Team.RED ? 1 : 0; + for (let goal of goals[indexTeam]) { + if (goal[0] != null) { + if (playerActionSummaryTeam.find(a => a[0].id == goal[0].id)) { + let index = playerActionSummaryTeam.findIndex(a => a[0].id == goal[0].id); + playerActionSummaryTeam[index][1]++; + } else { + playerActionSummaryTeam.push([goal[0], 1, 0, 0]); + } + if (goal[1] != null) { + if (playerActionSummaryTeam.find(a => a[0].id == goal[1].id)) { + let index = playerActionSummaryTeam.findIndex(a => a[0].id == goal[1].id); + playerActionSummaryTeam[index][2]++; + } else { + playerActionSummaryTeam.push([goal[1], 0, 1, 0]); + } + } + } + } + if (goals[indexOtherTeam].length == 0) { + let playerCS = getGK(team)?.player; + if (playerCS != null) { + if (playerActionSummaryTeam.find(a => a[0].id == playerCS.id)) { + let index = playerActionSummaryTeam.findIndex(a => a[0].id == playerCS.id); + playerActionSummaryTeam[index][3]++; + } else { + playerActionSummaryTeam.push([playerCS, 0, 0, 1]); + } + } + } + + playerActionSummaryTeam.sort((a, b) => (a[1] + a[2] + a[3]) - (b[1] + b[2] + b[3])); + return playerActionSummaryTeam; +} + +/* 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 += '====================='; + + for (let time of blueTeamTimes) { + var minutes = getMinutesReport(time[1]); + var seconds = getSecondsReport(time[1]); + fieldGametimeBlue.value += `> **${time[0].name}:** ${minutes > 0 ? `${minutes}m` : ''}` + + `${seconds > 0 || minutes == 0 ? `${seconds}s` : ''}\n`; + } + fieldGametimeBlue.value += `\n${redTeamTimes.length - blueTeamTimes.length > 0 ? '\n'.repeat(redTeamTimes.length - blueTeamTimes.length) : '' + }`; + fieldGametimeBlue.value += '====================='; + + return [fieldGametimeRed, fieldGametimeBlue]; +} + +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`; + } + } + + fieldReportRed.value += `\n${blueActions.length - redActions.length > 0 ? '\n'.repeat(blueActions.length - redActions.length) : '' + }`; + fieldReportRed.value += '====================='; + + fieldReportBlue.value += `\n${redActions.length - blueActions.length > 0 ? '\n'.repeat(redActions.length - blueActions.length) : '' + }`; + fieldReportBlue.value += '====================='; + + return [fieldReportRed, fieldReportBlue]; +} + +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); + + var possR = possession[0] / (possession[0] + possession[1]); + var possB = 1 - possR; + var possRString = (possR * 100).toFixed(0).toString(); + var possBString = (possB * 100).toFixed(0).toString(); + var zoneR = actionZoneHalf[0] / (actionZoneHalf[0] + actionZoneHalf[1]); + var zoneB = 1 - zoneR; + var zoneRString = (zoneR * 100).toFixed(0).toString(); + var zoneBString = (zoneB * 100).toFixed(0).toString(); + var win = (game.scores.red > game.scores.blue) * 1 + (game.scores.blue > game.scores.red) * 2; + var objectBodyWebhook = { + embeds: [ + { + title: `πŸ“ MATCH REPORT #${getIdReport()}`, + description: + `**${getTimeEmbed(game.scores.time)}** ` + + (win == 1 ? '**Red Team** ' : 'Red Team ') + game.scores.red + + ' - ' + + game.scores.blue + (win == 2 ? ' **Blue Team**' : ' Blue Team') + + '\n```c\nPossession: ' + possRString + '% - ' + possBString + '%' + + '\nAction Zone: ' + zoneRString + '% - ' + zoneBString + '%\n```\n\n', + color: 9567999, + fields: fields, + footer: { + text: `Recording: ${getRecordingName(game)}`, + }, + timestamp: new Date().toISOString(), + }, + ], + username: roomName + }; + if (logChannel != '') { + fetch(logChannel, { + method: 'POST', + body: JSON.stringify(objectBodyWebhook), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } +} + +/* EVENTS */ + +/* PLAYER MOVEMENT */ + +room.onPlayerJoin = function (player) { + authArray[player.id] = [player.auth, player.conn]; + if (roomWebhook != '') { + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: `[${getDate()}] ➑️ JOIN (${playersAll.length + 1}/${maxPlayers})\n**` + + `${player.name}** [${authArray[player.id][0]}] {${authArray[player.id][1]}}`, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } + room.sendAnnouncement( + `πŸ‘‹ Welcome ${player.name} !\nEnter "t" before your message to use team chat and "@@" followed by a player name to PM him !`, + player.id, + welcomeColor, + 'bold', + HaxNotification.CHAT + ); + updateTeams(); + updateAdmins(); + if (masterList.findIndex((auth) => auth == player.auth) != -1) { + room.sendAnnouncement( + `Master ${player.name} has connected to the room !`, + 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} has connected to the room !`, + 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(); +}; + +room.onPlayerTeamChange = function (changedPlayer, byPlayer) { + handleLineupChangeTeamChange(changedPlayer); + if (AFKSet.has(changedPlayer.id) && changedPlayer.team != Team.SPECTATORS) { + room.setPlayerTeam(changedPlayer.id, Team.SPECTATORS); + room.sendAnnouncement( + `${changedPlayer.name} is AFK !`, + null, + errorColor, + 'bold', + HaxNotification.CHAT + ); + return; + } + updateTeams(); + if (gameState != State.STOP) { + if (changedPlayer.team != Team.SPECTATORS && game.scores.time <= (3 / 4) * game.scores.timeLimit && Math.abs(game.scores.blue - game.scores.red) < 2) { + changedPlayer.team == Team.RED ? teamRedStats.push(changedPlayer) : teamBlueStats.push(changedPlayer); + } + } + handleActivityPlayerTeamChange(changedPlayer); + handlePlayersTeamChange(byPlayer); +}; + +room.onPlayerLeave = function (player) { + setTimeout(() => { + if (!kickFetchVariable) { + if (roomWebhook != '') { + var stringContent = `[${getDate()}] ⬅️ LEAVE (${playersAll.length}/${maxPlayers})\n**${player.name}**` + + `[${authArray[player.id][0]}] {${authArray[player.id][1]}}`; + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: stringContent, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } + } else kickFetchVariable = false; + }, 10); + handleLineupChangeLeave(player); + checkCaptainLeave(player); + updateTeams(); + updateAdmins(); + handlePlayersLeave(); +}; + +room.onPlayerKicked = function (kickedPlayer, reason, ban, byPlayer) { + kickFetchVariable = true; + if (roomWebhook != '') { + var stringContent = `[${getDate()}] β›” ${ban ? 'BAN' : 'KICK'} (${playersAll.length}/${maxPlayers})\n` + + `**${kickedPlayer.name}** [${authArray[kickedPlayer.id][0]}] {${authArray[kickedPlayer.id][1]}} was ${ban ? 'banned' : 'kicked'}` + + `${byPlayer != null ? ' by **' + byPlayer.name + '** [' + authArray[byPlayer.id][0] + '] {' + authArray[byPlayer.id][1] + '}' : ''}` + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: stringContent, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } + if ((ban && ((byPlayer != null && + (byPlayer.id == kickedPlayer.id || getRole(byPlayer) < Role.MASTER)) || getRole(kickedPlayer) == Role.MASTER)) || disableBans + ) { + room.clearBan(kickedPlayer.id); + return; + } + if (byPlayer != null && getRole(byPlayer) < Role.ADMIN_PERM) { + room.sendAnnouncement( + 'You are not allowed to kick/ban players !', + byPlayer.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + room.setPlayerAdmin(byPlayer.id, false); + return; + } + if (ban) banList.push([kickedPlayer.name, kickedPlayer.id]); +}; + +/* PLAYER ACTIVITY */ + +room.onPlayerChat = function (player, message) { + if (gameState !== State.STOP && player.team != Team.SPECTATORS) { + let pComp = getPlayerComp(player); + if (pComp != null) pComp.inactivityTicks = 0; + } + let msgArray = message.split(/ +/); + if (!hideClaimMessage || msgArray[0] != '!claim') { + if (roomWebhook != '') + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: `[${getDate()}] πŸ’¬ CHAT\n**${player.name}** : ${message.replace('@', '@ ')}`, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } + if (msgArray[0][0] == '!') { + let command = getCommand(msgArray[0].slice(1).toLowerCase()); + if (command != false && commands[command].roles <= getRole(player)) commands[command].function(player, message); + else + room.sendAnnouncement( + `The command you tried to enter does not exist for you. Please enter '!help' to get the available commands to you.`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + return false; + } + if (msgArray[0].toLowerCase() == 't') { + teamChat(player, message); + return false; + } + if (msgArray[0].substring(0, 2) === '@@') { + playerChat(player, message); + return false; + } + if (chooseMode && teamRed.length * teamBlue.length != 0) { + var choosingMessageCheck = chooseModeFunction(player, message); + if (choosingMessageCheck) return false; + } + if (slowMode > 0) { + var filter = slowModeFunction(player, message); + if (filter) return false; + } + if (!player.admin && muteArray.getByAuth(authArray[player.id][0]) != null) { + room.sendAnnouncement( + `You are muted !`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + return false; + } +}; + +room.onPlayerActivity = function (player) { + if (gameState !== State.STOP) { + let pComp = getPlayerComp(player); + if (pComp != null) pComp.inactivityTicks = 0; + } +}; + +room.onPlayerBallKick = function (player) { + if (playSituation != Situation.GOAL) { + var ballPosition = room.getBallPosition(); + if (game.touchArray.length == 0 || player.id != game.touchArray[game.touchArray.length - 1].player.id) { + if (playSituation == Situation.KICKOFF) playSituation = Situation.PLAY; + lastTeamTouched = player.team; + game.touchArray.push( + new BallTouch( + player, + 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() + ); + } + } +}; + +/* GAME MANAGEMENT */ + +room.onGameStart = function (byPlayer) { + clearTimeout(startTimeout); + if (byPlayer != null) clearTimeout(stopTimeout); + game = new Game(); + possession = [0, 0]; + actionZoneHalf = [0, 0]; + gameState = State.PLAY; + endGameVariable = false; + goldenGoal = false; + playSituation = Situation.KICKOFF; + lastTouches = Array(2).fill(null); + lastTeamTouched = Team.SPECTATORS; + teamRedStats = []; + teamBlueStats = []; + if (teamRed.length == teamSize && teamBlue.length == teamSize) { + for (var i = 0; i < teamSize; i++) { + teamRedStats.push(teamRed[i]); + teamBlueStats.push(teamBlue[i]); + } + } + calculateStadiumVariables(); +}; + +room.onGameStop = function (byPlayer) { + clearTimeout(stopTimeout); + clearTimeout(unpauseTimeout); + if (byPlayer != null) clearTimeout(startTimeout); + game.rec = room.stopRecording(); + if ( + !cancelGameVariable && game.playerComp[0].length + game.playerComp[1].length > 0 && + ( + (game.scores.timeLimit != 0 && + ((game.scores.time >= 0.5 * game.scores.timeLimit && + game.scores.time < 0.75 * game.scores.timeLimit && + game.scores.red != game.scores.blue) || + game.scores.time >= 0.75 * game.scores.timeLimit) + ) || + endGameVariable + ) + ) { + fetchSummaryEmbed(game); + if (fetchRecordingVariable) { + setTimeout((gameEnd) => { fetchRecording(gameEnd); }, 500, game); + } + } + cancelGameVariable = false; + gameState = State.STOP; + playSituation = Situation.STOP; + updateTeams(); + handlePlayersStop(byPlayer); + handleActivityStop(); +}; + +room.onGamePause = function (byPlayer) { + if (mentionPlayersUnpause && gameState == State.PAUSE) { + if (byPlayer != null) { + room.sendAnnouncement( + `Game paused by ${byPlayer.name} !`, + null, + defaultColor, + 'bold', + HaxNotification.NONE + ); + } else { + room.sendAnnouncement( + `Game paused !`, + null, + defaultColor, + 'bold', + HaxNotification.NONE + ); + } + } + clearTimeout(unpauseTimeout); + gameState = State.PAUSE; +}; + +room.onGameUnpause = function (byPlayer) { + unpauseTimeout = setTimeout(() => { + gameState = State.PLAY; + }, 2000); + if (mentionPlayersUnpause) { + if (byPlayer != null) { + room.sendAnnouncement( + `Game unpaused by ${byPlayer.name} !`, + null, + defaultColor, + 'bold', + HaxNotification.NONE + ); + } else { + room.sendAnnouncement( + `Game unpaused !`, + null, + defaultColor, + 'bold', + HaxNotification.NONE + ); + } + } + if ( + (teamRed.length == teamSize && teamBlue.length == teamSize && chooseMode) || + (teamRed.length == teamBlue.length && teamSpec.length < 2 && chooseMode) + ) { + deactivateChooseMode(); + } +}; + +room.onTeamGoal = function (team) { + const scores = room.getScores(); + game.scores = scores; + playSituation = Situation.GOAL; + ballSpeed = getBallSpeed(); + var goalString = getGoalString(team); + for (let player of teamRed) { + var playerComp = getPlayerComp(player); + team == Team.RED ? playerComp.goalsScoredTeam++ : playerComp.goalsConcededTeam++; + } + for (let player of teamBlue) { + var playerComp = getPlayerComp(player); + team == Team.BLUE ? playerComp.goalsScoredTeam++ : playerComp.goalsConcededTeam++; + } + room.sendAnnouncement( + goalString, + null, + team == Team.RED ? redColor : blueColor, + null, + HaxNotification.CHAT + ); + if (roomWebhook != '') { + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: `[${getDate()}] ${goalString}`, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } + if ((scores.scoreLimit != 0 && (scores.red == scores.scoreLimit || scores.blue == scores.scoreLimit)) || goldenGoal) { + endGame(team); + goldenGoal = false; + stopTimeout = setTimeout(() => { + room.stopGame(); + }, 1000); + } +}; + +room.onPositionsReset = function () { + lastTouches = Array(2).fill(null); + lastTeamTouched = Team.SPECTATORS; + playSituation = Situation.KICKOFF; +}; + +/* MISCELLANEOUS */ + +room.onRoomLink = function (url) { + console.log(`${url}\nmasterPassword : ${masterPassword}`); + if (roomWebhook != '') { + fetch(roomWebhook, { + method: 'POST', + body: JSON.stringify({ + content: `[${getDate()}] πŸ”— LINK ${url}\nmasterPassword : ${masterPassword}`, + username: roomName, + }), + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => res); + } +}; + +room.onPlayerAdminChange = function (changedPlayer, byPlayer) { + updateTeams(); + if (!changedPlayer.admin && getRole(changedPlayer) >= Role.ADMIN_TEMP) { + room.setPlayerAdmin(changedPlayer.id, true); + return; + } + updateAdmins(byPlayer != null && !changedPlayer.admin && changedPlayer.id == byPlayer.id ? changedPlayer.id : 0); +}; + +room.onKickRateLimitSet = function (min, rate, burst, byPlayer) { + if (byPlayer != null) { + room.sendAnnouncement( + `It is not allowed to change the kickrate limit. It must stay at "6-0-0".`, + player.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + room.setKickRateLimit(6, 0, 0); + } +}; + +room.onStadiumChange = function (newStadiumName, byPlayer) { + if (byPlayer !== null) { + if (getRole(byPlayer) < Role.MASTER && currentStadium != 'other') { + room.sendAnnouncement( + `You can't change stadium manually ! Please use the stadium commands.`, + byPlayer.id, + errorColor, + 'bold', + HaxNotification.CHAT + ); + stadiumCommand(emptyPlayer, `!${currentStadium}`); + } else { + room.sendAnnouncement( + `Map changed. After you're done with this map, please use the stadium commands.`, + byPlayer.id, + infoColor, + 'bold', + HaxNotification.CHAT + ); + currentStadium = 'other'; + } + } + checkStadiumVariable = true; +}; + +room.onGameTick = function () { + checkTime(); + getLastTouchOfTheBall(); + getGameStats(); + handleActivity(); +}; \ No newline at end of file