Undici floppy e un sogno rimasto nel 1992
Monkey Island 2: LeChuck's Revenge uscì su MS-DOS nel 1991 e arrivò su Amiga a cavallo tra il 1991 e il 1992. Fu uno di quei giochi che misero particolarmente in evidenza il divario che si stava creando tra la grafica VGA dei PC e quella del vecchio 16 bit Commodore.
LucasArts riuscì comunque a realizzare una conversione straordinaria. La grafica originale, ridotta dai 256 colori della VGA ai 32 dell'area di gioco Amiga, manteneva una somiglianza impressionante. A colpo d'occhio sembrava quasi la stessa avventura, con gli stessi splendidi fondali e una direzione artistica che ancora oggi considero tra le migliori mai viste in un videogioco.
Per essere precisi, l'interfaccia Amiga utilizzava una palette separata da quella dell'area di gioco, permettendo di visualizzare complessivamente più dei canonici 32 colori.
Ma qualcosa, inevitabilmente, era andato perduto. Molte animazioni ambientali erano state sacrificate, diversi elementi dei fondali erano diventati statici, mancavano effetti di parallasse e una parte considerevole delle musiche e degli effetti sonori originali non aveva trovato posto nella conversione.
Nonostante questi compromessi, per giocare alla seconda avventura di Guybrush Threepwood bastava un Amiga 500 equipaggiato con appena 1 MB di RAM.
No, non ho dimenticato l'hard disk. Su Amiga si poteva giocare direttamente da floppy, che erano addirittura undici!
Ricordo che all'epoca, pur non essendo particolarmente entusiasta di cambiare disco a ogni evoluzione dell'avventura, non ci davo poi troppa importanza. Era semplicemente una delle tante cose alle quali ero abituato.
Oggi, però, giocare con tutti quei compromessi non è più tollerabile. Almeno per me.
Memore dei tanti appassionati che negli anni hanno sostenuto che con il fratello maggiore dell'A500, ovvero l'Amiga 1200, sarebbe potuta nascere una conversione praticamente perfetta, ho deciso di provare a dare forma a quella vecchia convinzione.
Non volevo limitarmi a sostituire i fondali della versione Amiga con quelli VGA. Volevo ricostruire il motore che muove Monkey Island 2 e altre grandi avventure LucasArts: SCUMM5.
Un interprete nativo, scritto in C e progettato appositamente per sfruttare il chipset AGA.
L'obiettivo iniziale era eseguire la versione originale DOS/VGA su un Amiga 1200 standard, dotato soltanto di hard disk. Non ho mai preso in considerazione una versione su floppy, per i motivi che ho appena raccontato.
Durante lo sviluppo, però, mi sono reso conto che i soli 2 MB di Chip RAM non offrivano il margine necessario per realizzare tutto ciò che avevo in mente.
Nella mia ipotetica versione dei sogni non volevo rinunciare alle animazioni ambientali, agli effetti di parallasse, allo scrolling, allo scaling dei personaggi e, naturalmente, alla grafica originale a 256 colori.
Forse, almeno su una macchina standard, un progetto troppo ambizioso.
Per questo, nell'attuale fase di sviluppo, ho deciso di utilizzare anche 2 MB di Fast RAM.
All'epoca sarebbe stata una spesa aggiuntiva non proprio trascurabile, ma è anche vero che Commodore avrebbe dovuto favorire maggiormente l'espansione delle proprie macchine, anziché continuare a cullarsi sugli allori.
I computer stavano cambiando. Hard disk, memoria aggiuntiva e processori più veloci sarebbero diventati sempre più importanti. Commodore aveva tra le mani una piattaforma che poteva crescere, ma non riuscì a valorizzarne fino in fondo le possibilità.
Un altro compromesso riguarda l'audio. L'Amiga 1200 utilizzava ancora Paula, con i suoi quattro canali PCM a 8 bit. Una soluzione eccellente per determinati utilizzi, ma limitante quando si cerca di riprodurre la ricchezza delle colonne sonore originali PC, mantenendo contemporaneamente gli effetti sonori.
Per questa prima fase ho quindi scelto di conservare le musiche della versione Amiga, concentrandomi sul recupero degli effetti mancanti.
Ma su questo tornerò più avanti.
Programmare SCUMM5-Amiga con Codex
Prima di entrare nei dettagli tecnici, voglio chiarire un aspetto importante.
Ho sviluppato SCUMM5-Amiga utilizzando OpenAI Codex, lo strumento di programmazione basato sull'intelligenza artificiale.
Non sono un programmatore professionista di videogiochi e non ho motivo di nascondere di non aver scritto personalmente migliaia di righe di codice C per il Motorola 68020.
Codex ha scritto il codice dell'interprete, sviluppato gli strumenti di elaborazione delle risorse e realizzato l'infrastruttura tecnica necessaria per i test e la diagnostica.
Io ho diretto il progetto, definendo requisiti e priorità, scegliendo le soluzioni da approfondire, valutando i compromessi e verificando personalmente i risultati.
Contrariamente a quanto si possa pensare, però, non è stato sufficiente scrivere un prompt chiedendo di convertire Monkey Island 2 per Amiga e aspettare che comparisse per magia.
Magari fosse così semplice!
Lo sviluppo è stato caratterizzato da continui tentativi, test, regressioni e correzioni. A volte un intervento produceva un miglioramento enorme. Altre volte, dopo ore di analisi, il risultato era talmente modesto da convincermi a scartare completamente la modifica.
Fin dall'inizio ho insistito su un principio: non volevo un motore composto da trucchi specifici per far funzionare questa o quella stanza, ma un interprete capace di gestire le situazioni previste dagli script originali senza ricorrere a scorciatoie.
Monkey Island 2 è il primo gioco che ho scelto di eseguire, ma l'obiettivo è rendere SCUMM5-Amiga utilizzabile anche con altre avventure LucasArts.
SCUMM5 non è soltanto un motore grafico
SCUMM, come ben saprete, è l'acronimo di Script Creation Utility for Maniac Mansion, il sistema sviluppato da Lucasfilm Games per gestire le proprie avventure grafiche.
Nel corso degli anni è stato ampliato e modificato per adattarsi a produzioni sempre più complesse, fino a diventare il cuore di titoli come Monkey Island 2 e Indiana Jones and the Fate of Atlantis.
Non si occupa soltanto di visualizzare fondali e personaggi. Deve interpretare gli script originali, gestire dialoghi, inventario, oggetti, animazioni, movimenti degli attori, transizioni fra le stanze e tutte quelle variabili che determinano lo stato dell'avventura.
Per questo ho scelto di realizzare un interprete capace di eseguire direttamente il bytecode SCUMM5 originale.
Le risorse grafiche vengono elaborate quando necessario per renderle utilizzabili dall'AGA, ma la logica narrativa continua a provenire dagli script del gioco.
Questo approccio ha complicato parecchio lo sviluppo.
Più di una volta sono arrivato a una scena apparentemente funzionante, salvo scoprire che una particolare istruzione SCUMM non era ancora supportata o che una risorsa non veniva caricata e mantenuta correttamente in memoria.
Un fondale perfetto e un Guybrush che si muove correttamente servono a poco se poi, tentando di raccogliere un oggetto o avviare un dialogo, l'avventura si blocca.
Otto bitplane: i 256 colori dell'AGA presentano il conto
La prima grande difficoltà è stata naturalmente quella grafica.
Monkey Island 2 VGA utilizza una risoluzione di 320×200 pixel, con 256 colori selezionati da una palette RGB.
L'Amiga 1200 è perfettamente in grado di visualizzare un'immagine con queste caratteristiche grazie al chipset AGA.
Almeno sulla carta.
Il PC e l'Amiga, però, organizzano i dati grafici in maniera profondamente diversa.
Nella modalità VGA utilizzata dal gioco, ogni pixel è rappresentato da un indice di colore a 8 bit. Questa organizzazione, chiamata chunky, permette di manipolare direttamente i pixel in un buffer.
L'Amiga utilizza invece una rappresentazione planare. Per visualizzare 256 colori servono otto bitplane, ognuno dei quali contribuisce con un bit alla definizione del colore di ciascun pixel.
Disegnare e comporre i personaggi direttamente in questo formato, soprattutto quando entrano in gioco trasparenze, scaling e sovrapposizioni, non è affatto semplice.
Per questo ho adottato una pipeline grafica che utilizza buffer di lavoro e una conversione chunky-to-planar, comunemente abbreviata in C2P.
Il problema è che convertire i dati grafici su un 68020 a circa 14 MHz richiede tempo. E quel tempo si somma a quello necessario per interpretare gli script, preparare le animazioni, disegnare i personaggi e gestire tutto il resto.
Ho quindi cercato di limitare le operazioni superflue, sfruttando una gestione delle regioni modificate dello schermo e routine di conversione ottimizzate.
Il Blitter e il Copper vengono utilizzati per le operazioni nelle quali possono risultare realmente vantaggiosi, mentre il puntatore del mouse sfrutta uno sprite hardware.
Anche la gestione delle palette ha richiesto parecchio lavoro. Non bastava caricare i colori VGA: dovevo preservare la corretta visualizzazione dei dialoghi, dell'interfaccia, del cursore e degli effetti cromatici originali.
E poi c'è la Chip RAM.
Sull'Amiga, il processore deve condividere con il chipset l'accesso a questa memoria. Quando il display utilizza otto bitplane, il traffico generato dal sistema video diventa particolarmente impegnativo.
Avere 256 colori disponibili non significa poterli utilizzare gratuitamente.
L'AGA offre possibilità grafiche notevoli, ma sfruttarle su un 68020 originale richiede un'attenzione continua alla memoria, agli accessi DMA e alla quantità di lavoro necessaria per preparare ogni immagine.
Guybrush deve muoversi, non soltanto farsi fotografare
Ottenere la visualizzazione corretta di un fondale è stato soltanto il primo passo.
Il problema successivo era far muovere Guybrush al suo interno, rispettando il comportamento originale.
Monkey Island 2 utilizza le walkbox per delimitare le aree percorribili, coordinate per stabilire le destinazioni e fattori di scala che modificano le dimensioni dei personaggi in base alla loro posizione.
Quando Guybrush si allontana, diventa più piccolo. Quando si avvicina, aumenta di dimensioni. E tutto questo deve avvenire preservando le animazioni originali.
Bisogna inoltre gestire la Z-occlusion, ovvero il sistema che permette agli elementi del fondale di nascondere parzialmente un personaggio quando passa dietro un oggetto.
Una passeggiata apparentemente semplice richiede quindi parecchie operazioni: aggiornare posizione e scala, recuperare la posa corretta, comporre il personaggio, applicare le eventuali maschere Z e convertire nel formato planare i pixel interessati.
Uno dei risultati che mi hanno dato maggiore soddisfazione riguarda proprio Woodtick.
Volevo vedere Guybrush attraversare la scena mentre la telecamera lo segue, con lo scaling originale, l'acqua animata e gli elementi ambientali in movimento.
Ho dedicato parecchio tempo anche alla barca e al suo parallasse, incontrando limiti tutt'altro che banali nell'utilizzo contemporaneo degli sprite hardware, dello scrolling e degli otto bitplane.
Alcune configurazioni sperimentali si sono rivelate impraticabili e il lavoro su questi effetti non è ancora concluso.
Ma arrivare a un gameplay nel quale Guybrush può attraversare Woodtick, entrare negli edifici, interagire con i personaggi e proseguire nell'avventura è stato un passaggio fondamentale.
A quel punto non stavo più osservando soltanto un esperimento grafico. Stavo iniziando a giocare davvero a Monkey Island 2.
Captain Dread e i millisecondi recuperati
Raggiungere una buona fedeltà grafica non significa automaticamente ottenere una buona fluidità.
Uno dei casi più emblematici riguarda Captain Dread.
Durante le sue animazioni, il motore impiegava inizialmente circa 562 millisecondi per preparare un aggiornamento. Più di mezzo secondo.
Analizzando il comportamento del programma con Codex, ho scoperto che una parte enorme di quel tempo veniva consumata rileggendo continuamente dal disco le stesse risorse grafiche.
Ogni movimento della bocca di Dread comportava operazioni I/O che potevano essere evitate.
L'introduzione di una cache per le sorgenti immutabili ha ridotto il tempo medio da circa 562 a 123 millisecondi. Una successiva ottimizzazione del ciclo di composizione delle immagini lo ha portato a circa 61 millisecondi.
Da 562 a 61 millisecondi, senza alterare gli script o accelerare artificialmente le animazioni.
Un risultato che mi ha fatto capire quanto fosse importante individuare il vero collo di bottiglia, anziché cercare genericamente di velocizzare tutto il motore.
Purtroppo non sempre è andata così bene.
La sequenza della palude, durante la quale Guybrush si muove all'interno della bara, continua a essere particolarmente impegnativa.
Dopo una prima serie di miglioramenti importanti, ho tentato di spostare una parte dei buffer di lavoro dalla Chip RAM alla Fast RAM.
Il risultato è stato un miglioramento di appena il 6,6%, al prezzo di circa 268 KB di Fast RAM sottratti al margine disponibile.
Troppo poco. Ho quindi deciso di non adottare quella modifica.
Anche il falò dell'introduzione, con Guybrush e i pirati seduti intorno al fuoco, ha richiesto un lavoro notevole.
In questo caso il problema riguardava soprattutto la composizione degli attori e la preparazione delle loro animazioni.
L'analisi ha evidenziato che il fuoco utilizzava soltanto quattro pose differenti, ma il sistema di cache continuava a ricostruirle quasi a ogni aggiornamento perché ne conservava una sola per quell'attore.
Ho quindi fatto generalizzare la gestione di una cache già esistente, permettendole di mantenere più pose anche per gli altri attori configurati.
Il tempo medio di preparazione è sceso da circa 170 a 146 millisecondi, con un miglioramento vicino al 14%.
Non sufficiente, purtroppo, a rendere il falò perfettamente fluido: nella prova misurata la scena continuava ad aggiornarsi mediamente circa sei volte al secondo.
Ho preferito fermarmi, conservando il miglioramento ottenuto e rimandando interventi più profondi.
Sette secondi per aprire un menu
Non tutte le difficoltà hanno riguardato il rendering del gioco.
A un certo punto mi sono accorto che, premendo F5 per aprire il menu, bisognava aspettare quasi sette secondi prima di vedere comparire il pannello.
Anche mettere in pausa il gioco richiedeva più di quattro secondi.
Un comportamento francamente inaccettabile.
La cosa curiosa è che il sistema di input funzionava correttamente: gli eventi della tastiera venivano acquisiti quasi immediatamente.
Il problema era nella preparazione grafica del menu, in particolare in alcune operazioni estremamente costose di scansione della palette, riempimento dei buffer planari e verifica della loro integrità.
Dopo aver sostituito quelle operazioni con primitive più efficienti, il tempo di apertura del menu F5 è passato da circa 6,95 secondi a 0,9 secondi.
Anche la pausa è scesa da circa 4,17 a 0,88 secondi.
Non è una risposta istantanea, ma il miglioramento è enorme e, almeno per il momento, considero il comportamento accettabile.
Il sistema Save/Load richiede invece ancora lavoro.
Sono riuscito a verificarne tecnicamente il funzionamento, compresa la scrittura dei salvataggi, la chiusura dell'emulatore, il riavvio e il ripristino dello stato di gioco.
Tuttavia, l'interfaccia rimane troppo lenta. In alcune prove, la sola procedura di scrittura e verifica del salvataggio ha richiesto circa cinque secondi.
Una correzione sperimentale ha eliminato conferme duplicate e alcuni problemi di presentazione del pannello, ma non ho ancora integrato quella variante nella versione principale.
Copper, framebuffer e altri piccoli incubi
Se dovessi raccontare tutti i problemi incontrati durante lo sviluppo, probabilmente questo articolo diventerebbe un libro.
Una parte considerevole del lavoro è stata dedicata alla gestione del display AGA.
Ho dovuto affrontare situazioni nelle quali il framebuffer appariva corretto nei controlli diagnostici, ma l'immagine visualizzata presentava comunque anomalie.
Altre volte il programma funzionava regolarmente, salvo lasciare artefatti sullo schermo quando tornava alla Shell AmigaOS.
Il motivo era spesso legato alla sincronizzazione fra Copper, DMA, Blitter e buffer video.
Non basta preparare correttamente un'immagine: bisogna anche assicurarsi che venga pubblicata nel momento giusto, senza modificare un buffer che il chipset sta già utilizzando per la visualizzazione.
Ho dovuto verificare attentamente queste condizioni, insieme alla corretta restituzione delle risorse hardware al sistema operativo quando il gioco termina.
Un problema particolarmente interessante riguardava alcuni aggiornamenti di palette durante l'introduzione. In determinate condizioni il motore ricostruiva e pubblicava una Copper list troppo tardi, producendo anomalie visive.
La soluzione è stata correggere il percorso di aggiornamento dei colori, evitando di ricostruire inutilmente l'intera lista.
Ci sono stati poi gli errori legati ai caricamenti delle risorse, alla memoria frammentata, alle pose dei personaggi, ai salvataggi e persino alla geometria degli hard disk virtuali.
In un caso, una discrepanza di appena quaranta settori fra la dimensione reale di un HDF e quella annunciata dal controller IDE emulato impediva una scrittura durante l'uscita dal programma.
È stato sufficiente correggere la geometria del disco, senza modificare una sola riga del motore.
Anche questo ha fatto parte dello sviluppo: imparare a distinguere un difetto dell'interprete da un problema dell'ambiente di test.
Il problema della musica e degli effetti sonori
Ricostruire integralmente la musica Roland o Sound Blaster attraverso campioni digitali avrebbe richiesto un sistema di riproduzione differente, introducendo ulteriori compromessi su memoria, processore e qualità sonora.
Per questo ho inizialmente conservato le musiche della conversione Amiga originale, concentrandomi sul recupero degli effetti sonori previsti dalla versione DOS/VGA.
La difficoltà, però, non consiste semplicemente nel trovare i campioni.
Alcuni effetti originali sono digitalizzati, altri vengono generati attraverso sequenze e sistemi di sintesi. Non possono quindi essere trattati tutti come semplici file WAV da convertire.
Ho dovuto analizzare le risorse originali, individuare gli eventi richiesti dagli script e sviluppare percorsi di riproduzione compatibili con Paula.
Il limite dei quattro canali rende inoltre necessario gestire attentamente la convivenza fra musica ed effetti sonori.
Una parte del sistema è già funzionante, ma la copertura non è ancora completa.
Uno degli esempi più curiosi riguarda il rumore del barista del Bloody Lip mentre pulisce i bicchieri con lo strofinaccio.
Sono riuscito a recuperare l'effetto originale, che non è un semplice campione PCM, e a farlo riprodurre correttamente attraverso un controller audio dedicato.
La successiva integrazione ha però evidenziato alcuni problemi di latenza, soprattutto durante il caricamento delle risorse necessarie alla prima riproduzione. Ho quindi preferito mantenere temporaneamente questo effetto in una variante sperimentale.
Un capitolo separato riguarda la musica Roland MT-32.
L'obiettivo è utilizzare gli eventi MIDI originali del gioco, inviandoli attraverso la porta seriale dell'Amiga a un sintetizzatore Roland reale oppure, tramite un collegamento appropriato, a un'emulazione software come Munt.
Questa soluzione permetterebbe di riprodurre la musica Roland senza impegnare i quattro canali Paula.
I primi esperimenti hanno dato risultati incoraggianti. Ho verificato il trasporto MIDI attraverso FS-UAE fino a Munt e ottenuto l'esecuzione tecnica di un primo cue musicale originale, Sound169, comandato direttamente dalla macchina virtuale SCUMM5.
Il backend rimane però sperimentale. La resa musicale del cue deve ancora essere confermata manualmente e il comportamento completo di iMUSE, comprese le transizioni e la sincronizzazione musicale, richiede ulteriori verifiche.
Non mi interessa avviare una musica esterna scollegata dal gioco. Voglio che sia realmente l'interprete a comandarla, come previsto dal sistema originale.
La pergamena della Parte II
La prima conferma del completamento della Parte I è arrivata attraverso un checkpoint precedente al finale di Largo.
L'interprete ha eseguito gli script originali: Guybrush ha sconfitto Largo, recuperato il libro della Voodoo Lady, ottenuto il monocolo di Wally e completato l'accordo con Captain Dread.
La pergamena “Part II: Four Map Pieces” è stata caricata e visualizzata attraverso il normale percorso previsto dal gioco, senza ricostruzioni artificiali.
Il framebuffer è stato confrontato con il riferimento originale: 64.000 pixel, nessuna differenza cromatica rilevata.
Ma volevo verificare personalmente l'intera progressione.
Ho quindi avviato Monkey Island 2 in FS-UAE e giocato normalmente, risolvendo gli enigmi, attraversando Woodtick e le altre ambientazioni di Scabb Island fino a completare The Largo Embargo.
Sono arrivato alla pergamena della Parte II senza incontrare intoppi.
L'avvio utilizza ancora l'introduzione attualmente supportata, mentre il bootstrap originale con il menu Full Game / Monkey 2 Lite deve essere completato. La prova non certifica quindi ogni possibile interazione del gioco, ma conferma che l'intera progressione principale della Parte I è giocabile.
La prova sul vero Amiga 1200
Fino a quel momento avevo sviluppato e collaudato il progetto principalmente attraverso FS-UAE, utilizzando una configurazione vicina a quella originale: Motorola 68020 a circa 14 MHz, chipset AGA, 2 MB di Chip RAM, 2 MB di Fast RAM e hard disk.
Niente processori accelerati o JIT per nascondere le difficoltà del motore.
Volevo però verificare il funzionamento anche sul mio Commodore Amiga 1200 originale, equipaggiato con il 68EC020 standard, 2 MB di Chip RAM, 8 MB di Fast RAM e una CompactFlash collegata all'interfaccia IDE interna.
Ho trasferito lo stesso eseguibile utilizzato nei test e l'ho installato sulla CompactFlash.
Ho completato la Parte I anche sulla macchina reale, arrivando nuovamente alla pergamena della Parte II.
Una soddisfazione enorme, soprattutto ripensando a quel 1992.
Un interprete ancora in costruzione
SCUMM5-Amiga è tutt'altro che concluso.
Restano da migliorare le prestazioni nelle scene più impegnative, completare la gestione degli effetti sonori, ottimizzare il Save/Load e implementare il bootstrap originale.
La Parte II di Monkey Island 2 non è ancora giocabile e anche la possibilità di utilizzare il motore senza Fast RAM rimane da verificare.
Voglio continuare a lavorare sulle prestazioni del renderer, sulla gestione delle risorse, sull'audio e sulle funzionalità ancora mancanti della macchina virtuale, senza sacrificare la fedeltà agli script originali.
L'obiettivo è completare Monkey Island 2 e successivamente affrontare un'altra delle mie avventure preferite: Indiana Jones and the Fate of Atlantis.
Questa volta, però, senza dover ricominciare tutto da zero.



Memorie dei lettori
Commenta l’articolo e partecipa alla discussione.
Regolamento commentiAccedi o registrati per lasciare un commento.
Crea il tuo account
Caricamento commenti...