Geas MUD, enter the Aventure!
Geas Home | Play the Game

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.3 Object-inherent command handling

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] [ ? ]

This document was generated by Ronny Wikh on July, 8 2003 using texi2html