From 7e29b4b6a2a0db0c114ddcfa8709409b35d27d79 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 15 May 2026 18:34:46 +0200 Subject: [PATCH] DX: malos atrapats als forats, com en Lode Runner classic --- config.lua | 1 + pepe_runner_dx.lua | 170 +++++++++++++++++++++++++++++++++------------ 2 files changed, 127 insertions(+), 44 deletions(-) diff --git a/config.lua b/config.lua index 9a83c85..88f1a53 100644 --- a/config.lua +++ b/config.lua @@ -43,6 +43,7 @@ skin = "native" -- colors.pepe_invuln = COLOR_LIGHT_GREEN -- parpadeig en invulnerabilitat -- colors.malo = COLOR_LIGHT_RED -- enemics -- colors.malo_carrega = COLOR_LIGHT_MAGENTA -- enemic portant diners +-- colors.malo_atrapat = COLOR_BROWN -- enemic atrapat en un forat -- colors.hud_text = COLOR_WHITE -- text del rotul inferior -- colors.hud_bg = COLOR_BLACK -- fons del rotul inferior -- colors.border = COLOR_BLUE -- vora exterior de la finestra diff --git a/pepe_runner_dx.lua b/pepe_runner_dx.lua index 123d960..f6336c4 100644 --- a/pepe_runner_dx.lua +++ b/pepe_runner_dx.lua @@ -79,6 +79,7 @@ colors = { pepe_invuln = COLOR_LIGHT_GREEN, -- parpadeig de Pepe quan es invulnerable malo = COLOR_LIGHT_RED, malo_carrega = COLOR_LIGHT_MAGENTA, -- enemic portant diners + malo_atrapat = COLOR_BROWN, -- enemic atrapat en un forat (color de pedra) hud_text = COLOR_WHITE, hud_bg = COLOR_BLACK, border = COLOR_BLUE, @@ -307,6 +308,23 @@ function tipo_a(x, y) return mapa[x][y].tipo end +-- Es comporta com una paret (impedeix passar lateralment, fa de suport): +-- PEDRA, qualsevol fase de forat tancant-se (BLOC1/2/3) o un malo atrapat. +-- Aço unifica el comportament: "rellenat" o "rellenant" → solid. +function es_paret(x, y) + local t = tipo_a(x, y) + if t == PEDRA or t == BLOC1 or t == BLOC2 or t == BLOC3 then return true end + for i = 1, NUM_MALOS do + if malos[i].atrapat and malos[i].x == x and malos[i].y == y then return true end + end + return false +end + +-- Es comporta com a suport per a no caure (paret + escala). +function es_suport(x, y) + return es_paret(x, y) or tipo_a(x, y) == ESCALA +end + function carregar_mapa(num) filein("maps/"..tostr(num)..".map", 0, MAP_W*MAP_H) diners_pantalla = 0 @@ -390,7 +408,7 @@ end 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 + and not es_paret(pepe.x+dx, pepe.y) end -- Tic de joc del Pepe: input de moviment, gravetat, recollir diners, emparedat @@ -398,22 +416,26 @@ function tic_pepe() local actual = tipo_a(pepe.x, pepe.y) local sotto = tipo_a(pepe.x, pepe.y+1) - -- Moviment vertical (com en RUNNER.PAS, son if/else) + -- Moviment vertical (com en RUNNER.PAS, son if/else). + -- Bloquegem entrar dins de qualsevol cel·la "paret" (inclou malos atrapats). if btn(keys.up) then - if actual == ESCALA then pepe.y = pepe.y - 1 end + if actual == ESCALA and not es_paret(pepe.x, pepe.y-1) then + pepe.y = pepe.y - 1 + end elseif btn(keys.down) then - if sotto == ESCALA or sotto == BUIT or sotto == DINERS then + if not es_paret(pepe.x, pepe.y+1) + and (sotto == ESCALA or sotto == BUIT or sotto == DINERS) then pepe.y = pepe.y + 1 end end -- Moviment horitzontal (no es pot moure si esta caent) if btn(keys.left) then - if tipo_a(pepe.x-1, pepe.y) ~= PEDRA and pepe.estat ~= CAENT then + if not es_paret(pepe.x-1, pepe.y) and pepe.estat ~= CAENT then pepe.x = pepe.x - 1 end elseif btn(keys.right) then - if tipo_a(pepe.x+1, pepe.y) ~= PEDRA and pepe.estat ~= CAENT then + if not es_paret(pepe.x+1, pepe.y) and pepe.estat ~= CAENT then pepe.x = pepe.x + 1 end end @@ -446,10 +468,9 @@ function tic_pepe() 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 + -- Gravetat: si la cel·la actual es buit/diners i la de baix no fa de suport → cau actual = tipo_a(pepe.x, pepe.y) - sotto = tipo_a(pepe.x, pepe.y+1) - if (sotto ~= ESCALA and sotto ~= PEDRA) + if not es_suport(pepe.x, pepe.y+1) and (actual == BUIT or actual == DINERS) then pepe.y = pepe.y + 1 pepe.estat = CAENT @@ -726,11 +747,12 @@ end -- ==================================================================== function init_malos() - malos = { - { x= 9, y=2, color=colors.malo, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, - { x=20, y=2, color=colors.malo, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, - { x=39, y=2, color=colors.malo, estat=ESQUERRA, iaclock=0, carrega={ok=false, x=0, y=0} }, - } + local function novo(x, y) + return { x=x, y=y, color=colors.malo, estat=ESQUERRA, iaclock=0, + carrega={ok=false, x=0, y=0}, atrapat=false, + dropped_x=nil, dropped_y=nil } + end + malos = { novo(9, 2), novo(20, 2), novo(39, 2) } end function pintar_malos() @@ -746,8 +768,8 @@ end -- 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 not es_paret(m.x+1, m.y) then nou = nou | DRETA end + if not es_paret(m.x-1, m.y) 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 @@ -773,8 +795,7 @@ function select_estat(m) -- 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 + if not es_suport(m.x, m.y+1) then sestat = CAENT end return sestat end @@ -795,56 +816,106 @@ end -- 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. + -- Cas A: encara duu carrega (no era atrapat) → solta al lloc original. + -- Cas B: era atrapat i ja havia soltat la carrega sobre la cabeça → + -- si l'has sepultat (cel·la torna a ser pedra), restaura al + -- lloc original perque el mapa segueix sent acabable. if m.carrega.ok then local c = mapa[m.carrega.x][m.carrega.y] c.tipo = DINERS c.color = colors.diners + elseif m.dropped_x then + local t = mapa[m.dropped_x][m.dropped_y].tipo + -- BUIT = Pepe la va recollir; DINERS = encara hi es; pedra/bloc = sepultada + if t ~= BUIT and t ~= DINERS then + local c = mapa[m.carrega.x][m.carrega.y] + c.tipo = DINERS + c.color = colors.diners + end end m.x = 39; m.y = 1 m.color = colors.malo m.estat = CAENT m.iaclock = 0 + m.atrapat = false m.carrega.ok = false m.carrega.x = 0 m.carrega.y = 0 + m.dropped_x = nil + m.dropped_y = nil sfx_malo_die() end +-- Marca un enemic com a atrapat en un forat obert. Es queda quiet fins +-- que la cel·la es rellena (i llavors mor per emparedat). Solta la carrega +-- de forma immediata sobre la cabeça (o al lloc original si la cabeça no +-- pot acollir-la). +function atrapar(m) + if m.atrapat then return end + m.atrapat = true + m.estat = NORMAL + m.color = colors.malo_atrapat + + if m.carrega.ok then + local cy = m.y - 1 + if cy >= 0 and mapa[m.x][cy].tipo == BUIT and mapa[m.x][cy].temps <= 0 then + mapa[m.x][cy].tipo = DINERS + mapa[m.x][cy].color = colors.diners + m.dropped_x = m.x + m.dropped_y = cy + else + -- cabeça ocupada o fora de mapa: fallback al lloc original + mapa[m.carrega.x][m.carrega.y].tipo = DINERS + mapa[m.carrega.x][m.carrega.y].color = colors.diners + m.dropped_x = m.carrega.x + m.dropped_y = m.carrega.y + end + m.carrega.ok = false + end +end + function tic_malos() for i = 1, NUM_MALOS do local m = malos[i] + -- Malo atrapat: nomes comprovem si la cel·la s'ha rellenat (emparedat). + -- No es mou, no agafa diners, no reaccionara fins que muiga. + if m.atrapat then + if tipo_a(m.x, m.y) == PEDRA then mort_malo(m) end + goto seguent + end + 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) + do + local actual = tipo_a(m.x, m.y) - -- 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) + -- caiguda (aquesta SI comprova corda — els malos s'agafen a la corda) + if not es_suport(m.x, m.y+1) and actual ~= CORDA then + m.estat = CAENT + end + -- si toca terra i venia caent → reconsidera + if es_suport(m.x, m.y+1) 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 paret sota → reconsidera + if es_paret(m.x, m.y+1) and m.estat == BAIXAR then + m.estat = select_estat(m) + end 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 + -- aplicar moviment (nomes si la cel·la desti no es paret; + -- aixi els malos no es fiquen dins d'altres malos atrapats) + if m.estat == DRETA and not es_paret(m.x+1, m.y) then m.x = m.x + 1 + elseif m.estat == ESQUERRA and not es_paret(m.x-1, m.y) then m.x = m.x - 1 + elseif m.estat == PUJAR and not es_paret(m.x, m.y-1) then m.y = m.y - 1 + elseif m.estat == BAIXAR and not es_paret(m.x, m.y+1) then m.y = m.y + 1 + elseif m.estat == CAENT and not es_paret(m.x, m.y+1) then m.y = m.y + 1 end -- bordes X (rebot) @@ -863,11 +934,21 @@ function tic_malos() m.carrega.y = m.y end + -- caure dins d'un forat obert (BUIT cavat) → atrapat. No comprovem + -- suport sota: en el Lode Runner classic el malo queda agarrat al + -- vora del forat encara que sota hi haja aire (forats "flotants" + -- a una planta amb buit a sota també atrapen el malo que cau). + if mapa[m.x][m.y].tipo == BUIT and mapa[m.x][m.y].temps > 0 then + atrapar(m) + end + -- emparedat → mort if tipo_a(m.x, m.y) == PEDRA then mort_malo(m) end + ::seguent:: + m.iaclock = m.iaclock + 1 if m.iaclock == TEMPS_IA then m.iaclock = 0 end end @@ -876,7 +957,8 @@ end function check_mort_per_malos() if pepe.invuln_t > 0 or pepe.mort_t > 0 then return end for i = 1, NUM_MALOS do - if malos[i].x == pepe.x and malos[i].y == pepe.y then + local m = malos[i] + if not m.atrapat and m.x == pepe.x and m.y == pepe.y then mort_pepe() return end