VAI ALLA HOME PAGE

Il codice sorgente e altre amenità

di Anima Prava (2023)



Questo articolo è rivolto agli appassionati. Tratta argomenti che i giocatori occasionali potrebbero considerare difficili. D'altro canto per gli sviluppatori queste cose sono ovvie e risapute.

Compilare Descent 2 (e 1) dai Sorgenti.

La compilazione consiste nel trasformare il codice sorgente di un programma in un eseguibile da utilizzare, collegato alle librerie che avremo installato. Durante la compilazione, il compilatore (gcc, g++) legge il codice sorgente e crea un eseguibile (d2x-rebirth) collegato alle librerie necessarie, che devono essere già installate (SDL, PhysFS).

Di seguito vedremo come compilare una versione recente di DXX-Rebirth su una distribuzione Linux, preferibilmente derivata da Debian.


Cosa occorre.
Se tutto va bene andiamo avanti.


Istruzioni.

Per procurarci i sorgenti vedere Descent II su un PC moderno.

Seguiamo le istruzioni del file INSTALL.markdown nei sorgenti, ovvero pressappoco quanto segue.

Occorrono scons, gcc, g++, Python 3.
Occorrono le librerie SDL1.2, PhysFS 3 (PhysicsFS), libpng, libsdl-image, libsdl-mixer con i rispettivi pacchetti DEV.

Nelle distribuzioni derivate da Debian (Ubuntu, Linux Mint, ...) si può installare tutto rapidamente come segue. Nelle altre distro cambia il comando per l'installazione, leggere il file INSTALL.markdown.

sudo apt update
sudo apt upgrade
sudo apt install build-essential scons libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libphysfs-dev libpng-dev

Se alcuni elementi sono già installati non fa niente, meglio così.

Dagli stessi sorgenti si compilano D1 e D2.

Per avviare la compilazione apriamo una shell (un "terminale") nella directory principale dei sorgenti.
    Poi digitiamo: scons.
    Per compilare solo D2 (senza D1): scons d2x=1.
    Per compilare solo D1 (senza D2): scons d1x=1.

Prima dell'avvio è d'uso l'impiego di gesti apotropaici: fare le corna, incrociare le dita, toccare ferro, eccetera. Non è chiaro se serva davvero.


Se la compilazione ha successo.

Verremo premiati dal messaggio "scons: done building targets" (o qualcosa del genere).

Nelle versioni recenti troveremo i file eseguibili per D1 (d1x-rebirth) e D2 (d2x-rebirth) nella directory build.

Non c'è più bisogno di dargli il permesso di esecuzione (chmod u+x d2x-rebirth).

Possiamo rinominare l'eseguibile come vogliamo. Possiamo metterlo dove ci pare, di solito in una cartella comoda, oppure insieme all'eseguibile dei Repo (il comando which d2x-rebirth ci dice dove si trova, di solito in /urs/games/). Attenzione, mettendolo nella directory dove si trovano gli altri file (~/.d2x-rebirth) a volte funziona a volte no (dipende dalla versione).

D'ora in poi useremo una versione compilata da noi.
Che bella soddisfazione, vero?


Se la compilazione non ha successo...

...Non c'è niente di strano: può mancare una libreria, oppure la sua versione o posizione non sono quelle attese. Leggiamo il messaggio di errore e cerchiamo di capirne il significato. Leggiamo il file INSTALL.markdown. Facciamo più di una ricerca in rete in base al testo del messaggio di errore. Approfondiamo il problema e insistiamo.

Se non ne veniamo a capo è normale chiedere aiuto. Però attenzione: quelli di Anima Prava sono brava gente, ma in rete si trovano anche persone da evitare. Non perdiamo troppo tempo con i forum in lingua italiana perché se ne cava poco. Se siamo sicuri del fatto nostro possiamo chiedere aiuto direttamente ai manutentori del programma.

In ogni caso dovremo essere pronti a fornire almeno quanto segue:
- nome e versione esatta del sistema operativo,
- versione esatta del programma (il Commit),
- il testo completo ottenuto lanciando scons,
- il contenuto del file sconf.log,
- come abbiamo tentato di risolvere il problema,
- i risultati che abbiamo ottenuto.


NOTE.




Modificare il Source Code.

Perché non modificare i sorgenti.
Noi non giochiamo in Multiplayer. Se lo facessimo useremmo esclusivamente una versione originale priva di modifiche di qualsiasi tipo.

Perché modificare i sorgenti (solo Single Player).
- Per risolvere piccoli bachi o problemi.
- Per aggiungere funzioni o caratteristiche che agli sviluppatori non interessano, non piacciono o che non hanno il tempo di implementare.
IMPORTANTE. Il codice sorgente cambia: le modifiche che funzionano adesso (nel 2023) potrebbero non funzionare con i sorgenti dell'anno prossimo.

Cosa occorre.
Abbiamo compilato una versione di DXX-Rebirth e la usiamo normalmente per giocare.




Modifiche - Esempi storici.


Esempio storico 1. Migliorare i movimenti.


Nelle versioni originali di D1 e D2, i movimenti di rotazione erano poco uniformi (vedere i dettagli nell'articolo D2 - Il menu del 1996). A partire dal 2000, col Source Port D2X, molti appassionati iniziarono a modificare il codice sorgente per rendere i movimenti più scorrevoli e uniformi. Però altri appassionati ritenevano intoccabili le caratteristiche originali e il solo discuterne in pubblico scatenava reazioni negative. Persino nelle recensioni di Overload (un gioco pubblicato nel 2018) si leggono le critiche di qualche vecchio appassionato perché i movimenti sono troppo diversi da quelli di D1 (1995) e D2 (1996).
Nel 2023: in molte versioni moderne i movimenti del Pyro-GX sono abbastanza fluidi e uniformi, mentre il menù offre opzioni per regolarne a piacimento le caratteristiche.


Esempio storico 2. Eliminare il Robot Ladro.

Non tutti apprezzano il Robot Ladro. Si poteva modificare il codice sorgente dei Source Port per eliminarlo ma anche questa modifica era controversa.
Nel 2023: nel menù di alcune versioni moderne sono presenti opzioni per eliminare il Robot Ladro o limitarne le capacità.


Esempio storico 3. Accesso libero a tutti i livelli.

Vedere l'articolo Accesso libero a tutti i livelli. In Descent 2 originale un semplice trucco permetteva di accedere a tutti i livelli di una missione multilivello senza doverli giocare prima in sequenza. Questo divenne più difficile e poi impossibile nelle versioni Source Port, ma i giocatori trovarono il modo di rimediare.
Nel 2023: l'accesso libero a tutti i livelli è la norma delle versioni recenti.


Esempio storico 4. Tasti F9/F10 con ripetizione automatica.
Contributo di InfernalCore.

Risoluzione del Bug #539.
(
https://github.com/dxx-rebirth/dxx-rebirth/issues/539).
InfernalCore ha comunicato agli sviluppatori di DXX-Rebirth la risoluzione di questo baco il 2023.10.08 che hanno accettato la modifica il 2023.12.25 (commit d724905).

Nota. InfernalCore ha contribuito a risolvere altri bachi:
https://github.com/dxx-rebirth/dxx-rebirth/issues/742
https://github.com/dxx-rebirth/dxx-rebirth/issues/739

Nella Mappa (Automap, tasto predefinito TAB) i tasti F9/F10 cambiano la distanza di vista, nascondendo progressivamente i tunnel più lontani. Vedere la spiegazione completa nella Introduzione della Guida Single Player.

In D1/D2 originali i comandi di questa funzione non erano F9/F10 ma avevano la ripetizione automatica (non era necessario premerli ripetutamente, bastava tenerli premuti). Nei Source Port la ripetizione automatica andò persa e venne ripristinata in DXX-Rebirth solo a fine 2023.

Soluzione. Funziona in D1 e D2. Nel file automap.cpp dalle parti della riga 1139 la riga key_toggle_repeat(0); diventa key_toggle_repeat(1);    (vedere sotto).

switch (event.type)
{
   case EVENT_WINDOW_ACTIVATED:
     game_flush_inputs(controls);
     event_toggle_focus(1);
     key_toggle_repeat(1);  //MODIFICATO
     break;

   case EVENT_WINDOW_DEACTIVATED:
     event_toggle_focus(0);
     key_toggle_repeat(1);
     break;

Collaudo. La soluzione è stata collaudata in D1 e D2 giocando molte ore. Risulta che nessun altro tasto tra quelli normalmente in uso prende la ripetizione automatica. Evidentemente, questa funzione key_toggle_repeat() agisce solo nell'ambiente della mappa. Ora la Full Map in D2X-Rebirth funziona meglio che in D2 originale (provare per credere). Per non parlare di D2X-Rebirth versione 0.58.1 dove era praticamente inutilizzabile.





Modifiche - Personalizzazioni.


Personalizzazione 1. Modificare il nome di un Cheat Code.

Se ci piace esplorare i livelli Single Player abbiamo notato che è scomodo digitare il Cheat Code ROCKRGRL per vedere la Full Map e magari ogni tanto sbagliamo a digitarlo. Proviamo a sostituirlo con MAPPA. Oltre a essere più semplice da digitare, MAPPA non lascia attivata la vista posteriore (tasto R). Ma questa modifica difficilmente interessa a chi non scrive in italiano. Seguono le istruzioni dettagliate (anche troppo, ma questo è un allenamento per modifiche più complicate).

- Copiamo e rinominiamo la cartella con i sorgenti da modificare per non fare confusione (per esempio: dxx-rebirth-master-20230202-modifica-mappa).

- Cerchiamo il file gamecntl.cpp.

- Facciamo una copia di sicurezza di questo file (gamecntl.cpp.ORIGINALE).

- Apriamo il file gamecntl.cpp con un Editor di testo.

- Cerchiamo la riga che contiene il testo "rockrgrl".

- Mettiamo due Slash (//) davanti a questa riga. In questo modo l'abbiamo trasformata in un commento: non verrà compilata, non funziona più.

    //  { "rockrgrl", &game_cheats::fullautomap },

- Aggiungiamo un nostro commento.

    // Modificato Cheat Code in data giorno/mese/anno.

- Copiamo la riga originale (senza //) e la modifichiamo come segue.

     { "mappa", &game_cheats::fullautomap },

- Salviamo il file.

- Compiliamo il nuovo codice, con gesti apotropaici a nostra scelta (facciamo le corna, incrociamo le dita, tocchiamo ferro, eccetera...)

- Rinominiamo il file eseguibile per non confonderlo (per esempio: d2x-rebirth-20230202-MAPPA) e copiamolo dove teniamo gli altri eseguibili di D2 (/usr/games/).

- Lanciamolo e se funziona facciamoci tanti complimenti. Se non funziona torniamo sui nostri passi per trovare dove abbiamo sbagliato.








Personalizzazione 2. Full Map a comando in D1.

In D1 originale (DOS, 1995), se si attivano i Cheat Code digitando GABBAGABBAHEY, quando si apre la Mappa (TAB) si può vedere e nascondere la FullMap a piacere premendo ALT-F. Purtroppo le aree inesplorate non sono in blu (questa è una prerogativa di D2). Chiudendo la mappa e riaprendola, bisognava premere nuovamente ALT-F per riattivare la Full Map.

Ecco come avere la Full Map in D1 (senza Cheat Code).
Attenzione: molti giocatori non approverebbero questa modifica.
Partiamo da un codice pulito (privo di personalizzazioni).
Apriamo il file automap.cpp.
Cerchiamo il codice seguente, attorno alla riga 1022.

#if defined(DXX_BUILD_DESCENT_I)
  case KEY_Q:    // ERA: case KEY_ALTED+KEY_F:
    if (1==1)   // ERA: if (cheats.enabled)
    {
      cheats.fullautomap = !cheats.fullautomap;
       // if cheat of map powerup,
      // work with full depth
      auto &plrobj = get_local_plrobj();
      recompute_automap_segment_visibility(LevelUniqueAutomapState, plrobj, am);
    }
  return window_event_result::handled;
#endif

Sostituiamo  case KEY_ALTED+KEY_F:  
  
con  case KEY_Q:
Sostituiamo  if (cheats.enabled)     
   con  if (1==1) 

Compiliamo solo D1 (scons d1x=1). Otteniamo una versione di D1 nella quale se apriamo la Mappa (TAB) basta premere il tasto Q per attivare e disattivare a piacere la FullMap. Il tasto Q è comodo perché è vicino al tasto TAB ed è libero (in D2 noi lo colleghiamo all'Afterburner che in D1 non esiste). Purtroppo le aree inesplorate non sono in blu ma si riesce lo stesso a scoprirle. Vedere la figura seguente.

Launcher





Personalizzazione 3. Eternal Full Map in D2.

Ecco come avere sempre la Full Map in D2, con le aree inesplorate in blu, senza bisogno del potenziamento Full Map e senza digitare un Cheat Code. Attenzione: molti giocatori non approverebbero questa modifica.

Vedi file: automap.cpp

zona della riga 259: mostra tutto (ma non in blu)
zona della riga 1573: (zone non esplorate in blu)

riga 259: sostituito:
  if (1==1)  //  if (cheats.fullautomap) MODIFICA


riga 1571:          
{
   auto &player_info = get_local_plrobj().ctype.player_info;
   if ((cheats.fullautomap || player_info.powerup_flags & PLAYER_FLAGS_MAP_ALL) && !LevelUniqueAutomapState.Automap_visited[seg])
   color = am.wall_revealed_color;
    }

// AGGIUNTO
  {
   if ((1==1) && !LevelUniqueAutomapState.Automap_visited[seg])
   color = am.wall_revealed_color;
  }

// FINE AGGIUNTA

Compiliamo solo D2 (scons d2x=1). Otteniamo una versione di D2 con la Full Map permanente (con le aree inesplorate in blu). Non compiliamo D1 perché otterremmo una versione di D1 dove le aree inesplorate sono visibili ma non in blu.

Spiegazione.
- Cerchiamo di modificare il codice il meno possibile.
- Riga 259. Vogliamo vedere la mappa di tutto il livello sempre, anche quando il Cheat Code non è stato digitato: if (1==1) equivale a dire "sempre", perché 1 è sempre uguale a 1.
- Dalle parti della riga 1573 si trova il codice che rende le zone non ancora esplorate in blu (c'era un difetto nella versione 0.58.1, le zone inesplorate non erano mai rappresentate in blu). Facciamo in modo che le zone non ancora esplorate siano sempre rappresentate in blu, anche quando il Cheat Code non è stato digitato.




Come impostare delle directory alternative.

Se possibile, vorremmo tenere versioni di dxx-rebirth diverse in cartelle ben separate. In Windows è facile. In Linux no: sembra che tutte le versioni vadano a salvare i loro file nella directory predefinita (~/.d2x-rebirth/) o (~/.d1x-rebirth/).

Ecco due cose che non funzionano: (1) l'opzione da riga di comando -hogdir e (2) compilare dxx-rebirth con l'opzione sharepath=path  ("sets system directory to search for game data"). Il programma leggerà la directory che vogliamo noi ma scriverà sempre nella directory predefinita.

Soluzione.
Vedere https://github.com/dxx-rebirth/dxx-rebirth/issues/79

- Un utente chiede come far girare sia la versione Rebirth standard sia la versione Retro, ma in modo che ciascun programma legga e scriva in una directory specifica (Players, Demo, Savegame). Vorrebbe invece mantenere le directory Missions e Data in comune.
- Lo sviluppatore risponde consigliando di usare una variabile di ambiente (environment variable) per cambiare la path predefinita.

Questo comportamento è stato introdotto con il Commit 03b57ab del 18 Ottobre 2015. Il codice in questione si trova nei sorgenti nel file physfsx.cpp.

Il programma considera prima le variabili $D1X_REBIRTH_HOME e $D2X_REBIRTH_HOME. Se non sono definite considera $REBIRTH_HOME. Se anche questa non è definita sceglie le directory predefinite (~/.d1x-rebirth/) o (~/.d2x-rebirth/).

Nota: lo sviluppatore non lo dice, ma per mantenere le directory Missions e Data in comune tra più versioni si può usare l'opzione da riga di comando -hogdir.

(https://github.com/dxx-rebirth/dxx-rebirth/commit
/03b57abff0d8447f6a5ff0954b45894aa7da9c65).

Per impostare una variabile ambiente:
  export REBIRTH_HOME=~/.d2x-VERSIONE-1
  export D1X_REBIRTH_HOME=~/.d1x-VERS-ALT
  export D2X_REBIRTH_HOME=~/.d2x-VERS-ALT
Per controllare una variabile ambiente:  
  echo $REBIRTH_HOME
  echo $D1X_REBIRTH_HOME
  echo $D2X_REBIRTH_HOME

- Se avviamo D2 da riga di comando. Bisogna creare due script bash che impostano la variabile ambiente come desiderato (per esempio: export REBIRTH_HOME=~/.d2x-VERS-ALT) poi lanciano la versione desiderata. In questo modo la variabile non è permanente.

- Se avviamo D2 con il Launcher (figure seguenti). Prepariamo due Launcher che avviano versioni diverse in directory diverse. Mettiamo i Launcher in ~/.local/share/applications.

Per passare una variabile d'ambiente in un Launcher, usiamo il comando env:
Exec=env REBIRTH_HOME=~/.d2x-VERS-ALT /usr/games/d2x-rebirth 0.61-20230421

Launcher
Launcher
LAUNCHER 1
[Desktop Entry]
Name=Descent 2
Comment=DXX-Rebirth source port of Descent 2: Counterstrike from 1996...
Exec=/usr/games/d2x-rebirth-0.61-20230421
Icon=~/.d2x-rebirth/data/d2x-rebirth.ico
Terminal=false
Type=Application
Categories=Game;ActionGame;
StartupNotify=false

LAUNCHER 2
[Desktop Entry]
Name=Descent 2 - ALT DIR
Comment=DXX-Rebirth source port of Descent 2: Counterstrike from 1996...
Exec=env REBIRTH_HOME=~/.d2x-VERS-ALT /usr/games/d2x-VERS-ALT
Icon=~/.d2x-VERS-ALT/data/d2x-rebirth.ico
Terminal=false
Type=Application
Categories=Game;ActionGame;
StartupNotify=false

NOTA. Non impostiamo queste variabili d'ambiente in ~/.bashrc o ~/.profile, perché così diventerebbero permanenti. Tra parentesi, ricordiamo che Launcher onora solo quelle scritte in ~/.profile mentre Bash quelle in ~/.bashrc e ~/.profile.






I segreti dei file DXA.

DXA sta per Descent-X-Addon.

Funzionano in D2X-Rebirth, D1X Rebirth e Source Port derivati.

Contengono file multimediali che vanno a sostituire i media originali della missione principale (D1 FIRST STRIKE o D2 COUNTERSTRIKE): immagini, font, musiche, i testi dei Briefing, ma non i testi dei menu o interni al gioco.

I file DXA vanno messi nella directory dove si trova il file HOG della missione principale (.../data/). DXX-Rebirth li vede, li apre e usa i file contenuti al loro interno al posto dei file con lo stesso nome che si trovano all'interno del file HOG della missione principale.

I file DXA non funzionano per le missioni aggiuntive. Se li mettiamo nella directory di una missione aggiuntiva non vengono letti. Questa è la situazione nel 2023.

Dettagli sui contenuti:
  - Immagini: formato .pcx
  - Font: formato .fnt (font raster per windows)
  - Musica: formato .ogg
  - Testi: file in formato .txb (formato speciale per Descent)

I file DXA sono archivi di file compressi in formato ZIP con l'estensione cambiata in DXA. In passato avevano l'estensione .ZIP, poi nel 2012 gli sviluppatori cambiarono l'estensione in .DXA per evitare malfunzionamenti: capitava che il programma si piantasse cercando di aprire un file ZIP (per esempio un back-up creato dal giocatore) credendolo un AddOn. Fonte delle informazioni: il file Changelog nei sorgenti.

Se si scompatta un file DXA si ottiene una directory che contiene dei file. Per ricreare il DXA originale comprimere SOLO I FILE (senza la directory) in formato ZIP e poi modificare l'estensione in .dxa (minuscolo).

Nella directory del codice sorgente <sorgenti>/d2x-rebirth/utilities/ troviamo dei programmi accessori che risalgono al 1995 e sono stati aggiornati nel corso degli anni.

Qui troviamo i programmi che convertono un normale file di testo in TXB (e viceversa):
   tex2txb.c
   txb2tex.c
Attenzione: il formato TXB supporta i caratteri ASCII. Non supporta le vocali accentate italiane (o altri caratteri non ASCII).

Si compilano così (in Linux):
   gcc ./tex2txb.c
   gcc ./txb2tex.c

Invece questi altri programmi (che si compilano come sopra) estraggono il contenuto dei file HOG (e viceversa):
   hogextract.c
   hogcreate.c

In pratica, se vogliamo tradurre i testi dei Briefing di D1 o D2:
   - hogextract descent2.hog
   - txb2tex <file TXB> <file di testo TXT>
   - Tradurre il file di testo
   - tex2txb <file di testo TXT> <file TXB>
     (se occorre, rinominare i file e sistemare i permessi)
   - comprimere i file TXB in formato ZIP
     (solo i file, non la directory)
   - cambiare l'estensione in .dxa (minuscolo)
   - copiare il file DXA dove si trova il file HOG.

Non possiamo usare i file DXA per tradurre i testi di Vertigo (o di altre missioni aggiuntive che stanno nella directory MISSION). Quindi andremo a creare un nuovo file HOG, così:
   - hogextract d2x.hog
   - txb2tex d2x.txb d2x.txt
   - tradurre il file di testo (d2x.txt)
   - tex2txb d2x.txt d2x.txb
   - mettiamo il file d2x.txb tradotto al posto di quello originale
   - hogcreate d2x.hog
   - mettiamo il nuovo file HOG al posto dell'originale (BACKUP!!!)