Classifica globale: API dei punteggi, schermata iniziale e nome memorizzato

- services/scores-api: microservizio (solo stdlib) con SQLite WAL, idempotenza per
  submission_id, limiti di frequenza e validazione; immagine Docker non-root.
- nginx: reverse proxy su /api/zombie-fps/ (stessa origine del gioco, niente CORS).
- scripts/leaderboard.gd: client HTTP con retry idempotente; su desktop la classifica
  resta disattivata senza --api=, cosi' i test non sporcano la classifica pubblica.
- scripts/player_profile.gd: nome, id anonimo e miglior punteggio in user:// e in
  window.localStorage; il nome scelto non viene piu' richiesto; riparazione dei
  profili con la stringa "null".
- scripts/start_screen.gd: menu con nome, GIOCA e classifica; la partita parte solo
  dal pulsante (via la rete di sicurezza sull'input, Invio nel campo non avvia).
- scripts/main.gd, player.gd: avvio esplicito, segnale died, nota dell'invio.
- tools: test_scores_api.py (42), test_leaderboard (14), test_player_profile (21),
  test_start_screen (10); suite esistenti adeguate all'avvio manuale.
- docs/HIGHSCORES.md + docs/WEB-DEPLOY.md aggiornati.
This commit is contained in:
enne2
2026-10-13 23:26:00 +02:00
parent 9d1988c48b
commit ae32ad9615
27 changed files with 2071 additions and 32 deletions
+23
View File
@@ -1,4 +1,5 @@
extends CharacterBody3D
signal died
var camera: Camera3D
var damage_pivot: Node3D
var damage_feedback: CanvasLayer
@@ -81,6 +82,14 @@ func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
var restart_button: Button
var death_note: Label
## Riga sotto il messaggio di morte: punteggio inviato, posizione in classifica o
## motivo del fallimento. Richiamata da main.gd a conclusione dell'invio.
func set_death_note(text: String) -> void:
if is_instance_valid(death_note):
death_note.text = text
death_note.modulate.a = 1.0
func _input(event: InputEvent) -> void:
# Touch nativo: funziona anche con emulate_mouse_from_touch disattivato.
@@ -248,6 +257,20 @@ func _die() -> void:
layer.add_child(message)
message.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
tween.tween_property(message, "modulate:a", 1.0, 0.5).set_delay(2.2)
death_note = Label.new()
death_note.text = ""
death_note.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
death_note.add_theme_font_size_override("font_size", 22)
death_note.add_theme_color_override("font_color", Color(1.0, 0.66, 0.16))
death_note.modulate.a = 0
layer.add_child(death_note)
death_note.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
death_note.offset_top = 60
death_note.offset_bottom = 100
death_note.offset_left = -420
death_note.offset_right = 420
tween.tween_property(death_note, "modulate:a", 1.0, 0.5).set_delay(2.6)
died.emit()
if touch_mode:
var restart := Button.new()
restart_button = restart