!------------------------------------------------------------------------ ! Objlstr.h Version 1.50 A Debugging Aid ! Marnie Parker aka FemaleDeer aka Doe doeadeer3@aol.com 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 ! -- 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 ! -- 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 with ! -- 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 has ! -- 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 . 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 "^^"; 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 "^^"; 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*cc; 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++; ; 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++; ; 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++; ; 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++; ; 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++; ; 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++; ; 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++; ; 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++; ; 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++; ; 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;