diff --git a/pepe_runner.lua b/pepe_runner.lua index b648d60..b85dfc1 100644 --- a/pepe_runner.lua +++ b/pepe_runner.lua @@ -20,22 +20,31 @@ COL_ESCALA = COLOR_LIGHT_GRAY -- 7 COL_CORDA = COLOR_LIGHT_GRAY -- 7 COL_BUIT = COLOR_BLACK -- 0 --- Estats del Pepe (com en TIPOS.PAS) -NORMAL = 0 -CAENT = 4 +-- 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) +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) -- Estat global mapa = {} -- mapa[x][y] = { tipo=, color=, temps= } level = 1 pepe = { x=19, y=23, dibuix=PEPE_C, color=COLOR_WHITE, vides=0, estat=NORMAL } +malos = {} score = 0 diners_pantalla = 0 +game_tic = 0 function definir_glifs() setchar(BUIT, 0,0,0,0,0,0,0,0) @@ -178,6 +187,165 @@ function mort_pepe() pepe.estat = NORMAL 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(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) + if m.carrega.ok then + local c = mapa[m.carrega.x][m.carrega.y] + c.tipo = DINERS + c.color = COL_DINERS + diners_pantalla = diners_pantalla + 1 + 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 +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 + -- Anima els forats: decrementa temps i cambia el tipus segons la fase -- (idem case statement de CheckMapa al RUNNER.PAS) function check_mapa() @@ -211,6 +379,7 @@ function init() color(COLOR_LIGHT_GRAY, COLOR_BLACK) definir_glifs() carregar_mapa(level) + init_malos() cls() end @@ -223,12 +392,19 @@ function update() -- 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() end -- Render: cada frame cls() pintar_mapa() + pintar_malos() pintar_pepe() end