! Nameable.h
! Inform Library extension by John Colagioia (
[email protected])
! based heavily on code by Graham Nelson for "Balances." All errors
! should be considered mine, rather than Graham's.
!
! To use:
! Include "nameable.h" after the parser. Create objects of type Nameable,
! and store their "short_name" in the "original_short_name" property.
! Since short_name does a significant amount of the work, here, do not
! give the object a short_name, whether it's like this:
! Nameable Thing_One "thing one";
! or like this:
! Nameable Thing_Two
! with short_name "thing two";
! as both of these will cause chaos of one sort or another.
!
! Customization:
! There are three hooks that the game programmer is encouraged to
! use to customize this library:
! name_in_caps: This global variable, if set nonzero, capitalizes
! the name assigned to the Nameable object (the
! default behavior). If set to 0, the name
! is left as lowercase.
! name_as_proper: Another global variable. If set nonzero (the
! default), the name is treated as a proper
! name, meaning that articles are not used in
! descriptions (i.e., "Bob is here" rather than
! "The Bob is here"). Otherwise, do not set the
! "proper" attribute.
! naming_function:
! This variable, if set, should hold a function
! that will describe the naming process. It gets
! the object as a parameter. An example of such
! a function might be:
!
! [ Namer obj i ;
! print "You decide that ", (the) obj, " looks like
! a ~";
! for (i=0:i<8:i++)
! print (char)(obj.&given_name)->i;
! print "~.";
! rtrue;
! ];
!
! If unset, the variable is ignored and nothing
! will be printed when naming occurs.
!
! Note: With no licensing notice to the contrary in "Balances," it can be expected
! to be under copyright. Therefore, the portions of this code should be considered
! as such until notified otherwise by Graham Nelson. Any modifications to that code
! made by John Colagioia, however, are in the Public Domain, for whatever that's
! worth.
! Storage for the name
Array name_text_buffer -> 8;
Array temp_buffer -> 8;
! Internal directives and pseudo-pointers shared among routines
Global from_buffer = false;
Global the_named_word = 0;
Global from_char;
Global to_char;
! User configuration flags and hooks
Global name_in_caps = 1;
Global name_as_proper = 1;
Global naming_function;
Class Nameable with
original_short_name, ! The default name to display, until the player
! comes up with something better.
article "a", ! Easily changed, but anything nameable is likely
! to be conceptually non-unique/one of a set, rather
! than something which gets the article "the."
given_name 0 0 0 0 0 0 0 0,
! This is the array where the name will be stored.
parse_name ! Check for the typical names as well as the name
! given to the object by the player.
[ i j flag ;
if (parser_action == ##TheSame)
{
for (i=0:i<8:i++)
if ((parser_one.&number)->i ~=
(parser_two.&number)->i)
return (-2);
return (-1);
}
for (::j++)
{
i = NextWord ();
flag = false;
if (WordInProperty (i, self, name))
flag = true;
else if (self provides optname && self.optname ~= 0)
{
if (WordInProperty (i, self, optname))
flag = true;
}
else if ((self.&given_name)->0 ~= 0)
{
wn--;
if (TextReader (0) == 0)
return (j);
for (i=0:i<8:i++)
if ((self.&given_name)->i ~= name_text_buffer->i)
return (j);
flag = true;
}
if (flag == false)
return (j);
}
],
short_name ! Print out the name given by the player, if one exists.
! Otherwise, use self.original_short_name.
[ i ;
if ((self.&given_name)->1 ~= 0)
{
if (((self.&given_name)->0) ~= 0)
for (i=0:i<8:i++)
print "", (char) (self.&given_name)->i;
}
else print "", (string) self.original_short_name, "";
rtrue;
],
baptise ! Collect the name from the player's naming command, and
! place them into the given_name array.
[ i ;
wn = the_named_word;
if (TextReader(1)==0) return i;
for (i=0: i<8: i++)
(self.&given_name)->i = name_text_buffer->i;
if (name_in_caps) ! Configure capitalization using this flag.
(self.&given_name)->0 = (self.&given_name)->0 - 32;
self.article="the";
if (name_as_proper) ! Configure "properness" using this flag.
give self proper;
if (naming_function) ! Use this to print out message or do other
! handling.
naming_function (self);
rtrue;
];
[ QuotedText i j f ; ! Accept only quoted strings as names.
! This could also be done for non-quoted strings, but that causes
! confusion if the player types:
! > name the troll Buddy then go west
! If not quoted, "Buddy then go west" is interpreted as the name.
i = WordAddress (wn++);
i = i - buffer;
if (buffer->i == '"')
{
for (j=i+1:(j<=(buffer->1)+1)&&(buffer->j~='"'):j++)
{
f = j - (i + 1);
temp_buffer->f = buffer->j;
}
for (f=f+1:f<8:f++)
temp_buffer->f = 0;
if (buffer->j == '"')
f = j;
else f = 0;
if (f == 0)
return (-1);
from_char = i + 1;
to_char = f - 1;
if (from_char > to_char)
return -1;
the_named_word = wn;
while ((buffer + f) > WordAddress (wn))
wn++;
wn++;
return (player);
}
return (-1);
];
[ TextReader flag point i j len where_from start stop ;
if (from_buffer == true)
{
where_from = temp_buffer;
start = 0;
stop = 7;
}
else {
where_from = buffer;
start = from_char;
stop = to_char;
}
for (i=0:i<8:i++)
name_text_buffer->i = 0;
if (flag==1 && start~=stop)
{
for (i=start,j=0:i<=stop&&j<7:i++)
{
name_text_buffer->j = where_from->i;
if (where_from->i ~= ' ' or ',' or '.')
j++;
}
from_char=0;
to_char=0;
rtrue;
}
if (wn > parse->1)
{
wn++;
rfalse;
}
i = wn * 4 + 1;
j = parse->i;
point = j + buffer;
len = parse->(i-1);
for (i=0:i<len && i<8:i++)
name_text_buffer->i = point->i;
wn++;
rtrue;
];
[ RenameSub ;
from_buffer = true;
if (noun provides baptise)
{
noun.baptise ();
rtrue;
}
from_buffer = false;
"", (The) noun, " surely already has a name!";
! Note that this comment is only for objects of the wrong
! class. Players can currently rename the same object
! as much as they see fit.
];
Verb "name" "call" "rename"
* noun QuotedText -> Rename;