******************************************************************
COME GESTIRE I CONTENITORI 
(tratto dall'articolo sulla programmazione in Inform di Giancarlo 
Niccolai, apparsi sul numero 2 di Terra d'IF)
http://www.robertograssi.net/at/terradif.asp
*******************************************************************

Un importante prerequisito: questi articoli sono riservati a coloro che già 
conoscono le basi della programmazione inform. Per i principianti di Inform 
consigliamo i seguenti siti:

	Guida a Inform per Principianti (GIP):
	http://www.inform-italia.org/docs/gip/
	Un manuale su Inform:
	http://www.casalengo.it/vscarpa/inform/manuale/


In questo secondo e ultimo numero dedicato ai contenitori, vediamo due aspetti che
li riguardano: il primo è la modalità di visualizzazione del contenuto, e il secondo 
è la modalità di apertura. Dato che i contenitori condividono con le porte due
caratteristiche molto importanti (quella di poter essere aperti e possibilmente 
chiusi a chiave), parleremo incidentalmente anche di queste ultime.


Controllo dei contenitori

Iniziamo dunque con il contenitore più semplice possibile, e vediamo cosa ci offre:

Class VerboseContainer
	has container openable lockable;

VerboseContainer -> "scatoletta"
	with
	name 'scatola' 'piccola' 'scatoletta',
	description "Una scatola nera abbastanza grande.",
	has open female;


Piuttosto elementare. Al suo interno ho inserito due monete, per vedere cosa succede
aprendo la scatola e osservandone il contenuto; ecco il risultato (si noti che la 
scatola è inizialmente aperta):


!=============================================================================!
La stanza
Una stanza dimostrativa con qualche piccolo oggetto ed un contenitore "verboso".
Puoi vedere una scatoletta (nella quale ci sono una moneta piccola e una moneta 
grande) qui.

>esamina la scatoletta
Una scatola nera abbastanza grande.

>guarda nella scatoletta
Dentro la scatoletta vedi una moneta piccola e una moneta grande.

>chiudi la scatoletta
Ora hai chiuso la scatoletta.

>apri la scatoletta
Hai aperto la scatoletta, trovando una moneta piccola e una moneta grande.
!=============================================================================!


Possiamo qui vedere alcune caratteristiche molto interessanti:

Prima di tutto, viene stampato un "messaggio standard" tra parentesi nella descrizione
della stanza, che indica il contenuto dell'oggetto, nel caso questo sia aperto. Potremmo
desiderare qualcosa di più "discreto" (evitare qualsiasi riferimento agli oggetti
contenuti, anche se il contenitore è aperto), oppure potremmo volere una descrizione
più elegante;

La seconda cosa che salta all'occhio è che il verbo "esamina" non dà alcuna informazione
sul suo contenuto. Anche questo dettaglio è da rivedere; un giocatore che esamina un
oggetto che contiene altri oggetti (visibili) si aspetta che essi siano indicati;
Il terzo dettaglio riguarda l'apertura dell'oggetto. Quando viene aperto, il contenitore
standard indica il proprio contenuto al giocatore; questo è un comportamento il più
delle volte desiderabile, ma anche qui potremmo voler configurare il messaggio
oppure escluderlo completamente;
Infine, anche se il risultato dell'azione "guarda dentro" è coerente, potremmo voler
fornire una descrizione diversa.
Per cambiare questi comportamenti, dovremo intercettare le azioni Open, Examine e
Search (corrispondente a "guarda dentro"), e dovremo scrivere una routine describe
che ha il compito di descrivere il contenitore all'interno di una stanza. Creeremo anche
una nuova proprietà, chiamata verbosity, che ci permetterà di selezionare il grado di
verbosità, ossia di descrittività del nostro oggetto.


Il livello di verbosità avrà il seguente significato:
0: il contenitore non indica mai il proprio contenuto, eccetto quando esaminato;
1: il contenitore indica il proprio contenuto anche quando viene aperto;
2: il contenuto viene riportato anche quando il contenitore è descritto nella pagina.


Come ultimo tocco di configurabilità, useremo un metodo list_content() che riceverà
come parametro un numero diverso a seconda di quale di queste tre routine chiede la
lista degli oggetti. 
Questo consentirà di modificare uno o più <di uno dei> messaggi
di default, e addirittura di modificarli "dinamicamente", ossia di cambiare la verbosità
dei contenitori durante il gioco. Vediamo come si fa:


Class VerboseContainer
	with
	! Supponiamo massima verbosità di default.
	verbosity 2,
	describe [;
		print "In questa stanza vedi ", (the) self;
		if ( self.verbosity > 1 && self has open && child(self) ~= nothing ) {
			print " ";
			self.list_contents( 0 );
		}
		print ".^";
		rtrue;
	],
	before [;

	! Diciamo al sistema di interpretare un "esamina" esattamente 
	! come un "guarda in".
	Examine: <Search self>;
	Search:
		if ( self provides description )
			PrintOrRun( self, description );
		if ( child(self) ~= nothing ){
			self.list_contents(2);
			rtrue;
		}
		else if ( self provides description )
			rtrue;
		! In questo modo, la libreria gestirà il caso di un contenitore senza
		! descrizione e contenuto
		rfalse;
	Open:
		! Lasciamo che il sistema risolva da solo il caso di un contenitore
		! chiuso a chiave, o già aperto o non apribile.
		if ( self has locked || self has open || self hasnt openable )
		rfalse;

		! Ma gestiamo noi l'apertura di un contenitore chiuso e apribile
		if ( self.verbosity > 0 && child(self) ~= nothing ) {
			print "Fatto. Aprendo ", (the) self, " ";
			self.list_contents( 1 );
		}
		else {
			print "Fatto";
		}
		print ".^";

		! Diremo al sistema che abbiamo fatto tutto noi, quindi dobbiamo 
		! ricordarci di aprire davvero l'oggetto...
		give self open;
		rtrue;
	],

list_contents[ type;
	switch( type ) {
		! Richiesta proveniente dalla descrizione della stanza
		0: print "(contenente ";
		WriteListFrom( child(self), ENGLISH_BIT | TERSE_BIT );
		print ")";

		! Richiesta proveniente dall'apertura di un oggetto
		1: print "trovi ";
		WriteListFrom( child(self), ENGLISH_BIT | TERSE_BIT );

		! Richiesta proveniente da "esamina/guarda in"
		2: print "Dentro ", (the) self,", vedi ";
		WriteListFrom( child(self), ENGLISH_BIT | TERSE_BIT );
		print ".^";
	}
],
has container openable lockable;


WriteListFrom() è una routine di libreria che stampa una lista di oggetti (a partire 
dal primo "fratello", il child() del contenitore), usando diversi stili. 
ENGLISH_BIT in realtà viene usato per stampare una lista "discorsiva", ossia 
una serie di elementi separati da virgole e congiunzioni adeguate, nella lingua 
utilizzata dal programma. Per ulteriori dettagli si veda il DM4. 
La classe è ora pronta per essere usata in oggetti abbastanza
complessi, con la possibilità di configurare, anche durante il gioco stesso, le modalità
con le quali gli oggetti vengono visualizzati.
Segue un piccolo programmino che può essere utilizzato per testare il nostro lavoro.



!--------------------------------------------------------
! Dimostrazione di VerboseContainer
!--------------------------------------------------------
! libreria di inform

include "parser";
include "verblib";

! replace di infit
include "replace";

!
! Inserire qui la definizione di VerboseContainer definita
! sopra

Object room "La stanza"
	with
	description "Una stanza dimostrativa con qualche piccolo
	oggetto ed un contenitore ~verboso~."
	has light;

VerboseContainer -> "scatoletta"
	with
	name 'scatola' 'piccola' 'scatoletta',
	capacity 4,
	description "Una scatola nera abbastanza grande.",
	has open female;

Object -> -> coin1 "moneta piccola"
	with
	name 'moneta' 'piccola',
	size 1,
	description "Una graziosa moneta dorata. Probabilmente,
	oro falso.
	@`E molto leggera...",
	has female;

Object -> -> coin2 "moneta grande"
	with
	name 'moneta' 'grande',
	size 2,
	description "Una graziosa moneta dorata. Sta comodamente
	in un palmo della mano.",
	has female;

[ Initialise;
	location = room;
];

! grammatica italiana per inform
include "ItalianG";




Ecco come si presenta il nostro oggetto in azione:

!=============================================================================!
La stanza
Una stanza dimostrativa con qualche piccolo oggetto ed un
contenitore "verboso".
In questa stanza vedi la scatoletta (contenente una moneta
piccola e una moneta grande).

>chiudi la scatola
Ora hai chiuso la scatoletta.

>l
La stanza
Una stanza dimostrativa con qualche piccolo oggetto ed un
contenitore "verboso".
In questa stanza vedi la scatoletta.

>prendi la scatola
Presa.

>aprila
Fatto. Aprendo la scatoletta trovi una moneta piccola e una
moneta grande.

>esaminala
Una scatola nera abbastanza grande.
Dentro la scatoletta, ci sono una moneta piccola e una moneta
grande.
!=============================================================================!


Il nostro contenitore è ora quasi completo; abbiamo visto nell'articolo 
precedente come rendere il contenitore capace di determinare il peso o 
l'ingombro del proprio contenuto, e ora abbiamo visto come configurarne la 
visualizzazione. Non abbiamo parlato però della visualizzazione durante 
l'inventario, che sarà argomento di un articolo futuro, ma il codice di libreria 
per la visualizzazione dei contenitori nell'inventario è ritenuto da molti 
piuttosto buono.
Inoltre, si è tralasciata la possibilità di scrivere se un oggetto è "aperto" 
o "chiuso" nella routine list_contents; come si usa dire, questo "è lasciato 
come esercizio al lettore" ;-).

A parte questi due aspetti, uno troppo complesso per trovare spazio qui e l'altro
decisamente triviale, resta il problema degli oggetti "chiusi a chiave".
Programmazione






