haxball_server/script.js
2024-05-10 14:39:46 +02:00

1101 lines
23 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///////////////////////////////// SERVER CONFIG
// HOST: https://html5.haxball.com/headless
// DOCS: https://github.com/haxball/haxball-issues/wiki/Headless-Host
// AUTH: https://www.haxball.com/playerauth
var room = HBInit({
roomName: "🇪🇸....3⃣🆚3⃣....⚽FUTBOL SALA⚽",
maxPlayers: 16,
noPlayer: true, // Borrar el jugador "host" de la partida
public: false
});
room.setScoreLimit(1);
room.setTimeLimit(7);
room.setTeamsLock(true);
var adminsIds = [
"amuZ3Vk-M6Vk8_DuphOjismmfRRo4SQ44RyUuLb9nLc", // borrageiros
"_LSQgSnedi0Y2E86tf5-ql6fLYORVHUDsEvilNFXKA4" // xoel
];
///////////////////////////////// FIN SERVER CONFIG
///////////////////////////////// GLOBAL VARIABLES
var nOfPlayers = 0; // Numero de jugadores en la sala
var radiusBall = 6.4; // Radio del balón (el clásico es 10)
var radiusPlayer = 15; // Radio del jugador (el clásico es 15)
var triggerDistance = radiusBall + radiusPlayer + 0.00; // Tolerancia de distancia entre jugador y balón, se puede modificar
var lastPlayerToTouchBall = null; // Último jugador en tocar el balón (se guarda el "usarname" no el objeto)
var adminsInRoom = []; // Lista de jugadores con permisos de adminitración (lista de objetos)
var captains = []; // Lista de capitanes que eligen jugadores (2 por partida y solo los habrá cuando hay 6 o más jugadores)
var team1Count = 0; // Numero de jugadores en el equipo 1
var team2Count = 0; // Numero de jugadores en el equipo 2
var captainsChoosing = true; // Boolean que determina el estado de selección (cuando esté activado se le cambia el nombre al jugador para mostrar su ID y se ejecuta la funcion de seleccion)
var stadium3v3 = `{
"name": "DISCTOPIA 3v3",
"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"
}
}`
room.setCustomStadium(stadium3v3);
///////////////////////////////// FIN GLOBAL VARIABLES
///////////////////////////////// EVENTS
room.onPlayerJoin = function(newPlayer) {
nOfPlayers += 1;
updateAdmins(newPlayer);
}
room.onPlayerLeave = function( playerLeaving ) {
nOfPlayers -= 1;
updateAdminsRemove( playerLeaving );
}
room.onGameTick = function handleGameTick() {
updateLastPlayerToTouchBall();
}
room.onTeamGoal = function (team) {
golAnimation();
}
room.onPlayerChat = function( player, message ) {
startTheGame(); // DEV
if ( captainsChoosing ) { choosePlayer( player, message ); }
}
room.onTeamVictory = function( scores ) {
printScore(scores);
}
room.onGameStop = function( byPlayer ) {
clearTeams();
startTheGame();
}
///////////////////////////////// FIN EVENTS
///////////////////////////////// FUNCTIONS
function choosePlayer( player, message ) {
const isCaptain = captains.find(captain => captain.id === player.id) !== undefined;
if (isCaptain && Number.isInteger( message )) {
//
// TO DO
//
// metar en el equipo del capitan el jugador selecionado por mensaje hasta que los equipos estén completos y empezar el partido
}
}
function updateAdmins(newPlayer) {
if (adminsIds.includes(newPlayer.auth)) {
room.setPlayerAdmin(newPlayer.id, true);
adminsInRoom.push(newPlayer);
}
}
function updateAdminsRemove(playerLeaving) {
const index = adminsInRoom.indexOf(playerLeaving);
if (index !== -1) {
adminsInRoom.splice(index, 1);
}
}
function updateLastPlayerToTouchBall() {
function pointDistance(p1, p2) {
var d1 = p1.x - p2.x;
var d2 = p1.y - p2.y;
return Math.sqrt(d1 * d1 + d2 * d2);
}
var players = room.getPlayerList();
var ballPosition = room.getBallPosition();
for (var player of players) {
if ( player.position == null ) continue;
var distanceToBall = pointDistance(player.position, ballPosition);
if (distanceToBall < triggerDistance) {
lastPlayerToTouchBall = player;
}
}
}
function golAnimation() {
if (lastPlayerToTouchBall) {
room.sendAnnouncement("¡GOOOOL DE " + lastPlayerToTouchBall.name + "!!!", null, 0xFF0000, "bold", 0);
room.setPlayerDiscProperties(lastPlayerToTouchBall.id, { radius: 30 });
room.setPlayerAvatar(lastPlayerToTouchBall.id, "⚽");
setTimeout(() => {
room.setPlayerAvatar(lastPlayerToTouchBall.id, null);
room.setPlayerDiscProperties(lastPlayerToTouchBall.id, { radius: radiusPlayer });
}, 1500);
}
};
// Si el total de jugadores es de 6 o más, 2 capitanes serán asignados de manera aleatoria (los admins tienen preferencia)
// estos 2 capitanes tendrán permisos para elegir jugadores por turnos mediante sus ids (estos mostrados delante del nombre sólo en el lobby)
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function createTeams() {
var players = room.getPlayerList();
// Si el numero de jugadores en la seala es menor que 6:
// equipos aleatorios
// si es mayor de 6:
// ejecutamos sistema de capitanes
if (players.length > 6) { // DEV - PRO sería : <
// Asignar jugadores a equipos aleatoriamente
var middle = 0;
var shuffledPlayers = shuffleArray(players);
// Si el numero de jugadores es par, coge la mitad de jugadores para cada equipo
// Si el numero de jugadores es impar, distribuye de manera aleatoria al 50% el jugador sobrante en cualquiera de los equipos
if ( players.length % 2 === 0 ) {
middle = players.length / 2;
}else {
if (Math.random() < 0.5) {
middle = Math.ceil(players.length / 2);
} else {
middle = Math.floor(players.length / 2);
}
}
for (var i = 0; i < shuffledPlayers.length; i++) {
var player = shuffledPlayers[i];
if (team1Count < middle) {
room.setPlayerTeam(player.id, 1);
team1Count++;
} else {
room.setPlayerTeam(player.id, 2);
team2Count++;
}
}
} else{
// Función para obtener un número aleatorio entre min y max (ambos inclusive)
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Filtrar administradores de la lista de jugadores
const admins = players.filter(player => player.admin);
// Si hay al menos un administrador, selecciona uno o dos de ellos como capitanes
if (admins.length > 0) {
const captainCount = Math.min(2, admins.length);
for (let i = 0; i < captainCount; i++) {
captains.push(admins[i]);
}
// Si aún falta un capitán, selecciona un jugador no administrador como capitán
if (captainCount === 1) {
const nonAdminPlayers = players.filter(player => !player.admin);
const randomIndex = getRandomInt(0, nonAdminPlayers.length - 1);
captains.push(nonAdminPlayers[randomIndex]);
}
} else {
// Si no hay administradores, selecciona dos jugadores al azar como capitanes
const playerCount = Math.min(2, players.length);
for (let i = 0; i < playerCount; i++) {
const randomIndex = getRandomInt(0, players.length - 1);
captains.push(players[randomIndex]);
}
}
room.setPlayerTeam(captains[0].id, 1);
// room.setPlayerTeam(captains[1].id, 2); // DEV
captainsChoosing = true;
}
}
function printEmptyLine() {
room.sendAnnouncement(" ", null, 0xFF0000, "bold", 0);
}
// Enviar por chat resultado del partido
function printScore( scores ) {
room.sendAnnouncement(" FINAL DE PARTIDO", null, 0xFF0000, "bold", 0);
printEmptyLine();
if (scores.red > scores.blue) {
room.sendAnnouncement(" VITORIA DEL EQUIPO ROJO", null, 0xFF0000, "bold", 0);
} else if (scores.blue > scores.red) {
room.sendAnnouncement(" VITORIA DEL EQUIPO AZUL", null, 0x1700ff, "bold", 0);
} else {
room.sendAnnouncement(" ¡¡¡EMPATE!!!", null, 0xFF0000, "bold", 0);
}
printEmptyLine();
}
// Eliminar a todos los jugadores de los equipos, mandarlos a espectador y borrar a los espectadores
function clearTeams() {
captains.splice(0, captains.length);
team1Count = 0;
team2Count = 0;
var players = room.getPlayerList();
for (var player of players) {
room.setPlayerTeam(player.id, 0);
}
}
function startTheGame() {
if (!nOfPlayers == 0) {
setTimeout(() => {
room.sendAnnouncement("El partido empieza en:", null, 0xFF0000, "bold", 0);
createTeams();
}, 1500);
setTimeout(() => {
room.sendAnnouncement(" 3", null, 0xFF0000, "bold", 0);
}, 4000);
setTimeout(() => {
room.sendAnnouncement(" 2", null, 0xFF0000, "bold", 0);
}, 5000);
setTimeout(() => {
room.sendAnnouncement(" 1", null, 0xFF0000, "bold", 0);
}, 6000);
setTimeout(() => {
room.sendAnnouncement(" VAMOS!", null, 0xFF0000, "bold", 0);
}, 7000);
setTimeout(() => {
room.startGame();
}, 8000);
}
}
///////////////////////////////// FIN FUNCTIONS