diff --git a/chuleta_font_ascii.png b/chuleta_font_ascii.png new file mode 100644 index 0000000..5356fa5 Binary files /dev/null and b/chuleta_font_ascii.png differ diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..149df57 --- /dev/null +++ b/config.lua @@ -0,0 +1,22 @@ +-- Configuracio del Pepe Runner DX +-- Aquest fitxer es carrega amb dofile() al iniciar el joc. +-- Si no existeix o te errors, s'usen els valors per defecte. +-- Comenta una linia (--) per a deixar el seu valor per defecte. + +-- ==================================================================== +-- ASPECTE GRAFIC +-- ==================================================================== + +-- Skin: quina familia de glifs s'utilitza per a pintar el joc. +-- +-- "custom" — Redefinim els caracters CP437 (estil del Pascal original): +-- bloc solid █, escala ═ doble, corda ─, cara ☻ del Pepe... +-- Es el look "fidel a l'original de 2000". +-- +-- "native" — Usem els glifs ja dibuixats al ROM d'ascii, sense redefinir +-- cap. Per a vore quin glif te cada codi, mira la +-- chuleta_font_ascii.png. Estil mes fantasy console. +-- +-- (En els dos casos el char 0 es reescriu a zeros, perque el ROM d'ascii +-- hi te una caixa hueca que taparia tot el mapa.) +skin = "native" diff --git a/pepe_runner_dx.lua b/pepe_runner_dx.lua new file mode 100644 index 0000000..ab9839b --- /dev/null +++ b/pepe_runner_dx.lua @@ -0,0 +1,676 @@ +-- Pepe Runner DX — versio millorada del port amb QoL i extres. +-- Carrega config.lua si existeix per a sobreescriure els valors per defecte. + +-- ==================================================================== +-- VALORS PER DEFECTE DE CONFIGURACIO (sobreescriuibles per config.lua) +-- ==================================================================== +skin = "custom" -- "custom" | "native" (vore config.lua per descripcio) + +-- Codis CP437 dels sprites del joc original (de TIPOS.PAS). +-- Els usem com a IDs logics de tipus de cel·la (i coincideixen amb el +-- format binari dels .map). El codi de glif real per a pintar surt +-- de la taula glif[] segons la skin activa. +BUIT = 0 +DINERS = 36 +PEDRA = 219 +ESCALA = 205 +CORDA = 196 +BLOC1 = 176 +BLOC2 = 177 +BLOC3 = 178 +PEPE_C = 2 +MALO_C = 88 + +-- Skins: cada skin es una taula tile_id → codi_de_glif_a_pintar. +-- "custom" usa els mateixos codis CP437 (redibuixats amb setchar). +-- "native" remapeja als glifs que ja existeixen al ROM d'ascii +-- (mira chuleta_font_ascii.png per a identificar-los). +SKINS = { + custom = { + [BUIT]=0, [DINERS]=36, [PEDRA]=219, [ESCALA]=205, [CORDA]=196, + [BLOC1]=176, [BLOC2]=177, [BLOC3]=178, + [PEPE_C]=2, [MALO_C]=88, + }, + native = { + [BUIT]=0, [DINERS]=36, [PEDRA]=233, [ESCALA]=61, [CORDA]=45, + [BLOC1]=216, [BLOC2]=218, [BLOC3]=220, + [PEPE_C]=224,[MALO_C]=88, + }, +} +glif = SKINS.custom -- s'actualitza a init() segons la config + +-- Colors (de TIPOS.PAS, paleta CGA — coincideix amb la d'ascii) +COL_PEDRA = COLOR_BROWN -- 6 +COL_DINERS = COLOR_YELLOW -- 14 +COL_ESCALA = COLOR_LIGHT_GRAY -- 7 +COL_CORDA = COLOR_LIGHT_GRAY -- 7 +COL_BUIT = COLOR_BLACK -- 0 + +-- Estats (de TIPOS.PAS — son bitflags per a SelectEstat dels enemics) +NORMAL = 0 +PUJAR = 0x01 +BAIXAR = 0x02 +CAENT = 4 +ESQUERRA = 0x10 +DRETA = 0x20 + +-- Constants del joc +MAP_W = 40 +MAP_H = 25 +BLOC_OUT = 100 -- temps que dura un forat obert (de TIPOS.PAS) +TICS = 6 -- frames per tick de joc (60fps / 6 = 10 Hz) +NUM_MALOS = 3 +TEMPS_IA = 30 -- iteracions del malo entre canvis de direccio +MALO_RATIO = 4 -- els malos van 1/4 del ritme del Pepe (com en RUNNER.PAS) +NUM_FASES = 10 -- mapes 1..10 (el 0 esta reservat per al titol) +VIDES_INI = 3 -- l'original arrancava amb 0 (1 vida); 3 es mes raonable + +-- Estats del joc (maquina d'estats global) +ESTAT_TITLE = "title" +ESTAT_PLAYING = "playing" +ESTAT_GAMEOVER = "gameover" +ESTAT_ENTERNAME = "entername" + +-- Estat global +mapa = {} -- mapa[x][y] = { tipo=, color=, temps= } +level = 1 +pepe = { x=19, y=23, dibuix=PEPE_C, color=COLOR_WHITE, vides=VIDES_INI, estat=NORMAL } +malos = {} +score = 0 +diners_pantalla = 0 +game_tic = 0 +hi_score = 0 +nom_hi_score = "AAA" +estat_joc = ESTAT_TITLE +estat_inici = 0 +enter_name_idx = 1 + +function definir_glifs() + -- Char 0 sempre buit (el ROM d'ascii hi te una caixa que taparia el mapa) + setchar(0, 0,0,0,0,0,0,0,0) + + -- Nomes la skin "custom" redibuixa els glifs CP437. La "native" usa + -- els que ja existeixen al ROM d'ascii (cap setchar mes). + if skin ~= "custom" then return end + + setchar(219, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF) -- PEDRA █ + setchar(36, 0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00) -- DINERS $ + setchar(205, 0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00) -- ESCALA ═ + setchar(196, 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00) -- CORDA ─ + setchar(176, 0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11) -- BLOC1 ░ + setchar(177, 0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55) -- BLOC2 ▒ + setchar(178, 0xBB,0xEE,0xBB,0xEE,0xBB,0xEE,0xBB,0xEE) -- BLOC3 ▓ + setchar(2, 0x7E,0x81,0xA5,0x81,0xBD,0x99,0x81,0x7E) -- PEPE ☻ + setchar(88, 0x00,0xC3,0x66,0x3C,0x18,0x3C,0x66,0xC3) -- MALO X +end + +-- ==================================================================== +-- SFX (l'original no tenia so — afegim els minims raonables) +-- ==================================================================== +function sfx_coin() sound(2000, 40) end +function sfx_dig() play("l0o2c") end +function sfx_die() play("l1o4cl0o3bagfed") end +function sfx_malo_die() play("l0o3ao4c") end +function sfx_level() play("l1o4ceg") end +function sfx_gameover() play("l1o3bal0gfedco2c") end + +function color_de(tipo) + if tipo == PEDRA then return COL_PEDRA end + if tipo == DINERS then return COL_DINERS end + if tipo == ESCALA then return COL_ESCALA end + if tipo == CORDA then return COL_CORDA end + return COL_BUIT +end + +-- Helper segur per llegir el tipus d'una cel·la (fora de mapa = pedra virtual) +function tipo_a(x, y) + if x < 0 or x >= MAP_W or y < 0 or y >= MAP_H then return PEDRA end + return mapa[x][y].tipo +end + +function carregar_mapa(num) + filein("maps/"..tostr(num)..".map", 0, MAP_W*MAP_H) + diners_pantalla = 0 + for x = 0, MAP_W-1 do + mapa[x] = {} + for y = 0, MAP_H-1 do + local tipo = peek(x*MAP_H + y) + mapa[x][y] = { tipo=tipo, color=color_de(tipo), temps=-1 } + if tipo == DINERS then diners_pantalla = diners_pantalla + 1 end + end + end +end + +function pintar_mapa() + for x = 0, MAP_W-1 do + for y = 0, MAP_H-1 do + local c = mapa[x][y] + if c.tipo ~= BUIT then + color(c.color, COL_BUIT) + print(chr(glif[c.tipo]), x, y) + end + end + end +end + +function pintar_pepe() + color(pepe.color, COL_BUIT) + print(chr(glif[pepe.dibuix]), pepe.x, pepe.y) +end + +-- Marca una cel·la com a forat (sols si actualment es pedra) +function foradar(x, y) + if tipo_a(x, y) == PEDRA then + mapa[x][y].temps = BLOC_OUT + end +end + +-- Pot Pepe cavar a esquerra/dreta? Condicions del MouPepe original: +-- - la cel·la diagonal-baix ha de ser pedra (per a obrir-hi forat) +-- - la cel·la lateral no pot ser pedra (per a que Pepe s'hi puga assomar) +-- - Pepe ha d'estar en estat normal (no caent) +function pot_cavar(dx) + return pepe.estat == NORMAL + and tipo_a(pepe.x+dx, pepe.y+1) == PEDRA + and tipo_a(pepe.x+dx, pepe.y) ~= PEDRA +end + +-- Tic de joc del Pepe: input de moviment, gravetat, recollir diners, emparedat +function tic_pepe() + local actual = tipo_a(pepe.x, pepe.y) + local sotto = tipo_a(pepe.x, pepe.y+1) + + -- Moviment vertical: Q/A (com en RUNNER.PAS, son if/else) + if btn(KEY_Q) then + if actual == ESCALA then pepe.y = pepe.y - 1 end + elseif btn(KEY_A) then + if sotto == ESCALA or sotto == BUIT or sotto == DINERS then + pepe.y = pepe.y + 1 + end + end + + -- Moviment horitzontal: O/P (no es pot moure si esta caent) + if btn(KEY_O) then + if tipo_a(pepe.x-1, pepe.y) ~= PEDRA and pepe.estat ~= CAENT then + pepe.x = pepe.x - 1 + end + elseif btn(KEY_P) then + if tipo_a(pepe.x+1, pepe.y) ~= PEDRA and pepe.estat ~= CAENT then + pepe.x = pepe.x + 1 + end + end + + -- Si no passa res especial, estat = normal (gravetat pot canviar-ho mes avall) + pepe.estat = NORMAL + + -- Final pantalla: si arriba a la fila 1, passa al nivel seguent + if pepe.y == 1 then + fase_nova() + return + end + + -- Emparedat: si la cel·la actual s'ha tornat pedra, Pepe mor + if tipo_a(pepe.x, pepe.y) == PEDRA then + mort_pepe() + return + end + + -- Recollir diners + if tipo_a(pepe.x, pepe.y) == DINERS then + mapa[pepe.x][pepe.y].tipo = BUIT + score = score + 1 + diners_pantalla = diners_pantalla - 1 + sfx_coin() + end + + -- Bordes X + if pepe.x < 0 then pepe.x = 0 end + if pepe.x > MAP_W-1 then pepe.x = MAP_W-1 end + + -- Gravetat: si la cel·la actual es buit/diners i la de baix no es escala/pedra → cau + actual = tipo_a(pepe.x, pepe.y) + sotto = tipo_a(pepe.x, pepe.y+1) + if (sotto ~= ESCALA and sotto ~= PEDRA) + and (actual == BUIT or actual == DINERS) then + pepe.y = pepe.y + 1 + pepe.estat = CAENT + end + + -- Bordes Y + if pepe.y < 0 then pepe.y = 0 end + if pepe.y > MAP_H-1 then pepe.y = MAP_H-1 end +end + +function mort_pepe() + pepe.vides = pepe.vides - 1 + pepe.x = 19 + pepe.y = 23 + pepe.estat = NORMAL + sfx_die() +end + +-- Inicialitza tot per a una nova partida (reset complet) +function inicialitzacio() + level = 1 + score = 0 + pepe.vides = VIDES_INI + pepe.x = 19; pepe.y = 23; pepe.estat = NORMAL + carregar_mapa(level) + init_malos() + game_tic = 0 +end + +-- Avanca al nivell seguent (sense reset de score ni vides) +function fase_nova() + level = level + 1 + if level > NUM_FASES then level = 1 end + pepe.x = 19; pepe.y = 23; pepe.estat = NORMAL + carregar_mapa(level) + init_malos() + sfx_level() +end + +-- ==================================================================== +-- ESTATS DEL JOC (title / playing / game over / enter name) +-- ==================================================================== + +function set_estat(nou) + estat_joc = nou + estat_inici = cnt() +end + +function temps_estat() return cnt() - estat_inici end + +-- Records I/O. Usem io.open (estandard de Lua) en lloc de filein/fileout +-- per a poder gestionar el cas de fitxer inexistent sense petar. +-- Format: 6 bytes = 3 (centenes, desenes, unitats del score) + 3 (lletres nom) +function carregar_records() + local f = io.open("records", "rb") + if not f then return end + local data = f:read(6) + f:close() + if not data or #data < 6 then return end + local b = { string.byte(data, 1, 6) } + hi_score = b[1]*100 + b[2]*10 + b[3] + -- Validar que les lletres del nom siguen imprimibles + if b[4] >= 32 and b[4] < 127 + and b[5] >= 32 and b[5] < 127 + and b[6] >= 32 and b[6] < 127 then + nom_hi_score = string.char(b[4], b[5], b[6]) + end +end + +function guardar_records() + local f = io.open("records", "wb") + if not f then return end + f:write(string.char( + flr(hi_score / 100), + flr((hi_score % 100) / 10), + hi_score % 10, + string.byte(nom_hi_score, 1) or 65, + string.byte(nom_hi_score, 2) or 65, + string.byte(nom_hi_score, 3) or 65 + )) + f:close() +end + +-- Quina lletra A-Z s'ha pulsat este frame (escaneig manual amb btnp, +-- perque ascii no exposa whichbtn() al Lua malgrat estar al ascii.h). +function lletra_pulsada() + for sc = KEY_A, KEY_Z do + if btnp(sc) then + return string.char(65 + sc - KEY_A) + end + end + return nil +end + +-- ----- TITLE ----- +function init_title() + carregar_mapa(0) -- mapa 0 es l'art del titol +end + +function update_title() + if btnp(KEY_SPACE) then + inicialitzacio() + set_estat(ESTAT_PLAYING) + return + end + + cls() + pintar_mapa() + + -- "PRESS SPACE TO PLAY" parpadejant + if flr(cnt() / 30) % 2 == 0 then + color(COLOR_WHITE, COLOR_BLACK) + print("PRESS SPACE TO PLAY", 10, 22) + end + + pintar_hud() +end + +-- ----- GAME OVER ----- +function update_gameover() + -- Render congelat: ultim estat del joc + overlay "GAME OVER" + cls() + pintar_mapa() + pintar_malos() + pintar_pepe() + + color(COLOR_LIGHT_RED, COLOR_BLACK) + print("G A M E O V E R", 11, 12) + + pintar_hud() + + -- Despres de 2 segons (120 frames), transicio + if temps_estat() > 120 then + if score > hi_score then + hi_score = score + nom_hi_score = "AAA" + enter_name_idx = 1 + set_estat(ESTAT_ENTERNAME) + else + init_title() + set_estat(ESTAT_TITLE) + end + end +end + +-- ----- ENTER NAME ----- +function update_entername() + cls() + color(COLOR_LIGHT_RED, COLOR_BLACK) + print("NOU RECORD!", 14, 10) + color(COLOR_YELLOW, COLOR_BLACK) + print("SCORE "..string.format("%03d", hi_score), 15, 12) + color(COLOR_WHITE, COLOR_BLACK) + print("NOM: "..nom_hi_score, 16, 15) + print("(A-Z)", 17, 17) + + pintar_hud() + + local lletra = lletra_pulsada() + if lletra then + nom_hi_score = string.sub(nom_hi_score, 1, enter_name_idx-1) + ..lletra.. + string.sub(nom_hi_score, enter_name_idx+1) + enter_name_idx = enter_name_idx + 1 + if enter_name_idx > 3 then + guardar_records() + init_title() + set_estat(ESTAT_TITLE) + end + end +end + +-- ----- PLAYING ----- +function update_playing() + -- Cavar es immediat (un sol forat per pulsacio) + if pepe.estat == NORMAL then + if btnp(KEY_SPACE) and pot_cavar(-1) then foradar(pepe.x-1, pepe.y+1); sfx_dig() end + if btnp(KEY_M) and pot_cavar( 1) then foradar(pepe.x+1, pepe.y+1); sfx_dig() end + end + + -- Logica del joc: cada TICS frames + if (cnt() % TICS) == 0 then + game_tic = game_tic + 1 + tic_pepe() + check_mort_per_malos() + if (game_tic % MALO_RATIO) == 0 then + tic_malos() + check_mort_per_malos() + end + check_mapa() + if pepe.vides < 0 then + sfx_gameover() + set_estat(ESTAT_GAMEOVER) + return + end + end + + -- Render + cls() + pintar_mapa() + pintar_malos() + pintar_pepe() + pintar_hud() +end + +-- ==================================================================== +-- ENEMICS +-- ==================================================================== + +function init_malos() + malos = { + { x= 9, y=2, color=COLOR_CYAN, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, + { x=20, y=2, color=COLOR_CYAN, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, + { x=39, y=2, color=COLOR_CYAN, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, + } +end + +function pintar_malos() + for i = 1, NUM_MALOS do + local m = malos[i] + color(m.color, COL_BUIT) + print(chr(glif[MALO_C]), m.x, m.y) + end +end + +-- Tria una nova direccio per a un enemic (port de SelectEstat de RUNNER.PAS). +-- 50% prob persegueix Pepe, 50% prob direccio aleatoria entre les valides. +-- Si no te suport sota els peus, override a CAENT. +function select_estat(m) + local nou = 0 + if tipo_a(m.x+1, m.y) ~= PEDRA then nou = nou | DRETA end + if tipo_a(m.x-1, m.y) ~= PEDRA then nou = nou | ESQUERRA end + if tipo_a(m.x, m.y) == ESCALA then nou = nou | PUJAR end + if tipo_a(m.x, m.y+1) == ESCALA then nou = nou | BAIXAR end + + local sestat = 0 + if nou == 0 then sestat = 10 end -- atrapat: valor que cap case reconeix + + local pX = (m.x > pepe.x) and ESQUERRA or DRETA + local pY = (m.y > pepe.y) and PUJAR or BAIXAR + + if rnd(100) < 50 and (((nou & pX) == pX) or ((nou & pY) == pY)) then + if (nou & pX) == pX then sestat = pX else sestat = pY end + else + local x = rnd(4) + while sestat == 0 do + if x == 0 and (nou & DRETA) == DRETA then sestat = DRETA + elseif x == 1 and (nou & ESQUERRA) == ESQUERRA then sestat = ESQUERRA + elseif x == 2 and (nou & PUJAR) == PUJAR then sestat = PUJAR + elseif x == 3 and (nou & BAIXAR) == BAIXAR then sestat = BAIXAR + end + x = (x + 1) & 3 + end + end + + -- override de caiguda (igual que en el Pascal — no comprova corda aci, + -- la comprovacio amb corda es fa al tic_malos) + local sotto = tipo_a(m.x, m.y+1) + if sotto ~= PEDRA and sotto ~= ESCALA then sestat = CAENT end + + return sestat +end + +-- Si va horitzontal i hi ha escala adalt/abaix, 80% prob s'enganxa +function agafar_escala(m) + if m.estat == DRETA or m.estat == ESQUERRA then + if rnd(100) < 80 then + if tipo_a(m.x, m.y) == ESCALA then return PUJAR + elseif tipo_a(m.x, m.y+1) == ESCALA then return BAIXAR + end + end + end + return m.estat +end + +-- Mort d'un enemic (per emparedat). Respawn a (39, 1). +-- A diferencia del Pascal, sols solta diners si en duia (l'original sempre +-- escrivia diners a (carrega.x, carrega.y), deixant un $ a (0,0) com a bug). +function mort_malo(m) + -- El comptador diners_pantalla NO canvia: l'enemic agafant/soltant es + -- transitori, sols compta el que el Pepe recull definitivament. + if m.carrega.ok then + local c = mapa[m.carrega.x][m.carrega.y] + c.tipo = DINERS + c.color = COL_DINERS + end + m.x = 39; m.y = 1 + m.color = COLOR_CYAN + m.estat = CAENT + m.iaclock = 0 + m.carrega.ok = false + m.carrega.x = 0 + m.carrega.y = 0 + sfx_malo_die() +end + +function tic_malos() + for i = 1, NUM_MALOS do + local m = malos[i] + + if m.iaclock == 0 then m.estat = select_estat(m) end + m.estat = agafar_escala(m) + + local actual = tipo_a(m.x, m.y) + local sotto = tipo_a(m.x, m.y+1) + + -- caiguda (aquesta SI comprova corda — els malos s'agafen a la corda) + if sotto ~= PEDRA and sotto ~= ESCALA and actual ~= CORDA then + m.estat = CAENT + end + -- si toca terra i venia caent → reconsidera + if (sotto == PEDRA or sotto == ESCALA) and m.estat == CAENT then + m.estat = select_estat(m) + end + -- si vol pujar pero no esta en escala → reconsidera + if actual == BUIT and m.estat == PUJAR then + m.estat = select_estat(m) + end + -- si vol baixar pero te pedra sota → reconsidera + if sotto == PEDRA and m.estat == BAIXAR then + m.estat = select_estat(m) + end + + -- aplicar moviment + if m.estat == DRETA then m.x = m.x + 1 + elseif m.estat == ESQUERRA then m.x = m.x - 1 + elseif m.estat == PUJAR then m.y = m.y - 1 + elseif m.estat == BAIXAR then m.y = m.y + 1 + elseif m.estat == CAENT then m.y = m.y + 1 + end + + -- bordes X (rebot) + if m.x < 0 then m.x = 0; m.estat = DRETA end + if m.x > MAP_W-1 then m.x = MAP_W-1; m.estat = ESQUERRA end + -- bordes Y (clamp) + if m.y < 0 then m.y = 0 end + if m.y > MAP_H-1 then m.y = MAP_H-1 end + + -- agafar diners + if tipo_a(m.x, m.y) == DINERS and not m.carrega.ok then + mapa[m.x][m.y].tipo = BUIT + m.color = COLOR_LIGHT_CYAN + m.carrega.ok = true + m.carrega.x = m.x + m.carrega.y = m.y + end + + -- emparedat → mort + if tipo_a(m.x, m.y) == PEDRA then + mort_malo(m) + end + + m.iaclock = m.iaclock + 1 + if m.iaclock == TEMPS_IA then m.iaclock = 0 end + end +end + +function check_mort_per_malos() + for i = 1, NUM_MALOS do + if malos[i].x == pepe.x and malos[i].y == pepe.y then + mort_pepe() + return + end + end +end + +-- Si Pepe ha recollit tots els diners, fa apareixer una escala a la columna 0 +-- des de la fila 1 cap avall, parant si troba pedra. (CheckMapaComplet) +function check_mapa_complet() + if diners_pantalla > 0 then return end + for j = 1, MAP_H-2 do + if mapa[0][j].tipo == PEDRA then break end + mapa[0][j].tipo = ESCALA + mapa[0][j].color = COL_ESCALA + end +end + +-- Anima els forats: decrementa temps i cambia el tipus segons la fase +-- (idem case statement de CheckMapa al RUNNER.PAS) +function check_mapa() + for x = 0, MAP_W-1 do + for y = 0, MAP_H-1 do + local c = mapa[x][y] + local t = c.temps + if t == 0 then + c.temps = -1 + c.tipo = PEDRA + c.color = COL_PEDRA + elseif t == 1 or t == BLOC_OUT-1 then + c.tipo = BLOC3; c.color = COL_PEDRA; c.temps = t - 1 + elseif t == 2 or t == BLOC_OUT-2 then + c.tipo = BLOC2; c.color = COL_PEDRA; c.temps = t - 1 + elseif t == 3 or t == BLOC_OUT-3 then + c.tipo = BLOC1; c.color = COL_PEDRA; c.temps = t - 1 + elseif t == 4 or t == BLOC_OUT-4 then + c.tipo = BUIT; c.color = COL_BUIT; c.temps = t - 1 + elseif t > 0 then + c.temps = t - 1 + end + -- t == -1 → idle, no fer res + end + end + check_mapa_complet() +end + +-- HUD: rotul inferior amb level/score/vides/hi-score sobre banda blava +function pintar_hud() + color(COLOR_LIGHT_GRAY, COLOR_BLUE) + local blank = " " + print(blank, 0, 25) + print(blank, 0, 26) + print(blank, 0, 27) + print(" LEVEL "..string.format("%02d", level), 0, 26) + print("SCORE "..string.format("%03d", score), 14, 26) + print("LIVES "..tostr(pepe.vides), 28, 26) + print("HI-SCORE "..string.format("%03d", hi_score).." "..nom_hi_score, 9, 27) +end + +-- Carrega config.lua si existeix. Si falta o te errors, queden els defaults. +function carregar_config() + pcall(dofile, "config.lua") +end + +function init() + carregar_config() + glif = SKINS[skin] or SKINS.custom + mode(1) + border(COLOR_BLUE) + color(COLOR_LIGHT_GRAY, COLOR_BLACK) + definir_glifs() + carregar_records() + init_title() + set_estat(ESTAT_TITLE) + cls() +end + +function update() + if estat_joc == ESTAT_TITLE then update_title() + elseif estat_joc == ESTAT_PLAYING then update_playing() + elseif estat_joc == ESTAT_GAMEOVER then update_gameover() + elseif estat_joc == ESTAT_ENTERNAME then update_entername() + end +end