!------------------------------------------------------------------------
! Objlstr.h Version 1.50 A Debugging Aid
! Marnie Parker aka FemaleDeer aka Doe
[email protected] 3/18/00
!------------------------------------------------------------------------
! One could properly call this include file essentially a hack. The code I
! wrote myself is very simple. The main code comes from Tony Lewis's
! debugrtn.h (a forever-to-be-unreleased h file -- I swear there is no
! connection between Tony sharing his code with me and his later strange
! disappearance ;-)) and Graham Nelson's parserm.h.
!
! Back when I was writing Paradox programs (which uses forms that have
! fields that can be defined with "pictures") I often used a third party
! product that would print out a list of those fields and their pictures.
! Very handy, because double checking them while in the program was tedious.
!
! So I wished for something similar for Inform. An object lister that
! would help me debug my games. (Because Showobj only shows one at a time.)
! Instead of poring over code to double check whether I had made something I
! wanted to be static, static (it's lots a fun when the player can walk off
! with a door), I wanted a list that would show me right away. Also one to
! quickly show me if my room directions matched up (player exits the tunnel
! south and enters the cave, player exits the cave north and enters the tunnel).
!
! This file is the result of that wishing. Not a perfect solution, because
! the information in routines will not be printed.
!
! Here's to better debugging (yeah!). Sorry this can't also help you with
! buggy routines (ah, there's the rub). :-) Doe
!
! Version 1.1 makes including certain objects optional so the user doesn't
! have to comment them out, but comment them in when they want to include
! them. A helpful change suggested by Roger Firth.
!
! Notes in this file break down into usage (how to use this as a debugging
! aid) and programming (what specific programming "tricks" are used).
!
! Usage:
!
! Include after parser.h and also invoke DEBUG (Constant Debug;) as this
! file uses Showobj. Script on before you list something so you can save
! it to a file for later printing. Script off, of course, when done.
!
! A list of objects, each object separated by a line, meeting the conditions
! you select will print to screen (and also be saved to file, with script on).
!
! To exclude some objects from inclusion see Special Objects below.
!
! Commands:
! list rooms -- will list all the rooms
! list dirs -- will list all rooms showing JUST directions
! (other information included in list rooms is
! omitted so one can debug directions quickly)
! list takeable -- will list all takeable objects
! list hidden -- will list all hidden ("takeable") objects
! list nontakeable -- will list all nontakeable objects
! list has <attr1> <attr2> <attr3>
! -- will list all objects with these attributes
! (limit of three attributes)
! Examples:
! list has supporter -- will list all supporters
! list has supporter static -- will list all static supporters
! list has animate -- will list all creatures
! list has animate neuter -- will list all neuter creatures
! list has door lockable locked -- will list all locked un/lockable doors
!
! list with <prop1> <prop2> <prop3>
! -- will list all objects with these properties
! (limit of three properties, although
! combinations are less useful here)
! Examples:
! list with found_in -- will list all floating objects
! list with time_out -- will list all objects that use timers
! list with daemon -- will list all objects with daemons
!
! list has <attr1> <attr2> <attr3> with <prop1> <prop2> <prop3>
! -- will list all objects with these attributes
! AND properties (limit of three each)
! Example:
! list has door with with_key -- will list all doors with keys
!
! list with <prop1> <prop2> <prop3> has <attr1> <attr2> <attr3>
! -- same as the above, just reversed wording
!
! Note: Entering a partial string may include a similar property or attribute.
! Example, "list with door", will list all objects with door_to and door_dir.
! But if you enter an invalid attribute or property, this file will print
! an error message <invalid attribute or property>. Then Inform will add,
! "I didn't understand that sentence.". The additional line has to do
! with the way Inform processes verbs and can't be skipped.
!-----------------------------------------------------------------------
! Others' Routines
!-----------------------------------------------------------------------
#ifdef DEBUG;
Array check_attr ->64;
Array attr_list -->48;
Array check_prop ->64;
Array prop_list -->63;
! Programming Note - The next four routines are lifted from Tony Lewis'
! debugrtn.h. I would never had known how to write z-machine memory to
! variables without having seen his code.
[ AttrCompare a word l anames i;
anames = #identifiers_table;
anames = anames + 2 * (anames-->0);
check_attr-->0 = 0;
@output_stream 3 check_attr;
print (string) anames-->a;
@output_stream -3;
for (i = 0 : i < l: i++){
if (check_attr->(2+i) >= 'A' && check_attr->(2+i) <= 'Z')
check_attr->(2+i) = check_attr->(2+i) + ('a' - 'A');
if (check_attr->(2+i) ~= word->i) rfalse;
}
rtrue;
];
[ MakeAttrList n w;
w = NextWordStopped();
if (w == -1) return -1;
attr_list-->0 = 0;
do
{ for (n=0: n < 48: n++)
if (AttrCompare(n, WordAddress(wn-1), WordLength(wn-1))) break;
if (n >= 0 && n < 48)
{
(attr_list-->0)++;
attr_list-->(attr_list-->0) = n;
}
else
{
print "^<invalid attribute, ~";
PrintByteArray(WordAddress(wn-1), WordLength(wn-1));
print "~>^";
return -1;
}
w = NextWordStopped();
} until (w == -1 or 'with');
if (attr_list-->0 == 0) return -1;
if (w=='with'){
n = MakePropList();
return n;
}
return 0;
];
! Programming Note - Next two routines are altered quite a bit from debugrtn.h.
[ PropertyCompare p word l i;
check_prop-->0 = 0;
@output_stream 3 check_prop;
print (property) p;
@output_stream -3;
for (i = 0 : i < l: i++ )
{
if (check_prop->(2+i) >= 'A' && check_prop->(2+i) <= 'Z')
check_prop->(2+i) = check_prop->(2+i) + ('a' - 'A');
if (check_prop->(2+i) ~= word->i) rfalse;
}
rtrue;
];
[ MakePropList n l w;
w = NextWordStopped();
if (w == -1) return -1;
prop_list-->0 = 0;
l = #identifiers_table-->0;
do
{ for (n=1: n < l: n++){
if (n~=2 or 3)
if (PropertyCompare(n, WordAddress(wn-1), WordLength(wn-1))) break;
}
if (n >= 0 && n < l)
{
(prop_list-->0)++;
prop_list-->(prop_list-->0) = n;
}
else
{
print "^<invalid property, ~";
PrintByteArray(WordAddress(wn-1), WordLength(wn-1));
print "~>^";
return -1;
}
w = NextWordStopped();
} until (w == -1 or 'has');
if (prop_list-->0 == 0) return -1;
if (w=='has'){
n = MakeAttrList();
return n;
}
return 0;
];
! Programming Note - Lifted directly from Graham Nelson's paserm.h
! (originally Showobj) and truncated to show JUST directions.
[ ShowDirsSub c f l a n x;
if (noun==0) noun=location;
objectloop (c ofclass Class) if (noun ofclass c) { f++; l=c; }
if (f == 1) print (name) l, " ~"; else print "Object ~";
print (name) noun, "~ (", noun, ")";
if (parent(noun)~=0) print " in ~", (name) parent(noun), "~";
new_line;
if (f > 1)
{ print " class ";
objectloop (c ofclass Class) if (noun ofclass c) print (name) c, " ";
new_line;
}
for (a=0,f=0:a<48:a++) if (noun has a) f=1;
if (f)
{ print " has ";
for (a=0:a<48:a++) if (noun has a) print (DebugAttribute) a, " ";
new_line;
}
if (noun ofclass Class) return;
! Altered slightly
f=0; l = #identifiers_table-->0;
for (a=1:a<=l:a++)
{ if ((a~=2 or 3) && noun.&a)
{ if (a == u_to or d_to or n_to or s_to or e_to or w_to or
ne_to or nw_to or se_to or sw_to or in_to or out_to or cant_go)
{ if (f==0) { print " with "; f=1; }
print (property) a;
n = noun.#a;
for (c=0:2*c<n:c++)
{ print " ";
x = (noun.&a)-->c;
switch(x)
{ NULL: print "NULL";
0: print "0";
1: print "1";
default:
switch(metaclass(x))
{ Class, Object: print (name) x;
String: print "~", (string) x, "~";
Routine: print "[...]";
}
print " (", x, ")";
}
}
if (f==1) print ",^ ";
}
}
}
new_line;
];
!----------------------------------------------------------------------
! List Routines - The simple little routines I wrote.
!----------------------------------------------------------------------
! Usage Note - If this routine this causes formating problems on your
! screen just replace where it appears with print
! "^----------------------^"; or something.
[ PrintLine col i;
col = 0->33;
if (col==0) col=80;
for (i = 0 : i < col : i++)
print (char) '-';
print "^";
];
! Programming Note - Prints byte "string" for error messages.
[ PrintByteArray arry l i;
for (i=0: i < l: i++)
print (char) arry->i;
];
! Programming Note - These listers use a simple loop to go through the game
! and show ALL the objects that match a set of conditions. This basic routine
! can be adapted for any combination of conditions. Which I have done, below.
! Usage Note - Special Objects
!
! Remove the exclamation point indicating a comment to exclude these objects
! when you are including these:
!
! topics - info.h by Jesse Burneko or another conversation system
! that uses topics
!
! temp_obj - L. Ross Raszewski's utility.h
!
! LibraryMessages - when you include your own LibraryMessages in your game
!
! Note: an unamed object will show up in the hidden list when using altmenu.h.
!
! By excluding these objects from lists, you won't have internal Inform
! objects listed, which can confuse matters. For instance, temp_obj
! showing up in a list of hidden objects.
! Programming Note - ofclass Class refers to an original class declaration and
! not to a specific object of a particular class.
[ ListRoomsSub o i;
for (o = player: o <= top_object: o++)
{ if ((~~(o ofclass Class)) &&
(parent(o)==0) && ((o provides u_to) || (o provides d_to) ||
(o provides n_to) || (o provides s_to) || (o provides e_to) ||
(o provides w_to) || (o provides ne_to) || (o provides nw_to) ||
(o provides se_to) || (o provides sw_to) || (o provides cant_go))){
i++;
<Showobj o>;
PrintLine();
}
}
if (i==0) print "^There are no rooms.^";
];
[ ListDirsSub o i;
for (o = player: o <= top_object: o++)
{ if ((~~(o ofclass Class)) &&
(parent(o)==0) && ((o provides u_to) || (o provides d_to) ||
(o provides n_to) || (o provides s_to) || (o provides e_to) ||
(o provides w_to) || (o provides ne_to) || (o provides nw_to) ||
(o provides se_to) || (o provides sw_to) || (o provides cant_go))){
i++;
<ShowDirs o>;
PrintLine();
}
}
if (i==0) print "^There are no rooms.^";
];
[ ListTakeableSub o i;
for (o = player: o <= top_object: o++)
{ if ((~~(o ofclass Class)) &&
(parent(o)~=0) && (o hasnt animate) && (o hasnt scenery) &&
(o hasnt static) && (o hasnt concealed)
! info.h -- && (o notin topics)
){
i++;
<Showobj o>;
PrintLine();
}
}
if (i==0) print "^There are no takeable objects.^";
];
! Usage Note - There could be objects that have no parent and aren't rooms,
! (although rooms which have no directions will show up here too), as they
! haven't been been found by the player yet. (i.e, They are deliberately left
! unconnected to the object tree by the game writer to "hide" them.)
! Not all of the hidden objects listed will also be takeable, just most.
[ ListHiddenSub o i;
for (o = player: o <= top_object: o++)
{ if ((~~(o ofclass Class)) &&
(parent(o)==0) && (~~((o provides u_to) || (o provides d_to) ||
(o provides n_to) || (o provides s_to) || (o provides e_to) ||
(o provides w_to) || (o provides ne_to) || (o provides nw_to) ||
(o provides se_to) || (o provides sw_to) || (o provides cant_go))) &&
(o hasnt animate) && (o ~=InformParser or InformLibrary
! your own -- or LibraryMessages
! info.h -- or topics
! utility.h -- or temp_obj
or thedark or compass)){
i++;
<Showobj o>;
PrintLine();
}
}
if (i==0) print "^There are no hidden objects.^";
];
[ ListNonTakeableSub o i;
for (o = player: o <= top_object: o++)
{ if ((~~(o ofclass Class)) &&
(parent(o)~=0) && ((o has scenery) || (o has static) ||
(o has concealed)) && (o hasnt animate) && (o notin compass)
! info.h -- && (o notin topics)
){
i++;
<Showobj o>;
PrintLine();
}
}
if (i==0) print "^There are no nontakeable objects.^";
];
[ ListAllSub o i;
for (o = player: o <= top_object: o++){
if ((~~(o ofclass Class)) &&
(o~=InformParser or InformLibrary
! your own -- or LibraryMessages
! info.h -- or topics
! utility.h -- or temp_obj
or thedark or compass) &&
(o notin compass)
! info.h -- && (o notin topics)
){
i++;
<Showobj o>;
PrintLine();
}
}
if (i==0) print "^There are no listable objects.^";
];
! Usage Note - Aliases cannot be listed specifically as attributes and their
! aliases cannot be split.
!
! Example: attribute out_doors alias proper
! >list has proper -- will list both (since they cannot be listed separately)
! >list has out_door -- will not work (since proper is the real attribute, the
! condition if has out_door means Inform
! really searches for if has proper)
[ ListByAttrSub a b c o max i;
max = attr_list-->0;
a = b = c = attr_list-->1;
if (max > 1) {
c = attr_list-->2;
if (max > 2) b = attr_list-->3;
}
for (o = player: o <= top_object: o++){
if (o has a && o has b && o has c)
{ i++; <Showobj o>; PrintLine(); }
}
if (i==0) print "^There are no objects with that/those attribute/s.^";
];
! Usage Note - Ditto for aliases for properties (see ListByAttr comments).
! But this WILL list local properties, they don't have to be global.
[ ListByPropSub a b c o max i;
max = prop_list-->0;
a = b = c = prop_list-->1;
if (max > 1) {
c = prop_list-->2;
if (max > 2) b = prop_list-->3;
}
for (o = player: o <= top_object: o++){
if (o provides a && o provides b && o provides c)
{ i++; <Showobj o>; PrintLine(); }
}
if (i==0) print "^There are no objects with that/those property/ies.^";
];
[ ListByBothSub a b c d e f o maxa maxp i;
maxa = attr_list-->0;
maxp = prop_list-->0;
a = b = c = attr_list-->1;
if (maxa > 1) {
c = attr_list-->2;
if (maxa > 2) b = attr_list-->3;
}
d = e = f = prop_list-->1;
if (maxp > 1) {
f = prop_list-->2;
if (maxp > 2) e = prop_list-->3;
}
for (o = player: o <= top_object: o++){
if (o has a && o has b && o has c && o provides d && o provides e && o provides f)
{ i++; <Showobj o>; PrintLine(); }
}
if (i==0) print "^There are no objects with that/those property/ies.^";
];
!----------------------------------------------------------------------
! Verb Declarations
!----------------------------------------------------------------------
! Programming Note - 'has' MakeAttrList 'with' (blank) -- is a way to fool
! Inform. Only one routine is allowed on a verb parameter line, so
! MakeAttrList() itself will call MakePropList() if the word 'with' is
! entered. Same for the reverse.
Verb meta 'list'
* 'rooms' -> ListRooms
* 'dirs'/'directions' -> ListDirs
* 'takeable' -> ListTakeable
* 'hidden' -> ListHidden
* 'nontakeable'/'non-takeable'/'notake' -> ListNonTakeable
* 'all' -> ListAll
* 'has' MakeAttrList -> ListByAttr
* 'with' MakePropList -> ListByProp
* 'has' MakeAttrList 'with' -> ListByBoth
* 'with' MakePropList 'has' -> ListByBoth;
#endif;