Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #Requires AutoHotkey v2.0
- #SingleInstance Force
- #WinActivateForce
- ; ===== CONFIGURACIÓN ACELERADA =====
- SendMode "Input"
- SetWorkingDir A_ScriptDir
- ; ===== DISTRIBUCIÓN POR PERFIL =====
- global symbols := Map("cherry", 32, "bell", 26, "lemon", 17, "star", 13, "diamond", 7, "seven", 4, "joker", 1)
- global symbolValues := Map("cherry", 2, "bell", 4, "lemon", 7, "star", 12, "diamond", 24, "seven", 48, "joker", 0, "three_jokers", 80)
- global spinning := false
- global imgPath := "imgs\"
- global soundPath := "sounds\"
- global spinDuration := 500
- global spinInterval := 30
- global img1, img2, img3
- global lastWin := false
- global statsFile := "slot_stats.ini"
- global detailedStatsFile := "detailed_stats.ini"
- global configFile := "slot_config.ini"
- global savedSettingsFile := "AfinacionesGuardadas.ini" ; <<< NUEVA VARIABLE PARA AFINACIONES
- global autoSpin := false
- global autoSpinCount := 0
- global maxAutoSpins := 1000
- global lastUpdateCount := 0
- global jackpotValue := 100
- global jackpotCounter := 0
- global testingMode := true ; ← ACTIVADO PARA PRUEBAS
- global DetailedStatsGui := ""
- global ReportEdit := ""
- global symbolWin := ""
- ; ===== ESTADÍSTICAS DE SISTEMAS DE AYUDA (SIMPLIFICADAS) =====
- global pityActivations := 0, pityWins := 0, pityPesos := 0
- global multiplierActivationsCount := 0, multiplierWins := 0, multiplierPesosExtra := 0
- global jokerActivations := 0, jokerWins := 0, jokerPesos := 0
- global jackpotActivations := 0, jackpotWins := 0, jackpotPesos := 0
- ; ===== NUEVAS VARIABLES PARA ANÁLISIS AVANZADO =====
- global symbolFrequency := Map()
- global combinationStats := Map()
- global volatilityStats := Map()
- global rtpBreakdown := Map()
- ; ===== SISTEMA DE MULTIPLICADORES =====
- global multiplierProbability := 25
- global multiplierValue := 2.0
- global multiplierActivations := 0
- global totalMultiplierPesos := 0
- ; ===== SISTEMA DE PERFILES RTP =====
- global RTPProfiles := Map("RTP35", 35.0, "RTP40", 40.0, "RTP45", 45.0, "RTP50", 50.0)
- global enableJokerSounds := false
- global currentProfile := "RTP40"
- global targetRTP := RTPProfiles[currentProfile]
- ; ===== SISTEMA PITY COUNTER =====
- global pityCounter := 0
- global pityThreshold := 25
- global originalPityThreshold := 20
- ; ===== SISTEMA BONUS MEJORADO =====
- global bonusLights := 0
- global maxBonusGiros := 20
- global bonusLetters := ["B", "O", "N", "U", "S"]
- global letterOrder := []
- global bonusThresholds := []
- ; ===== INICIALIZAR ESTADISTICAS =====
- global totalSpins := 0
- global totalWins := 0
- global totalPesos := 0
- global winStats := Map()
- global pesosStats := Map()
- ; ===== ESTADISTICAS DETALLADAS =====
- global detailedTotalSpins := 0
- global detailedTotalWins := 0
- global detailedTotalPesos := 0
- global detailedJackpotsWon := 0
- global detailedCompensations := 0
- global detailedCompensationCount := 0
- global detailedWinStats := Map()
- global detailedPesosStats := Map()
- global detailedJokerRespines := 0
- global detailedJokerRespinWins := 0
- global detailedJokerRespinPesos := 0
- ; ===== NUEVAS ESTADISTICAS AVANZADAS =====
- global currentLosingStreak := 0
- global longestLosingStreak := 0
- global symbolWinCounts := Map()
- global symbolRTPContributions := Map()
- global jokerRTPContribution := 0
- ; ===== INICIALIZAR LISTA DE SÍMBOLOS =====
- global symbolList := []
- ; ===== VARIABLES RTP MEJORADO =====
- global safetyNetThreshold := 40
- global safetyNetActive := false
- global safetyNetBoost := false
- global jokerEffectivenessRTP35 := 35
- global jokerEffectivenessRTP40 := 25
- global jokerEffectivenessRTP45 := 45
- global jokerEffectivenessRTP50 := 65
- ; ===== SISTEMA DE RESCATE DE VOLATILIDAD MEJORADO =====
- global rescueSpinsWithoutWin := 0
- global lastRescueSpin := 0
- global rescueMinSpinsBetween := 200
- global rescueActivations := 0
- global rescuePesos := 0
- global rescueSymbols := ["lemon", "star", "bell"] ; Símbolos naturales para rescates
- global rescueActive := false ; Nueva variable para controlar estado
- ; ===== INTERFAZ GRAFICA =====
- MyGui := Gui("+AlwaysOnTop +Resize +OwnDialogs -MaximizeBox", "Tragamonedas JACKPOT 5000 giros")
- MyGui.MarginX := 10
- MyGui.MarginY := 10
- MyGui.SetFont("s12", "Arial")
- MyGui.Opt("+OwnDialogs")
- ; Slot machine frame
- MyGui.Add("GroupBox", "w340 h150 Center", "Tragamonedas")
- MyGui.Add("Picture", "vSlot1 xp+10 yp+25 w100 h100 Border", imgPath . "question.png")
- MyGui.Add("Picture", "vSlot2 x+10 w100 h100 Border", imgPath . "question.png")
- MyGui.Add("Picture", "vSlot3 x+10 w100 h100 Border", imgPath . "question.png")
- ; Mostrar jackpot actual en una línea
- MyGui.Add("Text", "xm y+10 w180 Center", "Contador Jackpot:")
- JackpotCounterText := MyGui.Add("Text", "x+0 yp w160 Center", "0/5000")
- ; Logo Joker Giro Gratis - CENTRADO
- MyGui.Add("Picture", "vJokerLogo xm+80 y+5 w180 h35", imgPath . "joker_giro_gratis_apagado.png")
- ; Display de BONUS
- MyGui.Add("Picture", "vBonusSlot1 xm+125 y+10 w20 h30", imgPath . "bonus_empty.png")
- MyGui.Add("Picture", "vBonusSlot2 x+2 w20 h30", imgPath . "bonus_empty.png")
- MyGui.Add("Picture", "vBonusSlot3 x+2 w20 h30", imgPath . "bonus_empty.png")
- MyGui.Add("Picture", "vBonusSlot4 x+2 w20 h30", imgPath . "bonus_empty.png")
- MyGui.Add("Picture", "vBonusSlot5 x+2 w20 h30", imgPath . "bonus_empty.png")
- ; Botones de giro en una línea
- SpinBtn := MyGui.Add("Button", "xm y+20 w100 h25", "1 Moneda")
- SpinBtn.OnEvent("Click", StartSpin)
- SpinBtn.Opt("+Default")
- Spin1000Btn := MyGui.Add("Button", "x+10 w100 h25", "1000")
- Spin1000Btn.OnEvent("Click", Start1000Spins)
- Spin10000Btn := MyGui.Add("Button", "x+10 w100 h25", "10000")
- Spin10000Btn.OnEvent("Click", Start10000Spins)
- ; === NUEVO BOTÓN ULTRA-RÁPIDO ===
- UltraTestBtn := MyGui.Add("Button", "xm y+10 w340 h30 cFFFFFF Background009900", "🔥 PRUEBA ULTRA-RÁPIDA 50000")
- UltraTestBtn.OnEvent("Click", StartUltraTest)
- ; === NUEVO BOTÓN EXPORTAR DATOS ===
- ExportBtn := MyGui.Add("Button", "xm y+5 w165 h25 cFFFFFF Background3366FF", "📊 EXPORTAR CSV")
- ExportBtn.OnEvent("Click", ExportTestData)
- ; === NUEVO BOTÓN EXPORTAR TXT ===
- ExportTxtBtn := MyGui.Add("Button", "x+10 yp w165 h25 cFFFFFF BackgroundFF6600", "📝 EXPORTAR TXT")
- ExportTxtBtn.OnEvent("Click", ExportTestResults)
- ; Boton de seleccion de perfil
- ProfileBtn := MyGui.Add("Button", "xm y+10 w340 h30", "Seleccionar Perfil RTP")
- ProfileBtn.OnEvent("Click", ShowProfileMenu)
- ; Indicador de perfil actual
- CurrentProfileText := MyGui.Add("Text", "xm y+5 w340 Center cFF9900", "Perfil Actual: RTP 40%")
- ; Estadisticas
- MyGui.Add("GroupBox", "xm y+10 w340 h190 Center", "Estadisticas") ; ← Reducir altura
- MyGui.Add("Text", "xp+10 yp+25 w120", "Monedas totales:")
- TotalSpinsText := MyGui.Add("Text", "vTotalSpinsText x+5 w50", "0")
- MyGui.Add("Text", "xp-125 y+5 w120", "Pesos ganados:")
- TotalPesosText := MyGui.Add("Text", "vTotalPesosText x+5 w50", "0")
- MyGui.Add("Text", "xp-125 y+5 w120", "Jugador gana:")
- PlayerWinPercent := MyGui.Add("Text", "vPlayerWinPercent x+5 w70", "0%")
- MyGui.Add("Text", "xp-125 y+5 w120", "Maquina gana:")
- MachineWinPercent := MyGui.Add("Text", "vMachineWinPercent x+5 w70", "100%")
- MyGui.Add("Text", "xp-125 y+5 w120", "Giros sin ganar:")
- PityCounterText := MyGui.Add("Text", "vPityCounterText x+5 w70", "0/20")
- ; === NUEVO INDICADOR DE RESCATE ===
- MyGui.Add("Text", "xp-125 y+5 w120", "Rescates:")
- RescueCounterText := MyGui.Add("Text", "vRescueCounterText x+5 w70", "0")
- StatsBtn := MyGui.Add("Button", "xm+20 y+15 w140 h35", "Ver Detalles")
- StatsBtn.OnEvent("Click", ShowStats)
- ResetBtn := MyGui.Add("Button", "x+20 w140 h35", "Resetear Stats")
- ResetBtn.OnEvent("Click", ResetStats)
- ; Atajo de teclado para abrir el menú de estadísticas detalladas
- 9::ShowDetailedStats
- MyGui.OnEvent("Close", GuiClose)
- MyGui.Show("AutoSize Center")
- ; Inicializar después de crear la GUI
- UpdateSymbolList()
- LoadStats()
- LoadDetailedStats()
- InitializeAdvancedStats()
- RandomizeBonusOrder()
- RandomizeBonusThresholds()
- LoadConfig()
- LoadAfinacionesGuardadas() ; <--- ¡NUEVA LLAMADA PARA CARGAR AFINACIONES!
- ; Inicializar RTP de sesión
- UpdateJokerStatus()
- ;
- ; ===== FUNCIÓN PARA CARGAR AFINACIONES GUARDADAS (AfinacionesGuardadas.ini) =====
- ;
- LoadAfinacionesGuardadas() {
- ; Declarar variables globales necesarias
- global savedSettingsFile, currentProfile, symbols, pityThreshold, jokerEffectivenessRTP35
- global jokerEffectivenessRTP40, jokerEffectivenessRTP45, jokerEffectivenessRTP50, multiplierProbability
- global multiplierValue, safetyNetThreshold, targetRTP, RTPProfiles, CurrentProfileText
- global PityCounterText, MyGui, testingMode, symbolList
- ; 1. Comprobar si el archivo de afinaciones existe
- if (!FileExist(savedSettingsFile)) {
- if (testingMode) {
- OutputDebug("⚠️ Archivo de afinaciones '" . savedSettingsFile . "' no encontrado. Usando configuración por defecto/slot_config.ini.`n")
- }
- return
- }
- ; 2. Leer el perfil actualmente activo del archivo de afinaciones.
- ; Asumimos que el perfil activo está guardado en la sección "Afinacion" bajo la clave "CurrentProfile".
- savedProfile := IniRead(savedSettingsFile, "Afinacion", "CurrentProfile", currentProfile)
- ; 3. Cargar configuraciones guardadas si el perfil existe como sección en el INI.
- ; Los valores se leerán bajo una sección que coincide con el nombre del perfil (e.g., [RTP40])
- sectionName := savedProfile
- ; Leer valores, usando "" como default para saber si fueron encontrados
- loadedPity := IniRead(savedSettingsFile, sectionName, "PityThreshold", "")
- loadedProb := IniRead(savedSettingsFile, sectionName, "MultiplierProbability", "")
- loadedValue := IniRead(savedSettingsFile, sectionName, "MultiplierValue", "")
- ; 4. Aplicar los nuevos valores SOLO si se encontraron
- if (loadedPity != "") {
- pityThreshold := Integer(loadedPity)
- }
- if (loadedProb != "") {
- multiplierProbability := Integer(loadedProb)
- }
- ; Asegurarse de que el valor del multiplicador se lea como Float
- if (loadedValue != "") {
- multiplierValue := Float(loadedValue)
- }
- ; 5. Si el perfil guardado es diferente al actual, sobrescribir y recargar la configuración base.
- ; Esto asegura que los defaults de símbolos y otros parámetros se actualicen correctamente
- if (savedProfile != currentProfile) {
- currentProfile := savedProfile
- LoadConfig() ; Se re-ejecuta LoadConfig() para aplicar los defaults del nuevo perfil (símbolos, etc.).
- }
- ; 6. Mensaje de depuración y actualización de interfaz
- if (testingMode) {
- OutputDebug("✅ Afinaciones Guardadas cargadas. Perfil: " . currentProfile . ". Pity: " . pityThreshold . ". Prob Multi: " . multiplierProbability . ". Valor Multi: " . multiplierValue . "`n")
- }
- ; Re-actualizar display después de posibles cambios en pityThreshold y targetRTP
- targetRTP := RTPProfiles.Has(currentProfile) ? RTPProfiles[currentProfile] : 0.0
- CurrentProfileText.Value := "Perfil Actual: " . currentProfile . " (" . targetRTP . "%)"
- PityCounterText.Value := pityCounter . "/" . pityThreshold
- UpdateSymbolList() ; Asegurar que la lista de símbolos se actualice.
- }
- ; ===== FUNCIONES =====
- ; ===== FUNCIÓN EXPORTAR RESULTADOS TXT CORREGIDA =====
- ExportTestResults(*) {
- global currentProfile, targetRTP, totalSpins, totalPesos, detailedTotalSpins, detailedTotalPesos
- global multiplierProbability, multiplierValue, testingMode
- if (totalSpins = 0) {
- MsgBox("No hay datos para exportar. Realiza algunos giros primero.", "Sin Datos", "48")
- return
- }
- ; ✅ CALCULAR RTP CON SEGURIDAD
- currentRTP := 0
- if (totalSpins > 0) {
- currentRTP := (totalPesos / totalSpins) * 100
- }
- deviation := currentRTP - targetRTP
- ; Crear nombre de archivo con timestamp
- timestamp := FormatTime(, "yyyy-MM-dd_HH-mm-ss")
- filename := "Resultado_Precision_" . currentProfile . "_" . timestamp . ".txt"
- content := "=== RESULTADO PRECISIÓN " . currentProfile . " ===`n"
- content .= "Timestamp: " . timestamp . "`n"
- content .= "Perfil: " . currentProfile . " (Objetivo: " . targetRTP . "%)`n"
- content .= "Giros totales: " . totalSpins . "`n"
- content .= "RTP Final: " . Round(currentRTP, 3) . "%`n"
- content .= "Desviación: " . Round(deviation, 3) . "%`n"
- content .= "Multiplicador final: " . multiplierProbability . "% / " . multiplierValue . "x`n"
- content .= "Precisión: " . (Abs(deviation) <= 0.5 ? "✅ EXCELENTE" : (Abs(deviation) <= 1.0 ? "⚠️ ACEPTABLE" : "❌ INACEPTABLE")) . "`n"
- content .= "`n"
- content .= "=== DETALLES ADICIONALES ===`n"
- content .= "Giros detallados: " . detailedTotalSpins . "`n"
- content .= "Pesos detallados: " . detailedTotalPesos . "`n"
- content .= "Fecha de análisis: " . FormatTime(, "dd/MM/yyyy HH:mm:ss") . "`n"
- try {
- FileAppend(content, filename)
- if (testingMode) {
- OutputDebug("📊 RESULTADO EXPORTADO: " . filename . "`n")
- }
- MsgBox("✅ Archivo TXT exportado correctamente:`n" . filename, "Exportación Exitosa", "64")
- } catch Error as e {
- OutputDebug("❌ ERROR exportando: " . e.Message . "`n")
- MsgBox("❌ Error al exportar archivo TXT:`n" . e.Message, "Error de Exportación", "16")
- }
- }
- ; ===== SISTEMA DE RESCATE DE VOLATILIDAD MEJORADO =====
- CheckVolatilityRescue() {
- global rescueSpinsWithoutWin, lastRescueSpin, rescueMinSpinsBetween, totalSpins
- global currentProfile, rescueActivations, rescuePesos, rescueSymbols
- global img1, img2, img3, symbolWin, symbolValues, totalPesos, detailedTotalPesos
- global totalWins, detailedTotalWins, winStats, detailedWinStats, pesosStats, detailedPesosStats
- global pityCounter, currentLosingStreak, MyGui, imgPath, rescueActive
- ; Evitar activación múltiple
- if (rescueActive) {
- return false
- }
- ; Umbral de activación: 80 giros sin victoria y mínimo 200 giros entre rescates
- if (rescueSpinsWithoutWin >= 45 && (totalSpins - lastRescueSpin) >= 120) {
- rescueActive := true
- ; 🎯 MODIFICACIÓN CRÍTICA IMPLEMENTADA: SOLO SÍMBOLOS DE BAJO VALOR
- lowValueRescueSymbols := ["cherry", "bell"] ; Solo símbolos de 2-4 pesos
- ; Seleccionar símbolo de bajo valor para el rescate
- rescueSymbol := lowValueRescueSymbols[Random(1, lowValueRescueSymbols.Length)]
- ; El premio será el valor natural del símbolo (2-4 pesos)
- rescuePrize := symbolValues[rescueSymbol]
- if (rescuePrize > 0) {
- ; Forzar combinación ganadora
- img1 := rescueSymbol
- img2 := rescueSymbol
- img3 := rescueSymbol
- symbolWin := rescueSymbol
- ; Actualizar display visual inmediatamente
- MyGui["Slot1"].Value := imgPath . rescueSymbol . ".png"
- MyGui["Slot2"].Value := imgPath . rescueSymbol . ".png"
- MyGui["Slot3"].Value := imgPath . rescueSymbol . ".png"
- ; Procesar la victoria
- HandleRescueWin(rescueSymbol, rescuePrize)
- ; Actualizar contadores
- rescueActivations++
- rescuePesos += rescuePrize
- lastRescueSpin := totalSpins
- rescueSpinsWithoutWin := 0
- pityCounter := 0
- currentLosingStreak := 0
- ; Actualizar display de estadísticas
- UpdateStatsDisplay()
- ; Mostrar notificación en modo testing
- if (testingMode) {
- OutputDebug("🎯 RESCATE ACTIVADO: " . rescueSymbol . " - " . rescuePrize . " pesos`n")
- }
- rescueActive := false
- return true
- }
- rescueActive := false
- }
- return false
- }
- GetRescuePrize() {
- global rescueSymbols, symbolValues
- ; Seleccionar símbolo natural para el rescate
- rescueSymbol := rescueSymbols[Random(1, rescueSymbols.Length)]
- ; Pagar el valor EXACTO de la figura
- return symbolValues[rescueSymbol]
- }
- HandleRescueWin(symbol, prize) {
- global totalWins, detailedTotalWins, winStats, detailedWinStats
- global totalPesos, detailedTotalPesos, pesosStats, detailedPesosStats
- global lastWin, pityCounter, currentLosingStreak, rescueSpinsWithoutWin
- lastWin := true
- totalWins++
- detailedTotalWins++
- pityCounter := 0
- currentLosingStreak := 0
- rescueSpinsWithoutWin := 0
- ; Registrar estadísticas
- winStats[symbol] := winStats.Has(symbol) ? winStats[symbol] + 1 : 1
- detailedWinStats[symbol] := detailedWinStats.Has(symbol) ? detailedWinStats[symbol] + 1 : 1
- pesosStats[symbol] := pesosStats.Has(symbol) ? pesosStats[symbol] + prize : prize
- detailedPesosStats[symbol] := detailedPesosStats.Has(symbol) ? detailedPesosStats[symbol] + prize : prize
- totalPesos += prize
- detailedTotalPesos += prize
- ; Actualizar display
- UpdateStatsDisplay()
- UpdateJokerStatus()
- }
- ; ===== NUEVA FUNCIÓN: INICIALIZAR ESTADÍSTICAS AVANZADAS =====
- InitializeAdvancedStats() {
- global symbolFrequency, combinationStats, volatilityStats, rtpBreakdown, symbols
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos, rescueActive
- ; Inicializar frecuencia de símbolos
- symbolFrequency := Map()
- for symbol in symbols {
- symbolFrequency[symbol] := 0
- }
- ; Inicializar estadísticas de combinaciones
- combinationStats := Map()
- ; Inicializar métricas de volatilidad
- volatilityStats := Map()
- volatilityStats["CurrentLosingStreak"] := 0
- volatilityStats["LongestLosingStreak"] := 0
- volatilityStats["CurrentWinningStreak"] := 0
- volatilityStats["LongestWinningStreak"] := 0
- volatilityStats["SpinsBetweenWins"] := []
- volatilityStats["WinDistribution"] := Map()
- ; Inicializar desglose de RTP
- rtpBreakdown := Map()
- rtpBreakdown["Base_Symbols"] := 0
- rtpBreakdown["Pity_System"] := 0
- rtpBreakdown["Joker_Respins"] := 0
- rtpBreakdown["Multipliers"] := 0
- rtpBreakdown["Jackpot"] := 0
- rtpBreakdown["Rescue_System"] := 0
- rtpBreakdown["Total"] := 0
- ; Inicializar sistema de rescate
- rescueSpinsWithoutWin := 0
- lastRescueSpin := 0
- rescueActivations := 0
- rescuePesos := 0
- rescueActive := false
- }
- UpdateSymbolList() {
- global symbols, symbolList
- symbolList := []
- for symbol, count in symbols {
- Loop count {
- symbolList.Push(symbol)
- }
- }
- }
- LoadStats() {
- global statsFile, totalSpins, totalWins, totalPesos, winStats, pesosStats, symbols, jackpotCounter, pityCounter
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos
- if FileExist(statsFile) {
- totalSpins := Integer(IniRead(statsFile, "Stats", "TotalSpins", "0"))
- totalWins := Integer(IniRead(statsFile, "Stats", "TotalWins", "0"))
- totalPesos := Integer(IniRead(statsFile, "Stats", "TotalPesos", "0"))
- jackpotCounter := Integer(IniRead(statsFile, "Stats", "JackpotCounter", "0"))
- pityCounter := Integer(IniRead(statsFile, "Stats", "PityCounter", "0"))
- rescueSpinsWithoutWin := Integer(IniRead(statsFile, "Rescue", "SpinsWithoutWin", "0"))
- lastRescueSpin := Integer(IniRead(statsFile, "Rescue", "LastRescueSpin", "0"))
- rescueActivations := Integer(IniRead(statsFile, "Rescue", "Activations", "0"))
- rescuePesos := Integer(IniRead(statsFile, "Rescue", "TotalPesos", "0"))
- for symbol in symbols {
- winStats[symbol] := Integer(IniRead(statsFile, "Symbols", symbol, "0"))
- pesosStats[symbol] := Integer(IniRead(statsFile, "Pesos", symbol, "0"))
- }
- winStats["three_jokers"] := Integer(IniRead(statsFile, "Symbols", "three_jokers", "0"))
- pesosStats["three_jokers"] := Integer(IniRead(statsFile, "Pesos", "three_jokers", "0"))
- } else {
- ; Inicializar valores si no existen
- totalSpins := 0
- totalWins := 0
- totalPesos := 0
- jackpotCounter := 0
- pityCounter := 0
- rescueSpinsWithoutWin := 0
- lastRescueSpin := 0
- rescueActivations := 0
- rescuePesos := 0
- for symbol in symbols {
- winStats[symbol] := 0
- pesosStats[symbol] := 0
- }
- winStats["three_jokers"] := 0
- pesosStats["three_jokers"] := 0
- }
- ; Actualizar la interfaz
- UpdateStatsDisplay()
- }
- SaveStats() {
- global statsFile, totalSpins, totalWins, totalPesos, winStats, pesosStats, jackpotCounter, pityCounter
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos
- IniWrite(totalSpins, statsFile, "Stats", "TotalSpins")
- IniWrite(totalWins, statsFile, "Stats", "TotalWins")
- IniWrite(totalPesos, statsFile, "Stats", "TotalPesos")
- IniWrite(jackpotCounter, statsFile, "Stats", "JackpotCounter")
- IniWrite(pityCounter, statsFile, "Stats", "PityCounter")
- IniWrite(rescueSpinsWithoutWin, statsFile, "Rescue", "SpinsWithoutWin")
- IniWrite(lastRescueSpin, statsFile, "Rescue", "LastRescueSpin")
- IniWrite(rescueActivations, statsFile, "Rescue", "Activations")
- IniWrite(rescuePesos, statsFile, "Rescue", "TotalPesos")
- for symbol, count in winStats {
- IniWrite(count, statsFile, "Symbols", symbol)
- IniWrite(pesosStats[symbol], statsFile, "Pesos", symbol)
- }
- }
- LoadDetailedStats() {
- global detailedStatsFile, detailedTotalSpins, detailedTotalWins, detailedTotalPesos, detailedJackpotsWon, detailedWinStats, detailedPesosStats, symbols, detailedCompensations, detailedCompensationCount, multiplierActivations, totalMultiplierPesos, detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global currentLosingStreak, longestLosingStreak
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos
- if FileExist(detailedStatsFile) {
- detailedTotalSpins := Integer(IniRead(detailedStatsFile, "Stats", "TotalSpins", "0"))
- detailedTotalWins := Integer(IniRead(detailedStatsFile, "Stats", "TotalWins", "0"))
- detailedTotalPesos := Integer(IniRead(detailedStatsFile, "Stats", "TotalPesos", "0"))
- detailedJackpotsWon := Integer(IniRead(detailedStatsFile, "Stats", "JackpotsWon", "0"))
- detailedCompensations := Integer(IniRead(detailedStatsFile, "Stats", "TotalCompensations", "0"))
- detailedCompensationCount := Integer(IniRead(detailedStatsFile, "Stats", "CompensationCount", "0"))
- multiplierActivations := Integer(IniRead(detailedStatsFile, "Multipliers", "ActivationCount", "0"))
- totalMultiplierPesos := Integer(IniRead(detailedStatsFile, "Multipliers", "TotalPesos", "0"))
- detailedJokerRespines := Integer(IniRead(detailedStatsFile, "Joker", "Respines", "0"))
- detailedJokerRespinWins := Integer(IniRead(detailedStatsFile, "Joker", "RespinWins", "0"))
- detailedJokerRespinPesos := Integer(IniRead(detailedStatsFile, "Joker", "RespinPesos", "0"))
- rescueSpinsWithoutWin := Integer(IniRead(detailedStatsFile, "Rescue", "SpinsWithoutWin", "0"))
- lastRescueSpin := Integer(IniRead(detailedStatsFile, "Rescue", "LastRescueSpin", "0"))
- rescueActivations := Integer(IniRead(detailedStatsFile, "Rescue", "Activations", "0"))
- rescuePesos := Integer(IniRead(detailedStatsFile, "Rescue", "TotalPesos", "0"))
- for symbol in symbols {
- detailedWinStats[symbol] := Integer(IniRead(detailedStatsFile, "Symbols", symbol, "0"))
- detailedPesosStats[symbol] := Integer(IniRead(detailedStatsFile, "Pesos", symbol, "0"))
- }
- detailedWinStats["three_jokers"] := Integer(IniRead(detailedStatsFile, "Symbols", "three_jokers", "0"))
- detailedPesosStats["three_jokers"] := Integer(IniRead(detailedStatsFile, "Pesos", "three_jokers", "0"))
- ; Cargar nuevas estadísticas avanzadas
- currentLosingStreak := Integer(IniRead(detailedStatsFile, "AdvancedMetrics", "CurrentLosingStreak", "0"))
- longestLosingStreak := Integer(IniRead(detailedStatsFile, "AdvancedMetrics", "LongestLosingStreak", "0"))
- } else {
- ; Inicializar valores si no existen
- detailedTotalSpins := 0
- detailedTotalWins := 0
- detailedTotalPesos := 0
- detailedJackpotsWon := 0
- detailedCompensations := 0
- detailedCompensationCount := 0
- multiplierActivations := 0
- totalMultiplierPesos := 0
- currentLosingStreak := 0
- longestLosingStreak := 0
- rescueSpinsWithoutWin := 0
- lastRescueSpin := 0
- rescueActivations := 0
- rescuePesos := 0
- for symbol in symbols {
- detailedWinStats[symbol] := 0
- detailedPesosStats[symbol] := 0
- }
- detailedWinStats["three_jokers"] := 0
- detailedPesosStats["three_jokers"] := 0
- }
- }
- SaveDetailedStats() {
- global detailedStatsFile, detailedTotalSpins, detailedTotalWins, detailedTotalPesos, detailedJackpotsWon, detailedWinStats, detailedPesosStats, detailedCompensations, detailedCompensationCount, multiplierActivations, totalMultiplierPesos, detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global longestLosingStreak, symbolRTPContributions, jokerRTPContribution, symbolValues
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos
- RTP := 0
- if (detailedTotalSpins > 0) {
- RTP := Round((detailedTotalPesos / detailedTotalSpins) * 100, 2)
- }
- ; Calcular RTP por símbolo
- symbolRTPContributions := Map()
- for symbol, pesos in detailedPesosStats {
- if (detailedTotalPesos > 0) {
- symbolRTPContributions[symbol] := Round((pesos / detailedTotalPesos) * RTP, 2)
- } else {
- symbolRTPContributions[symbol] := 0
- }
- }
- ; Calcular contribución del Joker
- jokerRTPContribution := 0
- if (detailedTotalPesos > 0) {
- jokerRTPContribution := Round((detailedJokerRespinPesos / detailedTotalPesos) * RTP, 2)
- }
- IniWrite(detailedTotalSpins, detailedStatsFile, "Stats", "TotalSpins")
- IniWrite(detailedTotalWins, detailedStatsFile, "Stats", "TotalWins")
- IniWrite(detailedTotalPesos, detailedStatsFile, "Stats", "TotalPesos")
- IniWrite(detailedJackpotsWon, detailedStatsFile, "Stats", "JackpotsWon")
- IniWrite(detailedCompensations, detailedStatsFile, "Stats", "TotalCompensations")
- IniWrite(detailedCompensationCount, detailedStatsFile, "Stats", "CompensationCount")
- IniWrite(RTP, detailedStatsFile, "Stats", "RTP")
- IniWrite(multiplierActivations, detailedStatsFile, "Multipliers", "ActivationCount")
- IniWrite(totalMultiplierPesos, detailedStatsFile, "Multipliers", "TotalPesos")
- IniWrite(detailedJokerRespines, detailedStatsFile, "Joker", "Respines")
- IniWrite(detailedJokerRespinWins, detailedStatsFile, "Joker", "RespinWins")
- IniWrite(detailedJokerRespinPesos, detailedStatsFile, "Joker", "RespinPesos")
- IniWrite(rescueSpinsWithoutWin, detailedStatsFile, "Rescue", "SpinsWithoutWin")
- IniWrite(lastRescueSpin, detailedStatsFile, "Rescue", "LastRescueSpin")
- IniWrite(rescueActivations, detailedStatsFile, "Rescue", "Activations")
- IniWrite(rescuePesos, detailedStatsFile, "Rescue", "TotalPesos")
- for symbol, count in detailedWinStats {
- IniWrite(count, detailedStatsFile, "Symbols", symbol)
- IniWrite(detailedPesosStats[symbol], detailedStatsFile, "Pesos", symbol)
- }
- ; Escribir nuevas métricas avanzadas
- IniWrite(longestLosingStreak, detailedStatsFile, "AdvancedMetrics", "LongestLosingStreak")
- IniWrite(currentLosingStreak, detailedStatsFile, "AdvancedMetrics", "CurrentLosingStreak")
- ; Escribir contribución RTP por símbolo
- for symbol, rtp in symbolRTPContributions {
- IniWrite(rtp, detailedStatsFile, "RTPBySymbol", symbol)
- }
- ; Escribir contribución RTP del Joker
- IniWrite(jokerRTPContribution, detailedStatsFile, "RTPBySymbol", "joker_respin_rtp")
- }
- LoadConfig() {
- ; DECLARAR EXPLÍCITAMENTE TODAS LAS VARIABLES GLOBALES
- global currentProfile, symbols, pityThreshold, jokerEffectivenessRTP35, jokerEffectivenessRTP40
- global jokerEffectivenessRTP45, jokerEffectivenessRTP50, multiplierProbability, multiplierValue
- global safetyNetThreshold, targetRTP, RTPProfiles, CurrentProfileText, MyGui, PityCounterText
- global rescueSpinsWithoutWin, rescueMinSpinsBetween
- currentProfile := IniRead(configFile, "Config", "CurrentProfile", "RTP40")
- ; CONFIGURACIÓN MEJORADA
- if (currentProfile = "RTP35") {
- symbols := Map("cherry", 25, "bell", 26, "lemon", 17, "star", 12, "diamond", 8, "seven", 6, "joker", 1)
- pityThreshold := 25
- jokerEffectivenessRTP35 := 20
- multiplierProbability := 10
- multiplierValue := 2.0
- safetyNetThreshold := 45
- rescueSpinsWithoutWin := 60
- rescueMinSpinsBetween := 200
- LoadAfinacionesGuardadas()
- }else if (currentProfile = "RTP40") {
- symbols := Map("cherry", 30, "bell", 25, "lemon", 19, "star", 12, "diamond", 7, "seven", 5, "joker", 2)
- pityThreshold := 25
- jokerEffectivenessRTP40 := 20
- multiplierProbability := 10
- multiplierValue := 2.2
- safetyNetThreshold := 50
- rescueSpinsWithoutWin := 80
- rescueMinSpinsBetween := 250
- } else if (currentProfile = "RTP45") {
- symbols := Map("cherry", 25, "bell", 22, "lemon", 20, "star", 15, "diamond", 9, "seven", 7, "joker", 2)
- pityThreshold := 25
- jokerEffectivenessRTP45 := 20
- multiplierProbability := 6
- multiplierValue := 2.5
- safetyNetThreshold := 50
- rescueSpinsWithoutWin := 80
- rescueMinSpinsBetween := 250
- } else if (currentProfile = "RTP50") {
- symbols := Map("cherry", 26, "bell", 22, "lemon", 22, "star", 14, "diamond", 7, "seven", 6, "joker", 3)
- pityThreshold := 25
- jokerEffectivenessRTP50 := 65
- multiplierProbability := 40
- multiplierValue := 3.2
- safetyNetThreshold := 25
- }
- ; Leer valores de configuración si existen
- pityThreshold := Integer(IniRead(configFile, "Config", "PityThreshold", pityThreshold))
- multiplierProbability := Integer(IniRead(configFile, "Multipliers", "ActivationProbability", multiplierProbability))
- multiplierValue := Float(IniRead(configFile, "Multipliers", "MultiplierValue", multiplierValue))
- targetRTP := RTPProfiles[currentProfile]
- CurrentProfileText.Value := "Perfil Actual: " . currentProfile . " (" . targetRTP . "%)"
- if (currentProfile = "RTP35")
- CurrentProfileText.Opt("c007ACC")
- else if (currentProfile = "RTP40")
- CurrentProfileText.Opt("cFF9900")
- else if (currentProfile = "RTP45")
- CurrentProfileText.Opt("cFF3366")
- else if (currentProfile = "RTP50")
- CurrentProfileText.Opt("c00FF00")
- MyGui.Title := "Tragamonedas AHK - JACKPOT a 5000 giros"
- PityCounterText.Value := pityCounter . "/" . pityThreshold
- UpdateSymbolList() ; ← ACTUALIZAR LISTA DE SÍMBOLOS
- }
- SaveConfig() {
- global configFile, currentProfile, pityThreshold, multiplierProbability, multiplierValue
- IniWrite(currentProfile, configFile, "Config", "CurrentProfile")
- IniWrite(pityThreshold, configFile, "Config", "PityThreshold")
- IniWrite(multiplierProbability, configFile, "Multipliers", "ActivationProbability")
- IniWrite(multiplierValue, configFile, "Multipliers", "MultiplierValue")
- }
- RandomizeBonusOrder() {
- global bonusLetters, letterOrder
- letterOrder := ["B", "O", "N", "U", "S"]
- }
- RandomizeBonusThresholds() {
- global bonusThresholds
- bonusThresholds := []
- bonusThresholds.Push(Random(3, 5))
- bonusThresholds.Push(Random(7, 9))
- bonusThresholds.Push(Random(11, 13))
- bonusThresholds.Push(Random(15, 17))
- bonusThresholds.Push(20)
- }
- UpdateBonusLights() {
- global pityCounter, bonusThresholds, letterOrder, imgPath, MyGui
- lettersToShow := 0
- Loop 5 {
- if (pityCounter >= bonusThresholds[A_Index]) {
- lettersToShow := A_Index
- }
- }
- ; Apagar todas las luces primero
- Loop 5 {
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_empty.png"
- }
- ; Encender las luces en ORDEN CONSECUTIVO
- Loop lettersToShow {
- letter := letterOrder[A_Index]
- if (letter = "B")
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_B_red.png"
- else if (letter = "O")
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_O_blue.png"
- else if (letter = "N")
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_N_green.png"
- else if (letter = "U")
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_U_yellow.png"
- else if (letter = "S")
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_S_purple.png"
- }
- }
- ShowProfileMenu(*) {
- try {
- ProfileMenu := Menu()
- ProfileMenu.Add("RTP 35%", SetRTPProfile.Bind("RTP35"))
- ProfileMenu.Add("RTP 40%", SetRTPProfile.Bind("RTP40"))
- ProfileMenu.Add("RTP 45%", SetRTPProfile.Bind("RTP45"))
- ProfileMenu.Add("RTP 50%", SetRTPProfile.Bind("RTP50"))
- ProfileMenu.Show()
- }
- }
- SetRTPProfile(profileName, *) {
- ; DECLARAR EXPLÍCITAMENTE TODAS LAS VARIABLES GLOBALES
- global currentProfile, targetRTP, RTPProfiles, symbols, MyGui
- global pityThreshold, jokerEffectivenessRTP35, jokerEffectivenessRTP40
- global jokerEffectivenessRTP45, jokerEffectivenessRTP50, multiplierProbability, multiplierValue
- global safetyNetThreshold
- global rescueSpinsWithoutWin, rescueMinSpinsBetween
- currentProfile := profileName
- targetRTP := RTPProfiles[profileName]
- ; === CONFIGURACIÓN OPTIMIZADA GAMIFICACIÓN ===
- if (currentProfile = "RTP35") {
- symbols := Map("cherry", 25, "bell", 26, "lemon", 17, "star", 12, "diamond", 8, "seven", 6, "joker", 1)
- pityThreshold := 25
- jokerEffectivenessRTP35 := 20
- multiplierProbability := 10
- multiplierValue := 2.0
- safetyNetThreshold := 45
- rescueSpinsWithoutWin := 60
- rescueMinSpinsBetween := 200
- LoadAfinacionesGuardadas()
- } else if (currentProfile = "RTP40") {
- symbols := Map("cherry", 30, "bell", 25, "lemon", 19, "star", 12, "diamond", 7, "seven", 5, "joker", 2)
- pityThreshold := 25
- jokerEffectivenessRTP40 := 20
- multiplierProbability := 10
- multiplierValue := 2.2
- safetyNetThreshold := 50
- rescueSpinsWithoutWin := 80
- rescueMinSpinsBetween := 250
- } else if (currentProfile = "RTP45") {
- symbols := Map("cherry", 25, "bell", 22, "lemon", 20, "star", 15, "diamond", 9, "seven", 7, "joker", 2)
- pityThreshold := 25
- jokerEffectivenessRTP45 := 20
- multiplierProbability := 6
- multiplierValue := 2.5
- safetyNetThreshold := 50
- rescueSpinsWithoutWin := 80
- rescueMinSpinsBetween := 250
- } else if (currentProfile = "RTP50") {
- symbols := Map("cherry", 26, "bell", 22, "lemon", 22, "star", 14, "diamond", 7, "seven", 6, "joker", 3)
- pityThreshold := 25
- jokerEffectivenessRTP50 := 65
- multiplierProbability := 40
- multiplierValue := 3.2
- safetyNetThreshold := 25
- }
- UpdateSymbolList()
- UpdateProfileDisplay()
- ResetStats(0)
- ; GUARDAR CONFIGURACIÓN
- SaveConfig()
- MyGui.Opt("+OwnDialogs")
- MsgBox("RTP configurado al " . targetRTP . "%", "Perfil Cambiado", "64")
- MyGui.Title := "Tragamonedas AHK - JACKPOT a 5000 giros"
- UpdateJokerStatus()
- }
- ResetProfileSettings() {
- global currentProfile, pityThreshold
- if (currentProfile = "RTP35") {
- pityThreshold := 25
- } else if (currentProfile = "RTP40") {
- pityThreshold := 25
- } else if (currentProfile = "RTP45") {
- pityThreshold := 25
- } else if (currentProfile = "RTP50") {
- pityThreshold := 25
- }
- SaveConfig()
- }
- UpdateProfileDisplay() {
- global currentProfile, targetRTP, CurrentProfileText, MyGui
- CurrentProfileText.Value := "Perfil Actual: " . currentProfile . " (" . targetRTP . "%)"
- if (currentProfile = "RTP35")
- CurrentProfileText.Opt("c007ACC")
- else if (currentProfile = "RTP40")
- CurrentProfileText.Opt("cFF9900")
- else if (currentProfile = "RTP45")
- CurrentProfileText.Opt("cFF3366")
- else if (currentProfile = "RTP50")
- CurrentProfileText.Opt("c00FF00")
- MyGui.Title := "Tragamonedas AHK - JACKPOT a 5000 giros"
- }
- CalculatePlayerWinPercent() {
- global totalSpins, totalPesos
- if (totalSpins = 0)
- return "0%"
- playerWinPercent := (totalPesos / totalSpins) * 100
- return Round(playerWinPercent, 1) . "%"
- }
- CalculateMachineWinPercent() {
- global totalSpins, totalPesos
- if (totalSpins = 0)
- return "100%"
- machineWinPercent := ((totalSpins - totalPesos) / totalSpins) * 100
- return Round(machineWinPercent, 1) . "%"
- }
- UpdateWinPercentages() {
- PlayerWinPercent.Value := CalculatePlayerWinPercent()
- MachineWinPercent.Value := CalculateMachineWinPercent()
- }
- UpdateJokerStatus() {
- global currentRTP, totalSpins, totalPesos, MyGui, imgPath
- if (totalSpins > 0) {
- currentRTP := (totalPesos / totalSpins) * 100
- } else {
- currentRTP := 0
- }
- if (currentRTP < targetRTP) {
- MyGui["JokerLogo"].Value := imgPath . "joker_giro_gratis_prendido.png"
- } else {
- MyGui["JokerLogo"].Value := imgPath . "joker_giro_gratis_apagado.png"
- }
- }
- Start1000Spins(*) {
- global spinning, autoSpin, testingMode, autoSpinCount, maxAutoSpins
- if spinning
- return
- autoSpin := true
- testingMode := true
- autoSpinCount := 0
- maxAutoSpins := 1000
- SpinBtn.Enabled := false
- Spin1000Btn.Enabled := false
- Spin10000Btn.Enabled := false
- SetTimer(AutoSpinLoop, 80)
- }
- Start10000Spins(*) {
- global spinning, autoSpin, testingMode, autoSpinCount, maxAutoSpins
- if spinning
- return
- autoSpin := true
- testingMode := true
- autoSpinCount := 0
- maxAutoSpins := 50000
- SpinBtn.Enabled := false
- Spin1000Btn.Enabled := false
- Spin10000Btn.Enabled := false
- SetTimer(AutoSpinLoop, 80)
- }
- StartUltraTest(*) {
- global spinning, autoSpin, testingMode, autoSpinCount, maxAutoSpins
- global symbols, symbolList ; ← Asegurar que estas globales estén declaradas
- if spinning
- return
- ; === AGREGAR ESTA LÍNEA CRÍTICA ===
- UpdateSymbolList() ; ← ¡ACTUALIZAR LA LISTA DE SÍMBOLOS!
- MyGui.Opt("+OwnDialogs")
- MsgBox("🚀 INICIANDO PRUEBA ULTRA-RÁPIDA`n`n• 50,000 giros en 5-9 minutos`n• RTP teórico puro (sin ajustes dinámicos)`n• Sin animaciones ni sonidos`n• Resultados válidos al 100%", "Modo Pruebas Rápido", "64")
- autoSpin := true
- testingMode := true
- autoSpinCount := 0
- maxAutoSpins := 50000
- SpinBtn.Enabled := false
- Spin1000Btn.Enabled := false
- Spin10000Btn.Enabled := false
- UltraTestBtn.Enabled := false
- UltraTestBtn.Text := "🔥 PROCESANDO... " . autoSpinCount . "/50000"
- SetTimer(UltraSpinLoop, 1)
- }
- UltraSpinLoop() {
- ; DECLARAR TODAS LAS VARIABLES GLOBALES UNA POR UNA
- global autoSpin, autoSpinCount, maxAutoSpins, spinning, totalSpins, detailedTotalSpins
- global img1, img2, img3, symbolWin, symbolList, targetRTP, totalPesos
- global detailedJokerRespines, detailedJokerRespinWins, UltraTestBtn
- global symbolFrequency, combinationStats, jokerActivations
- global jackpotCounter, jackpotValue, detailedJackpotsWon, pityCounter
- global detailedTotalPesos, testingMode, UpdateBonusLights, symbolValues
- global detailedJokerRespinPesos, jokerWins, jokerPesos
- global jackpotActivations, jackpotWins, jackpotPesos
- global currentLosingStreak, longestLosingStreak
- global currentProfile, safetyNetActive, safetyNetThreshold
- global rescueSpinsWithoutWin, lastRescueSpin, rescueMinSpinsBetween, rescueActivations, rescuePesos
- if spinning || autoSpinCount >= maxAutoSpins {
- if (autoSpinCount >= maxAutoSpins) {
- SetTimer(UltraSpinLoop, 0)
- autoSpin := false
- testingMode := false
- lastUpdateCount := 0
- SaveStats()
- SaveDetailedStats()
- ; ✅ NUEVO: EXPORTAR RESULTADOS AUTOMÁTICAMENTE - AGREGADO
- if (testingMode) {
- ExportTestResults()
- }
- SpinBtn.Enabled := true
- Spin1000Btn.Enabled := true
- Spin10000Btn.Enabled := true
- UltraTestBtn.Enabled := true
- UltraTestBtn.Text := "🔥 PRUEBA ULTRA-RÁPIDA 50000"
- currentRTP := (totalPesos / totalSpins) * 100
- MyGui.Opt("+OwnDialogs")
- MsgBox("✅ PRUEBA COMPLETADA`n`nGiros: " . maxAutoSpins . "`nRTP Final: " . Round(currentRTP, 2) . "%`nDesviación: " . Round(currentRTP - targetRTP, 2) . "%`n`n📊 Datos guardados en archivos INI", "Resultados Ultra-Rápidos", "64")
- }
- return
- }
- Critical true
- totalSpins++
- detailedTotalSpins++
- autoSpinCount++
- ; ACTUALIZACIÓN GARANTIZADA CADA 100 GIROS
- if (Mod(autoSpinCount, 100) == 0) {
- UltraTestBtn.Text := "🔥 PROCESANDO... " . autoSpinCount . "/50000"
- UpdateStatsDisplay()
- }
- randIndex := Random(1, symbolList.Length)
- img1 := symbolList[randIndex]
- randIndex := Random(1, symbolList.Length)
- img2 := symbolList[randIndex]
- randIndex := Random(1, symbolList.Length)
- img3 := symbolList[randIndex]
- symbolFrequency[img1] := symbolFrequency.Get(img1, 0) + 1
- symbolFrequency[img2] := symbolFrequency.Get(img2, 0) + 1
- symbolFrequency[img3] := symbolFrequency.Get(img3, 0) + 1
- symbolWin := CheckWinCombination(img1, img2, img3)
- ; ===== VERIFICAR RESCATE DE VOLATILIDAD MEJORADO =====
- if (!symbolWin || symbolWin = false) {
- rescueSpinsWithoutWin++
- if (CheckVolatilityRescue()) {
- ; El rescate ya manejó la victoria, continuar al siguiente giro
- Critical false
- return
- }
- } else {
- rescueSpinsWithoutWin := 0
- }
- if (symbolWin is String && symbolWin != "") {
- HandleTripleWinUltra()
- } else if (img1 = "joker" || img2 = "joker" || img3 = "joker") {
- currentRTP := 0
- if (totalSpins > 0) {
- currentRTP := (totalPesos / totalSpins) * 100
- }
- if (currentRTP < targetRTP) {
- jokerActivations += 1
- detailedJokerRespines++
- if (img1 != "joker") {
- randIndex := Random(1, symbolList.Length)
- img1 := symbolList[randIndex]
- }
- if (img2 != "joker") {
- randIndex := Random(1, symbolList.Length)
- img2 := symbolList[randIndex]
- }
- if (img3 != "joker") {
- randIndex := Random(1, symbolList.Length)
- img3 := symbolList[randIndex]
- }
- symbolWin := CheckWinCombination(img1, img2, img3)
- if (symbolWin is String && symbolWin != "") {
- ; ✅ BLOQUE CORREGIDO - CONTADORES DE JOKER FIJOS
- pesosGanados := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 2
- HandleTripleWinUltra()
- detailedJokerRespinWins += 1 ; ← SOLO 1 VICTORIA POR RESPIN
- detailedJokerRespinPesos += pesosGanados
- jokerWins += 1
- jokerPesos += pesosGanados
- } else {
- HandleLossUltra()
- }
- } else {
- HandleLossUltra()
- }
- } else {
- HandleLossUltra()
- }
- ; VERIFICACIÓN JACKPOT
- if (jackpotCounter >= 5000) {
- totalPesos += jackpotValue
- detailedTotalPesos += jackpotValue
- detailedJackpotsWon++
- jackpotCounter := 0
- pityCounter := 0
- UpdateBonusLights()
- ; ✅ CONTADORES DE SISTEMAS DE AYUDA
- jackpotActivations += 1
- jackpotWins += 1
- jackpotPesos += jackpotValue
- }
- Critical false
- }
- HandleTripleWinUltra() {
- global lastWin, totalWins, detailedTotalWins, winStats, detailedWinStats, pityCounter
- global totalPesos, detailedTotalPesos, pesosStats, detailedPesosStats, symbolWin, symbolValues
- global totalMultiplierPesos, multiplierActivations, multiplierValue, multiplierProbability
- global detailedJokerRespinPesos, combinationStats, multiplierActivationsCount, multiplierWins, multiplierPesosExtra
- global jokerWins, jokerPesos
- global currentLosingStreak, safetyNetActive, safetyNetBoost
- global rescueSpinsWithoutWin
- lastWin := true
- currentLosingStreak := 0
- rescueSpinsWithoutWin := 0
- totalWins++
- detailedTotalWins++
- pityCounter := 0
- pesosGanados := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 2
- combinationStats[symbolWin] := combinationStats.Get(symbolWin, 0) + 1
- if (symbolWin = "three_jokers") {
- winStats["three_jokers"] := winStats.Has("three_jokers") ? winStats["three_jokers"] + 1 : 1
- detailedWinStats["three_jokers"] := detailedWinStats.Has("three_jokers") ? detailedWinStats["three_jokers"] + 1 : 1
- } else {
- winStats[symbolWin] := winStats.Has(symbolWin) ? winStats[symbolWin] + 1 : 1
- detailedWinStats[symbolWin] := detailedWinStats.Has(symbolWin) ? detailedWinStats[symbolWin] + 1 : 1
- if (Random(1, 100) <= (100 / multiplierProbability)) {
- multiplierActivations++
- multiplierActivationsCount++
- baseValue := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 0
- multipliedValue := Round(baseValue * multiplierValue)
- totalMultiplierPesos += (multipliedValue - baseValue)
- multiplierPesosExtra += (multipliedValue - baseValue)
- multiplierWins += 1
- pesosGanados := multipliedValue
- }
- }
- totalPesos += pesosGanados
- detailedTotalPesos += pesosGanados
- if (symbolWin = "three_jokers") {
- pesosStats["three_jokers"] := pesosStats.Has("three_jokers") ? pesosStats["three_jokers"] + pesosGanados : pesosGanados
- detailedPesosStats["three_jokers"] := detailedPesosStats.Has("three_jokers") ? detailedPesosStats["three_jokers"] + pesosGanados : pesosGanados
- } else {
- pesosStats[symbolWin] := pesosStats.Has(symbolWin) ? pesosStats[symbolWin] + pesosGanados : pesosGanados
- detailedPesosStats[symbolWin] := detailedPesosStats.Has(symbolWin) ? detailedPesosStats[symbolWin] + pesosGanados : pesosGanados
- }
- }
- HandleLossUltra() {
- global lastWin, pityCounter, jackpotCounter, totalPesos, detailedTotalPesos, detailedCompensations, detailedCompensationCount, testingMode, currentProfile, totalSpins, pityThreshold, pityActivations, pityWins, pityPesos
- global currentLosingStreak, longestLosingStreak
- global safetyNetActive, safetyNetThreshold
- global rescueSpinsWithoutWin
- lastWin := false
- currentLosingStreak++
- if (currentLosingStreak > longestLosingStreak) {
- longestLosingStreak := currentLosingStreak
- }
- pityCounter++
- jackpotCounter++
- rescueSpinsWithoutWin++ ; ← CONTAR GIROS SIN GANAR
- ; ✅ VERIFICAR SAFETY NET PARA RTP35
- if (currentProfile = "RTP35" && currentLosingStreak >= safetyNetThreshold && !safetyNetActive) {
- safetyNetActive := false
- ; En modo ultra, simplemente forzar una victoria
- symbolWin := "bell"
- HandleTripleWinUltra()
- safetyNetActive := false
- return
- }
- if (pityCounter >= pityThreshold) {
- pityCounter := 0
- compensation := 4 ; ← COMPENSACIÓN FIJA DE 4 PESOS
- if (compensation > 0) {
- detailedCompensations += compensation
- detailedCompensationCount++
- totalPesos += compensation
- detailedTotalPesos += compensation
- pityActivations += 1
- pityWins += 1
- pityPesos += compensation
- }
- }
- }
- ExportTestData(*) {
- global currentProfile, targetRTP, detailedTotalSpins, detailedTotalWins, detailedTotalPesos
- global symbolFrequency, combinationStats, symbols, symbolValues
- global detailedCompensations, detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global multiplierActivations, totalMultiplierPesos, detailedJackpotsWon, jackpotValue
- global longestLosingStreak, currentLosingStreak
- global pityActivations, pityWins, pityPesos, multiplierActivationsCount, multiplierWins, multiplierPesosExtra
- global jokerActivations, jokerWins, jokerPesos, jackpotActivations, jackpotWins, jackpotPesos
- global detailedPesosStats, detailedWinStats
- global rescueSpinsWithoutWin, rescueActivations, rescuePesos
- try {
- timestamp := FormatTime(, "yyyy-MM-dd_HH-mm-ss")
- filename := "RTP_Analysis_" . currentProfile . "_" . timestamp . ".csv"
- ; ✅ CALCULAR RTP CON SEGURIDAD
- currentRTP := 0
- if (detailedTotalSpins > 0) {
- currentRTP := (detailedTotalPesos / detailedTotalSpins) * 100
- }
- csvContent := ""
- csvContent .= "ANÁLISIS RTP - PERFIL " . currentProfile . "`n"
- csvContent .= "Timestamp,RTP_Teórico,RTP_Calculado,Total_Giros,Total_Victorias,Total_Pesos`n"
- csvContent .= timestamp . "," . targetRTP . "," . Round(currentRTP, 2) . "," . detailedTotalSpins . "," . detailedTotalWins . "," . detailedTotalPesos . "`n`n"
- ; ✅ SECCIÓN FRECUENCIA CORREGIDA - EVITA DIVISIÓN POR CERO
- csvContent .= "FRECUENCIA DE SÍMBOLOS`n"
- csvContent .= "Símbolo,Veces_Salió,Probabilidad_Real,Probabilidad_Teórica`n"
- totalSymbolAppearances := 0
- for symbol, count in symbolFrequency {
- totalSymbolAppearances += count
- }
- if (totalSymbolAppearances = 0) {
- ; Si no hay datos, mostrar valores en cero
- for symbol, count in symbolFrequency {
- theoreticalProbability := symbols.Has(symbol) ? (symbols[symbol] / 100) * 100 : 0
- csvContent .= symbol . "," . count . ",0%," . theoreticalProbability . "%`n"
- }
- } else {
- ; Calcular probabilidades normalmente
- for symbol, count in symbolFrequency {
- realProbability := (count / totalSymbolAppearances) * 100
- theoreticalProbability := symbols.Has(symbol) ? (symbols[symbol] / 100) * 100 : 0
- csvContent .= symbol . "," . count . "," . Round(realProbability, 2) . "%," . theoreticalProbability . "%`n"
- }
- }
- csvContent .= "`n"
- ; ✅ SECCIÓN COMBINACIONES GANADORAS CON SEGURIDAD
- csvContent .= "COMBINACIONES GANADORAS`n"
- csvContent .= "Combinación,Veces,Probabilidad,Pesos_Generados,Valor_Promedio`n"
- totalWins := detailedTotalWins
- if (totalWins = 0) {
- ; Si no hay victorias, mostrar combinaciones en cero
- for combination, count in combinationStats {
- pesosGenerados := detailedPesosStats.Has(combination) ? detailedPesosStats[combination] : 0
- csvContent .= combination . "," . count . ",0%," . pesosGenerados . ",0`n"
- }
- } else {
- ; Calcular probabilidades normalmente
- for combination, count in combinationStats {
- probability := (count / totalWins) * 100
- pesosGenerados := detailedPesosStats.Has(combination) ? detailedPesosStats[combination] : 0
- valorPromedio := (count > 0) ? (pesosGenerados / count) : 0
- csvContent .= combination . "," . count . "," . Round(probability, 2) . "%," . pesosGenerados . "," . Round(valorPromedio, 2) . "`n"
- }
- }
- csvContent .= "`n"
- ; ✅ SISTEMAS DE AYUDA CON VERIFICACIONES
- csvContent .= "SISTEMAS DE AYUDA`n"
- csvContent .= "Sistema,Activaciones,Victorias,Tasa_Éxito,Pesos_Generados`n"
- ; Pity Counter
- pitySuccessRate := (pityActivations > 0) ? ((pityWins / pityActivations) * 100) : 0
- csvContent .= "Pity_Counter," . pityActivations . "," . pityWins . "," . Round(pitySuccessRate, 1) . "%," . pityPesos . "`n"
- ; Multiplicador
- multiplierSuccessRate := (multiplierActivationsCount > 0) ? ((multiplierWins / multiplierActivationsCount) * 100) : 0
- csvContent .= "Multiplicador," . multiplierActivationsCount . "," . multiplierWins . "," . Round(multiplierSuccessRate, 1) . "%," . multiplierPesosExtra . "`n"
- ; Joker Respin
- jokerSuccessRate := (jokerActivations > 0) ? ((jokerWins / jokerActivations) * 100) : 0
- csvContent .= "Joker_Respin," . jokerActivations . "," . jokerWins . "," . Round(jokerSuccessRate, 1) . "%," . jokerPesos . "`n"
- ; Jackpot
- jackpotSuccessRate := (jackpotActivations > 0) ? ((jackpotWins / jackpotActivations) * 100) : 0
- csvContent .= "Jackpot," . jackpotActivations . "," . jackpotWins . "," . Round(jokerSuccessRate, 1) . "%," . jackpotPesos . "`n"
- ; Sistema de Rescate
- rescueSuccessRate := (rescueActivations > 0) ? 100 : 0 ; Siempre tiene éxito cuando se activa
- csvContent .= "Rescate_Volatilidad," . rescueActivations . "," . rescueActivations . "," . rescueSuccessRate . "%," . rescuePesos . "`n"
- csvContent .= "`n"
- ; ✅ VOLATILIDAD
- csvContent .= "VOLATILIDAD`n"
- csvContent .= "Métrica,Valor`n"
- csvContent .= "Racha_Pérdida_Más_Larga," . longestLosingStreak . "`n"
- csvContent .= "Racha_Pérdida_Actual," . currentLosingStreak . "`n"
- csvContent .= "Giros_Sin_Victoria_Actual," . rescueSpinsWithoutWin . "`n"
- avgSpinsBetweenWins := (detailedTotalWins > 0) ? (detailedTotalSpins / detailedTotalWins) : 0
- csvContent .= "Giros_Promedio_Entre_Victorias," . Round(avgSpinsBetweenWins, 1) . "`n"
- winRate := (detailedTotalSpins > 0) ? ((detailedTotalWins / detailedTotalSpins) * 100) : 0
- csvContent .= "Tasa_de_Victoria," . Round(winRate, 2) . "%`n"
- csvContent .= "`n"
- ; ✅ DESGLOSE RTP CON VERIFICACIONES
- csvContent .= "DESGLOSE RTP`n"
- csvContent .= "Componente,Contribución_RTP`n"
- ; Calcular con seguridad contra división por cero
- if (detailedTotalSpins > 0) {
- baseRTP := ((detailedTotalPesos - detailedCompensations - detailedJokerRespinPesos - totalMultiplierPesos - (detailedJackpotsWon * jackpotValue) - rescuePesos) / detailedTotalSpins) * 100
- pityRTP := (detailedCompensations / detailedTotalSpins) * 100
- jokerRTP := (detailedJokerRespinPesos / detailedTotalSpins) * 100
- multiplierRTP := (totalMultiplierPesos / detailedTotalSpins) * 100
- jackpotRTP := ((detailedJackpotsWon * jackpotValue) / detailedTotalSpins) * 100
- rescueRTP := (rescuePesos / detailedTotalSpins) * 100
- } else {
- baseRTP := 0
- pityRTP := 0
- jokerRTP := 0
- multiplierRTP := 0
- jackpotRTP := 0
- rescueRTP := 0
- }
- csvContent .= "Símbolos_Base," . Round(baseRTP, 2) . "%`n"
- csvContent .= "Sistema_Pity," . Round(pityRTP, 2) . "%`n"
- csvContent .= "Joker_Respins," . Round(jokerRTP, 2) . "%`n"
- csvContent .= "Multiplicadores," . Round(multiplierRTP, 2) . "%`n"
- csvContent .= "Jackpot," . Round(jackpotRTP, 2) . "%`n"
- csvContent .= "Rescate_Volatilidad," . Round(rescueRTP, 2) . "%`n"
- csvContent .= "TOTAL," . Round(currentRTP, 2) . "%`n"
- FileAppend(csvContent, filename)
- MyGui.Opt("+OwnDialogs")
- MsgBox("📈 DATOS EXPORTADOS`n`nArchivo: " . filename . "`n`nContiene análisis completo para afinación RTP", "Exportación Completada", "64")
- } catch Error as e {
- MyGui.Opt("+OwnDialogs")
- MsgBox("❌ ERROR al exportar datos:`n" . e.Message . "`nLínea: " . e.Line, "Error de Exportación", "16")
- }
- }
- UpdateStatsDisplay() {
- global totalSpins, totalWins, totalPesos, jackpotCounter, pityCounter, pityThreshold, multiplierActivations, rescueActivations
- TotalSpinsText.Value := totalSpins
- TotalPesosText.Value := totalPesos
- JackpotCounterText.Value := jackpotCounter . "/5000"
- PityCounterText.Value := pityCounter . "/" . pityThreshold
- RescueCounterText.Value := rescueActivations ; ← NUEVO: Mostrar rescates
- UpdateWinPercentages()
- }
- StartSpin(*) {
- global spinning, totalSpins, detailedTotalSpins, SpinBtn, Spin1000Btn, Spin10000Btn, imgPath, spinInterval, spinDuration
- global currentProfile
- if spinning
- return
- spinning := true
- SpinBtn.Enabled := false
- SpinBtn.Text := "Girando..."
- Spin1000Btn.Enabled := false
- Spin10000Btn.Enabled := false
- totalSpins++
- detailedTotalSpins++
- UpdateStatsDisplay()
- SaveStats()
- Loop 3
- MyGui["Slot" . A_Index].Value := imgPath . "question.png"
- SetTimer(SpinSlots, spinInterval)
- SetTimer(StopSpin, -spinDuration)
- }
- SpinSlots() {
- global symbolList, imgPath, MyGui, img1, img2, img3
- randIndex := Random(1, symbolList.Length)
- img1 := symbolList[randIndex]
- randIndex := Random(1, symbolList.Length)
- img2 := symbolList[randIndex]
- randIndex := Random(1, symbolList.Length)
- img3 := symbolList[randIndex]
- Loop 3 {
- currentImg := (A_Index = 1) ? img1 : (A_Index = 2) ? img2 : img3
- imgFile := imgPath . currentImg . ".png"
- fallback := imgPath . "question.png"
- if FileExist(imgFile)
- MyGui["Slot" . A_Index].Value := imgFile
- else
- MyGui["Slot" . A_Index].Value := fallback
- }
- }
- StopSpin() {
- global spinning, MyGui, imgPath, img1, img2, img3, symbolWin, jackpotCounter, pityCounter, pityThreshold
- global SpinBtn, Spin1000Btn, Spin10000Btn, lastWin
- global currentLosingStreak, longestLosingStreak
- global currentProfile, rescueSpinsWithoutWin
- SetTimer(SpinSlots, 0)
- Critical true
- try {
- MyGui["Slot1"].Value := imgPath . img1 . ".png"
- MyGui["Slot2"].Value := imgPath . img2 . ".png"
- MyGui["Slot3"].Value := imgPath . img3 . ".png"
- }
- Sleep 30
- symbolWin := CheckWinCombination(img1, img2, img3)
- ; ===== VERIFICAR RESCATE DE VOLATILIDAD MEJORADO =====
- if (!symbolWin || symbolWin = false) {
- rescueSpinsWithoutWin++
- if (CheckVolatilityRescue()) {
- ; El rescate manejó la victoria completamente
- spinning := false
- SpinBtn.Enabled := true
- SpinBtn.Text := "1 Moneda"
- SpinBtn.Opt("+Default")
- if (!autoSpin) {
- Spin1000Btn.Enabled := true
- Spin10000Btn.Enabled := true
- }
- ; Mostrar mensaje discreto en modo normal
- if (!testingMode && !autoSpin) {
- SetTimer(ShowRescueMessage, -500)
- }
- SaveStats()
- SaveDetailedStats()
- Critical false
- return
- }
- } else {
- rescueSpinsWithoutWin := 0
- }
- if (symbolWin is String && symbolWin != "") {
- HandleTripleWin()
- }
- if (jackpotCounter >= 5000) {
- HandleJackpotWin()
- }
- if (!symbolWin || symbolWin = false) {
- if (img1 = "joker" || img2 = "joker" || img3 = "joker") {
- HandleJokerRespin()
- } else {
- HandleLoss()
- }
- }
- if (!lastWin) {
- currentLosingStreak++
- } else {
- if (currentLosingStreak > longestLosingStreak) {
- longestLosingStreak := currentLosingStreak
- }
- currentLosingStreak := 0
- }
- PityCounterText.Value := pityCounter . "/" . pityThreshold
- JackpotCounterText.Value := jackpotCounter . "/5000"
- UpdateBonusLights()
- UpdateWinPercentages()
- UpdateJokerStatus()
- spinning := false
- SpinBtn.Enabled := true
- SpinBtn.Text := "1 Moneda"
- SpinBtn.Opt("+Default")
- if (!autoSpin) {
- Spin1000Btn.Enabled := true
- Spin10000Btn.Enabled := true
- }
- SaveStats()
- SaveDetailedStats()
- Critical false
- }
- ShowRescueMessage() {
- MyGui.Opt("+OwnDialogs")
- MsgBox("¡Combinación ganadora!`n`nHas obtenido una victoria.", "¡Ganaste!", "64")
- }
- CheckWinCombination(reel1, reel2, reel3) {
- symbolsInReels := [reel1, reel2, reel3]
- symbolCounts := Map()
- jokerCount := 0
- for symbol in symbolsInReels {
- if (symbol = "joker") {
- jokerCount++
- } else {
- symbolCounts[symbol] := symbolCounts.Has(symbol) ? symbolCounts[symbol] + 1 : 1
- }
- }
- for symbol, count in symbolCounts {
- if (count = 3) {
- return symbol
- }
- }
- for symbol, count in symbolCounts {
- if (count = 2 && jokerCount >= 1) {
- return symbol
- }
- }
- for symbol, count in symbolCounts {
- if (count = 1 && jokerCount >= 2) {
- return symbol
- }
- }
- if (jokerCount = 3) {
- return "three_jokers"
- }
- return false
- }
- ; ===== NUEVAS FUNCIONES RTP35 MEJORADO =====
- CheckSafetyNet() {
- global currentLosingStreak, safetyNetThreshold, safetyNetActive, safetyNetBoost
- global symbols, currentProfile, totalSpins
- ; Solo activar para RTP35/RTP40/RTP45/RTP50 y si no está ya activo
- if ((currentProfile != "RTP35" && currentProfile != "RTP40" && currentProfile != "RTP45" && currentProfile != "RTP50") || safetyNetActive || currentLosingStreak < safetyNetThreshold) {
- return
- }
- safetyNetActive := true
- safetyNetBoost := true
- ; ✅ DISTRIBUCIÓN DE EMERGENCIA TEMPORAL POR PERFIL
- if (currentProfile = "RTP35") {
- emergencySymbols := Map(
- "cherry", 25, ; -3 temporalmente
- "bell", 22, ; -2
- "lemon", 14, ; -2
- "star", 18, ; +3 (aumentar significativamente)
- "diamond", 12, ; +3 (más oportunidades alto valor)
- "seven", 8, ; +1 (más símbolos premium)
- "joker", 1 ; = (mantener)
- )
- } else if (currentProfile = "RTP40") {
- emergencySymbols := Map(
- "cherry", 28, ; -3 temporalmente
- "bell", 23, ; -3
- "lemon", 15, ; -2
- "star", 15, ; +3 (aumentar significativamente)
- "diamond", 10, ; +2 (más oportunidades alto valor)
- "seven", 6, ; +1 (más símbolos premium)
- "joker", 1 ; = (mantener)
- )
- } else if (currentProfile = "RTP45") {
- emergencySymbols := Map(
- "cherry", 38, ; -2 temporalmente
- "bell", 23, ; -2
- "lemon", 14, ; -1
- "star", 10, ; +2 (aumentar significativamente)
- "diamond", 6, ; +1 (más oportunidades alto valor)
- "seven", 5, ; +1 (más símbolos premium)
- "joker", 2 ; = (mantener)
- )
- } else if (currentProfile = "RTP50") {
- emergencySymbols := Map(
- "cherry", 45, ; -3 temporalmente
- "bell", 26, ; -2
- "lemon", 16, ; -2
- "star", 12, ; +2 (aumentar significativamente)
- "diamond", 7, ; +1 (más oportunidades alto valor)
- "seven", 6, ; +1 (más símbolos premium)
- "joker", 2 ; = (mantener)
- )
- }
- ; Aplicar distribución de emergencia
- ApplyEmergencyDistribution(emergencySymbols)
- ; Mostrar notificación
- MyGui.Opt("+OwnDialogs")
- MsgBox("🛡️ SISTEMA DE SEGURIDAD " . currentProfile . " ACTIVADO`n`nDespués de " . currentLosingStreak . " giros sin ganar`nProbabilidades premium aumentadas temporalmente`n¡La suerte está por cambiar!", "Red de Seguridad", "64")
- ; Restaurar después de 10 giros o primera victoria
- SetTimer(RestoreOriginalDistribution, 10000)
- }
- ApplyEmergencyDistribution(emergencySymbols) {
- global symbols
- symbols := emergencySymbols.Clone()
- UpdateSymbolList()
- }
- RestoreOriginalDistribution() {
- global safetyNetActive, safetyNetBoost, currentProfile
- if (safetyNetActive && currentProfile = "RTP35") {
- LoadConfig() ; Recargar configuración original
- safetyNetActive := false
- safetyNetBoost := false
- ; Notificar restauración silenciosa
- SetTimer(ClearRestoreMessage, 3000)
- }
- }
- ClearRestoreMessage() {
- }
- GetWeightedPremiumSymbol() {
- premiumSymbols := ["seven", "diamond", "star", "bell", "lemon"]
- weights := [15, 20, 25, 25, 15] ; Probabilidades ponderadas
- totalWeight := 0
- for weight in weights {
- totalWeight += weight
- }
- randomValue := Random(1, totalWeight)
- cumulativeWeight := 0
- Loop premiumSymbols.Length {
- cumulativeWeight += weights[A_Index]
- if (randomValue <= cumulativeWeight) {
- return premiumSymbols[A_Index]
- }
- }
- return "star" ; Fallback
- }
- EnhancedJokerRespin(spin1, spin2, spin3) {
- global img1, img2, img3, symbolList, MyGui, imgPath, jokerEffectivenessRTP35, jokerEffectivenessRTP40, jokerEffectivenessRTP45, jokerEffectivenessRTP50, currentProfile
- ; ✅ OBTENER EFECTIVIDAD CORRECTA SEGÚN PERFIL
- jokerEffectiveness := 35 ; Default
- if (currentProfile = "RTP35") {
- jokerEffectiveness := jokerEffectivenessRTP35
- } else if (currentProfile = "RTP40") {
- jokerEffectiveness := jokerEffectivenessRTP40
- } else if (currentProfile = "RTP45") {
- jokerEffectiveness := jokerEffectivenessRTP45
- } else if (currentProfile = "RTP50") {
- jokerEffectiveness := jokerEffectivenessRTP50
- }
- ; ✅ ALGORITMO MEJORADO - MÁS PROBABILIDAD DE ÉXITO
- if (spin1 && Random(1, 100) <= jokerEffectiveness) {
- ; Forzar símbolo de mayor valor
- img1 := GetWeightedPremiumSymbol()
- MyGui["Slot1"].Value := imgPath . img1 . ".png"
- } else if (spin1) {
- randIndex := Random(1, symbolList.Length)
- img1 := symbolList[randIndex]
- MyGui["Slot1"].Value := imgPath . img1 . ".png"
- }
- Sleep 120
- if (spin2 && Random(1, 100) <= jokerEffectiveness) {
- img2 := GetWeightedPremiumSymbol()
- MyGui["Slot2"].Value := imgPath . img2 . ".png"
- } else if (spin2) {
- randIndex := Random(1, symbolList.Length)
- img2 := symbolList[randIndex]
- MyGui["Slot2"].Value := imgPath . img2 . ".png"
- }
- Sleep 120
- if (spin3 && Random(1, 100) <= jokerEffectiveness) {
- img3 := GetWeightedPremiumSymbol()
- MyGui["Slot3"].Value := imgPath . img3 . ".png"
- } else if (spin3) {
- randIndex := Random(1, symbolList.Length)
- img3 := symbolList[randIndex]
- MyGui["Slot3"].Value := imgPath . img3 . ".png"
- }
- Sleep 120
- }
- StandardJokerRespin(spin1, spin2, spin3) {
- global img1, img2, img3, symbolList, MyGui, imgPath
- if (spin1) {
- randIndex := Random(1, symbolList.Length)
- img1 := symbolList[randIndex]
- MyGui["Slot1"].Value := imgPath . img1 . ".png"
- }
- Sleep 100
- if (spin2) {
- randIndex := Random(1, symbolList.Length)
- img2 := symbolList[randIndex]
- MyGui["Slot2"].Value := imgPath . img2 . ".png"
- }
- Sleep 100
- if (spin3) {
- randIndex := Random(1, symbolList.Length)
- img3 := symbolList[randIndex]
- MyGui["Slot3"].Value := imgPath . img3 . ".png"
- }
- Sleep 100
- }
- ShowEnhancedJokerWin(symbolWin) {
- global symbolValues
- pesosGanados := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 0
- MyGui.Opt("+OwnDialogs")
- MsgBox("¡JOKER MEJORADO!`n`nCombinación: " . symbolWin . "`nPremio: " . pesosGanados . " pesos`n`n¡El comodín te sonríe!", "Joker Potenciado", "64")
- }
- ; ===== FUNCIONES EXISTENTES MODIFICADAS =====
- HandleJokerRespin() {
- global img1, img2, img3, spinning, imgPath, symbolList, testingMode, totalSpins, totalPesos, targetRTP, symbolWin
- global detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global SpinBtn, Spin1000Btn, Spin10000Btn, MyGui, detailedTotalWins, detailedTotalPesos, detailedWinStats, detailedPesosStats
- global jokerActivations, jokerWins, jokerPesos, currentProfile
- currentRTP := 0
- if (totalSpins > 0) {
- currentRTP := (totalPesos / totalSpins) * 100
- }
- ; ✅ UMBRAL MÁS FLEXIBLE PARA PERFILES BAJOS
- activationThreshold := (currentProfile = "RTP35") ? targetRTP + 3 : targetRTP
- if (currentRTP < activationThreshold) {
- jokerActivations += 1
- detailedJokerRespines++
- spinning := true
- SpinBtn.Enabled := false
- SpinBtn.Text := "Re-Girando..."
- Spin1000Btn.Enabled := false
- Spin10000Btn.Enabled := false
- spin1 := (img1 != "joker")
- spin2 := (img2 != "joker")
- spin3 := (img3 != "joker")
- ; ✅ ANIMACIÓN MEJORADA PARA TODOS LOS PERFILES
- Loop 8 {
- if (spin1) {
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot1"].Value := imgPath . symbolList[randIndex] . ".png"
- }
- if (spin2) {
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot2"].Value := imgPath . symbolList[randIndex] . ".png"
- }
- if (spin3) {
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot3"].Value := imgPath . symbolList[randIndex] . ".png"
- }
- Sleep 40
- }
- ; ✅ RESULTADOS MEJORADOS PARA TODOS LOS PERFILES
- EnhancedJokerRespin(spin1, spin2, spin3)
- symbolWin := CheckWinCombination(img1, img2, img3)
- if (symbolWin is String && symbolWin != "") {
- HandleTripleWin()
- if (!testingMode && (currentProfile = "RTP35" || currentProfile = "RTP50")) {
- ShowEnhancedJokerWin(symbolWin)
- }
- pesosGanados := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 2
- detailedJokerRespinWins++
- detailedJokerRespinPesos += pesosGanados
- jokerWins += 1
- jokerPesos += pesosGanados
- } else {
- HandleJokerRespinLoss()
- }
- spinning := false
- SpinBtn.Enabled := true
- SpinBtn.Text := "1 Moneda"
- SpinBtn.Opt("+Default")
- Spin1000Btn.Enabled := true
- Spin10000Btn.Enabled := true
- } else {
- HandleLoss()
- }
- }
- HandleJokerRespinLoss() {
- global lastWin, testingMode
- lastWin := false
- }
- HandleJackpotWin() {
- global lastWin, totalWins, detailedTotalWins, pityCounter, totalPesos, detailedTotalPesos, detailedJackpotsWon, jackpotValue, jackpotCounter, testingMode, imgPath, symbolList, MyGui
- global jackpotActivations, jackpotWins, jackpotPesos
- if (!testingMode) {
- }
- Loop 5 {
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot1"].Value := imgPath . symbolList[randIndex] . ".png"
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot2"].Value := imgPath . symbolList[randIndex] . ".png"
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot3"].Value := imgPath . symbolList[randIndex] . ".png"
- Sleep 30
- }
- Loop 3 {
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot1"].Value := imgPath . symbolList[randIndex] . ".png"
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot2"].Value := imgPath . symbolList[randIndex] . ".png"
- randIndex := Random(1, symbolList.Length)
- MyGui["Slot3"].Value := imgPath . symbolList[randIndex] . ".png"
- Sleep 80
- }
- MyGui["Slot1"].Value := imgPath . "jackpot.png"
- if (!testingMode) {
- }
- Sleep 150
- MyGui["Slot2"].Value := imgPath . "jackpot.png"
- if (!testingMode) {
- }
- Sleep 150
- MyGui["Slot3"].Value := imgPath . "jackpot.png"
- if (!testingMode) {
- }
- Sleep 250
- Loop 2 {
- MyGui["Slot1"].Value := imgPath . "jackpot_glow.png"
- MyGui["Slot2"].Value := imgPath . "jackpot_glow.png"
- MyGui["Slot3"].Value := imgPath . "jackpot_glow.png"
- Sleep 100
- MyGui["Slot1"].Value := imgPath . "jackpot.png"
- MyGui["Slot2"].Value := imgPath . "jackpot.png"
- MyGui["Slot3"].Value := imgPath . "jackpot.png"
- Sleep 100
- }
- lastWin := true
- totalWins++
- detailedTotalWins++
- pityCounter := 0
- totalPesos += jackpotValue
- detailedTotalPesos += jackpotValue
- detailedJackpotsWon++
- jackpotActivations += 1
- jackpotWins += 1
- jackpotPesos += jackpotValue
- if (!testingMode) {
- }
- jackpotCounter := 0
- Loop 5 {
- MyGui["BonusSlot" . A_Index].Value := imgPath . "bonus_empty.png"
- }
- RandomizeBonusOrder()
- RandomizeBonusThresholds()
- UpdateStatsDisplay()
- UpdateJokerStatus()
- }
- HandleTripleWin() {
- global lastWin, totalWins, detailedTotalWins, winStats, detailedWinStats, pityCounter, totalPesos, detailedTotalPesos, pesosStats, detailedPesosStats, totalMultiplierPesos, multiplierActivations, symbolWin, testingMode, multiplierValue, imgPath, symbolValues, MyGui
- global safetyNetActive, safetyNetBoost, currentProfile
- global rescueSpinsWithoutWin
- if (!symbolWin is String || symbolWin = "") {
- return
- }
- lastWin := true
- totalWins++
- detailedTotalWins++
- pityCounter := 0
- rescueSpinsWithoutWin := 0 ; ← RESETEAR CONTADOR DE RESCATE
- ; ✅ BONUS EXTRA POR VICTORIA DURANTE SAFETY NET
- ;bonusPesos := 0
- ;if (safetyNetBoost && currentProfile = "RTP35") {
- ; bonusPesos := 10 ; Bonus adicional por romper racha mala
- ; totalPesos += bonusPesos
- ; detailedTotalPesos += bonusPesos
- ;}
- ; ✅ DESACTIVAR SAFETY NET SI ESTÁ ACTIVO
- if (safetyNetActive) {
- RestoreOriginalDistribution()
- ; if (!testingMode && bonusPesos > 0) {
- ; MsgBox("¡VICTORIA CON BONUS DE SEGURIDAD!`n`nBonus extra: " . bonusPesos . " pesos`nRacha mala rota - Sistema normal restaurado", "¡Éxito!", "64")
- ; }
- }
- if (!symbolValues.Has(symbolWin)) {
- pesosGanados := 2
- } else {
- pesosGanados := symbolValues[symbolWin]
- }
- if (symbolWin = "three_jokers") {
- if (!testingMode) {
- }
- winStats["three_jokers"] := winStats.Has("three_jokers") ? winStats["three_jokers"] + 1 : 1
- detailedWinStats["three_jokers"] := detailedWinStats.Has("three_jokers") ? detailedWinStats["three_jokers"] + 1 : 1
- } else {
- if (winStats.Has(symbolWin)) {
- winStats[symbolWin]++
- detailedWinStats[symbolWin]++
- } else {
- winStats[symbolWin] := 1
- detailedWinStats[symbolWin] := 1
- }
- extraMultiplier := CheckMultiplierActivation()
- if (extraMultiplier > 0) {
- totalMultiplied := pesosGanados + extraMultiplier
- if (!testingMode) {
- }
- pesosGanados := totalMultiplied
- totalMultiplierPesos += extraMultiplier
- } else {
- if (!testingMode && symbolWin != "three_jokers") {
- }
- }
- }
- totalPesos += pesosGanados
- detailedTotalPesos += pesosGanados
- if (symbolWin = "three_jokers") {
- pesosStats["three_jokers"] := pesosStats.Has("three_jokers") ? pesosStats["three_jokers"] + pesosGanados : pesosGanados
- detailedPesosStats["three_jokers"] := detailedPesosStats.Has("three_jokers") ? detailedPesosStats["three_jokers"] + pesosGanados : pesosGanados
- } else if (pesosStats.Has(symbolWin)) {
- pesosStats[symbolWin] += pesosGanados
- detailedPesosStats[symbolWin] += pesosGanados
- } else {
- pesosStats[symbolWin] := pesosGanados
- detailedPesosStats[symbolWin] := pesosGanados
- }
- UpdateStatsDisplay()
- UpdateJokerStatus()
- }
- CheckMultiplierActivation() {
- global multiplierProbability, multiplierValue, testingMode, multiplierActivations, symbolWin, symbolValues
- if (symbolWin = "three_jokers") {
- return 0
- }
- if (Random(1, 100) <= (100 / multiplierProbability)) {
- multiplierActivations++
- baseValue := symbolValues.Has(symbolWin) ? symbolValues[symbolWin] : 0
- multipliedValue := Round(baseValue * multiplierValue)
- return multipliedValue - baseValue
- }
- return 0
- }
- HandleLoss() {
- global lastWin, pityCounter, jackpotCounter, totalPesos, detailedTotalPesos, detailedCompensations, detailedCompensationCount, testingMode, currentProfile, totalSpins, pityThreshold, MyGui, imgPath
- global currentLosingStreak, longestLosingStreak
- global safetyNetActive, safetyNetThreshold
- global rescueSpinsWithoutWin
- lastWin := false
- pityCounter++
- jackpotCounter++
- rescueSpinsWithoutWin++ ; ← CONTAR GIROS SIN GANAR
- UpdateBonusLights()
- ; ✅ VERIFICAR SAFETY NET PARA TODOS LOS PERFILES MEJORADOS
- if ((currentProfile = "RTP35" || currentProfile = "RTP40" || currentProfile = "RTP45" || currentProfile = "RTP50") && currentLosingStreak >= safetyNetThreshold && !safetyNetActive) {
- CheckSafetyNet()
- }
- if (pityCounter >= pityThreshold) {
- pityCounter := 0
- compensation := 4 ; ← COMPENSACIÓN FIJA DE 4 PESOS
- compensationMessage := "¡Compensación!`n" . pityThreshold . " giros sin ganar"
- showCompensationMessage := true
- if (compensation > 0) {
- detailedCompensations += compensation
- detailedCompensationCount++
- totalPesos += compensation
- detailedTotalPesos += compensation
- if (!testingMode && showCompensationMessage) {
- ; Mensaje opcional de compensación
- }
- }
- }
- }
- AutoSpinLoop() {
- global autoSpin, autoSpinCount, maxAutoSpins, spinning, SpinBtn, Spin1000Btn, Spin10000Btn
- if spinning
- return
- if (autoSpinCount >= maxAutoSpins) {
- SetTimer(AutoSpinLoop, 0)
- autoSpin := false
- testingMode := false
- SpinBtn.Enabled := true
- Spin1000Btn.Enabled := true
- Spin10000Btn.Enabled := true
- return
- }
- StartSpin()
- autoSpinCount++
- }
- ResetStats(reason, *) {
- global totalSpins, totalWins, totalPesos, winStats, pesosStats, jackpotCounter, pityCounter
- global detailedTotalSpins, detailedTotalWins, detailedTotalPesos, detailedJackpotsWon, detailedCompensations, detailedCompensationCount, detailedWinStats, detailedPesosStats
- global detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global multiplierActivations, totalMultiplierPesos
- global currentLosingStreak, longestLosingStreak
- global symbolFrequency, combinationStats, volatilityStats, rtpBreakdown
- global pityActivations, pityWins, pityPesos, multiplierActivationsCount, multiplierWins, multiplierPesosExtra
- global jokerActivations, jokerWins, jokerPesos, jackpotActivations, jackpotWins, jackpotPesos
- global safetyNetActive, safetyNetBoost
- global rescueSpinsWithoutWin, lastRescueSpin, rescueActivations, rescuePesos, rescueActive
- totalSpins := 0
- totalWins := 0
- totalPesos := 0
- jackpotCounter := 0
- pityCounter := 0
- detailedTotalSpins := 0
- detailedTotalWins := 0
- detailedTotalPesos := 0
- detailedJackpotsWon := 0
- detailedCompensations := 0
- detailedCompensationCount := 0
- detailedJokerRespines := 0
- detailedJokerRespinWins := 0
- detailedJokerRespinPesos := 0
- multiplierActivations := 0
- totalMultiplierPesos := 0
- currentLosingStreak := 0
- longestLosingStreak := 0
- pityActivations := 0
- pityWins := 0
- pityPesos := 0
- multiplierActivationsCount := 0
- multiplierWins := 0
- multiplierPesosExtra := 0
- jokerActivations := 0
- jokerWins := 0
- jokerPesos := 0
- jackpotActivations := 0
- jackpotWins := 0
- jackpotPesos := 0
- safetyNetActive := false
- safetyNetBoost := false
- rescueSpinsWithoutWin := 0
- lastRescueSpin := 0
- rescueActivations := 0
- rescuePesos := 0
- rescueActive := false
- InitializeAdvancedStats()
- for symbol in symbols {
- winStats[symbol] := 0
- pesosStats[symbol] := 0
- detailedWinStats[symbol] := 0
- detailedPesosStats[symbol] := 0
- }
- winStats["three_jokers"] := 0
- pesosStats["three_jokers"] := 0
- detailedWinStats["three_jokers"] := 0
- detailedPesosStats["three_jokers"] := 0
- UpdateStatsDisplay()
- UpdateJokerStatus()
- SaveStats()
- SaveDetailedStats()
- if (!reason = 0) {
- MyGui.Opt("+OwnDialogs")
- MsgBox("Estadísticas reseteadas", "Reset", "64")
- }
- }
- ShowStats(*) {
- MyGui.Opt("+OwnDialogs")
- MsgBox("Estadísticas de la sesión actual:`nTotal giros: " . totalSpins . "`nVictorias: " . totalWins . "`nPesos ganados: " . totalPesos, "Estadísticas de sesión", "64")
- }
- ShowDetailedStats(*) {
- global DetailedStatsGui, ReportEdit, detailedTotalSpins, detailedTotalWins, detailedTotalPesos, detailedJackpotsWon, detailedCompensations, detailedCompensationCount, detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global longestLosingStreak, symbolRTPContributions, jokerRTPContribution
- global rescueSpinsWithoutWin, rescueActivations, rescuePesos
- LoadDetailedStats()
- if (IsObject(DetailedStatsGui)) {
- DetailedStatsGui.Destroy()
- }
- DetailedStatsGui := Gui("+Resize", "Reporte Detallado")
- DetailedStatsGui.SetFont("s10", "Courier New")
- ReportEdit := DetailedStatsGui.Add("Edit", "w600 h500 ReadOnly vReportEdit")
- ReportEdit.Value := GenerateDetailedReport()
- DetailedStatsGui.Show("Center")
- }
- GenerateDetailedReport() {
- global detailedTotalSpins, detailedTotalWins, detailedTotalPesos, detailedJackpotsWon, detailedCompensations, detailedCompensationCount, detailedWinStats, detailedPesosStats, symbols
- global detailedJokerRespines, detailedJokerRespinWins, detailedJokerRespinPesos
- global multiplierActivations, totalMultiplierPesos
- global longestLosingStreak, symbolRTPContributions, jokerRTPContribution
- global rescueSpinsWithoutWin, rescueActivations, rescuePesos
- report := ""
- report .= "============== REPORTE DETALLADO DE SIMULACIÓN ==============`n`n"
- report .= "--- GENERAL ---`n"
- report .= "Giros Totales: " . detailedTotalSpins . "`n"
- report .= "Victorias Totales: " . detailedTotalWins . "`n"
- report .= "Pesos Ganados Totales: " . detailedTotalPesos . "`n"
- report .= "Multiplicadores Activados: " . multiplierActivations . "`n"
- report .= "Pesos por Multiplicadores: " . totalMultiplierPesos . "`n"
- report .= "Rescates de Volatilidad: " . rescueActivations . "`n"
- report .= "Pesos por Rescates: " . rescuePesos . "`n"
- if (detailedTotalSpins > 0) {
- report .= "RTP Calculado: " . Round((detailedTotalPesos / detailedTotalSpins) * 100, 2) . "%`n"
- } else {
- report .= "RTP Calculado: N/A`n"
- }
- report .= "`n"
- report .= "--- VOLATILIDAD ---`n"
- report .= "Racha de giros perdidos más larga: " . longestLosingStreak . "`n"
- report .= "Giros sin victoria actual: " . rescueSpinsWithoutWin . "`n"
- report .= "Victorias por compensación: " . detailedCompensationCount . " (" . detailedCompensations . " pesos)`n"
- report .= "`n"
- report .= "--- JACKPOT ---`n"
- report .= "Jackpots Ganados: " . detailedJackpotsWon . "`n"
- report .= "`n"
- report .= "--- JOKER ---`n"
- report .= "Respines de Joker: " . detailedJokerRespines . "`n"
- report .= "Victorias por Respin: " . detailedJokerRespinWins . "`n"
- report .= "Pesos ganados por Respin: " . detailedJokerRespinPesos . "`n"
- report .= "Contribución RTP del Joker: " . jokerRTPContribution . "%`n"
- report .= "`n"
- report .= "--- SIMBOLOS (VICTORIAS & RTP) ---`n"
- report .= "`t" . "Simbolo" . "`t" . "Victorias" . "`t" . "Pesos" . "`t" . "RTP Cont.`n"
- report .= "--------------------------------------------------`n"
- for symbol, count in detailedWinStats {
- pesos := detailedPesosStats[symbol]
- rtp := symbolRTPContributions.Get(symbol, 0.00)
- report .= "`t" . symbol . "`t`t" . count . "`t" . pesos . "`t" . rtp . "%`n"
- }
- return report
- }
- GuiClose(*) {
- SaveStats()
- SaveDetailedStats()
- ExitApp
- }
- PlaySound(file) {
- global soundPath
- if FileExist(soundPath . file) {
- SoundPlay soundPath . file
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment