DX: malos atrapats als forats, com en Lode Runner classic

This commit is contained in:
2026-05-15 18:34:46 +02:00
parent 5b3b0b3f6a
commit 7e29b4b6a2
2 changed files with 127 additions and 44 deletions
+1
View File
@@ -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
+126 -44
View File
@@ -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