!============================================================================
!	AttrTest.h
!	A library extension for Inform 5.5 / Library 5/12
!	By Julian Arnold
!	Release 2
!============================================================================

!----------------------------------------------------------------------------
!	This library extension provides a new debugging verb, "attributes"
!	(or various synonyms, see below) allowing you to list or change the
!	attributes of any object in your game whilst you play it (provided
!	DEBUG has been set).
!
!	The command format is "attributes <reason> <noun> [<attribute(s)>]",
!	where <reason> is one of the following:
!		"list": Lists all the attributes which the object (specified
!		as <noun>) currently has.
!		"give": Gives <noun> <attribute(s)>.
!		"remove": Removes <attribute(s)> from <noun>.
!
!	Include this file in your source *after* you (and the library) have
!	declared all attributes and aliases, and *after* you have included
!	`grammar.h'.  Including `attrtest.h' at the very end of your source
!	may be a good idea then.
!
!	NOTES
!	-----
!	1: Absent is aliased with female in `parser.h'. This is invisible to
!	`attrtest.h', so these two attributes are synonymous for the purposes
!	of the this extension (as they are, in fact, for all other purposes)
!	and, if an object has either, will both be listed. This will be true
!	of any aliased attributes you add, too. It's up to you to remember
!	what is aliased with what.
!	2: Obviously I can't tell if you're going to add new attributes to
!	your game, or alias the old ones. This is a shame as it means that
!	`attrtest.h' can't account for such non-standard attributes "straight
!	out of the box." However, it is quite simple to update the list of
!	attributes which `attrtest.h' knows about. To do this, simply add the
!	name of the attribute to the array `attributes' (see below), and a
!	word (usually the attribute's name again) in single quotes.
!	3: Inform only recognizes the first 9 characters of dictionary words.
!	This means that attributes with names longer than this (eg,
!	transparent) will be truncated in lists generated by "attributes
!	list <noun>". This will have no bearing on the functioning of
!	`attrtest.h' unless you have multiple attributes with long names
!	which are the same for the first 9 characters, such as, say,
!	entertainer and entertainee. So don't do it.
!----------------------------------------------------------------------------

#ifdef DEBUG;

!============================================================================
!	Arrays
!============================================================================

#array attributes table
[;

	absent		'absent'
	animate		'animate'
	clothing	'clothing'
	concealed	'concealed'
	container	'container'
	door		'door'
	edible		'edible'
	enterable	'enterable'
	female		'female'
	general		'general'
	light		'light'
	lockable	'lockable'
	locked		'locked'
	moved		'moved'
	on		'on'
	open		'open'
	openable	'openable'
	proper		'proper'
	scenery		'scenery'
	scored		'scored'
	static		'static'
	supporter	'supporter'
	switchable	'switchable'
	talkable	'talkable'
	transparent	'transparent'
	visited		'visited'
	workflag	'workflag'
	worn		'worn'

];


!============================================================================
!	Grammar
!============================================================================

[ AttrAnything  i;

	switch ( scope_stage ) {
	1:	rfalse;
	2:
		for ( i = 0 : i <= top_object : i++ ) PlaceInScope( i );
		rtrue;
	3:	"[Error from AttrTest.h: No such object.]";
	}
                                                         
];

[ AttrConsult  w;

	consult_from = wn;
	do w = NextWordStopped();
	until ( w == -1 );
	consult_words = ( wn - 1 ) - consult_from;
	if ( consult_words == 0 ) return -1;
	rfalse;

];

[ AttrListSub  i label;

	print ( The ) noun, " currently has the following attributes:^";
	for ( i = 1 : i <= attributes-->0 : i = i + 2 ) {
		label = attributes-->i;
		if ( noun has label )
			print "  ", ( address ) attributes-->( i + 1 ), "^";
	}

];

[ AttrGiveSub; AttrChange(); ];

[ AttrRmveSub; AttrChange( 1 ); ];

[ AttrChange flag  i j w label match;

	wn = consult_from;

	for ( i = 1 : i <= consult_words : i++ ) {
		match = 0;
		w = NextWord();
		for ( j = 1 : j <= attributes-->0 : j = j + 2 )
			if ( w == attributes-->( j + 1 ) ) {
				match = 1;
				label = attributes-->j;
				if ( flag == 0 ) give noun label;
				else give noun ~label;
			}
		if ( match == 0 )
			"[Error from AttrTest.h: No such attribute.]";
	}

	"[Message from AttrTest.h: Successful.]";

];

#verb meta "attribute" "attr" "attrs" "attrib" "attribs"
	* "list" scope=AttrAnything                         -> AttrList
	* "give" scope=AttrAnything AttrConsult             -> AttrGive
	* "remove" scope=AttrAnything AttrConsult           -> AttrRmve;

#endif; ! DEBUG