Logica_EventosAleatorios.js

import { Eventos } from "../Events.js";
import { EventBus } from "../EventBus.js";

/**
 * Clase que gestiona los eventos aleatorios durante el juego.
 * @class EventosAleatorios
 * @memberof Logica
 */
class EventosAleatorios {
    /**
     * Constructor de EventosAleatorios.
     * @param {Tablero} tablero - el tablero del juego
     * @param {TableroGrafico} tableroGrafico - representación gráfica del tablero
     * @param {PanelEventos} panelEventoAleatorio - panel para mostrar eventos aleatorios
     * @constructor
     */
    constructor(escena, tablero, tableroGrafico, panelEventoAleatorio) {
        this.escena = escena;
        this.tablero = tablero;
        this.tableroGrafico = tableroGrafico;
        this.panelEventoAleatorio = panelEventoAleatorio;
        this.piezasAfectadas = [];
        this.terremotoCounter = 0;
        this.indiceEventoPrevio = null;
        this.miniJuego = this.escena.ia
        this.evento;

        EventBus.on(Eventos.RANDOM_EVENT, () => { if (this.terremotoCounter == 0) this.triggerEvent() });
        EventBus.on(Eventos.CHANGE_TURN, () => { this.resetEvents() });
        this.eventos = [{
            nombre: "Terremoto",
            descripcion: "Un terremoto sacude el campo de batalla. Las piezas en las zonas afectadas no podrán moverse este turno.",
            peso: 5,
            runEvent: (jugador) => {
                this.terremotoRun(jugador);
            },
            reset: () => {
                if (this.terremotoCounter < 1) {
                    this.terremotoCounter++;
                    // Volver a marcar como movidas las piezas afectadas durante el segundo turno del terremoto
                    for (let pieza of this.piezasAfectadas) {
                        if (pieza && pieza.getPosicion) {
                            const pos = pieza.getPosicion();
                            const celda = this.tablero.getCelda(pos.fila, pos.col);
                            if (celda && celda.getPieza() === pieza) {
                                pieza.setMovida(true);
                            }
                        }
                    }
                    return;
                }
                for (let pieza of this.piezasAfectadas) {
                    // Verificar que la pieza aún existe en el tablero
                    if (pieza && pieza.getPosicion) {
                        const pos = pieza.getPosicion();
                        const celda = this.tablero.getCelda(pos.fila, pos.col);
                        // Solo resetear si la pieza sigue en el tablero
                        if (celda && celda.getPieza() === pieza) {
                            pieza.resetMovida();
                        }
                    }
                }
                this.tableroGrafico.limpiarEventos();
                this.piezasAfectadas = [];
                this.terremotoCounter = 0;
            }
        },
        {
            nombre: "Fuerte Lluvia",
            descripcion: "Una fuerte lluvia erosiona el terreno conquistado, devolviendo algunas casillas a su estado neutral.",
            peso: 3,
            runEvent: (jugador) => {
                this.lluviaRun(jugador);
            },
            reset: () => {
                this.tableroGrafico.limpiarEventos();
            }
        }];
    }

    /**
     * Realiza el evento terremoto, si el minijuego se ha realizado antes, al ganador no le afecta
     * @param {*String} jugador // Jugador Ganador
     */
    terremotoRun(jugador) {
        let celdasAfectadas = [];
        for (let f = 0; f < this.tablero.filas; f++) {
            for (let c = 3; c < 7; c++) {
                let celda = this.tablero.getCelda(f, c);
                if (this.miniJuego) { // No afecta al ganador
                    if (Math.random() < 0.4) {
                        if (!celda.estaVacia()) {
                            let pieza = celda.getPieza();
                            if (!(pieza.getJugador() == jugador)) celdasAfectadas.push(celda);
                        }
                        else celdasAfectadas.push(celda);
                    }
                }
                else { // Normal
                    if (Math.random() < 0.25)
                        celdasAfectadas.push(celda);
                }
            }
        }

        for (let celda of celdasAfectadas) {
            if (celda.getPieza()) {
                celda.getPieza().setMovida(true);
                this.piezasAfectadas.push(celda.getPieza());
            }
            this.tableroGrafico.coloreaCelda(celda.fila, celda.columna, 0x0000FF, 0.4);
        }
    }

    /**
     * Ejecuta el evento de lluvia
     * @param {*String} jugador // Jugador Ganador
     */
    lluviaRun(jugador) {

        const key = (jugador === 'J1') ? 'mapaTopo' : 'mapaSat';

        let celdasAfectadas = [];
        for (let f = 0; f < this.tablero.filas; f++) {
            for (let c = 0; c < this.tablero.columnas; c++) {
                if (this.tablero.getCelda(f, c).estaVacia()) { // Solo afecta casillas conquistadas (con mapa) con 15% probabilidad
                    const grafico = this.tableroGrafico.graficos[f][c];

                    if (this.miniJuego) { // No afecta al ganador
                        if (grafico.imagen && Math.random() < 0.3) {
                            if (!(grafico.imagen.mapKey === key)) { // (Si la casilla es del ganador no le afecta)
                                celdasAfectadas.push({
                                    fila: f,
                                    columna: c,
                                    jugadorAnterior: grafico.imagen.mapKey == 'mapaTopo' ? 'J1' : 'J2'
                                });
                            }
                        }
                    }

                    else { // Normal
                        if (grafico.imagen && Math.random() < 0.15) {
                            celdasAfectadas.push({
                                fila: f,
                                columna: c,
                                jugadorAnterior: grafico.imagen.mapKey === 'mapaTopo' ? 'J1' : 'J2'
                            });
                        }
                    }
                }
            }
        }

        for (let celda of celdasAfectadas) {
            this.tableroGrafico.borrarFragmentoMapa(celda.fila, celda.columna, celda.jugadorAnterior);
            this.tableroGrafico.coloreaCelda(celda.fila, celda.columna, 0x0000ff, 0.3);
        }
    }


    /**
     * Reinicia el evento anterior ejecutando su función de reset.
     * Limpia los efectos del evento que fue disparado en el turno anterior.
     */
    resetEvents() {
        if (this.indiceEventoPrevio !== null) {
            const eventoActual = this.eventos[this.indiceEventoPrevio];
            eventoActual.reset();
            if (eventoActual.nombre === "Terremoto" && this.terremotoCounter < 2) {
                return;
            }
            this.indiceEventoPrevio = null;
        }
    }

    /**
     * Emite el evento actual despues del miniJuego
     * @param {*String} jugador 
     */
    runEventoActual(jugador) {
        this.panelEventoAleatorio.mostrar(this.evento.nombre, this.evento.descripcion, 'Evento Aleatorio', 'ACEPTAR', () => {
            this.evento.runEvent(jugador);
        });
    }

    /**
     * Dispara un evento aleatorio basado en los pesos definidos de cada evento.
     * Selecciona aleatoriamente un evento, muestra su panel y ejecuta su lógica con un delay.
     */
    triggerEvent() {
        if (!this.eventos.length) return;
        const total = this.eventos.reduce((s, e) => s + (e.peso || 1), 0);
        let r = Math.random() * total;
        for (let i = 0; i < this.eventos.length; i++) {
            r -= (this.eventos[i].peso || 1);
            if (r <= 0) {
                this.indiceEventoPrevio = i;
                this.evento = this.eventos[i];

                if (this.miniJuego) {
                    // Emitir evento para mostrar panel ANTES de ejecutar
                    this.panelEventoAleatorio.mostrar(this.evento.nombre, 'Para decidir a quien afecta el evento, preparate para un miniJuego ', 'EVENTO ALEATORIO', 'ACEPTAR', () => {
                        this.escena.lanzarMinijuego();
                    });
                }
                else this.panelEventoAleatorio.mostrar(this.evento.nombre, this.evento.descripcion, 'Evento Aleatorio', 'ACEPTAR', () => {
                    this.evento.runEvent();
                });
                //this.panelEventoAleatorio.mostrar(this.evento.evento.nombre, this.evento.evento.descripcion, 'Ha ganado' , 'ACEPTAR' );
                return;
            }
        }
    }
}

export default EventosAleatorios;