fase 4: enemics i IA
This commit is contained in:
+183
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user