📜 Guía Completa de BlitzScript

El lenguaje de scripting para crear comandos personalizados en TeleChars AI

Desarrollado por Marcos F R Games · Actualizado: Junio 2026

🚀 Introducción a BlitzScript

BlitzScript es un lenguaje de scripting sencillo, similar a BASIC, que te permite crear comandos y comportamientos personalizados para tus Telecharbots sin necesidad de saber programación avanzada. Se ejecuta en el servidor con un límite de 125 segundos por ejecución.

💡 Características principales:
  • Sintaxis simple estilo BASIC (fácil de leer y escribir)
  • Variables no tipadas (se adaptan automáticamente)
  • Case-insensitive (no distingue mayúsculas de minúsculas)
  • Soporta funciones de usuario, arrays, bucles y condicionales
  • Integración directa con Telegram (mensajes, botones, callbacks)
  • Almacenamiento persistente por chat/usuario
  • Generación de texto e imágenes con IA

¿Dónde se escribe?

El código se coloca en el campo "Inicio" de la pestaña "BlitzScript" de tu telecharbot. Se ejecuta antes de que el bot responda normalmente, permitiéndote interceptar comandos, modificar el contexto o incluso detener la respuesta.

Ciclo de vida

1️⃣ Entrada del usuario

Llega un mensaje al bot en Telegram/Web

2️⃣ Ejecución del script

Se ejecuta tu BlitzScript con el contexto del mensaje

3️⃣ Resultado

El script puede enviar mensajes, modificar variables o detenerse

4️⃣ Respuesta del bot

Si no se detuvo, el bot responde normalmente

✍️ Sintaxis Básica

Variables

Las variables se declaran implícitamente al asignarles un valor. No necesitas declarar su tipo.

nombre = "Adán"
edad = 25
esAdmin = True
lista = ["a", "b", "c"]
📌 Reglas de nombres de variables:
  • Deben empezar con una letra o _
  • Pueden contener letras, números y _
  • No son case-sensitive: Nombre = nombre = NOMBRE
  • No pueden ser palabras reservadas (IF, WHILE, etc.)

Strings (Cadenas de texto)

Los strings se pueden encerrar entre comillas dobles ". También dispones de atajos especiales:

AtajoEquivalenteUso
~q"Comillas dobles dentro de un string
~n\nSalto de línea
~t\tTabulación
; Usando comillas dobles
msg1 = "Hola ~qMundo~q~n¿Cómo estás?"

; Concatenación con &
saludo = "Hola, " & nombre & "!"

Operadores

TipoOperadores
Aritméticos+ - * / MOD ^ (potencia)
Comparación= <> < > <= >=
LógicosAND OR NOT
Concatenación&

Comentarios

; Comentario de una línea con punto y coma
# También se puede usar numeral
' O comilla simple

REM
  Este es un bloque de comentario
  de múltiples líneas.
  Ignorado completamente por el intérprete.
ENDREM

Conversión de tipos

num = Int("42")        ; Convierte a entero (42)
dec = Float("3.14")    ; Convierte a decimal (3.14)
txt = Str(123)        ; Convierte a string ("123")

🎛️ Control de Flujo

IF / THEN / ELSEIF / ELSE / ENDIF

Permite ejecutar código condicionalmente.

If edad >= 18 Then
  SendMessage("Eres mayor de edad")
ElseIf edad >= 13 Then
  SendMessage("Eres adolescente")
Else
  SendMessage("Eres un niño")
EndIf

; Forma corta en una línea
If x = 0 Then SendMessage("Cero")

WHILE / WEND

Bucle que se repite mientras la condición sea verdadera.

i = 1
While i <= 5
  SendMessage("Número: " & i)
  i = i + 1
Wend

FOR / TO / STEP / NEXT

Bucle con contador.

; Contador de 1 a 10
For i = 1 To 10
  SendMessage("i = " & i)
Next

; Con STEP personalizado
For i = 10 To 0 Step -2
  SendMessage("Cuenta regresiva: " & i)
Next

SELECT / CASE / DEFAULT / END SELECT

Alternativa más limpia a múltiples IF/ELSEIF.

Select color
  Case "rojo"
    SendMessage("🔴 Rojo")
  Case "verde", "azul"
    SendMessage("Color primario")
  Case 1 To 5
    SendMessage("Número bajo")
  Case > 10
    SendMessage("Mayor a 10")
  Default
    SendMessage("Desconocido")
End Select

FUNCTION / END FUNCTION

Define funciones reutilizables con parámetros opcionales.

Function sumar(a, b)
  Return a + b
End Function

; Con valores por defecto
Function saludar(nombre = "Anónimo", formal = False)
  If formal Then
    SendMessage("Estimado " & nombre)
  Else
    SendMessage("Hola " & nombre)
  EndIf
End Function

; Llamadas
res = sumar(5, 3)
saludar("Marcos")
saludar("Dr. García", True)

GOTO y etiquetas

Salto incondicional a una etiqueta. Úsalo con precaución.

If error Then Goto manejarError

; Código normal aquí

manejarError:
  SendMessage("Ocurrió un error")
  Stop

DIM (Arrays pre-dimensionados)

Crea un array con un tamaño fijo. Los índices empiezan en 1.

Dim notas[5]    ; Array de 5 elementos: notas[1] a notas[5]
notas[1] = 10
notas[2] = 8
notas[3] = 9

STOP

Detiene completamente la ejecución del script. Es crucial usarlo después de SendMessage() para evitar respuestas duplicadas del bot.

⚠️ Regla de oro: Siempre que envíes un mensaje manualmente con SendMessage(), termina con Stop si no quieres que el bot también responda.

💬 Envío de Mensajes y Comandos

SendMessage

Envía un mensaje al chat actual. Es la función más usada.

; Envío simple
SendMessage("¡Hola!")

; Con reply al mensaje del usuario (reply = 1)
SendMessage("Te respondo", 1)

; Con teclado inline (ver sección de teclados)
SendMessage("¿Aceptas?", 0, teclado)

; Con imagen
SendMessage("Mira esta foto", 0, "", "https://…")

Parámetros: SendMessage(texto, reply, teclado, imagen, chat)

EditMessage

Edita un mensaje previamente enviado.

EditMessage("Texto editado", messageId, teclado)

DeleteMessage

Elimina un mensaje del chat.

DeleteMessage(messageId)
DeleteMessage(0)  ; Elimina el mensaje actual

CopyMessage

Copia un mensaje de otro chat (útil para stickers o contenido de grupos). Ver ejemplo de stickers.

CopyMessage(123, "-1001234567890")  ; msgId, chatId
CopyMessage(123, "@MiGrupo")         ; También por username

IsCommand

Detecta si el mensaje empieza con un comando. Devuelve True o False.

; Detección simple
If IsCommand("/ayuda") Then
  SendMessage("Aquí está la ayuda…")
  Stop
EndIf

; Detección con eliminación del comando del texto
If IsCommand("/traducir", True) Then
  ; Ahora user_text solo contiene el texto a traducir
  SetLLMContext("Traduce al inglés")
EndIf

SendChatAction

Muestra una acción de chat (ej: "escribiendo…") en Telegram.

SendChatAction("typing")
SendChatAction("upload_photo")

; Mantener la acción viva (keepAlive = True)
SendChatAction("typing", True)

; Detener todas las acciones
StopChatAction()

Acciones válidas: typing, upload_photo, record_video, upload_video, record_voice, upload_voice, upload_document, choose_sticker, find_location, record_video_note, upload_video_note

⌨️ Teclados y Botones

BlitzScript ofrece dos tipos de teclados: teclados inline (botones bajo el mensaje) y teclados de respuesta (reemplazan el teclado del dispositivo).

Botones inline (bajo el mensaje)

CreateButton

Crea un botón individual con texto y callback_data (o URL).

; Botón con callback
btn1 = CreateButton("✅ Sí", "confirmar")

; Botón con URL
btn2 = CreateButton("Visitar web", "https://example.com")

CreateKeyboard

Combina botones en un teclado inline. Cada argumento puede ser un botón (se ponen en la misma fila) o un teclado/fila existente.

; Una fila con dos botones
teclado = CreateKeyboard(btn1, btn2)

; Dos filas: primero crea cada fila, luego las combina
fila1 = CreateKeyboard(CreateButton("A", "a"), CreateButton("B", "b"))
fila2 = CreateKeyboard(CreateButton("C", "c"))
teclado = CreateKeyboard(fila1, fila2)

SendMessage("Elige una opción:", 0, teclado)
Stop
⚠️ Importante: Para crear varias filas, primero crea cada fila por separado con CreateKeyboard y luego combínalas. No intentes añadir botones uno a uno a un teclado existente.

Teclados de respuesta (Reply Keyboard)

CreateOption y CreateOptions

Crea teclados que reemplazan el teclado del usuario.

opt1 = CreateOption("Opción A")
opt2 = CreateOption("Opción B")
teclado = CreateOptions(opt1, opt2)

SendMessage("Selecciona:", 0, teclado)
Stop

OneTimeKeyboard y RemoveKeyboard

; Teclado que desaparece tras un uso
teclado = OneTimeKeyboard(teclado)

; Eliminar el teclado del usuario
SendMessage("Adiós teclado", 0, RemoveKeyboard())

Manejar callbacks de botones

Cuando el usuario pulsa un botón inline, su callback_data llega como un nuevo mensaje. Usa GetCallbackText() para obtenerlo.

; Mostrar el menú inicial
If IsCommand("/menu") Then
  b1 = CreateButton("📊 Estadísticas", "stats")
  b2 = CreateButton("⚙️ Config", "config")
  kb = CreateKeyboard(b1, b2)
  SendMessage("Menú principal", 0, kb)
  Stop
EndIf

; Procesar el callback
cb = GetCallbackText()
If cb <> "" Then
  Select cb
    Case "stats"
      SendMessage("Aquí van tus estadísticas…")
    Case "config"
      SendMessage("Configuración…")
  End Select
  AnswerCallback()  ; Confirma el clic al servidor
  Stop
EndIf

💾 Almacenamiento Persistente

Puedes guardar datos entre mensajes e incluso entre chats usando SaveSettings y LoadSettings. Los datos se almacenan cifrados en la base de datos.

SaveSettings y LoadSettings

; Guardar un valor
SaveSettings("puntos_" & GetUserID(), "100")

; Leer un valor (devuelve "" si no existe)
puntos = LoadSettings("puntos_" & GetUserID())

; Eliminar un valor (pasar vacío)
SaveSettings("puntos_" & GetUserID())
📌 Límites:
  • Nombre: hasta 255 caracteres
  • Contenido: hasta 2048 caracteres

Guardar datos por chat o usuario

; Por usuario (datos personales)
claveUser = "perfil_" & GetUserID()
SaveSettings(claveUser, "Me gusta la pizza")

; Por chat (datos compartidos del grupo)
claveChat = "config_" & GetChatID()
SaveSettings(claveChat, "modo_serio")

; Por chat Y usuario (datos personales del usuario en ese chat)
claveMixta = GetChatID() & "_" & GetUserID()
SaveSettings(claveMixta, "50 puntos")

Bloqueos (Locks) AVANZADO

Evita que dos ejecuciones simultáneas sobrescriban los mismos datos.

; Crear un bloqueo por 60 segundos
CreateSettingsLock("miLock", 60)

; Esperar a que otro proceso libere el bloqueo
WaitSettingsLock("miLock")

; Comprobar si existe
If ExistsSettingsLock("miLock") Then
  SendMessage("Esperando…")
EndIf

; Eliminar el bloqueo manualmente
DeleteSettingsLock("miLock")

🧠 Funciones LLM

Estas funciones permiten interactuar con el modelo de IA de forma programática.

GenerateText

Genera texto con IA usando un prompt personalizado. Gratis

; Parámetros: user, system, filter, keepHistory, returnArray
respuesta = GenerateText("Cuéntame un chiste", "Eres un comediante")

; Sin filtro (útil para respuestas crudas)
raw = GenerateText(prompt, sys, False)

; Guardando el intercambio en el historial
resp = GenerateText(user, sys, True, True)

; Obtener también imágenes generadas como array
arr = GenerateText(user, sys, True, True, True)
; arr[0] = texto, arr[1..n] = URLs de imágenes

SetLLMContext

Añade contexto temporal solo para el mensaje actual. No consume tokens extra de tu cuenta.

; Hacer que el bot responda como experto
If IsCommand("/legal", True) Then
  SetLLMContext("Responde como un abogado experto en derecho digital")
  ; El bot responderá normalmente pero con este contexto
EndIf

SetLLMInstructions Requiere API Key

Define instrucciones permanentes al modelo. Consume tokens de TU cuenta.

; Solo funciona con API Key propia
If IsCommand("/ingles") Then
  SetLLMInstructions("Responde SIEMPRE en inglés")
  SendMessage("✅ Modo inglés activado")
  Stop
EndIf

SaveUserMessage

Fuerza que el mensaje actual del usuario se guarde en el historial (útil si quieres que el bot recuerde algo específico).

SaveUserMessage(True)   ; Guardar
SaveUserMessage(False)  ; No guardar

GenerateImage

Genera una imagen con IA. Requiere API Key de imágenes configurada.

If IsCommand("/imagen", True) Then
  url = GenerateImage(GetValue("user_text"))
  If url <> "" Then
    SendMessage("Aquí tienes:", 0, "", url)
  Else
    SendMessage("No pude generar la imagen")
  EndIf
  Stop
EndIf

🔢 Funciones Matemáticas

BlitzScript incluye todas las funciones matemáticas estándar. Todas trabajan con números decimales (float).

Básicas

Abs(x) - Valor absoluto

Ceil(x) - Redondeo hacia arriba

Floor(x) - Redondeo hacia abajo

Round(x, dec) - Redondeo

Sqrt(x) - Raíz cuadrada

Pow(x, y) - Potencia (x^y)

Fmod(x, y) - Módulo decimal

Hypot(x, y) - Hipotenusa

Trigonométricas

Sin(x), Cos(x), Tan(x)

Asin(x), Acos(x), Atan(x)

Atan2(y, x) - Arcotangente 2D

Sinh(x), Cosh(x), Tanh(x)

Deg2Rad(x) - Grados a radianes

Rad2Deg(x) - Radianes a grados

Logarítmicas

Log(x, base) - Logaritmo en base

Log10(x) - Logaritmo base 10

Log1p(x) - ln(1 + x)

Exp(x) - e^x

Expm1(x) - e^x - 1

Aleatorias y constantes

Rand(min, max) - Entero aleatorio

Rnd() - Float 0-1

Max(a, b, …) - Máximo

Min(a, b, …) - Mínimo

Pi - π (3.14159…)

Ejemplo: dado de rol

If IsCommand("/roll", True) Then
  txt = GetValue("user_text")
  caras = Int(txt)
  If caras < 2 Then caras = 6
  resultado = Rand(1, caras)
  SendMessage("🎲 Tiraste un d" & caras & " y sacaste: *" & resultado & "*")
  Stop
EndIf

📝 Funciones de Strings

FunciónDescripciónEjemplo
Len(s, modo)Longitud (modo 1 = bytes)Len("hola") → 4
Mid(s, ini, len)Subcadena desde iniMid("hola", 2, 2) → "ol"
Left(s, n)Primeros n caracteresLeft("hola", 2) → "ho"
Right(s, n)Últimos n caracteresRight("hola", 2) → "la"
Upper(s)MayúsculasUpper("hola") → "HOLA"
Lower(s)MinúsculasLower("HOLA") → "hola"
Trim(s)Elimina espaciosTrim(" hola ") → "hola"
LTrim(s)Elimina espacios inicio
RTrim(s)Elimina espacios final
Replace(s, a, b)Reemplaza a por bReplace("hola", "o", "0") → "h0la"
Instr(s, sub, ini)Posición de sub (0 = no)Instr("hola", "o") → 2
Split(s, sep)Divide en arraySplit("a,b,c", ",") → ["a","b","c"]
Chr(n)Carácter por códigoChr(65) → "A"
Asc(s)Código del primer carácterAsc("A") → 65

Ejemplo: Analizador de menciones

If IsCommand("/count") Then
  txt = GetValue("user_text")
  lenTxt = Len(txt)
  palabras = Len(Split(txt, " "))
  SendMessage("📊 Tu mensaje tiene:~n- " & lenTxt & " caracteres~n- " & palabras & " palabras")
  Stop
EndIf

📚 Arrays

Los arrays en BlitzScript tienen índices que empiezan en 1 (estilo BASIC).

Crear y usar arrays

; Crear con Dim
Dim nums[5]
nums[1] = 10
nums[2] = 20

; Array literal
colores = ["rojo", "verde", "azul"]

; Push al final (se autoextiende)
lista[] = "nuevo"

Funciones de array

FunciónDescripción
ArrayLen(arr)Tamaño del array
ArrayPush(arr, val)Añade valor al final
ArrayPop(arr)Extrae el último valor
ArrayMerge(a, b)Une dos arrays
ArraySort(arr)Ordena el array

Ejemplo: Lista de tareas

If IsCommand("/add", True) Then
  clave = "tareas_" & GetUserID()
  raw = LoadSettings(clave)
  If raw = "" Then
    raw = GetValue("user_text")
  Else
    raw = raw & "|" & GetValue("user_text")
  EndIf
  SaveSettings(clave, raw)
  SendMessage("✅ Tarea añadida")
  Stop
EndIf

If IsCommand("/tareas") Then
  raw = LoadSettings("tareas_" & GetUserID())
  If raw = "" Then
    SendMessage("No tienes tareas")
  Else
    tareas = Split(raw, "|")
    msg = "📋 *Tus tareas:*~n"
    For i = 1 To ArrayLen(tareas)
      msg = msg & i & ". " & tareas[i] & "~n"
    Next
    SendMessage(msg)
  EndIf
  Stop
EndIf

⏰ Tiempo y Contexto

CurrentTime

; Modo 0 (por defecto): hora actual como string "HH:MM:SS"
hora = CurrentTime()  ; "14:30:22"

; Modo 1: timestamp UNIX en segundos
ts = CurrentTime(1)  ; 1719691822

; Modo 2: timestamp con decimales
tsPrec = CurrentTime(2)  ; 1719691822.123

; Modo 3: string completo "HH:MM:SS|ts|ts.float"
todo = CurrentTime(3)

CurrentDate

; Fecha por defecto: "29 Jun 2026"
fecha = CurrentDate()

; Formato personalizado
custom = CurrentDate("YYYY-MM-DD")

GetValue - Obtener valores del contexto

Accede a información del bot, usuario y chat actual.

ClaveDescripción
user_nameNombre del usuario actual
user_textTexto del mensaje del usuario
user_username@username del usuario
bot_name / char_nameNombre del bot
personalityPersonalidad del bot
chat_nameID del chat
is_groupTrue si es grupo
is_privateTrue si es privado
replyingTrue si es reply al bot
replying_to_userNombre del usuario al que se responde
activeTrue si el bot está activo en el chat
think / cotTrue si el modo pensar está activo
fw / freewillTrue si libre albedrío está activo
respondTrue si el bot debería responder
start_textMensaje de inicio del bot
error_textMensaje de error del bot
wack_textMensaje al borrar memoria
reset_textMensaje al resetear
sleep_textMensaje al dormir
; Personalizar respuesta según el chat
If GetValue("is_group") Then
  SetLLMContext("Estás en un grupo, sé breve")
Else
  SetLLMContext("Estás en MD, puedes extenderte")
EndIf

GetUserID y GetChatID

Devuelven identificadores en formato hexadecimal. Útiles para crear claves únicas de almacenamiento.

uid = GetUserID()  ; "1a2b3c4d"
cid = GetChatID()  ; "5e6f7g8h"
clave = cid & "_" & uid

Exists

Verifica si una variable existe y opcionalmente su tipo.

If Exists("miVar") Then
  SendMessage("Existe")
EndIf

; Con tipo: "array", "string", "number", "boolean"
If Exists("lista", "array") Then
  SendMessage("Es un array")
EndIf

🎯 Casos de Uso Prácticos

🟢 Caso 1: Comando de saludo personalizado

If IsCommand("/saludo", True) Then
  nombre = GetValue("user_text")
  If nombre = "" Then nombre = GetValue("user_name")
  SendMessage("¡Hola, " & nombre & "! 👋")
  Stop
EndIf

🟢 Caso 2: Traductor simple

If IsCommand("/en", True) Then
  SetLLMContext("Traduce al inglés lo que te diga el usuario. Solo responde con la traducción, nada más.")
  ; No hacemos Stop para que el bot responda con la traducción
EndIf

If IsCommand("/es", True) Then
  SetLLMContext("Traduce al español lo que te diga el usuario. Solo responde con la traducción, nada más.")
EndIf

🟡 Caso 3: Sistema de puntos

If IsCommand("/puntos") Then
  clave = "puntos_" & GetUserID()
  pts = LoadSettings(clave)
  If pts = "" Then pts = 0
  SendMessage("💰 Tienes " & pts & " puntos")
  Stop
EndIf

If IsCommand("/darpunto") Then
  clave = "puntos_" & GetUserID()
  pts = Int(LoadSettings(clave))
  pts = pts + 1
  SaveSettings(clave, Str(pts))
  SendMessage("🎉 ¡+1 punto! Total: " & pts)
  Stop
EndIf

🟡 Caso 4: Botón de confirmación

If IsCommand("/borrar") Then
  b1 = CreateButton("✅ Sí, borrar", "confirmar_borrado")
  b2 = CreateButton("❌ Cancelar", "cancelar")
  kb = CreateKeyboard(b1, b2)
  SendMessage("⚠️ ¿Estás seguro de que quieres borrar todo?", 0, kb)
  Stop
EndIf

cb = GetCallbackText()
If cb = "confirmar_borrado" Then
  ; Ejecutar borrado
  SaveSettings("datos_" & GetUserID())
  SendMessage("🗑️ Datos borrados")
  AnswerCallback()
  Stop
ElseIf cb = "cancelar" Then
  SendMessage("✅ Operación cancelada")
  AnswerCallback()
  Stop
EndIf

🔴 Caso 5: Generador de IA con contexto dinámico

If IsCommand("/pregunta", True) Then
  pregunta = GetValue("user_text")
  If pregunta = "" Then
    SendMessage("❌ Escribe una pregunta: /pregunta [tu pregunta]")
    Stop
  EndIf

  SendChatAction("typing", True)

  sys = "Eres un profesor universitario. Explica de forma clara y didáctica."
  resp = GenerateText(pregunta, sys, True, False)

  StopChatAction()

  If resp = "" Then
    SendMessage("No pude generar una respuesta 😔")
  Else
    SendMessage(resp, 1)
  EndIf
  Stop
EndIf

🔴 Caso 6: Enviar stickers con CopyMessage

If IsCommand("/sticker") Then
  ; Supongamos que guardamos un sticker en un grupo especial
  ; Chat ID: -1001234567890, Message ID: 42
  CopyMessage(42, "-1001234567890")
  Stop
EndIf

If IsCommand("/stickerrandom") Then
  ids = [42, 43, 44, 45, 46]
  elegido = ids[Rand(1, ArrayLen(ids))]
  CopyMessage(elegido, "-1001234567890")
  Stop
EndIf

🔥 Ejemplo Complejo: Sistema de Créditos por Hora

Este ejemplo avanzado implementa un sistema de límites de uso basado en créditos que se recargan cada hora. Analicemos el código por partes:

📋 ¿Qué hace este script?
  • Da 12000 créditos por hora a cada chat
  • Cada carácter (del usuario y de la respuesta) consume 1 crédito
  • /imagine cuesta 500 créditos extra
  • Los créditos se recargan automáticamente al cambiar de hora
  • /info muestra los créditos actuales
  • Incluye publicidad del servicio al quedarse sin créditos

📖 Código completo

; ==========================================
; SISTEMA DE CRÉDITOS POR HORA
; ==========================================

; Creamos una clave única por chat+usuario
chatID = GetChatID() & "-" & GetUserID()
creditsPerHour = 12000

; Solo procesar si el bot va a responder
; Y NO es un comando (excepto /web e /imagine)
If GetValue("respond") And (Instr(GetValue("user_text"), "/") <> 1 Or IsCommand("/web") Or IsCommand("/imagine")) Then

  ; Cargar datos guardados: "creditos|horaUltimoReset"
  dataOrig = LoadSettings(chatID)
  If dataOrig = "" Then dataOrig = "0|0"

  data = Split(dataOrig, "|")
  dataCredits = Int(data[1])
  dataTime = Int(data[2])

  ; Calcular la hora actual (timestamp / 3600)
  thHour = Int(CurrentTime(1) / 3600)

  ; Si cambió la hora, resetear créditos
  If dataTime < thHour Then
    dataCredits = creditsPerHour
    dataTime = thHour
  EndIf

  ; Calcular coste del mensaje actual
  thMC = Len(GetValue("user_text"))

  ; Si es /imagine, añadir 500 créditos extra
  If IsCommand("/imagine") Then
    If GetValue("user_text") <> "/imagine" Then
      thMC = thMC + 500
      SaveSettings(chatID, Max(Int(dataCredits - thMC), 0) & "|" & thHour)
    EndIf
  EndIf

  ; Comprobar si hay créditos suficientes
  If thMC > dataCredits Then
    ; Calcular minutos hasta la próxima recarga
    minsRestantes = 60 - Int((CurrentTime(1) Mod 3600) / 60)
    SendMessage("Créditos insuficientes (necesitas " & thMC & " y tienes " & dataCredits & "), espera " & minsRestantes & " minutos para la recarga de " & creditsPerHour & ".~n~nSi quieres, puedes crear bots con IA como yo súper fácil con @TeleCharsAI 💪😎 (es completamente gratis y sin límites estrictos para modelos como DeepSeek V4 Flash 👀)")
    Stop
  ElseIf Not IsCommand("/imagine") Then
    ; Mensaje normal: generar respuesta y contar sus caracteres
    SendChatAction("typing", True)
    gen = GenerateText(GetValue("user_text"), GetValue("personality"), True, True)
    thMC = thMC + Len(gen)

    If gen = "" Then gen = GetValue("error")

    StopChatAction()
    SendMessage(gen)
    SaveSettings(chatID, Max(Int(dataCredits - thMC), 0) & "|" & thHour)
    Stop
  EndIf

ElseIf IsCommand("/info") Then
  ; Mostrar información de créditos
  actualInfo = Split(LoadSettings(chatID), "|")
  thHr = Int(CurrentTime(1) / 3600)

  If Int(actualInfo[2]) < thHr Then actualInfo[1] = creditsPerHour

  SendMessage("ℹ️ *Los créditos se consumen por caracter de texto, ya sea del usuario o del modelo de IA.*~n~nCréditos: " & Int(actualInfo[1]))
  Stop
EndIf

🔍 Análisis paso a paso

1. Inicialización y claves únicas

Se crea una clave única combinando el ID del chat y del usuario. Esto permite que cada usuario tenga sus propios créditos independientes en cada chat.

chatID = GetChatID() & "-" & GetUserID()
creditsPerHour = 12000
2. Filtrado inteligente de comandos

El sistema solo se aplica cuando el bot va a responder Y no es un comando, excepto /web e /imagine que sí consumen créditos.

If GetValue("respond") And (Instr(…, "/") <> 1 Or …) Then
  • GetValue("respond"): Solo si el bot debería responder
  • Instr(…, "/") <> 1: No empieza con "/" (no es comando)
  • Or IsCommand("/web") Or IsCommand("/imagine"): Pero sí procesa estos dos
3. Sistema de recarga horaria

Al dividir el timestamp UNIX por 3600, obtenemos la "hora actual" como número entero. Si cambió respecto a la última guardada, reseteamos los créditos.

thHour = Int(CurrentTime(1) / 3600)
If dataTime < thHour Then
  dataCredits = creditsPerHour
  dataTime = thHour
EndIf
4. Coste especial de /imagine

Las imágenes cuestan 500 créditos adicionales. Se descuentan inmediatamente antes de procesar.

5. Mensaje publicitario cuando no hay créditos

Calcula los minutos restantes hasta la próxima hora usando Mod 3600 y muestra un mensaje con publicidad del servicio.

6. Conteo de caracteres bidireccional

El truco más interesante: genera la respuesta primero con GenerateText, cuenta los caracteres de la respuesta, y descuenta TODO (entrada + salida).

gen = GenerateText(GetValue("user_text"), GetValue("personality"), True, True)
thMC = thMC + Len(gen)

📊 Ejemplo de ejecución

👤 Usuario

Escribe: "Hola, ¿cómo estás?" (20 chars)

🤖 Bot

Responde: "¡Hola! Muy bien…" (150 chars)

💰 Coste total

20 + 150 = 170 créditos

📊 Saldo restante

12000 - 170 = 11830 créditos

📖 Referencia Rápida de Funciones

📬 Sistema

SendMessage(text, reply, kb, img, chat)EditMessage(text, msgId, kb)CopyMessage(msgId, fromChat, reply, kb, chat)DeleteMessage(msgId)IsCommand(cmd, remove)GetCallbackText()AnswerCallback(msg, notify)Exists(var, type)GetUserID()GetChatID()CurrentTime(mode)CurrentDate(fmt)GetValue(key)SendChatAction(action, keep)StopChatAction()GenerateImage(prompt)

⌨️ Teclados

CreateButton(text, callback) CreateOption(text) CreateKeyboard(…) CreateOptions(…) OneTimeKeyboard(kb, oneTime) RemoveKeyboard()

💾 Almacenamiento

SaveSettings(name, content) LoadSettings(name) CreateSettingsLock(name, ttl) ExistsSettingsLock(name) WaitSettingsLock(name) DeleteSettingsLock(name)

🧠 LLM

GenerateText(user, sys, filter, history, arr) SetLLMContext(text) SetLLMInstructions(text) SaveUserMessage(bool)

🔢 Matemáticas

AbsCeilFloorRound SqrtPowFmodHypot SinCosTanAsin AcosAtanAtan2 LogLog10Exp RandRndMaxMin Pi

📝 Strings

LenMidLeftRight UpperLowerTrim LTrimRTrim ReplaceInstrSplit ChrAsc

📚 Arrays

ArrayLen ArrayPush ArrayPop ArrayMerge ArraySort

🔁 Conversión

Str Int Float

❓ Preguntas Frecuentes

¿Por qué mi script no ejecuta SendMessage?

Verifica que:

  • No haya errores de sintaxis (usa REM para comentar secciones dudosas)
  • El bot tenga token de Telegram configurado
  • El mensaje no supere los 4096 caracteres (Telegram lo rechaza)
  • El bot tenga permisos para enviar mensajes en ese chat
¿Cómo depuro mi script?

Usa SendMessage temporalmente para mostrar valores de variables en el chat, o revisa los logs del sistema en la pestaña de tu telecharbot.

; Debug temporal: mostrar valor de una variable
SendMessage("DEBUG: x = " & x)
Stop
¿Por qué responde dos veces el bot?

¡Olvidaste Stop después de SendMessage()! Sin Stop, el script termina pero el bot sigue con su respuesta normal, causando duplicación.

¿SetLLMInstructions no funciona?

Esta función requiere API Key propia configurada en el bot y consume tokens de tu cuenta. Si usas la API gratuita, usa SetLLMContext() en su lugar (funciona solo para el mensaje actual).

¿Cuánto tiempo puede ejecutarse un script?

Máximo 125 segundos. Si necesitas más tiempo, divide la tarea en varios comandos o usa almacenamiento para guardar el estado entre ejecuciones.

¿Los datos de SaveSettings caducan?

No.

¿Puedo usar BlitzScript para juegos complejos?

¡Sí! Con almacenamiento, arrays y funciones, puedes crear RPGs, quizzes, sistemas económicos, etc. El ejemplo del sistema de créditos es un buen punto de partida.

¿Hay límites de memoria?

Sí, el script tiene un límite de 64 MB de RAM. Evita crear arrays gigantes o cargar muchos datos a la vez.

⚠️ Errores comunes a evitar:
  • Olvidar Stop después de SendMessage()
  • Usar índices 0 en arrays (empiezan en 1)
  • Confundir = (asignación Y comparación) con == (no existe)
  • Usar & sin espacios puede causar errores con variables
  • No cerrar If con EndIf o While con Wend
  • Exceder el tiempo de 125 segundos en bucles infinitos

🎓 Consejos Avanzados

🎯 Modulariza con funciones

Divide tu script en funciones reutilizables. Hace el código más legible y fácil de mantener.

🔐 Usa locks en operaciones críticas

Cuando varios usuarios modifiquen los mismos datos, usa CreateSettingsLock para evitar condiciones de carrera.

⚡ Caché con GetValue

GetValue es rápido porque lee variables en memoria. Úsalo en lugar de LoadSettings cuando sea posible.

🧪 Prueba con mensajes temporales

Si algo no funciona como esperas, añade SendMessage temporales en puntos clave para rastrear el flujo (y recuerda quitarlos después).

🌟 Patrones útiles

Patrón: Comando con cooldown

If IsCommand("/daily") Then
  clave = "daily_" & GetUserID()
  ultimo = Int(LoadSettings(clave))
  ahora = CurrentTime(1)

  If ahora - ultimo < 86400 Then
    restan = 86400 - (ahora - ultimo)
    horas = Int(restan / 3600)
    SendMessage("⏳ Vuelve en " & horas & " horas")
    Stop
  EndIf

  SaveSettings(clave, Str(ahora))
  SendMessage("🎁 ¡Recompensa diaria reclamada!")
  Stop
EndIf

Patrón: Menú paginado con funciones

Function mostrarMenu(pagina)
  ; Definir items del menú
  items = ["Opción 1", "Opción 2", "Opción 3", "Opción 4", "Opción 5", "Opción 6", "Opción 7", "Opción 8", "Opción 9", "Opción 10"]

  ini = (pagina - 1) * 5 + 1
  fin = ini + 4
  total = ArrayLen(items)

  ; Crear botones de la página actual
  botones = []
  For i = ini To fin
    If i <= total Then
      botones[] = CreateButton(items[i], "opt_" & i)
    EndIf
  Next

  ; Crear fila con los botones
  filaItems = CreateKeyboard(botones[1], botones[2], botones[3], botones[4], botones[5])

  ; Botones de navegación
  filaNav = []
  If pagina > 1 Then filaNav[] = CreateButton("⬅️ Anterior", "pag_" & (pagina-1))
  If fin < total Then filaNav[] = CreateButton("Siguiente ➡️", "pag_" & (pagina+1))

  ; Combinar filas
  kb = CreateKeyboard(filaItems)
  If ArrayLen(filaNav) > 0 Then
    filaNavFinal = CreateKeyboard(filaNav[1], filaNav[2])
    kb = CreateKeyboard(kb, filaNavFinal)
  EndIf

  SendMessage("Menú - Página " & pagina, 0, kb)
End Function