Skip to content

Handling player commands

TheUnknownOne edited this page Jul 9, 2013 · 1 revision

Scripting/Server/Handling player commands

Now you want handling for player commands. Use code snippets below to do it gracefully.

Note: assuming commands used in the /command parameters or !command parameters form.

Support function

You will need this function to write less code later. It will add all properties of a from object to to object. If that property already exist in to it will be overwritten. In this case it will be used to add commands from lower level auths to higher level ones.

function push_properties(from, to) {
    for (var p in from) {
        to[p] = from[p];
    }
}

Setting accessible commands by auth

The following class describes which commands are accessible to players.

0 in basic_handlers describes commands that normal players can use. 1 - additional commands for moderators, 2 - for administrators, 3 - for owners. Higher level auths can use commands of lower level ones so you don't need to write them more than once.

Commands themselves are written in the command_name: command_function syntax. command_name is a command that a player need to enter. command_function is a name of a function that will handle given command (see section below). For example, me: command_me says that /me command should be handled with a function named command_me.

function POHandlers() {
    // Basic ones will have priority over special ones.
    // Number is an auth level.
    this.basic_handlers = {
        "0": {
            commands: command_commands,
            me: command_me,
            rules: command_rules
        },
        "1": {
            mute: command_mute,
            unmute: command_unmute
        },
        "2": {
            warn: command_warn
        },
        "3": {
            lock: command_lock
        }
    };
    // Will add commands to higher level auths.
    for (var i = 0; i < 3; ++i) {
        for (var j = i + 1; j <= 3; ++j) {
            push_properties(this.basic_handlers[i], this.basic_handlers[j]);
        }
    }
    // If you have additional auths that aren't in DB you can add commands to them like this.
    // This example can be used to hold data for some "Channel master" role implemented by your script.
    // These commands are additional to the basic ones.
    this.special_handlers = {
        channel_master: {
            topic: command_topic
        }//,
        // some_other_auth = {
            // some_other_command: command_some_other_command
        // }
    };
}

This will create a global object HANDLERS to hold data described above.

var HANDLERS = new POHandlers();

Command handlers

Functions that will handle command should be in the following form:

function function_name_here(chan, src, data) {
    // code here
}

chan is a channel id from which a command was issued. src is id of player that called a command. data is parameter string (you need to parse this yourself).

Note: command handlers should not check player's auth themselves unless they behave differently for different auths. This is because "can player even use this?" check is performed automatically elsewhere.

Example of (very basic) /me command implementation:

function command_me(chan, src, data) {
    if (data.length == 0) return; // nothing to print
    sys.sendAll("***" + sys.name(src) + " " + data, chan);
}

Then if you use /me blah blah in chat window it will print *** Your_nickname blah blah instead of usual Your_nickname: blah blah message.

Basic auth checking

You will need this function to check whether player has enough authority to use a command. It will call a handler for it if it is possible.

Code assumes there is a user function registered with registerUserFactory() and levels is a hash inside that stores true/false for a given non-DB auth. If you don't use them you don't need it just yet.

function handle_command(command_name, chan, src, data) {
    var src_auth = sys.auth(src);
    if ((src_auth < 0) || (src_auth > 3)) return; // What auth is this again?
    var src_object = SESSION.users(src);
    var handler = HANDLERS.basic_handlers[src_auth][command_name];
    if (!handler) {
        // Non-DB auths here. Remove if not needed.
        var non_db_levels = ["channel_master"]; // Example.
        for (var index in non_db_levels) {
            var level = non_db_levels[index];
            if (src_object.levels[level]) {
                var special_handler = HANDLERS.special_handlers[level][command_name];
                if (special_handler) {
                    handler = special_handler;
                    break; // Command found. Nothing else to do.
                }
            }
        }
    }
    if (handler) {
        handler(chan, src, data);
    }
}

Connecting dots

Now you need to make it actually called by PO. There is a beforeChatMessage event that can help with this. Therefore a basic implementation would be like this:

({

    beforeChatMessage: function(src, message, chan) {
        if ((message.length > 1) && (message[0] == '/' || message[0] == '!')) {
            // Command.
            sys.stopEvent(); // do not print this message automatically
            var command, command_data = "";
            var pos = message.indexOf(' ');
            if (pos == -1) {
                command = message.substring(1).toLowerCase();
            } else {
                command = message.substring(1, pos).toLowerCase();
                command_data = message.substr(pos + 1);
            }
            handle_command(command, chan, src, command_data);
        }
    }

})