Files
enne2 4af402f8bf Add Alt+F to toggle fullscreen and window mode
New remappable action `toggle_fullscreen` (Alt+F) handled in main.gd::_input(),
so it works in the menu, during a match with the pointer captured and in the boss
sandbox; the event is marked handled so the key does not reach the rest of the game.

toggle_fullscreen() switches between WINDOW_MODE_FULLSCREEN and WINDOW_MODE_WINDOWED;
the state lives in main.fullscreen (initialised from the real window mode) instead of
querying the driver on every press, so the toggle is deterministic and testable. On
Web it is a no-op because fullscreen belongs to the page.

Desktop HUD hint updated. New tools/test_fullscreen_shortcut.gd: 8 checks (action and
key mapping, alternation, bare F inert, works mid-match without freeing the cursor).
Verified on a real display: window_get_mode 0 -> 3 -> 0.
2026-10-24 12:55:15 +02:00

7.2 KiB
Raw Permalink Blame History

Modalità arcade/kiosk (macchina condivisa) e build Linux

1. Regola di flusso

Il gioco è installato su un computer condiviso. Il profilo precedente non viene mai dato per scontato:

  • il campo del nome del menu è sempre presente e vuoto a ogni avvio e a ogni riavvio;
  • alla morte (game over) il profilo viene sbloccato e il nome liberato, così al ritorno al menu — R o pulsante RICOMINCIA — viene richiesto il nome della nuova partita;
  • senza nome scritto la partita non parte (GIOCA non emette started), perché un punteggio senza nome sarebbe anonimo in classifica.

Il name lock delle versioni precedenti (zombie_fps_locked = 1 → menu con giocatore: Mat e nessun campo) è ignorato: Profile.is_name_locked() restituisce false con ALWAYS_ASK_NAME. I profili vecchi e i valori di localStorage arrivano ancora letti, ma solo come chiave del miglior punteggio.

Identità (backend invariato, API pubblica così com'è): player_id nasce dal nome inserito, player_id_for_name() = FNV-1a 32 bit con due semi → 16 caratteri esadecimali, accettato dal server (8–64 [A-Za-z0-9_-]). Stesso nome = stessa persona anche dopo un riavvio; nome diverso = identità diversa. Il record è tenuto per nome (bests nel file .cfg).

Permalink del flusso: start_screen.gd::_start() → main.gd::start_game() (id e best del nome, leaderboard.player_id, player.begin_play()) → morte → main.gd::_on_player_died() (record_best con il nome della partita appena conclusa, unlock_name, salvataggio, reset_for_new_player()) → reload → menu con campo vuoto.

1b. Cursore del mouse

Bug risolto: player.gd::_ready() catturava il pointer (MOUSE_MODE_CAPTURED) alla costruzione del giocatore, cioè prima del menu, quindi il cursore era già bloccato sulla schermata iniziale e i pulsanti non erano cliccabili.

  • player.gd::_ready() imposta sempre MOUSE_MODE_VISIBLE.
  • La cattura avviene solo in player.gd::begin_play(), chiamata da main.gd::start_game() quando si preme GIOCA.
  • Nuovo flag player.playing: Esc (pausa) e il click sul Web catturano il cursore solo durante la partita, mai nel menu.
  • In modalità touch il cursore non viene catturato (serve ai controlli on-screen).
  • Alla morte _die() lo riporta visibile, quindi la schermata di morte è cliccabile.

File toccati

File Modifica
scripts/player_profile.gd ALWAYS_ASK_NAME, player_id_for_name(), fnv1a32(), best_for_name(), record_best(), unlock_name(); nome non presupposto, record per nome
scripts/start_screen.gd campo del nome sempre mostrato e vuoto, reset_for_new_player(), GIOCA bloccato a campo vuoto
scripts/main.gd start_game() deriva id e record dal nome e chiama player.begin_play(); _on_player_died() sblocca il profilo e invia il nome della partita conclusa
scripts/player.gd cursore visibile al menu, begin_play() con la cattura, flag playing
scripts/game_hud.gd promemoria dei comandi desktop aggiornato con Alt+F
tools/test_player_profile.gd 30 controlli (campo libero, id derivato, record per nome, game over)
tools/test_start_screen.gd 15 controlli (campo sempre richiesto, partenza bloccata a campo vuoto, campo liberato dopo il game over, cursore libero al menu e catturato solo in partita)

1c. Scorciatoia Alt+F (finestra / schermo intero)

  • Azione in project.godot: toggle_fullscreen = Alt+F (rimappabile dal pannello Input Map come le altre).
  • Gestita in main.gd::_input(), quindi vale sempre: menu, partita (anche con il cursore catturato) e sandbox del boss. L'evento viene marcato come gestito, così il tasto non arriva al resto del gioco.
  • main.gd::toggle_fullscreen() alterna WINDOW_MODE_FULLSCREEN e WINDOW_MODE_WINDOWED; lo stato vive in main.fullscreen, inizializzato dalla modalità reale della finestra. Nel browser non fa nulla (il fullscreen è della pagina).
  • Verificato su display reale: window_get_mode 0 (finestra) → 3 (schermo intero) → 0.
  • tools/test_fullscreen_shortcut.gd: 8 controlli (azione e tasto mappati, alternanza, F da solo inerte, funzionamento in partita senza liberare il cursore).

2. Verifiche eseguite

G="$HOME/.local/opt/godot-4.7.1/Godot_v4.7.1-stable_linux.x86_64"
"$G" --headless --path . --script res://tools/test_player_profile.gd     # 30/30 PASS
"$G" --path . --rendering-method gl_compatibility --script res://tools/test_start_screen.gd   # 15/15 PASS
# suite precedenti, riuscite dopo la modifica:
"$G" --headless --path . --script res://tools/test_boss.gd                # 50/50
"$G" --headless --path . --script res://tools/test_rebalance_branding.gd  # 14/14
"$G" --headless --path . --script res://tools/test_spawn_windows.gd
"$G" --headless --path . --script res://tools/test_wave_growth.gd
"$G" --headless --path . --script res://tools/test_gameplay_improvements.gd
"$G" --headless --path . --script res://tools/test_fullscreen_shortcut.gd       # 8/8 PASS
python3 tools/test_scores_api.py                                          # 42/42

Nessuna modifica al backend: nessun cambiamento a nginx, Docker, API o database. La release Web pubblicata (https://enne2.net/pub/zombie-fps/) resta quella precedente finché non viene riesportata e rimpiantata con questa regola.

3. Build Linux portabile

export_presets.cfg → preset.1 (name Linux, platform Linux):

export_filter="all_resources"
exclude_filter="addons/*,tools/*,docs/*,build/*,assets/**/*.mdl,assets/half_life_manifest.json"
export_path="build/linux/work_death_balance.x86_64"
binary_format/embed_pck=true
binary_format/architecture="x86_64"
  • PCK incorporato: sul kiosk serve un solo file (work_death_balance.x86_64, 80.517.080 byte = template 73.470.264 + PCK 7.046.808), verificato eseguendolo da una cartella vuota (--headless -- --smoke → SMOKE: wave=0 alive=0 player_hp=100.0).
  • Dipendenze dinamica minime: libc, libm, librt, libpthread, libdl + ld-linux-x86-64.so.2. Nessuna libstdc++ (già linkata staticamente nel template).
  • Baseline glibc del template ufficiale 4.7.1: simboli richiesti fino a GLIBC_2.28 (readelf -V) → il binario gira su glibc ≥ 2.28 (distro dal 2018 in poi). È il miglior risultato ottenibile senza ricompilare l'engine.
  • musl statico scartato: un binario completamente statico non carica le librerie grafiche, perché i driver OpenGL/Vulkan linkano glibc (funziona solo headless). Non è adatto a un gioco con finestra.
  • Runtime richiesto sul kiosk (non linkato, caricato a runtime): driver OpenGL (Compatibility) o Vulkan (Forward+, renderer nativo attuale), X11 o Wayland, ALSA o PulseAudio. Sono dlopen, quindi non rompono la portabilità del binario.
  • Attenzione: # dentro export_presets.cfg non è un commento per il parser → una riga commentata dopo binary_format/embed_pck=true ha fatto esportare il PCK separato.

Avvio sul kiosk

La build nativa non ha un'origine di pagina, quindi la classifica va indicata esplicitamente (è la stessa API pubblica già in uso):

./work_death_balance.x86_64 --api=https://enne2.net/api/zombie-fps/

Senza --api= la classifica è disattiva di proposito (una build di prova non deve poter scrivere alla classifica pubblica).