! scrutinize.h v1.0 2007-09-23
!
! Library extension for Inform 6 to check for common problems in objects.
! Requires Inform 6.30 or higher. Tested only with 6.31 and library 6/11.
! Written by Fredrik Ramsberg, fredrikXYZramsberg.net (change XYZ to @).
! Comments and corrections are welcome.
!
! To use this extension, include it after including Grammar.h, in your Glulx
! or Zcode game. If you only want it enabled in DEBUG mode, you need to
! surround the inclusion line with "#ifdef DEBUG;" and "#endif;".
! In the compiled game, type "scrutinize" and you will get a list of all
! objects which look like they may have problems. The only kind of problem
! which it currently checks for is if the object has words in its printed name
! which aren't recognized as synonyms for the object. It works even on objects
! which have their own parse_name routine, but with the limitation that it can
! only find a single missing word at a time. To see if there are more missing
! synonyms for such an object, you need to fix the first missing synonym,
! recompile and use "scrutinize" again. Of course there are situations where
! the scrutinize verb will indicate trouble but you know it's wrong, like if
! you have behind-the-scenes objects which the player shouldn't be able to
! refer to anyway.
!
! Here's an example of a programmer's mistake which the scrutinize verb can
! help in finding: Object -> tray "small tray" with name 'tray';
! (The programmer forgot to add 'small' as a synonym)
!
! The ScrutinizeSub routine was written to be easily extensible with more
! tests on objects. In fact, it started as an integral component of the
! Swedish Inform library (and it still is), where it checks for a number of
! mistakes which are easy to make when using that particular library
! translation.
#ifdef TARGET_ZCODE;
Array _ScrutNameTestBuffer -> (160 + 2);
Constant _SCRUT_MAXPARSE 15;
Array _ScrutBadWords -> _SCRUT_MAXPARSE;
#ifnot; !Glulx
Array _ScrutBadWords -> MAX_BUFFER_WORDS;
Array _ScrutNameTestBuffer buffer 160;
#endif;
[_ScrutCheckName o prop i badcount;
indef_mode=false;
PrintToBuffer(_ScrutNameTestBuffer, 160, o, prop);
#ifdef TARGET_ZCODE;
parse->0 = _SCRUT_MAXPARSE;
for(i=2:i < (2 + _ScrutNameTestBuffer -> 1): i++) {
_ScrutNameTestBuffer -> i = LowerCase(_ScrutNameTestBuffer -> i);
if((_ScrutNameTestBuffer -> i)==',' or '.' or '"')
_ScrutNameTestBuffer -> i = ' ';
}
#ifnot; !Glulx
for(i=4:i < (4 + _ScrutNameTestBuffer --> 0): i++) {
_ScrutNameTestBuffer -> i = LowerCase(_ScrutNameTestBuffer -> i);
if((_ScrutNameTestBuffer -> i)==',' or '.' or '"')
_ScrutNameTestBuffer -> i = ' ';
}
#endif;
Tokenise__(_ScrutNameTestBuffer, parse);
if(o.parse_name~=0) { ! Method 1: Ask the object's parse_name routine
parser_action = NULL;
wn=1;
i = RunRoutines(o, parse_name);
#ifdef TARGET_ZCODE;
if(i < parse->1)
_ScrutBadWords->(badcount++) = i;
} else {! Method 2: Check the object's name property
for(i=0:i < parse->1 && i < _SCRUT_MAXPARSE: i++)
if(~~WordInProperty(parse-->(1+i*2), o, name))
_ScrutBadWords->(badcount++) = i;
}
#ifnot; !Glulx
if(i < parse-->0)
_ScrutBadWords->(badcount++) = i;
} else {! Method 2: Check the object's name property
for(i=0:i < parse-->0 && i < MAX_BUFFER_WORDS: i++)
if(~~WordInProperty(parse-->(1+i*3), o, name))
_ScrutBadWords->(badcount++) = i;
}
#endif;
return badcount;
];
[ScrutinizeSub i j err anyerr isNormalObj wordno;
style bold;
print "Scrutinizing all objects, looking for the following indications of problems:
^* Has words in the strings/routines which print the object's name, which aren't synonyms for the object
^^";
style roman;
anyerr=false;
objectloop(i>LibraryMessages && ~~(i ofclass class)) {
err=false;
isNormalObj=parent(i)~=0 || i hasnt light;
if(isNormalObj && parent(i)==0) { ! Check if dark, lonely objects have exits
objectloop(j in compass) isnormalobj=isnormalobj && (i.(j.door_dir)==0);
}
if(isNormalObj) {
! This is probably an object which the player should be able to refer to.
! Perform test #1
if(i.short_name~=0) {
wordno=_ScrutCheckName(i, short_name);
if(wordno) {
print "Has words in short_name which aren't synonyms for the object: ", (name) i, " ",(_ScrutPrintBadWords) wordno,".^";
err=true;
}
}
! Perform test #2
if(i.short_name_indef~=0) {
wordno=_ScrutCheckName(i, short_name_indef);
if(wordno) {
print "Has words in short_name_indef which aren't synonyms for the object: ", (name) i, " ",(_ScrutPrintBadWords) wordno,".^";
err=true;
}
}
! Perform test #3
if(i.short_name==0 && i.short_name_indef==0) {
wordno=_ScrutCheckName(i);
if(wordno) {
print "Has words in object name string which aren't synonyms for the object: ", (name) i, " ",(_ScrutPrintBadWords) wordno,".^";
err=true;
}
}
}
if(err) {
anyerr=true;
}
}
if(~~anyerr) "No problems were found.";
];
Verb meta 'scrutinize' 'scrutinise'
* -> Scrutinize;