← Novità

v0.24

2026-07-26 · 1 voce/i di changelog

Sprint 8: la skyline non è più a palazzi gemelli, il gattile apre, quattro KO chiusi2026-07-26

  • [feat] SU-120 — gli isolati si compongono a larghezze miste, e le torri svettano solo dove non nascondono niente. L'isolato non è più una griglia di sotto-celle da 96: si divide in file e ogni fila si riempie greedy usando la larghezza reale dello sprite. È la scelta che conta: le larghezze approvate in SU-118 sono irregolari (36/39/43/75/91/96/144, non i 48/96/144 nominali), quindi slot a larghezza fissa per taglia avrebbero lasciato buchi sistematici. Lo spazio avanzato si ridistribuisce fra bordi e vuoti. Torri: il tetto dei ~160px è caduto col KO di Ivan su SU-118, e le 7 torri da 211-252px sono entrate. Una torre è candidata solo nella fila davanti di un super-isolato e solo se altezza ≤ profondità del lotto — così sta tutta dentro il proprio isolato e non raggiunge mai la strada dietro; poi _cappello_libero() verifica che il «cappello» proiettato a nord non intersechi edifici, ingressi interagibili o consumabili, e se fallisce il generatore ripiega sulle taglie basse. Il cono occluso è escluso dagli spawn: niente gatti invisibili, che era il difetto citato da Ivan. Z-order da z_index = -5 a int(base_y) (schema y-sortato già in uso da rifugio e player): senza, un pedone sulla strada dietro sarebbe passato davanti alla facciata dei palazzi nuovi. Importati i 25 asset approvati, buildings_manifest rigenerato con BUILDING_SIZES, indice per taglia in BuildingDatabase (pick_building_fit/pick_torre, deterministiche). WorldGenerator.gd, BuildingDatabase.gd, buildings_manifest.gd, tools/import_buildings_sprites.py. Commit 8f2b644.
  • [feat] SU-142 — il GATTILE ha finalmente la sua faccia. Montato lo sprite approvato da Ivan (insegna «CATS», 96×124) al posto del placeholder residenziale, ancorato alla base come gli altri edifici; collisioni invariate sul rect 96×96 e fallback al placeholder se il PNG manca. Caricato per nome diretto e non dal discovery per-quartiere, così non può essere pescato a caso altrove. Commit 8f2b644.
  • [feat] SU-156 — qualche filo d'erba sul marciapiede. Le due varianti scelte da Ivan (B e D) sparse dal generatore, deterministiche dal seme, z_index -14 (sopra la piastra, sotto tutto il resto), zero collisioni e zero interazioni. Densità 35% dei blocchi con un ciuffo, 25% di questi con un secondo: 7-24 ciuffi a seconda del seme — se a Ivan sembrano pochi o troppi è un numero solo da cambiare. Commit 8f2b644.
  • [fix] SU-156 — i ciuffi finivano sull'asfalto una volta su due, ed è stato il collaudo a beccarlo. L'implementazione pescava i punti nella fascia larga wang_pad = 34 attorno all'isolato, dando per scontato che fosse tutta marciapiede: «per costruzione, non per filtro». Ma il marciapiede disegnato finisce a wang_pad − WANG_INSET = 18px, perché la cucitura della piastra sta dentro il pad. Misura su 4 semi: 33 ciuffi su 66 sulla strada, fino a 30px oltre il bordo. Ora si campiona sullo sbordo utile: 0 su 66. La lezione è che un'assunzione geometrica «vera per costruzione» va comunque misurata. Commit 8f2b644.
  • [fix] Il gattile aveva un quadratino bianco davanti alla porta. Interactable.Type.GATTILE non aveva un caso nel match di _add_interactable() e cadeva sul default (Color.WHITE, 16×16), mentre rifugio, liquor e negozio di vestiti hanno tutti il loro Color(1,1,1,0). Non si vedeva col placeholder generico, è saltato all'occhio appena montato lo sprite vero. Commit 8f2b644.
  • [fix] Difetto PREESISTENTE (dal v0.11): i bidoni rompevano «stesso seme, stessa mappa». _find_bin_point() usava corners.shuffle(), che pesca dall'RNG globale del motore invece che dal generatore seedato: in MP host e client mettevano i bidoni in angoli diversi. Non nasce da questo sprint, ma «deterministico dal seed» è un criterio di accettazione di SU-120, e consegnarlo sapendo che la mappa non lo era sarebbe stata una mezza consegna. Ora Fisher-Yates col RNG seedato; il codice nuovo di SU-120 era già deterministico bit-per-bit. Commit 8f2b644.
  • [feat] SU-158 (KO) — le carte super si dispongono e si scelgono esattamente come le normali. Terzo giro su questo ticket. Ventaglio, animazione di navigazione e ingresso portati da LevelUpScreen copiandone i valori invece di ritararli (OVERLAP 0.75, FAN_DEG 10, HILITE_SCALE 1.15, HILITE_RAISE 34, _animate_card_to 0.16s TRANS_QUAD): prima il passaggio da una carta all'altra scattava di colpo, senza tween. Scartata l'estrazione in helper condivisi, che avrebbe toccato LevelUpScreen contro il vincolo «carte normali invariate al pixel». Il difetto vero della selezione non era il touch, che era già a due stadi ed era corretto: la cerimonia ascoltava ui_accept (Invio/Spazio) mentre le carte normali usano l'azione interact — cioè E e soprattutto il bottone «A» dei controlli touch, che nella cerimonia non battezzava nulla. Brillio e coriandoli invariati, come approvati. SuperCeremony.gd. Commit 2a66f0f.
  • [fix] SU-132 (KO) — le stazioni bloccate si mascherano, e il reset azzera davvero. Dietro il KO «resettando mi compaiono tutte le stazioni» c'erano due difetti. Il primo: i pallini lungo la linea erano sempre e cambiava solo il colore — il ??? esisteva solo sulla scheda col nome; ora una stazione bloccata è ?. Gli indizi comici richiesti dal ticket c'erano già tutti in Quartieri.indizio(), non serviva scriverne di nuovi. Il secondo, che è la causa vera: nessuna azione di reset toccava MetaProgress — né OPZIONI → RESETTA STATISTICHE né il «Reset prog.» del DebugPanel — quindi gli sblocchi sopravvivevano a qualunque azzeramento. Nuovo MetaProgress.reset_all() agganciato al reset ufficiale delle Opzioni. Da confermare a Ivan: reset_all() azzera anche la ragnatela carte (coerente con «tabula rasa», ma è una scelta nostra), e il «Reset prog.» di F1 è stato lasciato com'è, per i test di bilanciamento. MainMenu.gd, MetaProgress.gd. Commit 8ea26f2.
  • [fix] SU-140 (KO) — il cerchio attorno al barbone si disegna solo di notte. Il buco del cerchio nella vignette era incondizionato: si ritagliava a qualunque ora e cancellava la tinta di quartiere, ed è per questo che Ivan vedeva sparire il giallo del Solleone in pieno giorno. Non era un PointLight2D ma due shader inline; ora il buco è legato a night_amt in entrambi, con transizione graduale per non fare un lampo al tramonto. Di giorno la tinta copre lo schermo uniforme, di notte il cerchio è invariato. World.gd. Commit df710c9.
  • [feat] SU-150 — la marmotta approvata entra nella notifica delle scorregge. Versione B, solo muso (quella che Ivan ha approvato), al posto del placeholder emoji 🐹, con fallback se il PNG manca. Nota di percorso: il call site non era in HUD.gd come diceva il ticket ma in Player.gd. Player.gd, assets/sprites/marmotta.png. Commit df710c9.
  • [feat] SU-160 — lampadina e tromba nei messaggi, con l'assegnazione dichiarata invece che indovinata. Il ticket diceva «da concordare con Ivan se non ovvia» e Ivan non ha risposto: applicato un default esplicito, da approvare o cambiare in una rigalampadina sui messaggi che insegnano (TutorialManager), tromba sugli annunci e i traguardi («NUOVA FERMATA», annunci di nuovo giorno). Dove c'era già un'emoji con lo stesso mestiere (🚇, 🗑, 🎩) è stata sostituita, non affiancata. Saltati i call site dove stonava (il commiato di fine tutorial, il banner di distretto): meglio quattro messaggi giusti che dodici a caso. TutorialManager.gd, World.gd, DifficultyManager.gd. Commit df710c9.
  • [feat] SU-166 (nuovo, in attesa di approvazione) — la texture del parco rifatta seamless. Nasce dal KO di SU-119 («si spacca file per file perché non sono allineate»): creata la coppia di generazione come da flusso sprite, e SU-119 resta bloccato finché Ivan non approva. Nuova texture 96×96 perfettamente tileable — differenza media al giunto 0.000 contro 7.7 (colonne) e 9.1 (righe) fra due linee interne adiacenti, cioè il bordo combacia meglio di due righe qualsiasi dentro la texture — più un foglio di tessere di bordo con angolo morbido e transizione dithered (maschera bilineare sui 4 angoli + Bayer ordinato), sul modello del bordo marciapiede. Nota onesta: la nuova erba è più piatta dell'attuale, che ha sentieri e cespugli — è lo stesso rilievo che Ivan aveva mosso al TileMap, ed è il compromesso strutturale del seamless (un motivo forte cotto in una tessera è proprio ciò che «si spacca» quando si ripete). Decide lui. sprites_raw/WORLD/temp/, anteprima TMP/su119_park_preview.png.
  • [test] Collaudo di fine sprint: 69 script / 24 scene, 0 falliti; run SP 150s con 0 SCRIPT ERROR, 0 orfani, gatti stabili 8/8. Il collaudo ha prodotto due strumenti diagnostici che restano nel repo perché si sono ripagati subito: su156_diag.gd (conta i ciuffi fuori dal marciapiede su più semi) e su120bc_diag.gd (confronta due generazioni dello stesso seme e stampa le differenze). Verificato inoltre che la fontana sparita dal parco fra gli screenshot prima/dopo non è un difetto: _spawn_fountain() non passa mai dal test di occlusione, è lo slittamento atteso del flusso RNG (su un altro seme le fontane aumentano invece di diminuire). Dettagli in TESTLOG.md.