Every game over unlocks the profile and frees the name, so the menu always asks for a new player name: the field is empty at every boot, restart or game over and the game does not start without a name (no anonymous scores). The player identity is derived from the entered name (deterministic FNV-1a, 16 hex chars valid for the public API) and the profile keeps the best score per name. Backend untouched. Mouse: player._ready() captured the pointer before the menu existed, so the start screen was not clickable. The cursor now always starts visible; the capture happens only in player.begin_play(), called by start_game(). New `playing` flag gates Esc and the Web click capture to the actual match. Linux export preset: single-file x86_64 binary with the PCK embedded, no libstdc++ dependency, official 4.7.1 template (glibc >= 2.28). Notes and the export_presets.cfg `#`-is-not-a-comment trap documented in docs/KIOSK-ARCADE.md. Tests: profile 30/30, start screen 15/15 (cursor free at menu, captured only in game), boss 50/50, rebalance 14/14, touch 14 PASS, API 42/42, all other suites pass.
6.2 KiB
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 —
Ro pulsanteRICOMINCIA— viene richiesto il nome della nuova partita; - senza nome scritto la partita non parte (
GIOCAnon emettestarted), 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 sempreMOUSE_MODE_VISIBLE.- La cattura avviene solo in
player.gd::begin_play(), chiamata damain.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 |
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) |
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
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. Nessunalibstdc++(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:
#dentroexport_presets.cfgnon è un commento per il parser → una riga commentata dopobinary_format/embed_pck=trueha 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).