-- ============================================================ -- GUANTE BLANCO — port a la fantasy console "ascii" del original -- de David Radisic para Amstrad CPC (AMSOFT, 1985). -- Sergi Valor, 2026. -- -- FASE 1: estructura base. Las 5 habitaciones se dibujan con -- sus paredes, puertas, ventanas y conmutadores. Tecla 1..5 -- conmuta la habitación visible para verificar el render. -- ============================================================ -- ============================================================ -- CONFIGURACION -- ============================================================ MODO = 3 -- mode(3) = 32x24 ANCHO = 32 ALTO = 24 -- Layout (HUD/banners alrededor del área de habitación) FILA_BANNER = 0 -- "Habitacion: X" FILA_MSG = 23 -- mensajes "Choque", "MORDIDO" AREA_Y0 = 1 -- primera fila donde se pinta la habitación AREA_Y1 = 22 -- última fila -- Ritmo del movimiento del jugador (frames entre pasos) TICS_JUGADOR = 4 -- Generación procedural (líneas 1000-1170 del original): -- joyar = INT(RND*8) + 2 → 2..9 joyas por habitación -- objr = INT(RND*10) + 5 → 5..14 obstáculos por habitación JOYAS_MIN = 2 JOYAS_RND = 8 OBJ_MIN = 5 OBJ_RND = 10 -- Retardo del perro (línea 60): empieza en 200, cada choque ruidoso resta 50, -- mínimo 50. La activación del perro la maneja la Fase 4. RETARDO_INI = 200 RETARDO_MIN = 50 RETARDO_STEP = 50 RUIDO_RND = 15 RUIDO_UMBRAL = 10 -- AFTER de BASIC del CPC trabaja en 1/50 s (jiffies de 20 ms). El original -- programa "AFTER retardo*4, 1 GOSUB 310" → retardo*4 jiffies = retardo*80 ms. MS_POR_JIFFY = 20 -- Cada cuántos movimientos del jugador avanza el perro (línea 1650: perro -- alterna 1,2 y solo se mueve cuando == 2 → 1 paso de perro cada 2 del jugador). PERRO_RATIO = 2 -- Duraciones de transición (ms) MS_ESCAPE = 2500 MS_MORDIDO = 1500 MS_PREGUNTA_MIN = 600 -- antes de aceptar S/N -- Estados de la máquina global ESTADO_PASE = "pase" ESTADO_JUEGO = "juego" ESTADO_ESCAPE = "escape" ESTADO_MORDIDO = "mordido" ESTADO_PREGUNTA = "pregunta" ESTADO_FIN = "fin" -- ============================================================ -- PALETA (mapeo CPC firmware → CGA disponible) -- Original: INK 0,0 (negro) / 1,26 (pastel) / 2,15 (blanco) / -- 3,25 (pastel verde) / 4,14 (amarillo) / 5,24,12 (parpadeo) / -- 6,0 (negro al inicio, luego 24,12) / 7,8 = paper de la habit. -- ============================================================ COL_FONDO = COLOR_BLACK COL_LADRON = COLOR_WHITE -- INK 1 pastel COL_PUERTA = COLOR_LIGHT_GRAY -- INK 2 blanco COL_VENTANA = COLOR_YELLOW -- INK 4 COL_CONMUT = COLOR_LIGHT_GREEN -- INK 3 COL_JOYA = COLOR_LIGHT_RED -- INK 5 (parpadeo en original) COL_OBSTACULO = COLOR_BROWN -- INK 6 COL_PERRO = COLOR_WHITE -- INK 1 COL_PARED = COLOR_LIGHT_BLUE -- el rectángulo L original era PEN 1 azul COL_PAPER_HAB_ON = COLOR_DARK_GRAY -- paper de la habitación con luz (INK 7,10) COL_PAPER_HAB_OFF = COLOR_BLACK -- paper de la habitación sin luz (INK 7,0) COL_TEXTO = COLOR_LIGHT_GRAY COL_MSG = COLOR_LIGHT_RED -- ============================================================ -- GLIFOS (códigos que vamos a redefinir con setchar) -- ============================================================ GL_LADRON = 224 -- hombre$ = chr(224) GL_LADRON_M = 225 -- ladrón "mordido" (línea 2570 del original) GL_VENT_H = 250 -- ventana horizontal (2 chars) GL_VENT_V = 251 -- ventana vertical (3 chars verticales) GL_PUERTA_H = 252 -- puerta horizontal GL_PUERTA_V = 253 -- puerta vertical GL_PERRO = 255 -- el perro GL_JOYA = 144 -- joya$ = chr(144) GL_OBSTACULO = 233 -- obj$ = chr(233) GL_CONM_L_OFF = 246 -- conm$(1,0) GL_CONM_L_ON = 247 -- conm$(1,1) GL_CONM_R_OFF = 248 -- conm$(2,0) GL_CONM_R_ON = 249 -- conm$(2,1) GL_PARED = 143 -- nuestro char de pared (el original usaba DRAW de líneas) -- ============================================================ -- TIPOS DE CELDA DEL MAPA -- ============================================================ T_VACIO = 0 T_PARED = 1 T_PUERTA_H = 2 T_PUERTA_V = 3 T_VENT_H = 4 T_VENT_V = 5 T_CONM_L = 6 T_CONM_R = 7 T_JOYA = 8 T_OBSTACULO = 9 T_PERRO = 10 -- ============================================================ -- DEFINIR GLIFOS (bitmaps idénticos a los SYMBOL del original -- cuando los hay, diseñados a mano cuando vienen del char-ROM -- CPC y no aparecen en el .bas). -- ============================================================ function definir_glifos() -- SYMBOL 240..245 del original (partes del sprite del ladrón -- y/o decoración — el código los ignora en colisiones con -- "IF ASC(ht$)>239 AND ASC(ht$)<246 THEN 1520") setchar(240, 8, 8, 8, 8, 8, 8, 8, 8) setchar(241, 0, 0, 0, 0, 255, 0, 1, 0) setchar(242, 0, 0, 0, 0, 15, 8, 8, 8) setchar(243, 0, 0, 0, 0, 248, 8, 8, 8) setchar(244, 8, 8, 8, 8, 248, 0, 0, 0) setchar(245, 8, 8, 8, 8, 15, 0, 0, 0) -- SYMBOL 246..249 — conmutadores L/R, on/off (bitmaps literales) setchar(GL_CONM_L_OFF, 8, 12, 13, 14, 12, 12, 8, 8) setchar(GL_CONM_L_ON, 8, 12, 12, 14, 13, 12, 9, 8) setchar(GL_CONM_R_OFF, 8, 24, 88, 56, 24, 24, 8, 8) setchar(GL_CONM_R_ON, 8, 24, 24, 56, 88, 24, 8, 8) -- SYMBOL 250..253 — ventanas y puertas (bitmaps literales) setchar(GL_VENT_H, 0, 0, 255, 129, 129, 129, 255, 0) setchar(GL_VENT_V, 28, 20, 20, 20, 20, 20, 20, 28) setchar(GL_PUERTA_H, 0, 0, 255, 255, 255, 255, 255, 0) setchar(GL_PUERTA_V, 28, 28, 28, 28, 28, 28, 28, 28) -- SYMBOL 255 — el perro (bitmap literal del original) setchar(GL_PERRO, 195, 165, 60, 126, 90, 60, 36, 24) -- chr 224 (ladrón normal) y 225 (ladrón mordido): el original usaba -- las caritas del char-ROM CPC tal cual. En ascii el charset trae -- esas mismas caritas en los mismos códigos, así que no se redefinen. -- Pared: bloque sólido para el rectángulo L del original setchar(GL_PARED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF) end -- ============================================================ -- DEFINICIÓN DE LAS 5 HABITACIONES -- Coordenadas tomadas LITERALMENTE de las DATAs del bombardero.bas: -- - minx, miny, maxx, maxy: interior (líneas 3020-3060) -- - puertas D y ventanas W: posición en pared (líneas 2680-3010) -- - conmutadores S: posición en pared, orient L/R -- - dir: N, S, E, O (-1 = bloqueado, 0 = escape, n = id habitación) -- ============================================================ HABITACIONES = { [1] = { nombre = "Pasillo", minx = 5, miny = 4, maxx = 8, maxy = 21, elementos = { { tipo="puerta_h", x=6, y=3 }, -- N: a dir[1]=0 (escape) { tipo="puerta_h", x=6, y=22 }, -- S: a dir[2]=4 (Cocina) { tipo="puerta_v", x=4, y=12 }, -- O: a dir[4]=2 (Sala) { tipo="puerta_v", x=9, y=11 }, -- E: a dir[3]=3 (Comedor) { tipo="conm", x=4, y=11, orient="L", on=false }, { tipo="conm", x=9, y=14, orient="R", on=false }, }, dir = { 0, 4, 3, 2 }, -- N, S, E, O luz = false, }, [2] = { nombre = "Sala", minx = 3, miny = 4, maxx = 9, maxy = 21, elementos = { { tipo="puerta_v", x=10, y=12 }, -- E: a dir[3]=1 (Pasillo) { tipo="vent_h", x=6, y=3 }, -- N (bloqueado, dir[1]=-1) { tipo="vent_v", x=2, y=12 }, -- O (bloqueado, dir[4]=-1) { tipo="conm", x=10, y=11, orient="R", on=false }, { tipo="conm", x=10, y=15, orient="R", on=false }, }, dir = { -1, -1, 1, -1 }, luz = false, }, [3] = { nombre = "Comedor", minx = 3, miny = 4, maxx = 9, maxy = 21, elementos = { { tipo="vent_v", x=10, y=12 }, -- E (bloqueado, dir[3]=-1) { tipo="vent_h", x=6, y=3 }, -- N (bloqueado, dir[1]=-1) { tipo="puerta_v", x=2, y=12 }, -- O: a dir[4]=1 (Pasillo) { tipo="conm", x=2, y=11, orient="L", on=false }, { tipo="conm", x=2, y=15, orient="L", on=false }, }, dir = { -1, -1, -1, 1 }, luz = false, }, [4] = { nombre = "Cocina", minx = 3, miny = 6, maxx = 13, maxy = 21, elementos = { { tipo="puerta_h", x=6, y=5 }, -- N: a dir[1]=1 (Pasillo) { tipo="puerta_h", x=6, y=22 }, -- S: a dir[2]=0 (escape) { tipo="vent_h", x=10, y=22 }, -- otra ventana en la pared S { tipo="vent_v", x=14, y=13 }, -- E (bloqueado, dir[3]=-1) { tipo="puerta_v", x=2, y=13 }, -- O: a dir[4]=5 (Despensa) { tipo="conm", x=2, y=16, orient="L", on=false }, }, dir = { 1, 0, -1, 5 }, luz = false, }, [5] = { nombre = "Despensa", minx = 3, miny = 6, maxx = 9, maxy = 21, elementos = { { tipo="puerta_v", x=10, y=12 }, -- E: a dir[3]=4 (Cocina) { tipo="conm", x=10, y=11, orient="R", on=false }, }, dir = { -1, -1, 4, -1 }, luz = false, }, } -- ============================================================ -- ESTADO GLOBAL -- ============================================================ rm = 1 -- habitación actual (variable rm del original) xp, yp = 6, 4 -- posición del ladrón hombre_glifo = GL_LADRON mapa = {} -- mapa[hab][x][y] = tipo de celda ultimo_tic = 0 -- contador de frames para temporizar el movimiento escapado = false -- se activa al alcanzar dir=0 (Fase 5 muestra el final) muerto = false -- se activa al ser mordido por el perro (Fase 4) -- Joyas y obstáculos (listas paralelas al mapa por habitación) joyas_lista = {} -- joyas_lista[rm] = { {x,y}, ... } obj_lista = {} -- obj_lista[rm] = { {x,y}, ... } joyas_total = 0 -- total inicial (suma de las 5 habitaciones) robado = 0 -- joyas recogidas por el ladrón mensaje_msg = "" -- mensaje de la fila inferior (Choque, etc.) retardo = RETARDO_INI -- Máquina de estados estado = ESTADO_PASE estado_t0_ms = 0 -- Perro guardián perro = { activo = false, -- perro==1 del original rm = 0, -- habitación donde se activó x = 0, y = 0, -- posición paso = 0, -- alterna 0/1 para PERRO_RATIO (línea 1650) pendiente = false, -- AFTER programado pero aún no disparado pend_t = 0, -- time() en que se disparará el AFTER } -- ============================================================ -- CONSTRUCCIÓN DEL MAPA LÓGICO -- Por habitación se construye una matriz [x][y] con el tipo de -- celda. Las paredes son el contorno (minx-1, maxx+1, miny-1, -- maxy+1). Las puertas, ventanas y conmutadores sobrescriben la -- pared. El interior queda como T_VACIO (se rellenará con joyas -- y obstáculos en la Fase 3). -- ============================================================ function init_mapa() for id, hab in pairs(HABITACIONES) do mapa[id] = {} for x = 0, ANCHO-1 do mapa[id][x] = {} for y = 0, ALTO-1 do mapa[id][x][y] = T_VACIO end end -- Paredes: contorno del rectángulo interior local x0, y0 = hab.minx - 1, hab.miny - 1 local x1, y1 = hab.maxx + 1, hab.maxy + 1 for x = x0, x1 do mapa[id][x][y0] = T_PARED mapa[id][x][y1] = T_PARED end for y = y0, y1 do mapa[id][x0][y] = T_PARED mapa[id][x1][y] = T_PARED end -- Elementos: sobrescriben la pared for _, e in ipairs(hab.elementos) do if e.tipo == "puerta_h" then mapa[id][e.x ][e.y] = T_PUERTA_H mapa[id][e.x+1][e.y] = T_PUERTA_H elseif e.tipo == "vent_h" then mapa[id][e.x ][e.y] = T_VENT_H mapa[id][e.x+1][e.y] = T_VENT_H elseif e.tipo == "puerta_v" then mapa[id][e.x][e.y ] = T_PUERTA_V mapa[id][e.x][e.y+1] = T_PUERTA_V mapa[id][e.x][e.y+2] = T_PUERTA_V elseif e.tipo == "vent_v" then mapa[id][e.x][e.y ] = T_VENT_V mapa[id][e.x][e.y+1] = T_VENT_V mapa[id][e.x][e.y+2] = T_VENT_V elseif e.tipo == "conm" then mapa[id][e.x][e.y] = (e.orient == "L") and T_CONM_L or T_CONM_R end end end end -- ============================================================ -- OFFSET DE CENTRADO -- En cada render, calcula el offset (off_x, off_y) para centrar -- el rectángulo de la habitación (paredes incluidas) dentro del -- área de juego. -- ============================================================ function offset_centrado() local hab = HABITACIONES[rm] local w = (hab.maxx + 1) - (hab.minx - 1) + 1 local h = (hab.maxy + 1) - (hab.miny - 1) + 1 local off_x = flr((ANCHO - w) / 2) - (hab.minx - 1) local off_y = flr((AREA_Y0 + AREA_Y1 - h) / 2) - (hab.miny - 1) + 1 return off_x, off_y end -- ============================================================ -- RENDER -- ============================================================ function pintar_fondo() color(COL_TEXTO, COL_FONDO) cls() end function pintar_banner() color(COL_TEXTO, COL_FONDO) print("Habitacion: "..HABITACIONES[rm].nombre, 1, FILA_BANNER) end function glifo_de(tipo, on) if tipo == T_PARED then return GL_PARED end if tipo == T_PUERTA_H then return GL_PUERTA_H end if tipo == T_PUERTA_V then return GL_PUERTA_V end if tipo == T_VENT_H then return GL_VENT_H end if tipo == T_VENT_V then return GL_VENT_V end if tipo == T_CONM_L then return on and GL_CONM_L_ON or GL_CONM_L_OFF end if tipo == T_CONM_R then return on and GL_CONM_R_ON or GL_CONM_R_OFF end if tipo == T_JOYA then return GL_JOYA end if tipo == T_OBSTACULO then return GL_OBSTACULO end if tipo == T_PERRO then return GL_PERRO end return nil end function color_de(tipo) if tipo == T_PARED then return COL_PARED end if tipo == T_PUERTA_H then return COL_PUERTA end if tipo == T_PUERTA_V then return COL_PUERTA end if tipo == T_VENT_H then return COL_VENTANA end if tipo == T_VENT_V then return COL_VENTANA end if tipo == T_CONM_L then return COL_CONMUT end if tipo == T_CONM_R then return COL_CONMUT end if tipo == T_JOYA then return COL_JOYA end if tipo == T_OBSTACULO then return COL_OBSTACULO end if tipo == T_PERRO then return COL_PERRO end return COL_TEXTO end -- Devuelve el "estado on/off" de un conmutador concreto buscando en -- los elementos de la habitación. function conm_estado(hab, x, y) for _, e in ipairs(hab.elementos) do if e.tipo == "conm" and e.x == x and e.y == y then return e.on end end return false end function pintar_habitacion() local hab = HABITACIONES[rm] local off_x, off_y = offset_centrado() local paper = hab.luz and COL_PAPER_HAB_ON or COL_PAPER_HAB_OFF -- Paper del interior color(COL_TEXTO, paper) local blank = " " for y = hab.miny, hab.maxy do for x = hab.minx, hab.maxx do print(blank, x + off_x, y + off_y) end end -- Paredes y elementos. Las joyas y obstáculos solo se ven con la luz -- encendida (línea 1280 del original: INK 7,10 ↔ INK 7,0). for y = hab.miny - 1, hab.maxy + 1 do for x = hab.minx - 1, hab.maxx + 1 do local t = mapa[rm][x][y] if t ~= T_VACIO then local oculto = (not hab.luz) and (t == T_JOYA or t == T_OBSTACULO) if not oculto then local on = false if t == T_CONM_L or t == T_CONM_R then on = conm_estado(hab, x, y) end local g = glifo_de(t, on) if g then local bg = (t == T_JOYA or t == T_OBSTACULO) and paper or COL_FONDO color(color_de(t), bg) print(chr(g), x + off_x, y + off_y) end end end end end -- Perro (si está activo y comparte habitación con el ladrón) if perro.activo and perro.rm == rm then color(COL_PERRO, paper) print(chr(GL_PERRO), perro.x + off_x, perro.y + off_y) end -- El ladrón color(COL_LADRON, paper) print(chr(hombre_glifo), xp + off_x, yp + off_y) end -- Marcador lateral de joyas robadas: una marca vertical por joya, replicando -- el "MOVE 400,150+(robado*2):DRAW 555,150+(robado*2)" del original. function pintar_marcador() color(COL_JOYA, COL_FONDO) print("Joyas", 26, 1) print(string.format("%02d", robado), 27, 2) for i = 1, robado do local y = AREA_Y1 - (i - 1) if y >= 4 then print(chr(154), 28, y) end end end function pintar_msg() if mensaje_msg ~= "" then color(COL_MSG, COL_FONDO) print(mensaje_msg, 4, FILA_MSG) end end -- ============================================================ -- GENERACIÓN PROCEDURAL DE JOYAS Y OBSTÁCULOS -- Líneas 980-1170 del original. Las posiciones se eligen al -- azar dentro del interior, sin comprobar conflictos (fiel al -- original — una joya/obstáculo puede caer encima de otra). -- ============================================================ function generar_objetos() joyas_total = 0 robado = 0 joyas_lista = {} obj_lista = {} for id, hab in pairs(HABITACIONES) do joyas_lista[id] = {} obj_lista[id] = {} local nj = rnd(JOYAS_RND) + JOYAS_MIN local no = rnd(OBJ_RND) + OBJ_MIN for i = 1, nj do local x = rnd(hab.maxx - hab.minx + 1) + hab.minx local y = rnd(hab.maxy - hab.miny + 1) + hab.miny joyas_lista[id][#joyas_lista[id] + 1] = { x=x, y=y } mapa[id][x][y] = T_JOYA joyas_total = joyas_total + 1 end for i = 1, no do local x = rnd(hab.maxx - hab.minx + 1) + hab.minx local y = rnd(hab.maxy - hab.miny + 1) + hab.miny obj_lista[id][#obj_lista[id] + 1] = { x=x, y=y } if mapa[id][x][y] ~= T_JOYA then mapa[id][x][y] = T_OBSTACULO end end end end -- ============================================================ -- TOGGLE DE CONMUTADOR Y LUZ (líneas 1700-1740 del original) -- ============================================================ function toggle_conmutador(x, y) local hab = HABITACIONES[rm] for _, e in ipairs(hab.elementos) do if e.tipo == "conm" and e.x == x and e.y == y then e.on = not e.on break end end hab.luz = not hab.luz -- línea 1730: luces(rm) XOR 1 sfx_conm() end -- ============================================================ -- RECOGIDA DE JOYAS (líneas 1980-2090 del original) -- El bucle recoge TODAS las joyas que estén en (x,y) — fiel al -- "GOTO 1990" del original. -- ============================================================ function recoger_joyas_en(x, y) local i = 1 while i <= #joyas_lista[rm] do local j = joyas_lista[rm][i] if j.x == x and j.y == y then table.remove(joyas_lista[rm], i) robado = robado + 1 sfx_joya() else i = i + 1 end end mapa[rm][x][y] = T_VACIO end -- ============================================================ -- CHOQUE CONTRA OBSTÁCULO (líneas 2100-2170 del original) -- ============================================================ function chocar_obstaculo() local ruido = rnd(RUIDO_RND) sfx_obstaculo(ruido) mensaje_msg = "Choque" if ruido >= RUIDO_UMBRAL and retardo > RETARDO_MIN then retardo = retardo - RETARDO_STEP -- AFTER retardo*4, 1 GOSUB 310 (línea 2160 del original) programar_perro(retardo * 4 * MS_POR_JIFFY) end end -- ============================================================ -- PERRO GUARDIÁN (líneas 310-330, 1650, 2560-2670 del original) -- ============================================================ function programar_perro(ms) perro.pendiente = true perro.pend_t = time() + ms end -- Rutina 310 del original: activa el perro si no lo estaba ya. function activar_perro() if perro.activo then return end perro.activo = true perro.rm = rm perro.x = HABITACIONES[rm].minx perro.y = HABITACIONES[rm].miny perro.paso = 0 hombre_glifo = GL_LADRON_M -- línea 2570: hombre$ = chr(225) end function hay_perro_en(rm_, x, y) return perro.activo and perro.rm == rm_ and perro.x == x and perro.y == y end -- Rutina 2560 del original: el perro se mueve 1 char hacia el jugador. function mover_perro() if not perro.activo then return end if perro.rm ~= rm then return end -- solo activo en su habitación -- Si ya está sobre el jugador, mordido (línea 2580) if perro.x == xp and perro.y == yp then muerto = true return end if perro.x < xp then perro.x = perro.x + 1 elseif perro.x > xp then perro.x = perro.x - 1 end if perro.y < yp then perro.y = perro.y + 1 elseif perro.y > yp then perro.y = perro.y - 1 end if perro.x == xp and perro.y == yp then muerto = true return end sfx_ladrido() end -- Llamada después de cada movimiento exitoso del jugador (línea 1650). function tick_perro_post_jugador() if not perro.activo then return end if perro.rm ~= rm then return end perro.paso = (perro.paso + 1) % PERRO_RATIO if perro.paso == 0 then mover_perro() end end -- Llamada cada frame: dispara la activación si ha vencido el AFTER. function tick_perro_pendiente() if perro.pendiente and time() >= perro.pend_t then perro.pendiente = false activar_perro() end end -- ============================================================ -- SFX -- ============================================================ function sfx_joya() sound(2000, 6) end function sfx_obstaculo(r) sound(3000, 5 + r) end function sfx_conm() sound(800, 3) end function sfx_ladrido() sound(rnd(40) + 60, 6) end -- ============================================================ -- MOVIMIENTO Y CAMBIO DE HABITACIÓN -- Reproducción de la lógica de las líneas 1520-1900 del original. -- ============================================================ -- Aplica la nueva posición del ladrón tras cambiar a otra habitación, -- según la dirección por la que ha entrado (línea 1810-1840 original). function aplicar_dir(dir) local hab = HABITACIONES[rm] if dir == 1 then xp = 6; yp = hab.maxy elseif dir == 2 then xp = 6; yp = hab.miny elseif dir == 3 then xp = hab.minx; yp = 13 elseif dir == 4 then xp = hab.maxx; yp = 13 end end -- Resuelve el cambio de habitación dada una dirección (1=N, 2=S, 3=E, 4=O). -- dir(rm, dir) = -1 → bloqueado; = 0 → escapar; = n → ir a habitación n. function cambiar_a_dir(dir) local destino = HABITACIONES[rm].dir[dir] if destino == -1 then return end if destino == 0 then escapado = true return end rm = destino aplicar_dir(dir) end -- Dirección estándar según el vector de movimiento (xf, yf). -- Original: línea 1770-1780 — prioridad al eje vertical si yf != 0. function dir_de_movimiento(xf, yf) local dir if xf < 0 then dir = 4 elseif xf > 0 then dir = 3 end if yf < 0 then dir = 1 elseif yf > 0 then dir = 2 end return dir end -- Parche del Pasillo para ventanas H (líneas 1860-1900 del original): -- según xp (no xf/yf), decide la dirección de salida. function dir_vent_h() if xp > 5 and xp < 8 then if yp > 13 then return 2 else return 1 end else if xp < 6 then return 4 else return 3 end end end -- Intenta mover el ladrón en (xf, yf). Replica la cadena gol del -- original (línea 1670 y siguientes). function mover_jugador(xf, yf) if xf == 0 and yf == 0 then return end local nx, ny = xp + xf, yp + yf -- Perro (gol=11): si la celda destino tiene el perro, mordido directo if hay_perro_en(rm, nx, ny) then muerto = true return end local t = mapa[rm][nx][ny] -- Conmutador (gol=1..4): toggle luz, no se mueve if t == T_CONM_L or t == T_CONM_R then toggle_conmutador(nx, ny) return end -- Puerta H o V (gol=5,6): cambio de habitación con dirección estándar if t == T_PUERTA_H or t == T_PUERTA_V then local d = dir_de_movimiento(xf, yf) if d then cambiar_a_dir(d) end return end -- Ventana H (gol=7): parche del Pasillo if t == T_VENT_H then cambiar_a_dir(dir_vent_h()) return end -- Ventana V (gol=8): escape directo (línea 1910 del original) if t == T_VENT_V then escapado = true return end -- Pared: bloqueada if t == T_PARED then return end -- Joya (gol=9): mover y recoger if t == T_JOYA then xp, yp = nx, ny recoger_joyas_en(nx, ny) mensaje_msg = "" tick_perro_post_jugador() return end -- Obstáculo (gol=10): no mueve, ruido if t == T_OBSTACULO then chocar_obstaculo() return end -- Vacío: mover xp, yp = nx, ny mensaje_msg = "" tick_perro_post_jugador() end -- ============================================================ -- MÁQUINA DE ESTADOS -- ============================================================ function set_estado(s) estado = s estado_t0_ms = time() end function tiempo_estado_ms() return time() - estado_t0_ms end -- Reset completo del estado de partida (equivale al RUN del original). function reset_partida() init_mapa() generar_objetos() retardo = RETARDO_INI mensaje_msg = "" rm = 1 xp = 6 yp = 4 escapado = false muerto = false hombre_glifo = GL_LADRON perro.activo = false perro.pendiente = false perro.paso = 0 end -- ----- PANTALLA PASE (líneas 720-960 del original) ----- function update_pase() pintar_fondo() color(COL_LADRON, COL_FONDO) print("- P A S E -", 11, 1) color(COL_TEXTO, COL_FONDO) print("Puertas y ventanas para escapar", 1, 3) -- Leyenda de simbolos (líneas 840-930 del original) color(COL_LADRON, COL_FONDO) print(chr(GL_LADRON).." Usted, el ladron", 2, 6) color(COL_PUERTA, COL_FONDO) print(chr(GL_PUERTA_H)..chr(GL_PUERTA_V).." Puertas", 2, 8) color(COL_CONMUT, COL_FONDO) print(chr(GL_CONM_L_OFF)..chr(GL_CONM_R_OFF).." Luces apagadas", 2, 10) print(chr(GL_CONM_L_ON) ..chr(GL_CONM_R_ON) .." Luces encendidas", 2, 11) color(COL_VENTANA, COL_FONDO) print(chr(GL_VENT_H)..chr(GL_VENT_V).." Ventanas", 2, 13) color(COL_JOYA, COL_FONDO) print(chr(GL_JOYA).." Piedras preciosas", 2, 15) color(COL_OBSTACULO, COL_FONDO) print(chr(GL_OBSTACULO).." Obstaculos", 2, 17) color(COL_PERRO, COL_FONDO) print(chr(GL_PERRO).." El perro", 2, 19) if (cnt() // 30) % 2 == 0 then color(COL_LADRON, COL_FONDO) print("Pulsa ESPACIO para empezar", 3, 22) end if btnp(KEY_SPACE) then reset_partida() set_estado(ESTADO_JUEGO) end end -- ----- JUEGO ----- function update_juego() tick_perro_pendiente() if (cnt() - ultimo_tic) >= TICS_JUGADOR then local xf, yf = 0, 0 if btn(KEY_UP) then yf = -1 elseif btn(KEY_DOWN) then yf = 1 end if btn(KEY_LEFT) then xf = -1 elseif btn(KEY_RIGHT) then xf = 1 end if xf ~= 0 or yf ~= 0 then mover_jugador(xf, yf) ultimo_tic = cnt() end end pintar_fondo() pintar_banner() pintar_habitacion() pintar_marcador() pintar_msg() if escapado then set_estado(ESTADO_ESCAPE) return end if muerto then set_estado(ESTADO_MORDIDO) return end end -- ----- ESCAPE (líneas 1910-1970 del original) ----- function update_escape() pintar_fondo() color(COL_LADRON, COL_FONDO) print("Usted ha escapado", 2, 3) color(COL_TEXTO, COL_FONDO) print("con", 7, 5) if robado == joyas_total then print("todas las", 7, 7) end color(COL_JOYA, COL_FONDO) print(string.format("%2d", robado), 7, 7 + ((robado == joyas_total) and 2 or 0)) color(COL_LADRON, COL_FONDO) print("joyas", 7, 9 + ((robado == joyas_total) and 2 or 0)) if tiempo_estado_ms() >= MS_ESCAPE then set_estado(ESTADO_PREGUNTA) end end -- ----- MORDIDO (línea 2660 del original) ----- function update_mordido() -- Sigue mostrando el último frame del juego con "MORDIDO" encima pintar_fondo() pintar_banner() pintar_habitacion() pintar_marcador() color(COL_MSG, COL_FONDO) print(" MORDIDO ", 12, FILA_MSG) if tiempo_estado_ms() >= MS_MORDIDO then set_estado(ESTADO_PREGUNTA) end end -- ----- PREGUNTA (líneas 240-300 del original) ----- function update_pregunta() pintar_fondo() color(COL_LADRON, COL_FONDO) print("Quiere jugar", 4, 3) print("otra vez?", 5, 5) color(COL_JOYA, COL_FONDO) print("S/N", 7, 7) if tiempo_estado_ms() < MS_PREGUNTA_MIN then return end if btnp(KEY_S) then reset_partida() set_estado(ESTADO_JUEGO) elseif btnp(KEY_N) then set_estado(ESTADO_FIN) end end -- ----- FIN ----- function update_fin() pintar_fondo() color(COL_LADRON, COL_FONDO) print("F I N", 13, 11) end -- ============================================================ -- BUCLE PRINCIPAL -- ============================================================ function init() wintitle("© 1985 Guante Blanco — David Radisic") mode(MODO) border(COL_FONDO) color(COL_TEXTO, COL_FONDO) definir_glifos() init_mapa() generar_objetos() retardo = RETARDO_INI mensaje_msg = "" rm = 1 xp = 6 yp = 4 escapado = false muerto = false hombre_glifo = GL_LADRON perro.activo = false perro.pendiente = false perro.paso = 0 set_estado(ESTADO_PASE) cls() end function update() if btnp(KEY_ESCAPE) then os.exit(0) end if estado == ESTADO_PASE then update_pase() elseif estado == ESTADO_JUEGO then update_juego() elseif estado == ESTADO_ESCAPE then update_escape() elseif estado == ESTADO_MORDIDO then update_mordido() elseif estado == ESTADO_PREGUNTA then update_pregunta() elseif estado == ESTADO_FIN then update_fin() end end