-- ============================================================ -- BOMBARDERO — port a la fantasy console "ascii" del original -- de Dave Town para Amstrad CPC (AMSOFT, 1984). -- Sergi Valor, 2026. -- ============================================================ -- ============================================================ -- CONFIGURACION (todo lo tuneable vive aqui) -- ============================================================ -- Pantalla y layout MODO = 1 -- mode(1) = 40x30, color por carácter ANCHO = 40 ALTO = 30 AVION_Y_MIN = 1 -- fila más alta a la que puede llegar el avión AVION_Y_MAX = 21 -- última fila antes de aterrizar (~ fila 21 del original) EDIF_BASE_Y = 22 -- los edificios apoyan aquí (justo encima del suelo) SUELO_Y = 23 -- línea visible del suelo HUD_Y0 = 25 -- banda HUD (filas 25..27) -- Avión (2 chars de ancho) AVION_W = 2 AVION_X_MIN = 0 AVION_X_MAX = ANCHO - AVION_W -- 38: a partir de aquí el avión "envuelve" AVION_X_INI = 0 AVION_Y_INI = AVION_Y_MIN + 1 -- empieza en fila 2 (como el original) -- Edificios EDIF_X_INI = 4 EDIF_X_FIN = 37 EDIF_X_STEP = 3 -- separación entre edificios (con avión de 2 chars deja 1 hueco) EDIF_RANGO = 7 -- variabilidad aleatoria del tejado -- Tejado más bajo (= edificio más alto) por nivel del jugador. -- Nivel 0 (AS) → tejados desde fila 9 (edificios altos, casi tocando el avión). -- Nivel 5 (principiante) → tejados desde fila 16 (edificios bajitos). EDIF_TEJADO_BASE = 9 EDIF_TEJADO_NIVEL = 1 -- cada punto de nivel sube los tejados esta cantidad -- Niveles y velocidad (escala "intuitiva": 0 = fácil/lento, máx = duro/rápido) NIVEL_MIN = 0 NIVEL_MAX = 5 VEL_MIN = 0 VEL_MAX = 9 TICS_AVION_BASE = 11 -- frames entre paso de avión a vel = 0 (≈ 5 mov/s) TICS_AVION_MIN = 2 -- a vel = 9 (≈ 30 mov/s) TICS_BOMBA = 4 -- frames entre paso de bomba (cae más rápido que el avión a vel baja) -- Profundidad de perforación de la bomba: en cada impacto destruye un número -- aleatorio en [BOMBA_PERF_MIN, BOMBA_PERF_MAX] de bloques de la columna y se -- consume (fiel al "FOR tr=1 TO INT(RND*3)+1" del original). BOMBA_PERF_MIN = 1 BOMBA_PERF_MAX = 3 -- Subida de dificultad al aterrizar (el original bajaba `vel-20` y `nivel-1`) SUBIDA_VEL_POR_ATERRIZAJE = 1 SUBIDA_NIVEL_POR_ATERRIZAJE = 1 -- nivel sube → edificios más altos (más difícil) -- Puntuaciones PUNTOS_BLOQUE = 5 PUNTOS_ATERRIZAJE = 100 PUNTOS_ATERRIZ_PEN = 10 -- restar por punto de nivel (más alto = menos puntos) -- Vidas (el original no tenía, se acababa al primer choque) VIDAS_INI = 1 -- Duraciones de transición (en ms, leídas con time()) MS_ATERRIZAJE = 1200 -- pausa al aterrizar antes de generar siguiente pantalla MS_CHOQUE = 1500 -- animación de explosión del avión MS_GAMEOVER_MIN = 800 -- antes de aceptar input en game over -- ============================================================ -- PALETA (mapeo aproximado CPC firmware → CGA disponible) -- ============================================================ COL_FONDO = COLOR_BLACK COL_AVION = COLOR_LIGHT_CYAN COL_BOMBA = COLOR_LIGHT_RED COL_SUELO = COLOR_RED COL_TEXTO = COLOR_LIGHT_GRAY COL_TITULO = COLOR_YELLOW COL_PROMPT = COLOR_LIGHT_GREEN COL_HUD_FG = COLOR_LIGHT_GRAY COL_HUD_BG = COLOR_BLUE COL_RECORD = COLOR_YELLOW COL_GAMEOVER = COLOR_LIGHT_RED -- Colores cíclicos para edificios (el original iba con PEN base-2: cada columna -- distinto). Se aplica módulo sobre el índice de edificio. COL_EDIFICIOS = { COLOR_BROWN, COLOR_LIGHT_GREEN, COLOR_LIGHT_BLUE, COLOR_LIGHT_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_LIGHT_RED, COLOR_GREEN, COLOR_MAGENTA, } -- Ciclo de colores para la animación de explosión (mismo patrón "FOR t=1 TO 10:PEN t" del original) COL_EXPLOSION = { COLOR_YELLOW, COLOR_LIGHT_RED, COLOR_RED, COLOR_LIGHT_MAGENTA, COLOR_WHITE, COLOR_YELLOW, COLOR_LIGHT_RED, COLOR_RED, COLOR_LIGHT_MAGENTA, COLOR_WHITE, } -- ============================================================ -- GLIFOS (códigos que vamos a redefinir con setchar) -- ============================================================ AVION_L = 241 -- mitad izquierda del avión (bitmap idéntico al SYMBOL del original) AVION_R = 242 -- mitad derecha BLOQUE = 143 -- ladrillo (el original usaba este código del char-ROM CPC) BLOQUE2 = 244 -- variante (el original alternaba con chr(8) para superponer) BOMBA = 252 -- bomba EXPLO_A = 253 -- frame A de la explosión EXPLO_B = 238 -- frame B de la explosión -- ============================================================ -- ESTADOS (máquina de estados global) -- ============================================================ ESTADO_TITULO = "titulo" ESTADO_INSTRUC = "instruc" ESTADO_NIVEL = "nivel" -- pidiendo elección de nivel (0-5) ESTADO_VELOCIDAD = "velocidad" -- pidiendo elección de velocidad (0-9) ESTADO_JUEGO = "juego" ESTADO_ATERRIZA = "aterriza" ESTADO_CHOQUE = "choque" ESTADO_GAMEOVER = "gameover" -- ============================================================ -- TIPOS DE CELDA DEL MAPA -- ============================================================ T_VACIO = 0 T_EDIFICIO = 1 -- ============================================================ -- ESTADO GLOBAL DEL JUEGO -- ============================================================ mapa = {} -- mapa[x][y] = { tipo=, color= } avion = { x=0, y=0 } bomba = { activa=false, fase="cayendo", x=0, y=0, restantes=0, ultimo_tic=0 } nivel = 0 -- el que ha elegido el jugador (0..NIVEL_MAX) nivel_act = 0 -- el que sube al aterrizar (puede crecer por encima) vel = 0 -- velocidad (0..VEL_MAX) puntos = 0 maxi = 0 nom_record = "AAA" vidas = VIDAS_INI ultimo_tic_avion = 0 -- contador de frames para temporizar al avión estado = ESTADO_TITULO estado_t0_ms = 0 -- time() cuando se entró al estado actual estado_t0_fr = 0 -- cnt() cuando se entró al estado actual -- Para la pantalla "elige nombre" tras batir récord record_letra_idx = 1 hay_nuevo_record = false -- ============================================================ -- UTILIDADES -- ============================================================ function set_estado(nuevo) estado = nuevo estado_t0_ms = time() estado_t0_fr = cnt() end function tiempo_en_estado_ms() return time() - estado_t0_ms end function tiempo_en_estado_fr() return cnt() - estado_t0_fr end function tics_por_paso_avion() -- vel 0 → TICS_AVION_BASE, vel VEL_MAX → TICS_AVION_MIN local span = TICS_AVION_BASE - TICS_AVION_MIN local t = TICS_AVION_BASE - flr(vel * span / VEL_MAX) if t < TICS_AVION_MIN then t = TICS_AVION_MIN end return t end -- ============================================================ -- GLIFOS PERSONALIZADOS -- ============================================================ function definir_glifos() -- Avión: bitmaps idénticos a los SYMBOL del bombardero.bas original setchar(AVION_L, 0x40, 0x60, 0x70, 0x7F, 0x7F, 0xEF, 0x07, 0x00) setchar(AVION_R, 0x00, 0x32, 0x7A, 0xFE, 0xFA, 0xF2, 0xE0, 0x00) -- Ladrillo macizo (con un patrón de mortero entre filas) setchar(BLOQUE, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF) -- Variante de ladrillo con junta desplazada (alterna con BLOQUE para textura) setchar(BLOQUE2, 0xFF, 0xEF, 0x00, 0xFB, 0xFF, 0xEF, 0x00, 0xFB) -- Bomba: óvalo con aleta setchar(BOMBA, 0x18, 0x3C, 0x7E, 0x7E, 0x7E, 0x3C, 0x18, 0x42) -- Explosión frame A: estrella radial setchar(EXPLO_A, 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99) -- Explosión frame B: chispazo más denso setchar(EXPLO_B, 0x42, 0xA5, 0xDB, 0x7E, 0x7E, 0xDB, 0xA5, 0x42) end -- ============================================================ -- MAPA Y EDIFICIOS -- ============================================================ function init_mapa() for x = 0, ANCHO-1 do mapa[x] = {} for y = 0, ALTO-1 do mapa[x][y] = { tipo=T_VACIO, color=COL_FONDO, glifo=BLOQUE } end end end function tipo_en(x, y) if x < 0 or x >= ANCHO or y < 0 or y >= ALTO then return T_VACIO end return mapa[x][y].tipo end -- Genera la skyline en base al nivel actual de la partida (nivel_act). -- A más nivel, edificios más bajos (= más fácil): mismo comportamiento que el -- bucle FOR base=5 TO 15 / FOR altura=21 TO INT(RND*8+nivel) del original. function generar_edificios() init_mapa() local idx_color = 0 local tejado_min = EDIF_TEJADO_BASE + nivel_act * EDIF_TEJADO_NIVEL for x = EDIF_X_INI, EDIF_X_FIN, EDIF_X_STEP do local tejado = rnd(EDIF_RANGO) + tejado_min if tejado > EDIF_BASE_Y then -- Si el "tejado calculado" cae por debajo de la base, no hay edificio -- (mismo "bug-feature" del original que dejaba huecos en niveles fáciles). else local col = COL_EDIFICIOS[(idx_color % #COL_EDIFICIOS) + 1] for y = tejado, EDIF_BASE_Y do -- Alternar BLOQUE / BLOQUE2 para variedad de textura local glifo = ((y - tejado) % 2 == 0) and BLOQUE or BLOQUE2 mapa[x][y] = { tipo=T_EDIFICIO, color=col, glifo=glifo } end end idx_color = idx_color + 1 end end -- ============================================================ -- RENDER -- ============================================================ function pintar_fondo() color(COL_TEXTO, COL_FONDO) cls() end function pintar_mapa() for x = 0, ANCHO-1 do for y = 0, ALTO-1 do local c = mapa[x][y] if c.tipo == T_EDIFICIO then color(c.color, COL_FONDO) print(chr(c.glifo), x, y) end end end end function pintar_suelo() color(COL_SUELO, COL_FONDO) -- Una línea horizontal usando el char 154 del CPC (─ trazo medio). -- Si no queda bien visualmente, cambiar por chr(140) o un BLOQUE bajo. local linea = "" for i = 1, ANCHO do linea = linea .. chr(154) end print(linea, 0, SUELO_Y) end function pintar_avion() color(COL_AVION, COL_FONDO) print(chr(AVION_L), avion.x, avion.y) print(chr(AVION_R), avion.x+1, avion.y) end function pintar_bomba() if not bomba.activa then return end color(COL_BOMBA, COL_FONDO) print(chr(BOMBA), bomba.x, bomba.y) end function pintar_hud() color(COL_HUD_FG, COL_HUD_BG) local blank = "" for i = 1, ANCHO do blank = blank .. " " end print(blank, 0, HUD_Y0) print(blank, 0, HUD_Y0 + 1) print(blank, 0, HUD_Y0 + 2) color(COL_HUD_FG, COL_HUD_BG) print("PUNTOS "..string.format("%05d", puntos), 1, HUD_Y0) print("MAX "..string.format("%05d", maxi).." "..nom_record, 22, HUD_Y0) print("NIVEL "..tostr(nivel_act).." VEL "..tostr(vel), 1, HUD_Y0 + 1) print("ESPACIO=bomba", 22, HUD_Y0 + 1) end -- ============================================================ -- LÓGICA DEL AVIÓN -- ============================================================ function reset_avion() avion.x = AVION_X_INI avion.y = AVION_Y_INI ultimo_tic_avion = cnt() end -- Devuelve true si el avión choca con un edificio en su posición actual function avion_choca() return tipo_en(avion.x, avion.y) == T_EDIFICIO or tipo_en(avion.x+1, avion.y) == T_EDIFICIO end function avanza_avion() avion.x = avion.x + 1 if avion.x > AVION_X_MAX then -- Llegó al final de la pasada: si estaba en la última fila, aterriza if avion.y >= AVION_Y_MAX then iniciar_aterrizaje() return end avion.x = AVION_X_MIN avion.y = avion.y + 1 end if avion_choca() then iniciar_choque() end end -- ============================================================ -- LÓGICA DE LA BOMBA -- ============================================================ function lanzar_bomba() if bomba.activa then return end -- Bomba cae desde la cola del avión (mitad derecha), 1 fila por debajo bomba.activa = true bomba.fase = "cayendo" bomba.x = avion.x + 1 bomba.y = avion.y + 1 bomba.restantes = 0 bomba.ultimo_tic = cnt() sfx_lanzar() end function avanza_bomba() if not bomba.activa then return end if bomba.fase == "cayendo" then if tipo_en(bomba.x, bomba.y + 1) == T_EDIFICIO then -- Impacto: arrancar la fase de perforación (1..3 bloques) bomba.fase = "explotando" local span = BOMBA_PERF_MAX - BOMBA_PERF_MIN + 1 bomba.restantes = rnd(span) + BOMBA_PERF_MIN else bomba.y = bomba.y + 1 if bomba.y >= SUELO_Y then bomba.activa = false sfx_suelo() end end return end -- fase == "explotando": destruye el bloque que tiene debajo, baja y resta local ty = bomba.y + 1 if ty < SUELO_Y and tipo_en(bomba.x, ty) == T_EDIFICIO then mapa[bomba.x][ty] = { tipo=T_VACIO, color=COL_FONDO, glifo=BLOQUE } puntos = puntos + PUNTOS_BLOQUE sfx_explo() end bomba.y = bomba.y + 1 bomba.restantes = bomba.restantes - 1 if bomba.restantes <= 0 or bomba.y >= SUELO_Y then bomba.activa = false end end -- ============================================================ -- TRANSICIONES -- ============================================================ function iniciar_aterrizaje() sfx_aterrizar() puntos = puntos + max(0, PUNTOS_ATERRIZAJE - PUNTOS_ATERRIZ_PEN * nivel_act) set_estado(ESTADO_ATERRIZA) end function iniciar_choque() sfx_choque() set_estado(ESTADO_CHOQUE) end function siguiente_pantalla() nivel_act = nivel_act + SUBIDA_NIVEL_POR_ATERRIZAJE vel = vel + SUBIDA_VEL_POR_ATERRIZAJE if vel > VEL_MAX then vel = VEL_MAX end bomba.activa = false reset_avion() generar_edificios() end function nueva_partida() nivel_act = nivel puntos = 0 vidas = VIDAS_INI bomba.activa = false reset_avion() generar_edificios() end -- ============================================================ -- RECORDS (persistencia en fichero "records", igual que pepe_runner) -- Formato: 5 bytes (centenas-millares..unidades) + 3 bytes nombre -- ============================================================ function cargar_record() local f = io.open("records", "rb") if not f then return end local data = f:read(8) f:close() if not data or #data < 8 then return end local b = { string.byte(data, 1, 8) } maxi = b[1]*10000 + b[2]*1000 + b[3]*100 + b[4]*10 + b[5] if b[6] >= 32 and b[6] < 127 and b[7] >= 32 and b[7] < 127 and b[8] >= 32 and b[8] < 127 then nom_record = string.char(b[6], b[7], b[8]) end end function guardar_record() local f = io.open("records", "wb") if not f then return end local p = maxi local d5 = flr(p / 10000); p = p - d5*10000 local d4 = flr(p / 1000); p = p - d4*1000 local d3 = flr(p / 100); p = p - d3*100 local d2 = flr(p / 10); p = p - d2*10 local d1 = p f:write(string.char(d5, d4, d3, d2, d1, string.byte(nom_record, 1) or 65, string.byte(nom_record, 2) or 65, string.byte(nom_record, 3) or 65)) f:close() end -- ============================================================ -- SFX -- ============================================================ function sfx_lanzar() play("l0o4cdefg") end function sfx_explo() sound(4000, 8) end function sfx_suelo() sound(800, 10) end function sfx_aterrizar() play("l1o4ceg>c") end function sfx_choque() play("l1o3bal0gfedco2c") end function sfx_select() sound(2000, 3) end function sfx_gameover() play("l2o3bal1gfedco2c") end -- ============================================================ -- ESTADOS — TÍTULO -- ============================================================ function update_titulo() pintar_fondo() color(COL_TITULO, COL_FONDO) print("B O M B A R D E R O", 10, 4) color(COL_TEXTO, COL_FONDO) print("(Dave Town / AMSOFT 1984)", 7, 6) print("port a ascii — Sergi Valor, 2026", 3, 8) -- Avión decorativo de muestra color(COL_AVION, COL_FONDO) print(chr(AVION_L), 18, 11) print(chr(AVION_R), 19, 11) color(COL_RECORD, COL_FONDO) print("RECORD "..string.format("%05d", maxi).." "..nom_record, 11, 14) if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa ESPACIO para jugar", 8, 18) end color(COL_TEXTO, COL_FONDO) print("I = instrucciones", 11, 20) if btnp(KEY_SPACE) then sfx_select() set_estado(ESTADO_NIVEL) elseif btnp(KEY_I) then sfx_select() set_estado(ESTADO_INSTRUC) end end -- ============================================================ -- ESTADOS — INSTRUCCIONES -- ============================================================ function update_instruc() pintar_fondo() color(COL_TITULO, COL_FONDO) print("- INSTRUCCIONES -", 11, 1) color(COL_TEXTO, COL_FONDO) print("Pilotas un avion sobre una ciudad", 3, 4) print("desierta. Debes bombardear los", 3, 5) print("edificios para poder aterrizar.", 3, 6) print("El avion vuela de izquierda a", 3, 8) print("derecha y, al llegar al borde,", 3, 9) print("vuelve a salir por la izquierda", 3, 10) print("una fila MAS BAJO.", 3, 11) print("Si chocas con un edificio: muerte.", 3, 13) print("Si aterrizas: subes de nivel y", 3, 14) print("velocidad.", 3, 15) print("Solo una bomba a la vez!", 3, 17) color(COL_PROMPT, COL_FONDO) print("ESPACIO = lanzar bomba", 3, 20) if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa una tecla para volver", 6, 23) end if btnp(KEY_SPACE) or btnp(KEY_RETURN) or btnp(KEY_ESCAPE) then sfx_select() set_estado(ESTADO_TITULO) end end -- ============================================================ -- ESTADOS — SELECCIÓN DE NIVEL -- ============================================================ function update_nivel() pintar_fondo() color(COL_TITULO, COL_FONDO) print("ELIGE NIVEL", 14, 8) color(COL_TEXTO, COL_FONDO) print("0 = AS (edificios altos, dificil)", 3, 11) print("5 = PRINCIPIANTE (edif. bajos)", 3, 12) if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa 0..5", 14, 16) end -- KEY_1..KEY_9 = 30..38 y KEY_0 = 39 (no contiguos como dígitos, así que va a mano) if btnp(KEY_0) then nivel = 0; arrancar_partida_nivel(); return end if btnp(KEY_1) then nivel = 1; arrancar_partida_nivel(); return end if btnp(KEY_2) then nivel = 2; arrancar_partida_nivel(); return end if btnp(KEY_3) then nivel = 3; arrancar_partida_nivel(); return end if btnp(KEY_4) then nivel = 4; arrancar_partida_nivel(); return end if btnp(KEY_5) then nivel = 5; arrancar_partida_nivel(); return end end function arrancar_partida_nivel() sfx_select() set_estado(ESTADO_VELOCIDAD) end -- ============================================================ -- ESTADOS — SELECCIÓN DE VELOCIDAD -- ============================================================ function update_velocidad() pintar_fondo() color(COL_TITULO, COL_FONDO) print("ELIGE VELOCIDAD", 12, 8) color(COL_TEXTO, COL_FONDO) print("0 = LENTA 9 = RAPIDA", 9, 11) print("Nivel elegido: "..tostr(nivel), 12, 13) if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa 0..9", 14, 16) end if btnp(KEY_0) then vel = 0; arrancar_juego(); return end if btnp(KEY_1) then vel = 1; arrancar_juego(); return end if btnp(KEY_2) then vel = 2; arrancar_juego(); return end if btnp(KEY_3) then vel = 3; arrancar_juego(); return end if btnp(KEY_4) then vel = 4; arrancar_juego(); return end if btnp(KEY_5) then vel = 5; arrancar_juego(); return end if btnp(KEY_6) then vel = 6; arrancar_juego(); return end if btnp(KEY_7) then vel = 7; arrancar_juego(); return end if btnp(KEY_8) then vel = 8; arrancar_juego(); return end if btnp(KEY_9) then vel = 9; arrancar_juego(); return end end function arrancar_juego() sfx_select() nueva_partida() set_estado(ESTADO_JUEGO) end -- ============================================================ -- ESTADOS — JUEGO -- ============================================================ function update_juego() -- Input: bomba if btnp(KEY_SPACE) then lanzar_bomba() end -- Tic del avión (según velocidad) if cnt() - ultimo_tic_avion >= tics_por_paso_avion() then ultimo_tic_avion = cnt() avanza_avion() if estado ~= ESTADO_JUEGO then return end -- aterrizó o chocó end -- Tic de la bomba (ritmo propio, independiente) if bomba.activa and (cnt() - bomba.ultimo_tic) >= TICS_BOMBA then bomba.ultimo_tic = cnt() avanza_bomba() end -- Render pintar_fondo() pintar_mapa() pintar_suelo() pintar_bomba() pintar_avion() pintar_hud() end -- ============================================================ -- ESTADOS — ATERRIZAJE (transición con pausa de ms) -- ============================================================ function update_aterriza() pintar_fondo() pintar_mapa() pintar_suelo() pintar_avion() pintar_hud() color(COL_PROMPT, COL_FONDO) print(" ATERRIZAJE ! ", 13, 10) if tiempo_en_estado_ms() >= MS_ATERRIZAJE then siguiente_pantalla() set_estado(ESTADO_JUEGO) end end -- ============================================================ -- ESTADOS — CHOQUE (animación de explosión sobre el avión) -- ============================================================ function update_choque() pintar_fondo() pintar_mapa() pintar_suelo() pintar_hud() -- Pintar el avión con explosión parpadeante en su posición local fr = tiempo_en_estado_fr() local idx = (fr // 4) % #COL_EXPLOSION + 1 color(COL_EXPLOSION[idx], COL_FONDO) local glifo = (fr // 2) % 2 == 0 and EXPLO_A or EXPLO_B print(chr(glifo), avion.x, avion.y) print(chr(glifo), avion.x+1, avion.y) if tiempo_en_estado_ms() >= MS_CHOQUE then vidas = vidas - 1 if vidas <= 0 then -- Game over: ¿récord? if puntos > maxi then maxi = puntos nom_record = "AAA" record_letra_idx = 1 hay_nuevo_record = true else hay_nuevo_record = false end sfx_gameover() set_estado(ESTADO_GAMEOVER) else reset_avion() set_estado(ESTADO_JUEGO) end end end -- ============================================================ -- ESTADOS — GAME OVER -- ============================================================ function update_gameover() pintar_fondo() pintar_mapa() pintar_suelo() pintar_hud() color(COL_GAMEOVER, COL_FONDO) print(" G A M E O V E R ", 10, 10) color(COL_TEXTO, COL_FONDO) print("Puntos: "..string.format("%05d", puntos), 14, 13) if hay_nuevo_record then color(COL_RECORD, COL_FONDO) print("NUEVO RECORD!", 13, 15) print("Nombre: "..nom_record, 14, 17) if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa A..Z (3 letras)", 9, 19) end if tiempo_en_estado_ms() >= MS_GAMEOVER_MIN then for sc = KEY_A, KEY_Z do if btnp(sc) then local lt = string.char(65 + sc - KEY_A) nom_record = string.sub(nom_record, 1, record_letra_idx-1) ..lt.. string.sub(nom_record, record_letra_idx+1) record_letra_idx = record_letra_idx + 1 sfx_select() if record_letra_idx > 3 then guardar_record() hay_nuevo_record = false set_estado(ESTADO_TITULO) end return end end end else if (cnt() // 30) % 2 == 0 then color(COL_PROMPT, COL_FONDO) print("Pulsa ESPACIO para volver", 8, 18) end if tiempo_en_estado_ms() >= MS_GAMEOVER_MIN and btnp(KEY_SPACE) then set_estado(ESTADO_TITULO) end end end -- ============================================================ -- BUCLE PRINCIPAL -- ============================================================ function init() wintitle("© 1984 Bombardero — Dave Town") mode(MODO) border(COL_FONDO) color(COL_TEXTO, COL_FONDO) definir_glifos() init_mapa() cargar_record() set_estado(ESTADO_TITULO) cls() end function update() if btnp(KEY_ESCAPE) then os.exit(0) end if estado == ESTADO_TITULO then update_titulo() elseif estado == ESTADO_INSTRUC then update_instruc() elseif estado == ESTADO_NIVEL then update_nivel() elseif estado == ESTADO_VELOCIDAD then update_velocidad() elseif estado == ESTADO_JUEGO then update_juego() elseif estado == ESTADO_ATERRIZA then update_aterriza() elseif estado == ESTADO_CHOQUE then update_choque() elseif estado == ESTADO_GAMEOVER then update_gameover() end end