Inform e Glulx/RUINS, l'avventura comincia/Chi ha paura del buio (gli insetti no di certo)?
Siete in una sala di pietra oscura e profonda, pervasa dalla foschia e larga circa dieci metri. Un raggio di sole, proveniente dalla cima della scalinata, la illumina diffusamente, ma le ombre del livello più basso rivelano dei passaggi verso est e sud, che non sapete dove conducono. Delle iscrizioni scolpite riempiono le pareti, il pavimento e il soffitto. Provate a dirigerti verso sud, e vi ritrovate al buio. Vi sentite quasi soffocare, e come se non bastasse, da qualche parte dei piccoli artigli si stanno muovendo velocemente. Il vostro respiro diventa sempre più affannoso, e del sudore freddo vi cola dalla fronte: la mamma vi ha sempre detto di evitare certi posti, ma non le avete mai dato retta, e se ora vi ritrovate in questa pessima situazione la colpa è soltanto vostra. Sentite un ticchettio ai vostri piedi e date un calcio contro qualcosa di cheratinoso che vola via. Il suono si è trasformato in un minaccioso stridio e avete la spiacevole sensazione che questi maledetti insetti vogliano divorarvi: non potete far altro che tornare indietro, salvandovi appena in tempo dai loro pericolosissimi artigli. Questa volta ve la siete vista davvero brutta...
Chi ha paura del buio (gli insetti no di certo)?
[modifica | modifica sorgente]Nel secondo paragrafo di questo capitolo abbiamo visto come mettere in relazione due oggetti fra di loro. Ma se voglio mettere in relazione un oggetto con più oggetti (se voglio cioè fare in modo che un oggetto sia visibile in due o più di locazioni) come posso fare?
Diamo un’occhiata alla definizione dell’oggetto low_mist
:
Object low_mist "nebbia bassa" with article "della", name 'bassa' 'foschia' 'nebbia', description "La nebbia ha un aroma che ricorda la tortilla.", before [; Examine, Search: ; Smell: <<Examine self>>; default: "La nebbia non @`e abbastanza consistente."; ], react_before [; Smell: if (noun == nothing) <<Smell self>>; ], found_in Square_Chamber Forest, has female scenery;
Alla penultima riga, l’istruzione found_in
fa in modo che la nebbia sia presente nella Sala Quadrata
e nel Grande Altopiano
; ne consegue quindi, che tutti gli eventi descritti al suo interno si verificano in entrambe le locazioni.
Altra cosa da notare, è che la maggior parte delle azioni in inform, sono incluse in due proprietà: after
e before
. Nell’appendice A è presente un elenco di tutte le azioni principali presenti in Inform (o meglio, di tutte le azioni principali definite in Infit), che sono a loro volta suddivise in tre gruppi:
- Gruppo 1 rappresentato dai cosiddetti comandi di sistema (come ad esempio "
esci
", "verifica
", "salva
", ecc.) che non vengono associati a nessuna proprietà:
if (yesorno()) <RESTORE>;
in questo esempio, se il giocatore digita "S
", viene caricata la situazione del gioco salvata precedentemente;
- Gruppo 2 a cui appartengono tutte le azioni controllate dalla proprietà
after
; - Gruppo 3 a cui appartengono, invece, tutte le azioni controllate dalla proprietà
before
.
Cerchiamo ora di capire meglio quanto detto. Nell’oggetto Forest
, per esempio, abbiamo definito il verbo ascolta
nel seguente modo:
before [; Listen: "Urla di scimmie, pipistrelli, pappagalli, macao."; ],
e tutto sembra quadrare con quanto fin qui detto. Infatti, andando a vedere la tabella dell’appendice A, vediamo che questo verbo corrisponde in inglese all’azione Listen
e che appartiene al gruppo 3.
Questo discorso però, è valido fino a un certo punto: nell’oggetto sodium_lamp
, che sarà descritto in dettaglio nel prossimo paragrafo, il verbo accendi
, appartenente al gruppo 2, è presente nella proprietà before
. Perché?
Il motivo è da ricercare nel funzionamento di queste due proprietà. Francesco Cordella[1] cerca di farcelo capire proponendo questo semplice esempio:
Object -> Cassa "cassa" with name 'cassa', initial "Per terra c'è un'enorme cassa." after [; Open: "Pensavi che fosse pi@`u difficile aprirla ma ci riesci in un batter d'occhio."; ], has static female container openable;
Abbiamo quindi una cassa chiusa ma apribile. Se il giocatore digita "apri la cassa
", Inform apre la cassa, ovvero dà a quest’ultima il valore open
. Poi, prima di stampare il messaggio standard ("Hai aperto la cassa
"), consulta after
e si chiede se c’è qualcos'altro che il programmatore gli ordina di fare prima di stamparlo. Se after
non c'è, Inform prosegue e stampa il messaggio standard. Ma se c'è, come nel nostro caso, stampa quello che c'è da stampare:
>apri la cassa Pensavi che fosse più difficile aprirla ma ci riesci in un batter d'occhio.</code> <code>>esamina la cassa La cassa è vuota.
Se invece sostituiamo la proprietà after
con before
, ecco cosa accade:
>apri la cassa Pensavi che fosse più difficile aprirla ma ci riesci in un batter d'occhio.</code> <code>>esamina la cassa Non puoi vedere dentro, perché la cassa è chiusa.
apparentemente tutto sembra andare per il verso giusto, ma non è così: esaminando la cassa infatti, scopriamo che è ancora chiusa. Usando before
Inform non apre la cassa, dobbiamo dirglielo noi:
before [; Open: give self open; ! give (dai) self (alla cassa) open "Pensavi che fosse pi@`u difficile aprirla ma ci riesci in un batter d'occhio."; ],
Se tutto questo vi ha confuso un po’ le idee, non preoccupatevi più di tanto e seguite questa semplice regola: quando definite un oggetto e stabilite una certa azione, provate a usare per prima la proprietà relativa al gruppo di appartenenza di quella azione: se fa quello che volete, bene, altrimenti provate con l’altra proprietà. Tenete inoltre presente che, all’interno della definizione di un oggetto, una stessa azione può essere usata in entrambe le proprietà (può cioè essere presente allo stesso tempo sia in after
che in before
a seconda di quello che deve fare). Se volete, potete provare come esercizio a invertire le proprietà delle azioni di tutti gli oggetti visti finora. Ne vedrete delle belle...
Riportiamo ora la nostra attenzione sull’oggetto low_mist
. In Inform, oltre alla after
e alla before
, esiste un’altra proprietà, chiamata react_before
, sulla quale occorre fare alcune considerazioni:
- agisce solo sugli oggetti
in_scope
(quelli cioè visibili dal giocatore); - il suo uso più comune è quello di evitare le azioni senza oggetto. Nel nostro caso, infatti, se
noun = nothing
(se scrivo cioè "annusa
" al posto di "annusa l'aria
", dovearia
è ilnoun
), Inform esegue il codice previsto per l’azionesmell
definita nella proprietàbefore
(ovvero di eseguire il comando "esamina la nebbia
" che, come già sappiamo, stampa a video il messaggio appartenente alla proprietàdescription
dell’oggetto stesso ➨self
); - alcuni programmatori, come ad esempio Tommaso Caldarola[2], la usano sull’azione
Examine
degli oggetti di tiposwitchable
(di oggetti cioè, che si possono attivare o disattivare, come vedremo meglio nel prossimo paragrafo), evitando così i fastidiosissimi messaggi di libreria del tipo "in questo momento è attivato/disattivato
".
Per qualsiasi altra azione eseguita sulla nebbia (ad esempio "prendi la nebbia
") viene visualizzato il messaggio di default della proprietà before
("La nebbia non è abbastanza consistente
").
Ora possiamo finalmente occuparci del buio, il tema principale di questo paragrafo. L’oggetto Corridor
:
Object Corridor "Corridoio in pendenza" with description "Un corridoio basso e squadrato va da nord verso sud, inclinandosi verso la fine.", n_to Square_Chamber;
non ha l’attributo light
. Come abbiamo già visto nel primo paragrafo di questo capitolo, Inform attiva in questo caso la modalità the_dark
. La prima cosa da notare è la possibilità personalizzare il messaggio di default, cosa che avviene nella funzione Initialise
:
[ Initialise; . . . thedark.description = "L'oscurit@`a intorno a te @`e opprimente e ti senti quasi soffocare."; . . . ];
the_dark
, a sua volta, viene visto da Inform come un oggetto vero e proprio, al quale si possono relazionare altri oggetti come nel caso del tiny_claws
:
Object tiny_claws "suono di piccoli artigli" thedark with name 'piccoli' 'artigli' 'suono' 'creature' 'mostri' 'insetti', initial "Da qualche parte, dei piccoli artigli si stanno muovendo velocemente.", before [; Listen: "Come sembrano intelligenti per essere solo degli insetti."; Touch, Taste: "Non dovresti volerlo. Davvero."; Smell: "Puoi solo sentire la tua paura."; Attack: "Le creature schivano facilmente i tuoi colpi."; default: "Le creature ti sfuggono squittendo."; ], each_turn [; StartDaemon(self); ], daemon [; if (location ~= thedark) { self.turns_active = 0; StopDaemon(self); rtrue; } switch (++(self.turns_active)) { 1: "^Senti che le creature si stanno avvicinando: il tuo respiro diventa sempre pi@`u affannoso."; 2: "^Del sudore freddo ti cola dalla fronte: le creature sono quasi qui!"; 3: "^Senti un ticchettio ai tuoi piedi e dai un calcio contro qualcosa di cheratinoso che vola via. Il loro suono si @`e trasformato in un minaccioso stridio."; 4: deadflag = true; "^Senti improvvisamente un dolore al polpaccio, simile a quello di una puntura ipodermica. Quasi subito i tuoi polmoni si paralizzano, le spalle e le ginocchia si bloccano, la lingua si gonfia..."; } ], turns_active 0;
La novità principale della definizione di questo nuovo oggetto è l’utilizzo di un Daemon
.
In Inform, ogni mossa che viene fatta dal giocatore equivale a un turno. Cercando di semplificare il più possibile, possiamo affermare che un Daemon
è un particolare oggetto che ci permette di correlare le azioni con lo scorrere del tempo (con l’avanzare cioè, delle numero dei turni). Proviamo allora a vedere in azione l’oggetto tiny_claws
:
>La Sala Quadrata Sei in una sala di pietra oscura e profonda, larga circa dieci metri. Un raggio di sole, proveniente dalla cima della scalinata, la illumina diffusamente, ma le ombre del livello più basso rivelano dei passaggi verso est e sud, che conducono verso la più profonda oscurità del Tempio. Delle iscrizioni scolpite riempiono le pareti, il pavimento e il soffitto.</code> <code>>s Oscurità L'oscurità intorno a te è opprimente e ti senti quasi soffocare. Da qualche parte, dei piccoli artigli si stanno muovendo velocemente.</code> <code>>aspetta Il tempo passa. Senti che le creature si stanno avvicinando: il tuo respiro diventa sempre più affannoso.</code> <code>>esamina le creature Le creature ti sfuggono squittendo. Del sudore freddo ti cola dalla fronte: le creature sono quasi qui!</code> <code>>uccidi le creature Le creature schivano facilmente i tuoi colpi. Senti un ticchettio ai tuoi piedi e dai un calcio contro qualcosa di cheratinoso che vola via. Il loro suono si è trasformato in un minaccioso stridio.</code> <code>>prendi le creature Le creature ti sfuggono squittendo. Senti improvvisamente un dolore al polpaccio, simile a quello di una puntura ipodermica. Quasi subito i tuoi polmoni si paralizzano, le spalle e le ginocchia si bloccano, la lingua si gonfia...</code> <code> *** Sei morto ***</code> <code>In questa partita hai totalizzato 0 punti su 0 possibili, in 10 turni. Vuoi RICOMINCIARE, CARICARE una partita salvata o USCIRE? ></code> |} L’istruzione <code>each_turn</code> esegue il suo contenuto a ogni mossa del giocatore, condizione ideale per il Daemon. L’istruzione <code>StartDaemon(self)</code> lo attiva e lo fa partire; subito dopo, segue la definizione vera e propria (il corpo del Daemon), che deve trovarsi all’interno della funzione <code>daemon</code>. Qui, la variabile locale <code>turns_active</code> viene incrementata di 1 ogni volta che il giocatore fa una mossa e, attraverso un ciclo <code>switch_case</code>, ne viene testato il contenuto: * alla prima mossa, <code>turns_active</code> vale 1 e viene stampato il messaggio corrispondente; * alla seconda mossa, <code>turns_active</code> vale 2 e viene stampato il messaggio corrispondente; * alla terza mossa, <code>turns_active</code> vale 3 e viene stampato il messaggio corrispondente; * alla quarta mossa, <code>turns_active vale 4</code> (viene quindi stampato il messaggio corrispondente), la variabile di libreria <code>deadflag</code> vale <code>true</code> (o meglio, vale 1) e il giocatore viene così ''ucciso'' facendo terminare il Daemon insieme al gioco. Notate che, se la locazione non è <code>the_dark</code>, il daemon termina (<code>StopDaemon(self);</code>), <code>turns_active</code> vale zero, e viene infine restituito il valore <code>true</code> che fa fermare Inform (nel senso che Inform non esegue più le istruzioni della funzione <code>daemon</code>). In questo modo, diamo la possibilità al povero archeologo di non essere sbranato dagli insetti famelici: <pre>>La Sala Quadrata Sei in una sala di pietra oscura e profonda, larga circa dieci metri. Un raggio di sole, proveniente dalla cima della scalinata, la illumina diffusamente, ma le ombre del livello più basso rivelano dei passaggi verso est e sud, che conducono verso la più profonda oscurità del Tempio. Delle iscrizioni scolpite riempiono le pareti, il pavimento e il soffitto.</code> <code>>s Oscurità L'oscurità intorno a te è opprimente e ti senti quasi soffocare. Da qualche parte, dei piccoli artigli si stanno muovendo velocemente.</code> <code>>aspetta Il tempo passa. Senti che le creature si stanno avvicinando: il tuo respiro diventa sempre più affannoso.</code> <code>>n La Sala Quadrata Delle iscrizioni scolpite riempiono le pareti, il pavimento e il soffitto.</code> <code>>
andando verso nord, si ritorna in una locazione che ha l’attributo light
e il daemon, come abbiamo già detto, termina[3].
Note
[modifica | modifica sorgente]- ↑ Autore di Flamel e Kazan, Francesco Cordella è anche il curatore del sito http://www.avventuretestuali.com/.
- ↑ Tommaso Caldarola è l’autore della bellissima Pecos Town, nonché uno dei programmatori più esperti di questo linguaggio di programmazione. Ulteriori informazioni potete trovarle all’indirizzo http://www.caldarola.net/.
- ↑ Cliccate qui per scaricare il listato di questo esercizio (il file 4.04.inf).