Volver al blog
Tutorial9 min de lectura

Sistema de lotería y apuestas para FiveM: guía de scripts de casino

Añade loterías y juegos de casino a FiveM. Máquinas tragaperras, blackjack, botes y los mejores scripts para animar tu servidor y equilibrar la economía.

Agency Scripts

Fundador y desarrollador principal en Agency Scripts

Por qué los sistemas de casino y apuestas atraen a los jugadores

Los sistemas de lotería y apuestas aprovechan uno de los incentivos más poderosos de los juegos: la emoción del azar. Cuando un jugador entra en un casino de tu servidor FiveM y se sienta en una máquina tragamonedas o compra un billete de lotería, interactúa con un sistema que genera emoción real sin importar el resultado. Los casinos sirven como puntos de encuentro social donde jugadores de todas las facciones se reúnen en territorio neutral, los grandes apostadores presumen de su riqueza y quienes tienen menos persiguen el sueño de ganar a lo grande. Desde la perspectiva de la economía del servidor, las apuestas funcionan como un sumidero de dinero controlado que retira efectivo de circulación cuando gana la casa, lo que ayuda a combatir la inflación que afecta a los servidores donde el dinero solo entra a través de los trabajos. Un sistema de apuestas bien diseñado, con probabilidades adecuadas, reglas transparentes y límites responsables, aporta entretenimiento y mantiene a los jugadores conectándose durante las horas de poca actividad, cuando de otro modo quizá no tendrían nada que hacer.

Arquitectura del sistema de lotería

La lotería es la mecánica de apuestas más sencilla de implementar y suele ser la más popular, porque cualquier jugador del servidor puede participar, sin importar dónde se encuentre. Diseña tu lotería con precios de los boletos, horarios de los sorteos, cálculos del pozo de premios y mecanismos configurables para acumular el premio mayor. Guarda en la base de datos las compras de boletos vinculadas a los identificadores de los jugadores, para que los boletos se conserven entre sesiones. Realiza los sorteos con un temporizador o en horarios programados del mundo real, usando lógica del servidor que seleccione números ganadores al azar y compruebe todos los boletos comprados. El pozo de premios debe acumularse a partir de la venta de boletos, con una comisión configurable para la casa que financie la economía del servidor:

Config.Lottery = {
    ticketPrice = 500,
    maxTicketsPerPlayer = 10,
    numberRange = { min = 1, max = 49 },
    numbersPerTicket = 6,
    drawInterval = 7200, -- seconds between draws
    houseCut = 0.15,     -- 15% goes to server economy
    jackpotSeed = 10000, -- minimum jackpot amount
    prizes = {
        [6] = { label = 'Jackpot',    multiplier = 1.0  },  -- all 6 match
        [5] = { label = '5 Match',    multiplier = 0.05 },
        [4] = { label = '4 Match',    multiplier = 0.01 },
        [3] = { label = '3 Match',    multiplier = 0.002 },
    },
}

-- Server-side lottery draw
function ExecuteLotteryDraw()
    local winningNumbers = {}
    local pool = {}
    for i = Config.Lottery.numberRange.min, Config.Lottery.numberRange.max do
        pool[#pool + 1] = i
    end

    for i = 1, Config.Lottery.numbersPerTicket do
        local idx = math.random(1, #pool)
        winningNumbers[#winningNumbers + 1] = pool[idx]
        table.remove(pool, idx)
    end

    table.sort(winningNumbers)

    -- Get current prize pool
    local prizePool = GetLotteryPrizePool()
    local tickets = MySQL.query.await(
        'SELECT * FROM lottery_tickets WHERE draw_id = ?',
        { currentDrawId }
    )

    local winners = {}
    for _, ticket in ipairs(tickets) do
        local playerNumbers = json.decode(ticket.numbers)
        local matches = CountMatches(playerNumbers, winningNumbers)
        if matches >= 3 then
            local prize = Config.Lottery.prizes[matches]
            if prize then
                local winAmount = math.floor(prizePool * prize.multiplier)
                winners[#winners + 1] = {
                    citizenid = ticket.citizenid,
                    matches = matches,
                    prize = winAmount,
                    label = prize.label
                }
            end
        end
    end

    -- Distribute prizes
    for _, winner in ipairs(winners) do
        local Player = QBCore.Functions.GetPlayerByCitizenId(winner.citizenid)
        if Player then
            Player.Functions.AddMoney('bank', winner.prize, 'lottery-win')
            TriggerClientEvent('QBCore:Notify', Player.PlayerData.source,
                string.format('You won the %s! Prize: $%s',
                    winner.label, FormatNumber(winner.prize)), 'success')
        else
            MySQL.update('UPDATE players SET bank = bank + ? WHERE citizenid = ?',
                { winner.prize, winner.citizenid })
        end
    end

    -- Announce results server-wide
    local jackpotWon = false
    for _, w in ipairs(winners) do
        if w.matches == 6 then jackpotWon = true break end
    end

    TriggerClientEvent('lottery:client:drawResults', -1, {
        numbers = winningNumbers,
        winners = #winners,
        jackpotWon = jackpotWon,
        nextJackpot = jackpotWon and Config.Lottery.jackpotSeed
            or (prizePool * (1 - Config.Lottery.houseCut) + Config.Lottery.jackpotSeed)
    })
end

Cuando ningún jugador gana el premio mayor, acumula el pozo de premios no reclamado para el siguiente sorteo. Esta mecánica genera premios mayores cada vez más grandes, que despiertan la emoción en todo el servidor a medida que aumenta el premio. Anuncia periódicamente el monto actual del premio mayor mediante notificaciones del chat y en las pantallas del casino para mantener el interés entre sorteos.

Implementación de máquinas tragamonedas

Las máquinas tragamonedas son el pilar de cualquier casino. Cada máquina debe tener cantidades de apuesta configurables, símbolos de carrete con probabilidades ponderadas y tablas de pagos que determinen las ganancias para cada combinación de símbolos. La clave para una máquina tragamonedas satisfactoria es la presentación visual: haz girar los carretes con animaciones fluidas, genera tensión con combinaciones que casi ganan y celebra las victorias con efectos de partículas y sonidos. Determina los resultados en el lado del servidor para evitar manipulaciones desde el cliente y luego envía el resultado al cliente para mostrarlo con una animación. Usa una selección aleatoria ponderada para los símbolos, de modo que puedas controlar con precisión la ventaja de la casa y el porcentaje de retorno esperado al jugador. Una máquina tragamonedas típica debería devolver entre 85 y 95 percent de las apuestas a lo largo del tiempo, para que la casa mantenga una ventaja constante y, a la vez, haya suficientes victorias para que los jugadores disfruten la experiencia.

Juegos de cartas y mecánicas de mesa

Las mesas de blackjack y póquer ofrecen la experiencia de juego más profunda de tu casino, porque combinan habilidad y toma de decisiones reales con el azar. Para el blackjack, implementa las reglas estándar, como pedir carta, plantarse, doblar, dividir y seguro, y haz que el crupier siga las reglas de la casa para pedir carta con un diecisiete suave. La lógica del blackjack se ejecuta íntegramente en el servidor, con una baraja barajada que se controla por sesión de mesa. Cuando un jugador se sienta en una mesa, se une a una instancia de juego que gestiona el estado de la baraja, las manos de los jugadores, las cantidades apostadas y el comportamiento del crupier. El póquer requiere más complejidad porque varios jugadores compiten entre sí, en lugar de jugar contra la casa. Implementa Texas Hold'Em con rondas de apuestas, cartas comunitarias, evaluación de manos y gestión del bote correctas. La función de evaluación de manos debe identificar correctamente todas las manos de póquer, desde carta alta hasta escalera real, y resolver los empates. En el póquer, la casa cobra una pequeña comisión de cada bote en vez de tener una ventaja directa, normalmente de entre dos y cinco percent, con un límite máximo.

Interior y ambiente del casino

El entorno del casino influye considerablemente en cómo los jugadores perciben y disfrutan la experiencia de apuestas. Usa interiores MLO personalizados o decora con cuidado interiores existentes para crear una sala de casino convincente, con zonas diferenciadas para tragamonedas, juegos de mesa, un área VIP, un bar y una caja. Coloca NPC crupieres en las mesas de cartas, con animaciones inactivas apropiadas y reacciones a los resultados del juego mediante gestos de celebración o empatía. Añade efectos de sonido ambiente del casino mediante audio NUI, con melodías de tragamonedas, fichas al barajarse y música de fondo. Implementa un sistema de fichas en el que los jugadores cambien dinero por fichas del casino en la caja, usen fichas para todas las apuestas y las cambien por dinero al salir. Este cambio de fichas crea una separación psicológica entre el dinero real y los fondos para apostar, como en los casinos del mundo real, y además ofrece un punto de transacción natural para los sistemas de seguimiento de la economía.

Límites para las apuestas responsables

Todo sistema de apuestas necesita protecciones integradas para evitar que los jugadores pierdan todas sus finanzas del juego en una sola sesión. Implementa límites diarios de pérdidas que restrinjan cuánto puede perder un jugador en todas las actividades de apuestas durante un período de veinticuatro horas. Cuando un jugador se acerque a su límite, muestra notificaciones de advertencia; cuando lo alcance, impídele apostar hasta que termine el tiempo de espera. Añade una opción de autoexclusión para que los jugadores puedan vetarse voluntariamente del casino durante un período configurable. Registra las estadísticas de apuestas de cada jugador, incluido el total apostado, el total ganado, las ganancias o pérdidas netas y la duración de la sesión. Haz que estas estadísticas estén disponibles para el jugador mediante un menú del historial de apuestas y para los administradores del servidor mediante un panel de gestión. Estas protecciones no solo son buenas prácticas de diseño de juegos, sino que son esenciales para mantener una economía de servidor saludable, donde las apuestas mejoren la experiencia de juego en vez de generar frustración y hacer que los jugadores se vayan.

Antitrampas e imparcialidad

Los sistemas de apuestas son objetivos prioritarios de explotación, porque convierten directamente las acciones en dinero. Toda generación de números aleatorios debe ejecutarse en el servidor y utilizar fuentes de aleatoriedad criptográficamente adecuadas. Nunca confíes en que el cliente informe de los resultados de las apuestas. Valida todas las apuestas en el servidor comprobando el saldo de fichas del jugador antes de procesarlas. Implementa límites de frecuencia para las acciones de apuestas, a fin de impedir scripts de apuestas automatizadas que puedan aprovechar vulnerabilidades de sincronización. Registra todas las transacciones de apuestas con marcas de tiempo, cantidades apostadas, resultados e identificadores de jugadores para que los administradores puedan auditar patrones sospechosos. Vigila a los jugadores que ganen sistemáticamente a tasas estadísticamente improbables, lo que podría indicar colusión en partidas de póquer o explotación de mecánicas de predicción. En los juegos de cartas multijugador, asegúrate de que el algoritmo para barajar la baraja produzca distribuciones verdaderamente aleatorias y que ningún cliente pueda ver las cartas ocultas de otros jugadores mediante la inspección de memoria o la captura de paquetes.

Consideraciones de rendimiento

Las zonas del casino concentran a muchos jugadores en un área pequeña, todos realizando interacciones frecuentes con el servidor mediante apuestas, robos de cartas y giros de tragamonedas. Optimiza tu sistema de apuestas agrupando las escrituras de las transacciones de fichas en la base de datos, usando estado en memoria para las sesiones de juego activas y guardando los cambios en la base de datos solo cuando un jugador cambie sus fichas por dinero o se desconecte. Las animaciones de las máquinas tragamonedas deben ejecutarse íntegramente en el cliente, con el resultado predeterminado por el servidor, lo que elimina la necesidad de comunicación continua con el servidor durante la animación del giro. En las mesas de póquer multijugador, usa un único objeto de estado de juego por mesa que transmita las actualizaciones a todos los jugadores sentados simultáneamente, en vez de enviar mensajes individuales. Limita la cantidad de instancias de juego simultáneas por tipo de mesa e implementa un sistema de cola para las mesas populares durante las horas pico. Limpia el estado del juego inmediatamente cuando los jugadores abandonen las mesas para evitar fugas de memoria por sesiones abandonadas que se acumulan durante largos períodos de actividad del servidor.

¿Listo para empezar?

Consigue los scripts en nuestra tienda, o únete al Discord para soporte, novedades y un adelanto de lo que viene.