DX: game over amb typewriter, cuadre de fons i Pepe trist

This commit is contained in:
2026-05-15 21:04:36 +02:00
parent 64bb710531
commit 5aca78a38e
2 changed files with 97 additions and 15 deletions
+89 -14
View File
@@ -69,7 +69,7 @@ keys = {
-- Tots en sentence case (Inicial Majuscula, resta minuscula).
textos = {
title_press_play = "Prem l'espai per a jugar",
game_over = "Fi de joc",
game_over = "FI DE JOC",
new_record = "Nou record !",
score_label = "Punts", -- HUD i pantalla de nou record
level_label = "Nivell",
@@ -96,7 +96,14 @@ 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
-- VIDES_INI = nombre de reserves (convencio arcade: el HUD mostra reserves,
-- no compta la vida actual). 2 reserves = 3 vides totals (1 actual + 2).
-- L'original arrancava amb 0 (= 1 vida total).
-- TEMPORAL DEBUG: posa'l a 0 per a provar la seqüencia de game over rapid.
VIDES_INI = 0
-- LEVEL_INI = fase per la que arranca la partida nova (1..NUM_FASES).
-- Util per a depuracio i per a saltar al mapa que vols provar.
LEVEL_INI = 3
-- Tots els temps i durations de les animacions del DX. Sobreescriuibles
-- per config.lua (en frames a 60 fps; 60 = 1 segon).
@@ -107,6 +114,9 @@ temps = {
respawn_delay_frames = 120, -- temps que Pepe queda invisible abans del respawn (2 s)
invuln_frames = 180, -- temps invulnerable despres del respawn (3 s)
escala_step_frames = 6, -- frames entre cada cel·la nova de l'escala lateral (0.1 s)
gameover_delay_frames = 15, -- espera al entrar a game over abans d'engegar el typewriter
typewriter_step_frames = 8, -- frames per cada lletra del typewriter de "FI DE JOC"
gameover_show_frames = 120, -- frames que el text final queda visible abans de la transicio
}
-- Estats del joc (maquina d'estats global)
@@ -297,6 +307,7 @@ 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 sfx_typewriter() sound(2500, 2) end -- tic agut i molt curt per a cada lletra
-- Neteja la pantalla amb el color de fons configurat (en lloc de negre).
function neteja_fons()
@@ -376,16 +387,38 @@ function pintar_pepe()
local col = colors.pepe
local g = glif[pepe.dibuix]
-- En game over, Pepe queda visible amb la cara trista alternant A/B
-- (parpadeig amb cnt() perque mort_t ja no es decrementa fora de playing).
if estat_joc == ESTAT_GAMEOVER then
if (cnt() % 12) < 6 then
g = glif[PEPE_MORT_A]
col = colors.pepe_mort_a
else
g = glif[PEPE_MORT_B]
col = colors.pepe_mort_b
end
color(col, colors.bg)
print(chr(g), pepe.x, pepe.y)
return
end
if pepe.mort_t > 0 then
-- En l'ultima vida no hi ha respawn_delay: tot el countdown es anim.
local mort_t_max
if pepe.vides == 0 then
mort_t_max = temps.mort_anim_frames
else
mort_t_max = temps.mort_anim_frames + temps.respawn_delay_frames
end
-- Fase d'espera (Pepe invisible, mapa segueix viu): no pintem res.
if pepe.mort_t <= temps.respawn_delay_frames then return end
local fase = mort_t_max - pepe.mort_t -- 0..mort_t_max-1
if fase >= temps.mort_anim_frames then return end
-- Animacio visual de mort, en dos trams desproporcionats (1/4 + 3/4):
-- tram curt: parpadeja blanc/roig amb la cara normal del Pepe.
-- tram llarg: alterna entre els dos sprites de mort de la skin
-- (pepe_mort_a / pepe_mort_b), cada un amb el seu color propi.
local fase = (temps.mort_anim_frames + temps.respawn_delay_frames)
- pepe.mort_t -- 0..mort_anim_frames-1
local tram_curt = flr(temps.mort_anim_frames / 4)
if fase < tram_curt then
col = (fase % 6 < 3) and colors.malo or colors.pepe
@@ -500,12 +533,21 @@ end
-- Inicia l'animacio de mort. El timer mort_t cobreix dos trams seguits:
-- [delay+1 .. delay+anim] → animacio visual de Pepe morint
-- [1 .. delay] → Pepe invisible, mapa segueix viu (pausa)
-- Si es l'ultima vida (vides==0), saltem el delay: l'animacio termina i
-- anem directament a game over, sense pausa invisible.
-- Al arribar a 0, update_playing descompta vida i fa el respawn.
-- Guarda contra reentrada per a no reiniciar si ja esta morint.
function mort_pepe()
if pepe.mort_t > 0 then return end
pepe.mort_t = temps.mort_anim_frames + temps.respawn_delay_frames
sfx_die()
if pepe.vides == 0 then
-- Ultima vida: directament sona sfx_gameover (no sfx_die seguit de
-- sfx_gameover, eren molt semblants i es solapaven com a doble eco).
pepe.mort_t = temps.mort_anim_frames
sfx_gameover()
else
pepe.mort_t = temps.mort_anim_frames + temps.respawn_delay_frames
sfx_die()
end
end
-- Reposiciona Pepe al spawn i activa la invulnerabilitat.
@@ -519,7 +561,7 @@ end
-- Inicialitza tot per a una nova partida (reset complet)
function inicialitzacio()
level = 1
level = LEVEL_INI
score = 0
score_display = 0
pepe.vides = VIDES_INI
@@ -626,20 +668,53 @@ end
-- ----- GAME OVER -----
function update_gameover()
set_music(nil)
-- Render congelat: ultim estat del joc + overlay "GAME OVER"
-- Render congelat: mapa + malos + Pepe trist (pintar_pepe detecta l'estat)
neteja_fons()
pintar_mapa()
pintar_malos()
pintar_pepe()
color(colors.title, colors.bg)
-- Typewriter: les lletres apareixen una a una despres d'un petit delay
-- inicial perque no es solapin amb la sonoritat de sfx_gameover().
-- Aban apareix un cuadre de fons (strlen+2 × 3) per a aillar el text
-- del mapa que queda darrere.
local g = textos.game_over
print(g, flr((40 - strlen(g)) / 2), 12)
local t = temps_estat() - temps.gameover_delay_frames
if t >= 0 then
local total_chars = strlen(g)
local frames_typewriter = total_chars * temps.typewriter_step_frames
local text_x = flr((40 - total_chars) / 2)
local text_y = 12
-- Cuadre de fons: una fila per damunt i una per davall del text,
-- i una columna a cada costat. Es pinta primer per a que el text
-- quede a sobre.
local box_w = total_chars + 2
color(colors.hud_bg, colors.hud_bg)
local blank = string.rep(" ", box_w)
for dy = -1, 1 do print(blank, text_x - 1, text_y + dy) end
-- Lletres del typewriter
local nletres = flr(t / temps.typewriter_step_frames) + 1
if nletres > total_chars then nletres = total_chars end
color(colors.title, colors.hud_bg)
print(substr(g, 0, nletres), text_x, text_y)
-- Tic nomes en el frame en que apareix una lletra nova, i nomes
-- mentre el typewriter encara escriu (no en bucle infinit).
if t < frames_typewriter and (t % temps.typewriter_step_frames) == 0 then
sfx_typewriter()
end
end
pintar_hud()
-- Despres de 2 segons (120 frames), transicio a title o entername
if not fade_actiu() and temps_estat() > 120 then
-- Quan el typewriter ha acabat i el text ha estat visible un temps,
-- transicionem a title o a la pantalla d'entrar nom (si hi ha record).
local total = temps.gameover_delay_frames
+ strlen(g) * temps.typewriter_step_frames
+ temps.gameover_show_frames
if not fade_actiu() and temps_estat() > total then
if score > hi_score then
transicio(function()
hi_score = score
@@ -708,7 +783,7 @@ function update_playing()
if pepe.mort_t == 0 then
pepe.vides = pepe.vides - 1
if pepe.vides < 0 then
sfx_gameover()
-- sfx_gameover ja s'ha tocat al inici de l'animacio (mort_pepe)
set_estat(ESTAT_GAMEOVER)
return
end