![]() |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
By now you know that nothing ever is really simple in this game. To confuse the issue when dealing with commands we actually have two different types of commands. One kind is the one that we will talk about here, commands that are defined by objects that you can touch or examine. The other kind is so called 'soul' commands. The soul commands is a pure mudlib convenience though. They are described later in chapter three.
Object-added commands work like this: Upon entering an object, such as a
room, a special lfun called init()
is called in the room and in
all other objects in the inventory of the room. The init()
function is actually an ordinary function that you could use for any
purpose, but the intended purpose is to have the command-adding
efun add_action()
there. In other words, when you enter an object
of any kind, the commands of that object as well as those of the other
object in the same inventory are added to your set of commands.
The add_action
command ties an action word to a function in the
object. Upon typing the special word as the first word on the line, the
function gets called with any other words you might have typed as
arguments. The third argument can be given as '1' if you want the
gamedriver to trigger on just a part of the word. For example if you
have the action word 'examine' and want to allow 'exa' or 'ex' as well.
add_action(function func, string action, void|int 1) e.g. init() { /* * The functions 'do_bow()' and 'leave_game()' are defined * somewhere in this object. However, if it's done later than * this function, they must exist as prototypes in the header. */ add_action(do_bow, "bow"); // Better get used to seeing add_action(&leave_game(), "quit"); // different kinds of function // reference declarations. } |
Is this true for any kind of object then? Will any object receive this
set of commands? No. Just living objects. An object is made living
by the efun enable_commands()
and dead, or inert, with the efun
disable_commands()
Note carefully that living in the
gamedriver only means being able to receive and execute commands,
in the mudlib it means a bit more.
Use these efuns whenever you want to switch on or off the command handling capabilities. However, remember that if the object already is moved into a room when you turn on living status, it will have no command lists. You will have to move it out/in to the room again in order for it to pick up all actions.
You can check if an object is living or not with the efun living()
.
enable_commands() disable_commands() int living(object ob) e.g. public void toggle_living_status() { if (living(this_object())) disable_commands(); else enable_commands(); } |
Actions can only be added and maintained by objects that exist in the inventory or environment of an object. If the object is moved from the action-defining object's presence, the action is removed as well.
As you now understand, the gamedriver expects the function init()
to be defined in any object that wishes to add actions to living
objects. Please be careful how you use the function though. If you for
example use the init()
function to test if an object belongs
there or not, and then move it out if it doesn't, you'll likely get
into trouble. The reason is that if you add actions after having moved
it, you will in fact be adding actions to a non-present object. The
gamedriver will notice this and you will have an error. I would like to
advice you not to use the init()
function for any other
purpose than adding actions. It's allowed to test the object that calls
the init()
function to determine if you should add actions to it
or not (if you limit access to some actions), but avoid any other kind
of code.
I'm sorry to say that the mudlib itself doesn't always conform to this rule, there's objects here and there that cheat. However, there's no reason why you should code things badly just because we did. :)
In most objects that inherit standard base objects it's necessary to
call the parent init()
as well, since otherwise you'll
override it and thereby miss lots of important actions. Just put the
statement ::init();
first in your init, before your
add_action()
statements, and all will be well.
To execute a command in a living object you use the efun command()
.
int command(string cmd) e.g. command("sneeze"); command("wield sword in left hand"); |
If you're doing this for mortals (which most often is the case) you're wise to use this construction instead. The reason is that the dollar sign will evade the internal alias mechanism so that it isn't fooled by an unfortunate macro.
int command(string cmd) e.g. command("$sneeze"); command("$wield sword in left hand"); |
The commands naturally only work if they have been added to the living
object by other objects in the environment or inventory. To get a list
of the available commands you can use the efuns commands()
or
get_localcmd()
depending on what kind of information you
want. commands()
return an array of arrays with all the commands
of a specified object, containing not only the command word, but also
what object defines it and which function is
called. get_localcmd()
is simpler, returning only an array with
the command words. If no object is specified, this_object()
is
used by default. See the manual entry for commands()
to get the
specification of what the command array contains.
mixed commands(void|object ob) string *get_localcmd(void|object ob) |
If you use one function for several command words it becomes necessary
to find out exactly what command word was used. You use the efun
query_verb()
for that.
string query_verb() e.g. init() { ::init(); add_action(&my_func(), "apa"); add_action(my_func, "bepa"); add_action(&my_func(), "cepa"); } public int my_func() { switch (query_verb()) { case "apa": < code > break; case "bepa": < code > break; case "cepa": < code > break; } return 1; } |
Action functions should return 1 if they were properly
evaluated, i.e. if the function called was the right one with the right
arguments. If you return 0, the gamedriver will look for other actions
with the same command word and try those, until one of them finally
returns 1, or there's no more to test. There's a special efun called
notify_fail()
that you can use for storing error messages in case
no function 'takes' the command. Instead of giving the very useless text
'What ?' when the player types the command you can give him some better
info. If there are several action commands using the same command word
who all fail, the one who last called notify_fail()
will
define the message actually used.
notify_fail(string message) e.g. public void init() { ::init(); add_action(&do_bow(), "bow"); } public int do_bow(string who) { if (!present(find_player(who)), environment(this_player())) { notify_fail("There's no " + who + " here to bow to!\n"); return 0; } < bow code > return 1; } |
If you are absolutely certain that the command given was directed only
to your object and you want to stop execution there, even if your object
finds an error with the command (arguments or context or whatever), you
can return 1. However, then you must use another method to display error
messages. The text stored with notify_fail()
is only used
if you return 0.
If your object changes the available set of actions during execution and
you want the surrounding living objects to update their command set, you
call the efun update_actions()
for the object in question. If you
don't specify any object this_object()
is used by default. What
happens is that all surrounding objects discard their command sets from
the specified object and call init()
in it again to get the new
set.
update_actions(object ob) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |