class Juego { constructor(jugador, url) { this.jugador = new Jugador(jugador, this); // Las blancas si soy observador this.rival; // Jugador rival, las negras si soy observador this.timer; this.hora_ultimo_movimiento; // Es necesario para poder descontar el tiempo aunque la pestaña no esté activa en el navegador // Los observadores no tienen color pero sí tienen turno this.turno; // Color del jugador que tiene el turno. Al empezar es null, cuando envía la táctica el turno es del rival, a menos que lleve las blancas y sea el 2º en enviar la táctica this.color; // Color del jugador, si está en una partida pero no como observador this.movimientos = []; // Lista de movimientos del turno this.tiempo = []; // { 'blancas', 'negras' } // En segundos this.duracion; // Para usarla al jugar un nuevo partido (en minutos) this.estado; // 0: sin iniciar // 1: táctica mandada // 2: saque inicial, turno blancas // 3: partido iniciado, turno blancas // 4: partido iniciado, turno negras // null: partido finalizado this.sala = new Sala(this, url); this.wakeLock = null; // Lock para que no se apague la pantalla en el móvil } async requestWakelock() { if ('wakeLock' in navigator) { try { this.wakeLock = await navigator.wakeLock.request("screen"); } catch (err) { console.log(`, `); } } } iniciar_cronometros() { if (this.tiempo['blancas'] || this.tiempo['negras']) { $('#tiempo_blancas').css("color", ""); $('#tiempo_negras').css("color", ""); this.hora_ultimo_movimiento = new Date(); this.pintar_tiempos(); if (!this.timer) { this.timer = setInterval(() => { if (this.turno) { this.pintar_tiempos(); if (this.tiempo_turno() <= 0) { clearInterval(this.timer); this.timer = null; this.sala.conexion.enviar("tiempo_agotado", null); } } }, 1000); } } } tiempo_turno() { if (this.hora_ultimo_movimiento) { return this.tiempo[this.turno] - parseInt((new Date().getTime() - this.hora_ultimo_movimiento.getTime()) / 1000); } else { return this.tiempo[this.turno]; } } actualizar_tiempos(tiempo_blancas, tiempo_negras) { if (this.duracion) { $('#span_tiempo_blancas').show(); $('#span_tiempo_negras').show(); this.tiempo['blancas'] = tiempo_blancas; this.tiempo['negras'] = tiempo_negras; if (this.estado && this.estado >= 2) { this.hora_ultimo_movimiento = new Date(); } } else { $('#span_tiempo_blancas').hide(); $('#span_tiempo_negras').hide(); } } pintar_tiempos() { if (this.turno && this.tiempo_turno() <= 60) { if (this.turno == 'blancas') { $('#tiempo_blancas').css("color", "red"); } else { $('#tiempo_negras').css("color", "red"); } } if (!this.turno) { $('#tiempo_blancas').text(secondsToTime(this.tiempo['blancas'])); $('#tiempo_negras').text(secondsToTime(this.tiempo['negras'])); } else if (this.turno == 'blancas') { $('#tiempo_blancas').text(secondsToTime(this.tiempo_turno())); $('#tiempo_negras').text(secondsToTime(this.tiempo['negras'])); } else { $('#tiempo_blancas').text(secondsToTime(this.tiempo['blancas'])); $('#tiempo_negras').text(secondsToTime(this.tiempo_turno())); } } cambiar_color(c) { return c == 'blancas' ? 'negras' : 'blancas'; } traducir(texto) { switch (texto) { case 'blancas': return '???room.white???'.toLowerCase(); case 'negras': return '???room.black???'.toLowerCase(); case 'principiante': return '???levels.apprentice???'; case 'aficionado': return '???levels.amateur???'; case 'experto': return '???levels.expert???'; case 'maestro': return '???levels.master???'; case 'maestro_internacional': return '???levels.international_master???'; case 'gran_maestro': return '???levels.great_master???'; case 'campeon_del_mundo': return '???levels.world_champion???'; case 'no_registrado': return '???levels.not_registered???'; } } actualizar_turno(c, mostrar_mensaje) { this.turno = c; if (!this.soy_observador() && this.estado) { if (this.turno == this.color && mostrar_mensaje) { showToast.show("???msg.yourTurn???"); } } this.actualizar_texto_turno(); } // Si estoy observando un partido, ninguno de los dos tendrá mi nombre, pero en especial el jugador, que debería ser yo en caso contrario soy_observador() { return this.jugador.nombre != ''; } // Tb se llama al reconectar observar_partido(blancas, negras, tiempo_blancas, tiempo_negras, duracion, estado, tablero) { this.duracion = duracion; this.estado = estado; this.actualizar_tiempos(tiempo_blancas, tiempo_negras); if (negras == '') { this.jugador = this.sala.usuarios[negras]; this.rival = this.sala.usuarios[blancas]; this.color = 'negras'; } else { // El observador tb tendrá las blancas this.jugador = this.sala.usuarios[blancas]; this.rival = this.sala.usuarios[negras]; this.color = 'blancas'; } if (blancas == '_Bot_' || negras == '_Bot_') { this.crear_bot(); } this.pintar_ui(); switch (this.estado) { case 2: this.iniciar_cronometros(); this.actualizar_turno('blancas', !this.soy_observador() && this.color == 'blancas'); this.habilitar_color(this.color == 'blancas'); break; case 3: this.iniciar_cronometros(); this.actualizar_turno('blancas', !this.soy_observador() && this.color == 'blancas'); this.habilitar_color(this.color == 'blancas'); break; case 4: this.iniciar_cronometros(); this.actualizar_turno('negras', !this.soy_observador() && this.color == 'negras'); this.habilitar_color(this.color == 'negras'); break; default: /* 0, 1 y null */ // Hasta que no empieza el partido no hay turno this.pintar_tiempos(); this.habilitar_color(this.estado == 0); this.actualizar_texto_turno(); } // Si el partido aún no ha empezado no decimos nada. Lo escribiremos cuando se manden las tácticas y empiece de verdad if (this.estado >= 2) { if (!this.soy_observador()) { this.escribir_servidor(null, '???connection.resuming??? ' + blancas + ' vs ' + negras); } else { this.escribir_servidor(null, '???msg.watching??? ' + blancas + ' vs ' + negras); } } this.pintar_movimientos(tablero, 0, 0, null); } accion_mostrar_ranking(ranking) { var mensaje = '
    '; ranking.forEach(j => { mensaje += '
  1. ' + new Jugador(j, this).mostrar_jugador() + '
  2. '; }); mensaje += '
'; const box = bootbox.alert({ title: 'emoji_events ???room.ranking???', size: 'small', scrollable: true, backdrop: true, closeButton: false, locale: 'en', message: mensaje, buttons: { ok: { className: 'button azul' } } }); box.on('shown.bs.modal', () => { $('.scroll ol').scrollTop(0); }); } // Cualquier partido (viene del servidor) partido_cancelado(resp) { // Si el partido es mío if (resp.jugador == this.jugador.nombre || this.rival && resp.jugador == this.rival.nombre) { if (this.rival && resp.jugador == this.rival.nombre) { // Si cancela el rival, pongo a null el partido del Endpoint this.sala.conexion.enviar('rival_cancela', null); if (this.estado) { mostrar_mensaje('???msg.gameAborted???', false); } } this.salir(); } this.sala.actualizar_sala(resp.jugadores, resp.partidos); } salir() { $('#juego').addClass('hidden'); $('.menu').slideUp(); this.jugador = this.sala.usuarios['']; this.rival = null; this.estado = null; if (this.wakeLock) { this.wakeLock.release().then(() => { this.wakeLock = null; }).catch(error => { console.error('Error al liberar el WakeLock:', error); }); } } volver_a_jugar() { this.estado = 0; this.actualizar_texto_turno(); // Intercambiamos los colores this.empezar(this.cambiar_color(this.color), this.duracion); } crear_bot() { let j = { nombre: "_Bot_", pais: 'bot' }; this.rival = new Jugador(j, this); } rival_bot() { return this.rival.nombre == '_Bot_'; } ///////// // CHAT ///////// escribir(mensaje, clase_mensaje, clase_hora) { const chat = $("#chat")[0]; const shouldScroll = chat.scrollTop + chat.clientHeight >= chat.scrollHeight - 1; const hora = dos_digitos(new Date().getHours()) + ":" + dos_digitos(new Date().getMinutes()); mensaje = '
' + '' + hora + ' ' + mensaje + '
'; $("#chat").append(mensaje); if (shouldScroll) { chat.scrollTop = chat.scrollHeight; } } escribir_mensaje(quien, mensaje) { if (this.soy_observador()) { this.escribir('' + quien + ' ' + mensaje + '', 'mensaje_observador', 'gris'); } else if (quien == '') { this.escribir('' + mensaje + '', 'mensaje_mio', 'verde_oscuro'); } else { this.escribir('' + mensaje + '', 'mensaje_rival', 'gris'); } } escribir_servidor(quien, mensaje) { this.escribir('' + (quien ? '' + quien + '' : '') + ' ' + mensaje + '', 'mensaje_servidor', 'rojo'); } //////////// // EVENTOS //////////// cancelar_click() { if (this.sala.sonido()) { $('#audio_boton')[0].play(); } this.sala.conexion.enviar('cancelar_partido', null); } opciones_click(e) { e.stopPropagation(); if (this.sala.sonido()) { $('#audio_seleccion')[0].play(); } $('.menu').slideDown(); } sonido_click() { this.sala.toggle_sonido(); this.sala.mostrar_sonido(); } abandonar_click() { if (this.sala.sonido()) { $('#audio_boton')[0].play(); } if (this.soy_observador()) { this.salir(); this.cancelar_click(this.jugador.nombre); } else { bootbox.confirm({ message: 'help ???game.abortGame???', backdrop: true, closeButton: false, locale: 'en', swapButtonOrder: true, buttons: { confirm: { className: 'button verde' }, cancel: { className: 'button rojo' } }, callback: (result) => { if (result) { this.sala.conexion.enviar('cancelar_partido', null); } } }); } } mostrar_ranking_click() { this.sala.conexion.enviar('ranking', null); } otro_click() { $('#boton_otro').html('
???msg.waitingOpponent???'); $('#boton_otro').prop('disabled', true); this.sala.conexion.enviar('otro_partido', null); if (this.sala.sonido()) { $('#audio_boton')[0].play(); } } //////////////////////////// // Funciones a sobrecargar //////////////////////////// pintar_tablero() {} pintar_figuras() {} mostrar_reglas_click() {} movimiento_rival(movs) {} empezar(c, duracion) { this.requestWakelock(); this.hora_ultimo_movimiento = null; } }