From a06b19497198c63cb1b5922c2e407eb8afe0e8c9 Mon Sep 17 00:00:00 2001 From: borrageiros Date: Sat, 27 Apr 2024 21:55:18 +0200 Subject: [PATCH] SAVE --- script.js | 1101 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1101 insertions(+) create mode 100644 script.js diff --git a/script.js b/script.js new file mode 100644 index 0000000..3fed48e --- /dev/null +++ b/script.js @@ -0,0 +1,1101 @@ +///////////////////////////////// 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) +let 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 \ No newline at end of file