!
!	Fichier d'exemple minimaliste avec INFORM 6
!	===========================================
!	
!	Ce document est une aide pour les nouveaux programmeurs en jeux d'aventure 
!	textuels. Il ne pourra pas couvrir tous les aspects de la programmation mais
!	permettra d'avoir une introduction aux principes généraux.
!	
!	Aides complémentaires : 
!	Site du traducteur des bibliothèques françaises : http://jlpo.free.fr/ 
!	Guide du débutant (en anglais) : http://www.firthworks.com/roger/IBG.html
!	Guide complet  (en anglais) : http://www.inform-fiction.org/manual/about_dm4.html
!	Notre site et forum pour une aide sur mesure et en ligne : http://ifiction.free.fr/forumBB
!
!	Et sinon, les commentaires en Inform sont précédés d'un point d'exclamation !
!	Nous vous conseillons d'utiliser un éditeur de texte qui supporte la coloration
!	syntaxique, pour plus de lisibilité.
!	Veuillez bien noter qu'il existe des syntaxes alternative parfois, et que certaines parties de codes
!	ne sont pas forcément expliquées en détail ici. Si vous trouvez qu'il manque certaines explications,
!	merci de nous en faire part sur le forum.

!% ! Les options ci-dessous sont destinées au compilateur :
!% ! (toutes sont désactivées dans cet exemple)
!% ! +include_path=..\..\bibliotheques 
!% ! language_name=French ;
!% ! -v5 ! version souhaitée : v5, v8, G, etc...
!% ! -s ! give statistics
!% ! -X ! infix (ne pas laisser dans la version publiée ; non disponible avec Glulx)
!% ! -D ! debug (ne pas laisser dans la version publiée)
!% ! -r ! imprime le contenu du jeu pour envoi vers un correcteur d'orthographe
!% !+transcript_name=gametext.txt ! fichier d'arrivée
!% !$MAX_SOURCE_FILES=512
!% !$MAX_INCLUSION_DEPTH=10 
!% !$MAX_LABELS=50000
!% !$MAX_INDIV_PROP_TABLE_SIZE=50000 
!% !$MAX_STATIC_DATA=20000

!--------------------------------------------
! Constantes générales
!--------------------------------------------

! Les constantes sont des valeurs fixées une fois pour toute dans le jeu, et qui 
! servent à définir des paramètres dans les mécanismes internes du jeu
! ou des définitions de l'univers (par exemple le système de fenêtrage, score 
! maximum, nombre max d'objets portés...)

Constant Story "Exemple titre";		! titre de l'histoire
Constant Headline "^sous titre^";	! sous titre de l'histoire
Release 1; 				! version


Constant MAX_CARRIED 6;		! nombre maximum d'objets transportés par le joueur.
Constant MAX_SCORE 2;		! score maximum
Constant OBJECT_SCORE 1;	! point gagné par objet spécial ramassé pour la première fois
Constant ROOM_SCORE 1;		! point gagné par pièce spéciale découverte

! Les variables peuvent être internes à un objet, ou définies de façon globales. 
! Lorsqu'elles sont valables pour tout le jeu, on les fait précéder de "Global" 
! pour les initialiser.

Global modereplay = 0; ! celle-ci sert pour des fonctiones de déboggage surtout.


! Les conditions avec #ifdef sont un peu spéciales. Elles servent lors de la compilation.
! Celle qui suit est pour faire la différence entre la version graphique (glulx) ou uniquement
! textuelle (zcode) du jeu. Vous n'avez pas besoin de vous préoccuper de cela pour le moment.

#ifdef TARGET_ZCODE;  	! "si le système cible est texte uniquement (zcode)...
			! ne rien exécuter de plus" (la ligne est vide)
#ifnot; ! TARGET_GLULX; ! "sinon, c'est à dire si c'est graphique (glulx)...
	Constant GG_MAPWIN_ROCK 210;	! initialiser ces constantes et ces variables pour le système de fenêtre..."
	Global gg_mapwin = 0;
	Global musicon = 1;
	Global gg_musicchan = 0;
	Constant theme;
	Constant fin;
	Constant outro;
	Global modeimages = 1; 
#endif;			! fin de la condition


!--------------------------------------------
! Directives de remplacement
!--------------------------------------------
[DeathMessage; print "Vous avez perdu !";];	! sert pour le message lorsque le joueur perd mais ne meurt pas.

Replace RestartSub;				! sert pour le système de fenêtrage. Ne pas s'occuper de cela.

!--------------------------------------------
! Attributs
!--------------------------------------------

!--------------------------------------------


Include "Parser";	! inclusion de bibliothèques Inform obligatoires.
Include "VerbLib";	! inclusion de bibliothèques Inform obligatoires.
Include "infglk";	! inclusion de bibliothèques Inform obligatoires (pour la partie glulx)


!--------------------------------------------

! Les fonctions débutent par un crochet, suivi du nom de la fonction, suivi d'un point virgule.
! (De façon générales les différentes parties de code sont délimitées par un point virgule ;)
! Celle-ci est une fonction native d'Inform, que l'on peut personnaliser à sa guise

[ PrintRank;	! fonction lors de l'affichage du score
print ", vous donnant le rang ";
if (score >= 1) "d'aventurier accompli.";
if (score < 1) "de touriste.";
"de touriste.";
];

! nous venons de découvrir une condition : cela permet de tester SI (if) une variable est supérieure (>)
! ou inférieure (<) à une valeur. Si la première condition est remplie, un message s'affiche et le test
! s'arrête, sinon on teste la suivante et ainsi de suite. 

! ---------------------------------------------------------------------------
! Ceci change le comportement du jeu quand on utilise le mot "tout"
! ou un mot ambigu
! --------------------------------------------------------------------------- 

[ChooseObjects obj code;
if (code<2) { if (obj has scenery) return 2; rfalse; }
if (action_to_be==##Eat && obj has edible) return 3;
if (obj hasnt scenery) return 2;
return 1;
];

!--------------------------------------------
! Variables
!--------------------------------------------

! il n'y en a pas ici de spécifiques pour un jeu aussi court... ;)

!--------------------------------------------
! Routines 
! -------------------------------------------

! encore des fonctions, permettant divers effets visuels.

[Attend;
    if (modereplay == 0)
        KeyCharPrimitive();
];

! par exemple pour attendre dans le jeu et continuer lorsque le joueur presse une touche,
! il suffit d'inclure la fonction " Attend(); " dans le code (cette fonction étant elle-même
! un appel à une autre fonction, mais ici on fait un petit test auparavant pour bloquer 
! cette fonction dans certains contextes.

[Pause;
    if (modereplay == 0)
        KeyDelay(40);
];

! similaire à l'attente, sauf que là le jeu continue tout seul au bout de 4 secondes

[Gras; ! style Gras
    #ifdef TARGET_ZCODE;
    #ifnot; ! TARGET_GLULX;
    glk_set_style(style_Emphasized);
    #endif; ! TARGET_
];

! fonction pour utiliser un style gras d'écriture

[Italique; ! Italique
    #ifdef TARGET_ZCODE;
    #ifnot; ! TARGET_GLULX;
    glk_set_style(style_Note);
    #endif; ! TARGET_
];

[Normal; ! style normal
    #ifdef TARGET_ZCODE;
    #ifnot; ! TARGET_GLULX;
    glk_set_style(style_Normal);
    #endif; ! TARGET_
];



!--------------------------------------------
! Modèles d'objets (déclarations de classes)
!--------------------------------------------

! les classes permettent de définir un modèle qui pourra resservir plus tard pour plusieurs objets.
! Nous reviendrons plus loin sur la structure type d'un objet.

Class Personnage
	with life [;
	! Answer,Ask,Order,Tell:
	! print_ret "Utilisez plutôt -parler à-", (the) self, "." ;
	Kiss: print "Vous essayez d'embrasser ce personnage mais il n'a pas l'air d'accord !^" ; rtrue ;
			  ],
	has animate;


Class Maison
	with before [;
	Listen: print "Vous n'entendez rien de spécial dans cette maison.^" ; rtrue ;
			  ],
	has light;

	
!--------------------------------------------
! Plan des lieux (pièces, portes...)
!--------------------------------------------

! Nous allons rencontrer ici notre premier objet. Un objet est de 2 types dans Inform : lieu ou chose. 
! Les objets ont cette structure :

! 	Objet nom_objet "nom d'affichage de l'objet" 
! 	with	! signifie que l'on commence les définitions, chaque définition est séparée par une virgule
!		description "Description de l'objet lorsqu'on l'examine ou bien ce qu'on voit dans une pièce"
!		n_to autre_piece, s_to encore_une_autre_piece ! lien vers autre pièce
!	has light ;	! ce qui suit has s'appelle Attribute, cela définit des attributs génériques
!			à l'objet, sous forme binaire (comme un interrupteur éteint ou allumé, seulement
!			deux valeurs sont possibles), c'est à dire que l'objet peut être par exemple 
!			ouvert ou fermé, féminin ou non, donnant un score ou pas etc.
!			Des attributs sont déjà prédéfinis, mais on peut en ajouter d'autres.
!			Ils servent généralement lors des tests et conditions.

Object salle1 "Salle 1" class Maison
	with 
		 description "Une pièce vide, avec une sortie au nord.",
		 n_to salle2	! ce lieu donne sur la salle n°2
	has ;			! pas besoin de préciser que le lieu est allumé, car la classe dont
				! il fait partie a déjà l'attribut "light"
				! a noter que si votre pièce reste dans le noir, le joueur 
				! ne pourra rien faire dedans, sauf s'il a un objet qui fournit
				! de la lumière.
	! à noter qu'il est possible de définir une classe en remplaçant Object par le nom de la classe
	! ou bien en écrivant à la suite class_ nom_de_la_classe
		 


Object salle2 "Salle 2"
	with 
		 description "Vous êtes à l'extérieur, pour entrer, c'est vers le sud.",
		 s_to salle1	! cela permet de retourner dans la salle n°1. Il faut définir dans les 2 sens !
	has light scored ;	! Cette pièce n'a pas la classe aussi il faut préciser qu'elle a 
				! de la lumière.
				! De plus lorsque l'on entre dedans cela donne un point


!--------------------------------------------
! NPCs (personnages non joueurs)
!--------------------------------------------


Personnage Homme "homme" salle2	! cet objet est de la classe personnage, 
				! et hérite de ses caractéristiques (essayez de l'embrasser pour voir ! )
	with 
		name 'homme' 'monsieur' 'bonhomme',	! noms de référence lors du jeu. Veuillez 
							! mettre le plus de synonymes possibles, essayez 
							! de prévoir comment le joueur voudra s'y référer.
		description  "Un personnage sans relief. À vous de l'améliorer !",
		times_spoken_to 0, 	! variable pour compter les sujets de conversation. Le nom de variable
					! est ici complètement arbitraire.
	life [;
		Attack: print "Vous frappez l'homme, et il disparaît.^"; remove self; rtrue ; 
			! ce qui se passe lorsque l'on se réfère à l'objet en utilisant certains verbes (ici attaquer)
		Parler: self.times_spoken_to = self.times_spoken_to + 1;	! incrémentation de la variable locale.
			switch (self.times_spoken_to) {
				1: print_ret "Vous lui parlez, et il vous rend un bref salut.";
				2: print_ret "Vous lui parlez, mais il ne réagit pas.";
				3: print "Rien à dire de plus^" ;rtrue ;
		default: return false;}
		;],
	has ;

! ici la variable locale (uniquement valable pour l'objet) times_spoken_to sert à vérifier combien
! de fois on parle au personnage. Lorsque l'on manipule une variable locale (mais pas à l'initialisation), 
! on ajoute le nom de l'objet à laquelle elle appartient avant, un point, puis le nom de la variable. 
! Lorsqu'on manipule la variable dans l'objet auquel elle appartient, on peut utiliser à la place self. 
! Ainsi dans l'exemple plus haut on pourrait dire self.times_spoken_to ou Homme.times_spoken_to
! Par contre si on manipulait la variable depuis un autre objet (par exemple si un second personnage
! devait être au courant du nombre de conversation avec le premier personnage, il faudrait 
! utiliser impérativement Homme.times_spoken_to.
! L'intérêt d'utiliser self permet de réutiliser facilement une partie de code répétitive.

!--------------------------------------------
! Objets déplaçables
!--------------------------------------------


Object Vase "vase" Salle2	! salle2 placé ici signifie que l'objet vase se trouve dans l'objet salle2
	with 
		 description "Un vase.",
		 before [;					
			Attack: remove self ; deadflag=3; print "Vous cassez le vase en mille morceaux. Ce vase précieux était inestimable !" ; rtrue ;
			Rub:	print "Vous frottez le vase et un génie en sort, qui dépose une fleur à vos pieds. Le génie disparaît ensuite.^" ; move Fleur to location ; rtrue ;
			Receive:	if (noun == Fleur) { deadflag=2; print "Félicitation, vous venez de décorer avec goût ce vase." ; rtrue ; } 
			  ; ], 
	name 'vase',
	has open container scored; 	! le vase est ouvert et a l'attribut container, 
				  	! donc on peut mettre quelque chose dedans.


Object Fleur "fleur" ! cet objet ne se trouve nulle part !
	with 
		 description "Une belle fleur odorante.",
		 before [;					
			Attack: remove self ; deadflag=3; print "Vous n'osez pas détruire une aussi belle plante" ; rtrue ;
			Smell:	print "Cette fleur sent très bon.^" ; rtrue ; 	! rtrue permet ici de ne pas afficher
										! le message par défaut lorsque l'on
										! respire quelque chose.
			Give: if (second == Homme && Fleur in Player) {print "L'homme sourit vaguement, prend la fleur, et la fait tomber sur le sol.^" ; move Fleur to location ; rtrue ; }
			  ; ], 
	name 'plante' 'fleur',
	has female ; 	! les objets de marque féminine en français doivent avoir cet attribut pour afficher
			! correctement les articles "la" / "une"

!--------------------------------------------
! Code spécifique
!--------------------------------------------

! ne pas s'occuper de cette partie...

#ifdef TARGET_ZCODE;
#ifnot; ! TARGET_GLULX;
	[ InitGlkWindow winrock;
	switch (winrock) {
	GG_MAINWIN_ROCK:
	}

	rfalse; ! leaving out this line will lead to a messy crash!
];
#endif; ! TARGET_



! Plus bas c'est initialisation principale du jeu. Permet notamment de définir dans quelle salle commence l'histoire.

[Initialise;
		location=salle1;
		lookmode = 2; ! mode long
		
		#ifdef TARGET_ZCODE;
		#ifnot; ! TARGET_GLULX;
			glk_window_clear(gg_mainwin);
			glk_image_draw(gg_mainwin,2,imagealign_InlineCenter, 1); ! Splash screen
			Musique_intro();
			attend();
			glk_window_clear(gg_mainwin);
			gg_mapwin = glk_window_open(gg_mainwin,
			(winmethod_Left+winmethod_Fixed),100,
			wintype_Graphics, GG_MAPWIN_ROCK);
			glk_image_draw(gg_mapwin,1, 0, 0); ! marge motif
		#endif; ! TARGET_
		 ];


!--------------------------------------------
Include "FrenchG";	! partie à inclure obligatoirement pour le français
!--------------------------------------------

!--------------------------------------------
! Verbes ajoutés (extension de FrenchG.h)
!-------------------------------------------- 
	
	
! les verbes avec -Sub à la fin sont les définitions des verbes initialisés plus bas

[MusicPlaySub topic;
  #ifdef TARGET_ZCODE;
print  "Pas de musique dans cette version.";
    #ifnot; ! TARGET_GLULX;
	gg_musicchan = glk_schannel_destroy(gg_musicchan); 
switch (topic) {
	theme : gg_musicchan = glk_schannel_create(0); glk_schannel_play_ext(gg_musicchan, 1, 1, 0);
	outro : gg_musicchan = glk_schannel_create(0); glk_schannel_play_ext(gg_musicchan, 3, 1, 0);
}
print_ret "morceaux disponibles : ~musique~ + theme, outro ...";
#endif; ! TARGET_
 ];

 [MusicOffSub;
#ifdef TARGET_ZCODE;
#ifnot; ! TARGET_GLULX;
if  (musicon == 1)  musicon = 0;
print "[la musique est désactivée]^"; rtrue ;
!else  musicon = 1;
#endif;
];

[MusicOnSub;
#ifdef TARGET_ZCODE;
#ifnot; ! TARGET_GLULX;
if  (musicon == 0)  musicon = 1;
print  "[la musique est activée]^"; rtrue ;
#endif;
];

! Attention juste en dessous ce n'est pas un verbe mais une fonction !

[Musique_intro;
#ifdef TARGET_ZCODE;
#ifnot; ! TARGET_GLULX;
	if (musicon == 1)	  {
			gg_musicchan = glk_schannel_destroy(gg_musicchan);
			gg_musicchan = glk_schannel_create(0);
			glk_schannel_play_ext(gg_musicchan, 100, 1, 0); ! musique intro
		}
#endif;
];

 
[MusicStopSub;
		#ifdef TARGET_ZCODE;
		#ifnot; ! TARGET_GLULX;
	gg_musicchan = glk_schannel_destroy(gg_musicchan);	
		#endif; ! TARGET_

];

[ParlerSub;
	if (noun == player) print_ret "Cela ne vous étonne pas d'apprendre cela.";
	if (RunLife(noun,##Parler) ~= false) return; ! consult life[; Parler: ]
	print_ret " Vous ne savez pas quoi dire.";
];


Extend 'parler' replace
		* 'aux'/'a'/'à'/'au'/'avec' creature -> Parler
		* creature -> Parler
		* 'à'/'a'/'au'/'aux'/'avec' creature 'de'/'du'/'des'/'l^' topic -> Tell
		* creature 'de'/'du'/'des'/'l^' topic -> Tell
		* creature topic -> Tell;


		

Verb "load"     
                *                                -> Restore;

Verb "Restore"    
                *                                -> Restore;


                
Verb 'music' 'musique'
		* 	   	       -> MusicStop
		* 'stop'		-> MusicStop
		* 'off'   	       -> MusicOff
		* 'on'   	       -> MusicOn
		* topic   	       -> MusicPlay;
		                


[ RestartSub;
	L__M(##Restart,1);
	if (YesOrNo() ~= 0) {
#ifdef TARGET_ZCODE;
#ifnot; ! TARGET_GLULX;
	<MusicStop>;   ! pour arrêter la musique
	if (modeimages ~= 0)
		{ glk_window_close(gg_mapwin,0);} 
!	modeimages = 1 ;
#endif; ! TARGET_
	@restart;
	L__M(##Restart, 2);
}
];


Extend 'recommencer' replace
	* 			-> Restart;