Files
guante-blanco-amstrad-ascii/guante_blanco.lua
T

397 lines
15 KiB
Lua

-- ============================================================
-- 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
-- ============================================================
-- 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
-- ============================================================
-- 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
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 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
color(color_de(t), COL_FONDO)
print(chr(g), x + off_x, y + off_y)
end
end
end
end
-- El ladrón
color(COL_LADRON, paper)
print(chr(hombre_glifo), xp + off_x, yp + off_y)
end
-- ============================================================
-- BUCLE PRINCIPAL — FASE 1
-- Solo render estático. Teclas 1..5 cambian habitación visible.
-- ============================================================
function init()
mode(MODO)
border(COL_FONDO)
color(COL_TEXTO, COL_FONDO)
definir_glifos()
init_mapa()
rm = 1
-- Posición inicial del ladrón en cada habitación (centrada-ish)
xp = flr((HABITACIONES[rm].minx + HABITACIONES[rm].maxx) / 2)
yp = HABITACIONES[rm].miny + 2
cls()
end
function update()
-- FASE 1: navegación manual entre habitaciones para verificar
if btnp(KEY_1) then rm = 1 end
if btnp(KEY_2) then rm = 2 end
if btnp(KEY_3) then rm = 3 end
if btnp(KEY_4) then rm = 4 end
if btnp(KEY_5) then rm = 5 end
-- Tecla L para alternar la luz de la habitación actual (debug)
if btnp(KEY_L) then HABITACIONES[rm].luz = not HABITACIONES[rm].luz end
-- Reposicionar al ladrón al cambiar de habitación
local hab = HABITACIONES[rm]
if xp < hab.minx or xp > hab.maxx or yp < hab.miny or yp > hab.maxy then
xp = flr((hab.minx + hab.maxx) / 2)
yp = hab.miny + 2
end
pintar_fondo()
pintar_banner()
pintar_habitacion()
color(COL_TEXTO, COL_FONDO)
print("1..5 hab. L luz", 1, FILA_MSG)
end