parent $body parent $interaction parent $mail_ui parent $command_aliases parent $bad_commands parent $user_data parent $set_ui parent $has_settings parent $help_ui parent $has_messages object $user var $root child_index 47 var $root owners [$user] var $root fertile 0 var $has_commands commands [["@quit", 'quit_cmd], ["i?nventory", 'inventory_cmd], ["@title *", 'title_cmd], ["@add-name-alias|@ana *", 'add_name_alias_cmd], ["@del-name-alias|@dna *", 'del_name_alias_cmd], ["@rename * to *", 'rename_cmd], ["@time *", 'time_cmd], ["@audit *", 'audit_cmd], ["@who *", 'who_cmd], ["@del-command-a?lias|@dca?lias *", 'del_command_alias_cmd], ["@command-a?liases|@ca?liases *", 'command_aliases_cmd], ["@wrap *", 'wrap_cmd], ["@prompt *", 'prompt_cmd], ["@password *", 'password_cmd], ["@idle", 'idle_cmd], ["@add-command-a?lias|@aca?lias *", 'add_command_alias_cmd], ["@login-watch *", 'watch_logins_cmd], ["@com?mands *", 'commands_cmd], ["@age *", 'age_cmd], ["@status", 'status_cmd], ["@spawn *", 'spawn_cmd], ["@rehash?-commands", 'rehash_cmd], ["@name-aliase?s|@na *", 'name_aliases_cmd], ["@news", 'news_cmd], ["@remember *", 'remember_cmd], ["@remembered *", 'remembered_cmd], ["@forget *", 'forget_cmd], ["@whereis|@where-is *", 'whereis_cmd], ["@ways", 'ways_cmd], ["@prose *", 'prose_cmd], ["@describe *", 'describe_cmd], ["@gender *", 'gender_cmd]] var $has_commands shortcuts [] var $has_verbs verbs #[] var $location contents [] var $located location $nowhere var $root inited 1 var $user password "*" var $user connected_at 0 var $user last_command_at 0 var $user connections [] var $user linelen 0 var $user title 0 var $user email 0 var $user action 0 var $user creation_time 0 var $user home $body_cave var $user pagelen 0 var $user activity 0 var $user parsers [] var $user filters [] var $user watch_logins 0 var $user tell_traceback 0 var $user last_name 0 var $root dbref 'user var $user prompt "" var $root owned [$user] var $command_aliases command_aliases [] var $mail_list letters #[] var $mail_list letters_index #[] var $mail_list senders 1 var $mail_list readers [$core] var $mail_list notify [$user] var $mail_list last_letter 0 var $mail_ui subscribed #[[$user, 791485891]] var $gendered gender $gender_neuter var $located obvious 1 var $described prose #[] var $root manager $user var $root writable [$user] var $root readable ['parameters, 'methods, 'code] var $help_interface current_help $ var $help_interface help_dict #[["*", $], ["help", $], ["**", $]] var $user context 0 var $named name ['uniq, "Generic User Object"] var $named name_aliases [] var $user_data user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]] var $old_has_settings setting_templates #[["terminated-tell", 'boolean], ["Content-type", 'string], ["error-syntax-prefix", 'string], ["error-prefix", 'string]] var $user remembered_places [] var $old_command_environment verb_cache #[] var $old_command_environment command_cache [["@quit", 'quit_cmd], ["i?nventory", 'inventory_cmd], ["@title *", 'title_cmd], ["@add-name-alias|@ana *", 'add_name_alias_cmd], ["@del-name-alias|@dna *", 'del_name_alias_cmd], ["@rename * to *", 'rename_cmd], ["@time *", 'time_cmd], ["@audit *", 'audit_cmd], ["@who *", 'who_cmd], ["@del-command-a?lias|@dca?lias *", 'del_command_alias_cmd], ["@command-a?liases|@ca?liases *", 'command_aliases_cmd], ["@wrap *", 'wrap_cmd], ["@prompt *", 'prompt_cmd], ["@password *", 'password_cmd], ["@idle", 'idle_cmd], ["@add-command-a?lias|@aca?lias *", 'add_command_alias_cmd], ["@login-watch *", 'watch_logins_cmd], ["@com?mands *", 'commands_cmd], ["@age *", 'age_cmd], ["@prose|@describe *", 'prose_cmd], ["@status", 'status_cmd], ["@spawn *", 'spawn_cmd], ["@rehash?-commands", 'rehash_cmd], ["@name-aliase?s|@na *", 'name_aliases_cmd], ["@news", 'news_cmd], ["@remember *", 'remember_cmd], ["@remembered *", 'remembered_cmd], ["@forget *", 'forget_cmd], ["@whereis|@where-is *", 'whereis_cmd], ["wh?isper * to *", 'whisper_cmd], ["@register-ch?annel|@reg-ch?annel *", 'register_channel_cmd], ["@delete-ch?annel|@del-ch?annel *", 'delete_channel_cmd], ["say *", 'say_cmd], ["to * say *", 'say_to_cmd], ["@paste *", 'paste_cmd], ["page * with *", 'page_cmd], ["emote *", 'emote_cmd], ["strip *", 'strip_cmd], ["@tuned|@ch?annels *", 'channels_cmd], ["repeat *", 'repeat_cmd], ["@tune in|out *", 'tune_channel_cmd], ["on * say *", 'on_subj_cmd], ["vowel?ize *", 'late_vowels_cmd], ["epage * with *", 'page_emote_cmd], ["@m?ail * on *", 'mail_on_cmd], ["@mail-s?end|@ms?end * to *", 'send_to_cmd], ["@mail-sub?scribe|@msub?scribe *", 'subscribe_cmd], ["@mail-unsub?scribe|@munsub?scribe *", 'unsubscribe_cmd], ["@mail-l?ists|@ml?ists *", 'mail_lists_cmd], ["@m?ail * subject|subject:|s *", 'mail_subj_cmd], ["@mail-r?ead|@mr?ead * on *", 'read_cmd], ["@mail-r?ead|@mr?ead *", 'read_cmd], ["@mail-rem?ove|@mrm * from|on *", 'mail_remove_cmd], ["@mail-rem?ove|@mrm *", 'mail_remove_cmd], ["quit", 'old_command_cmd], ["WHO", 'old_command_cmd], ["@create *", 'old_command_cmd], ["@dig *", 'old_command_cmd], ["news", 'old_command_cmd], ["@finger-data|@user-data * my * is|are *", 'data_is_cmd], ["@finger|@user-data *", 'data_cmd], ["@set-finger|@set-user-data * as|to *", 'set_info_cmd], ["@set *", 'set_cmd], ["@add-setting *", 'add_setting_cmd]] var $old_command_environment shortcuts_cache [["|*", '_interact, ["|", 1]], ["<*", '_interact, ["<", 1]], ["think *", 'think_cmd, [1]], ["%*", 'think_cmd, [1]], ["#*", 'channel_cmd, ["#", 1]], ["\"*", 'say_cmd, ["", 1]], [":*", 'emote_cmd, ["", 1]], ["!*", 'polite_spoof_cmd, [1]], ["''*", 'say_to_cmd, ["to", "", "say", 1]], ["'* *", 'say_to_cmd, ["to", 1, "say", 2]], ["--*", 'page_cmd, ["page", "", "with", 1]], ["-* *", 'page_cmd, ["page", 1, "with", 2]], ["++*", 'page_emote_cmd, ["epage", "", "with", 1]], ["+* *", 'page_emote_cmd, ["epage", 1, "with", 2]], ["]*", 'right_encapsulate_cmd, ["]", 1]], [")*", 'right_encapsulate_cmd, [")", 1]], ["@m?ail", 'mail_on_cmd, [1, "", "on", "me"]]] var $has_settings settings 0 var $has_settings setting_types #[["terminated-tell", #[['type, "boolean"], ['check, 'is_boolean], ['get, 'get_direct_setting], ['set, 'set_direct_setting], ['del, 'del_direct_setting], ['set_args, ['name, 'definer, 'value, 'style]], ['get_args, ['name, 'definer]]]], ["content-type", #[['type, "string"], ['check, 'is_anything], ['get, 'get_direct_setting], ['set, 'set_direct_setting], ['del, 'del_direct_setting], ['set_args, ['name, 'definer, 'value, 'style]], ['get_args, ['name, 'definer]]]]] var $has_settings setting_data #[[$user, #[["content-type", "text/plain"]]]] var $help_ui current_node $help_node_summary var $help_ui last_visited #[['pos, 1], ['nodes, [$help_node_summary]]] var $mail_list mail [] var $mail_ui current #[['location, 0], ['list, $user]] method init_user .perms(caller(), $root); password = "*"; connected_at = 0; last_command_at = 0; connections = []; creation_time = time(); parsers = [$command_parser, $verb_parser]; filters = [$ctext_filter]; action = ""; prompt = ""; context = #[]; .set_quota($sys.get_starting('quota)); $user_db.insert(.namef(), this()); .set_readable([]); .move_to($body_cave); . method uninit_user var conn; (> .perms(caller(), $root) <); if (.connected()) (| (.location()).did_disconnect() |); // and incase any are lying about for conn in (connections) (| conn.user_going_away() |); password = 0; connections = 0; (| $user_db.remove(.name()) |); . method trusted return pass() + ($parsers.children()); . method will_move arg mover, place; (> pass(mover, place) <); if (!(place.has_ancestor($place))) throw(~perm, "Players can only move into rooms."); . method watch_logins return watch_logins; . method connected_at return connected_at; . method last_command_at return last_command_at; . method tell arg what; var f; if (filters) { for f in (filters) what = f.filter(what); } ._tell(what); . method set_password arg str; var x, num; .perms(sender(), 'manager); if (strlen(str) < 5) throw(~badpasswd, "Passwords must be at least 5 characters long."); // this is assuming they have alphabetic characters as well (shrug). // for x in [1 .. strlen(str)] { // if (str[x] in "1234567890") // num = num + 1; // } // if (num < 2) // throw(~badpasswd, "Passwords must contain at least 2 numeric characters."); password = crypt(str); . method check_password arg str; return crypt(str, substr(password, 1, 2)) == password; . method did_move arg [args]; var loc; (> pass(@args) <); loc = .location(); (| loc.look_cmd("look") |); . method parsers .perms(sender(), 'trusts); return parsers; . method add_parser arg parser, [position]; // adds a new $parser at 'position. .perms(sender(), 'parser); // do this in three steps, first make sure the posistion is valid, // then check for it already, then figure its insert position. position = [@position, 'first][1]; if (!(position in ['last, 'first])) throw(~type, "Posistion types must be one of: 'last, 'first."); // does it exist? If so remove it. if (parser in parsers) parsers = setremove(parsers, parser); // figure position if (position == 'last) position = listlen(parsers) + 1; else if (position == 'first) position = 1; parsers = insert(parsers, position, parser); . method del_parser arg parser; var keepers; // removes a parser. Cannot remove $command_parser or $verb_parser keepers = [$command_parser, $verb_parser]; if (!(parser in parsers)) throw(~parsernf, ($data.unparse(parser)) + " is not in the parser list."); if (parser in keepers) throw(~twink, ("You must always have " + ($list.map_to_english(keepers, 'namef))) + "."); parsers = setremove(parsers, parser); . method parse_line arg line; var result, c; (> .perms(caller(), $connection) <); last_command_at = time(); catch any { result = parsers ? (parsers[1]).parse(this(), line, @sublist(parsers, 2), $null_parser) | 'failed; if (type(result) == 'list) return (result[1]).(result[2])(@sublist(result, 3)); switch (result) { case 'failed: // try one last time to at least give them an intelligent // answer... for c in (($places.coordinate_shortcuts()).keys()) { if (match_template(c, line)) return .tell(("There is no exit " + line) + " here."); } .tell(("I don't understand \"" + ($string.chop(line, (.linelen()) - 22))) + "\"."); case 'ok: default: .tell(tostr(result)); } } with handler { if (((traceback()[1])[3]) != 'no_traceback) .tell_traceback(traceback(), line, 0, error()); } . method login arg connection; var loc; if ((sender() != this()) || (definer() != caller())) throw(~perm, "Invalid access to private method."); .tell((("* * * Login successful (" + (connection.address())) + ") * * *").center(.linelen())); .tell((("* * Last connection at " + ($time.date(abs(.connected_at())))) + " * *").center(.linelen())); connected_at = time(); last_command_at = time(); // loc = .location(); if (loc == $body_cave) { if ((.home()) != $body_cave) (| .move_to(.home()) |); else (| .move_to($places.place('starting)) |); } else if ((loc == (.home())) || (loc != $body_cave)) { (| loc.look_cmd("look") |); } else { (| .move_to(.home()) |); } (| (.location()).did_connect() |); (| .login_notify() |); (| $login_watcher.did_connect() |); (| $user_db.did_connect() |); .rehash_command_environment(); . method login_again arg connection; if ((sender() != this()) || (definer() != caller())) throw(~perm, "Invalid access to private method."); last_command_at = time(); (| .tell($string.center(((("* * * " + ($integer.n_to_nth(connection in (.connections())))) + " Login successful (") + (connection.addr())) + ") * * *", .linelen())) |) || (| .tell($string.center(((("* * * " + ($integer.n_to_nth(connection in (.connections())))) + " Login successful (") + (connection.address())) + ") * * *", .linelen())) |); . method logout arg connection; if ((sender() != this()) || (definer() != caller())) throw(~perm, "Invalid access to private method."); (| (.location()).did_disconnect() |); // set this to -last_command so we know they aren't connected // (and using last command will be last_login) connected_at = -last_command_at; // user specific things if (!($guest in (.parents()))) { (| $housekeeper.did_disconnect() |); (| $user_db.last_log_disconnect(this()) |); } else { (| $user_db.last_log_disconnect($guest) |); } (| $user_db.did_disconnect() |); (| $login_watcher.did_disconnect() |); .purge_command_environment(); . method connections return connections; . method connected disallow_overrides; return connections ? 1 | 0; . method who_cmd arg com, [line]; var who, opts, opt, args; // just the basic who listing (> .perms(sender(), 'this) <); who = []; if (!(line[1])) { args = [$user_db.connected(), "Connected Users"]; } else if (((line[1])[1]) == "@") { args = ._who_at_place(substr(line[1], 2)); } else { args = $parse.options(line[1]); opts = args[2]; args = args[1]; if (opts) { for opt in (dict_keys(opts)) { switch (opt) { case "p", "programmers": args = ._who_programmers(args, opts); break; case "a", "admins": args = ._who_admins(args, opts); break; case "s", "short": ._who_short(); return; default: .tell("Unknown @who option: -" + tostr(opt)); return; } } } else { args = ._who_is(@line); } } if (!args) return; .tell($code.generate_listing(@args)); . method email return email || "**no email address**"; . method quit_cmd arg dummy; .perms(sender(), 'parser); return 'disconnect; . method inventory_cmd arg dummy; var i; .perms(sender(), 'parser); if (.contents()) { .tell("Carrying:"); for i in (.contents()) .tell(" " + (i.namef())); } else { .tell("You are empty-handed."); } . method match_env_nice arg name, [syntax]; var obj, args, line; // calls .match_environment() returns nice errors. as well as stopping if it // breaks. No returns neccessary syntax = [@syntax, ""][1]; catch any { obj = .match_environment(name); } with handler { switch (error()) { case ~ambig: args = (traceback()[1])[3]; line = ("\"" + (args[listlen(args)])) + "\" can match any of: "; line = line + ($list.map_to_english(args[1], 'namef)); (> $parse.tell_error(line, syntax) <); case ~objnf: line = ("Nothing found by the name \"" + ((traceback()[1])[3])) + "\"."; (> $parse.tell_error(line, syntax) <); default: line = (traceback()[1])[2]; (> $parse.tell_error(line, syntax) <); } } return obj; . method linelen return linelen || 79; . method idle_seconds return time() - last_command_at; . method title return title || ""; . method action // different from activity, returns a more accurate second to second action if (.connected()) return action || ""; else return "(asleep)"; . method fooz arg time; connected_at = time; . method title_cmd arg com, str; .perms(sender(), 'parser); .tell("Temporary until the real title setup is working"); catch any { .set_title(str); } with handler { $parse.tell_error((traceback()[1])[2]); } .tell(("Title Set as: \"" + str) + "\""); . method commands_cmd arg cmd, args; var obj, coms, c, len, lcoms, scoms, ulen, l, what, a, opts, lines; // returns all commands in a nice format. .perms(sender(), 'parser); args = explode(args); if (!args) { what = .ancestors(); .tell("All commands: (prepare to be spammed)"); } else { what = [.match_env_nice(args[1])]; .tell("Commands on " + ((what[1]).namef('ref))); } ulen = .linelen(); for obj in (what) { if (!((obj.has_ancestor($has_commands)) || (obj.has_ancestor($has_verbs)))) continue; coms = []; coms = coms + ((| $list.slice(obj.shortcuts(), 1) |) || []); coms = coms + ((| $list.slice(obj.commands(), 1) |) || []); coms = coms + ((| obj.verb_templates() |) || []); if (coms) { scoms = []; lcoms = []; for c in (coms) { len = strlen(c) + 2; if (len > (ulen / 3)) lcoms = [@lcoms, " " + c]; else scoms = [@scoms, " " + c]; } lines = ($list.lcolumnize(scoms, ulen)) + ($list.lcolumnize(lcoms, ulen)); for l in (lines) .tell($string.trim(l, 'right)); .tell(" -=-"); } if (obj == $has_commands) break; } . method tell_commands arg p, ps, pc, space; var x, a, c; // called by $builder.commands_cmd .tell(((((space + "Commands on ") + (p.namef('ref))) + " (") + toliteral(p)) + ")"); pc = ps + pc; if (!pc) { .tell(space + " None"); return; } for x in [1 .. listlen(pc)] { a = pad(tostr((pc[x])[1]), 30) + " "; c = pad(toliteral((pc[x])[2]), 20) + " "; .tell(((space + " ") + a) + c); } . method set_email arg email_str; var syn, email, host; if (!(.is_writable_by(sender()))) throw(~perm, "Sender is not an owner."); // kludgy way to check for semi valid email addresses: email = explode(email_str, "@"); if (listlen(email) < 2) throw(~invemail, "Invalid email: " + email_str); // check hostname for at least 1 subnet and a machine name. host = explode(email[2], "."); if (listlen(host) < 2) throw(~invemail, "Invalid hostname: " + (host[1])); // email is purposefully constructed this way, as at one point it will // be able to automatically tack on your host, if you do not provide it. set_var('email, ((email[1]) + "@") + (email[2])); . method set_watch_logins arg value; // either have a single reference, or: 'none|'all .perms(sender()); watch_logins = value; . method echo_file arg str; var con; for con in (connections) con.echo_file(str); . method set_home arg obj; // if (!obj.is_writable_by(sender())) // return .tell("You do not own " + obj.namef() + "."); home = obj; . method pagelen return pagelen || 24; . method set_pagelen arg len; if (!(.is_writable_by(sender()))) throw(~perm, "Sender not an owner."); if (type(len) != 'integer) throw(~type, "pagelength must be an integer"); pagelen = len; . method set_linelen arg len; if (!(.is_writable_by(sender()))) throw(~perm, "Sender not an owner."); if (type(len) != 'integer) throw(~type, "Linelength must be an integer"); linelen = len; . method name_aliases_cmd arg com, [obj]; if (!(.is_writable_by(sender()))) throw(~perm, "Sender not owner."); obj = .match_env_nice((obj[1]) ? obj[1] | (.dbref())); if (!(obj.has_ancestor($named))) { .tell(("Object `" + (obj.dbref())) + "' is not a named object."); throw(~stop, "", 'no_traceback); } .tell((("Aliases for " + (obj.namef())) + ": ") + ($list.to_english(obj.name_aliases(), "none"))); . method activity var idle; // different from action, returns a broader version of your doings if (!(.connected())) return "asleep"; if (activity) return activity; idle = .idle_seconds(); if (idle < 180) return ""; if (idle < 300) return "daydreaming"; if (idle < 900) return "zoned"; else return "long gone"; . method add_name_alias_cmd arg com, [args]; var syn, obj, what; if (!(.is_writable_by(sender()))) throw(~perm, "Sender not this"); syn = ("`" + com) + " <alias> to <object>' (to <object> is optional)"; args = explode(args[1]); what = args[1]; obj = .match_env_nice([@args, .dbref(), .dbref()][3]); if (!what) $parse.tell_error("You must name an alias.", syn); if (what in (.name_aliases())) $parse.tell_error(("You already have the name alias `" + what) + "'"); catch any { obj.add_name_alias(what); } with handler { switch (error()) { case ~methodnf: $parse.tell_error((obj.namef('ref)) + " is not a descendant of $xxxxxxxxx", syn); default: $parse.tell_error((traceback()[1])[2], syn); } } .tell(((("Name Alias `" + what) + "' added to ") + (obj.namef())) + "."); . method modes return modes; . method del_name_alias_cmd arg com, [args]; var syn, obj, what; if (!(.is_writable_by(sender()))) throw(~perm, "Sender not this"); syn = ("`" + com) + " <alias> from <object>' (from <object> is optional)"; args = explode(args[1]); what = args[1]; obj = .match_env_nice([@args, .dbref(), .dbref()][3]); if (!what) $parse.tell_error("You must name an alias to delete.", syn); if (!(what in (.name_aliases()))) $parse.tell_error((((obj.namef('ref)) + " doesn't have the name alias `") + what) + "'"); catch any { obj.del_name_alias(what); } with handler { switch (error()) { case ~methodnf: $parse.tell_error((obj.namef('ref)) + " is not a descendant of $matchable", syn); default: $parse.tell_error((traceback()[1])[2], syn); } } .tell(((((("Name Alias `" + what) + "' deleted from ") + (obj.namef())) + ", aliases are now: ") + ($list.to_english(.name_aliases()))) + "."); . method home return home || $body_cave; . method set_dbref disallow_overrides; arg new_dbref; if ((caller() != $user) && (!(sender() in ($sys.system())))) throw(~perm, "User dbrefs can only be changed by $user."); (> pass(new_dbref) <); . method rename_cmd arg com, what, prep, line; var syn, x, article, name; if (sender() != this()) throw(~perm, "Sender is not this"); syn = ((com + " <object> ") + prep) + " <newname> [-proper|-unique]"; what = .match_env_nice(what); if (!(what.has_ancestor($named))) $parse.tell_error(("Object \"" + ($data.unparse(what))) + "\" is not descended from $named.", syn); line = explode(line); article = 'uniq; for x in [1 .. listlen(line)] { if ((line[x]) in "-proper") { article = 'prop; line = delete(line, x); break; } if ((line[x]) in "-unique") { article = 'uniq; line = delete(line, x); break; } } name = $list.to_string(line); catch any { what.set_name(name, article); } with handler { $parse.tell_error((traceback()[1])[2], syn); } .tell("Name is now: " + (what.name())); . method time_cmd arg command, [args]; var rtime, itime, ptime; .perms(sender(), 'parser); // rtime = "Terran Time: " + $time.ltime('12hr, 'ampm) + " " + $time.ltime(); rtime = "Terran Time: " + ctime(); itime = (("Ilraitheen Time: " + ($dark_time.ilraitheen_time())) + " day ") + tostr($dark_time.day()); ptime = "Paradisical Time: " + ($dark_time.paradise_time()); .tell([rtime, itime, ptime]); . method audit_cmd arg com, [args]; var owner, obj, col, total, line, syntax, loc, size; if (sender() != this()) throw(~perm, "Sender not this."); syntax = ""; owner = (args[1]) ? args[1] | "me"; owner = .match_env_nice(owner, syntax); if (!(owner.owned())) { .tell(" None"); } else { col = (.linelen()) / 2; line = ("Objects owned by " + (owner.namef('ref))) + ":"; .tell((pad(line, col) + pad("bytes", -10)) + " Location"); for obj in (owner.owned()) { if (!valid(obj)) { .tell((" ** invalid object (" + toliteral(obj)) + ") **"); continue; } line = pad(" " + (obj.namef('xref)), col); size = $integer.to_english(obj.size()); line = (line + pad(size, -((strlen(size) > 10) ? strlen(size) | 10))) + " "; loc = (obj.has_ancestor($located)) ? ("[" + ((obj.location()).name())) + "]" | ""; .tell(pad(line + loc, .linelen())); total = total + (obj.size()); } } .tell(("Total usage: " + ($integer.to_english(total))) + " bytes"); size = owner.get_quota(); line = ("Total quota: " + ($integer.to_english(size))) + " bytes "; line = ((line + "Remaining: ") + ($integer.to_english(size - total))) + " bytes"; .tell(line); . method login_notify // called by .login, set items here that will 'notify' a user of various // different things, such as new mail, news, etc. if ($news.new()) .tell("There is new News (use `@news` to read it)."); if ((.last_received_on()) > ((.subscribed())[this()])) .tell("You have new mail (use `@help mail` to learn about mail)."); .subscribed_cmd(""); . method _set_watch_logins arg value; if (sender() != this()) throw(~perm, "Invalid call to private method"); watch_logins = value; . method get_mode arg mode; // returns the variable for the mode if (mode in dict_keys(modes)) return modes[mode]; throw(~modenf, ("Mode \"'" + tostr(mode)) + "\" is not found in the users dictionary"); . method add_mode arg mode, setting; if (!(.is_writable_by(sender()))) throw(~perm, "Sender is not an owner."); if (type(mode) != 'symbol) throw(~type, "Modes must be a symbol"); modes = dict_add(modes, mode, setting); . method news_cmd arg [args]; (> .perms(sender(), 'parser) <); $news.read_vrb("read", "news"); . method del_mode arg mode; if (!(.is_writable_by(sender()))) throw(~perm, "Sender is not an owner."); if (mode in dict_keys(modes)) { modes = dict_del(modes, mode); return; } throw(~modenf, "Mode is not in users modes dictionary"); . method add_command_alias_cmd arg com, input; var syn, alias, actual, tmpalias, tmpactual, num; if (sender() != this()) throw(~perm, "Sender is not this"); input = explode(input, "\""); // hell, i'll be nice and check for a few possibilities: syn = com + " \"<alias>\" [to] \"<actual command>\""; if (listlen(input) < 2) $parse.tell_error("Not enough arguments (enclose each alias in quotes)", syn); if (listlen(input) > 3) $parse.tell_error("Too many arguments (enclose each alias in quotes)", syn); // sort and get the alias and actual if (listlen(input) == 3) input = delete(input, 2); alias = input[1]; actual = input[2]; // make sure the %foo's match up tmpalias = alias; tmpactual = actual; while ("%" in tmpalias) { num = tmpalias[("%" in tmpalias) + 1]; if (!toint(num)) $parse.tell_error("referece cards must be integers", syn); num = "%" + num; if (!(num in tmpactual)) $parse.tell_error("reference cards to not match up", syn); tmpalias = strsub(tmpalias, num, ""); tmpactual = strsub(tmpactual, num, ""); } if ("%" in tmpactual) $parse.tell_error("reference cards do not match up", syn); .add_command_alias(alias, actual); .tell(((("New command alias \"" + alias) + "\" => \"") + actual) + "\" added."); . method del_command_alias_cmd arg com, template; if (sender() != this()) throw(~perm, "Sender is not this"); template = explode(template, "\"")[1]; catch ~aliasnf { .del_command_alias(template); } with handler { $parse.tell_error(("No command alias is found matching the template \"" + template) + "\"."); } .tell(("Command alias \"" + template) + "\" deleted."); . method command_aliases_cmd arg com, what; var aliases, a, line; if (!what) what = this(); else what = .match_env_nice(what); if ((what != this()) && (!(what.is_writable_by(this())))) $parse.tell_error("You are not allowed to read the command aliases on " + (what.namef())); .tell(("--- Command aliases on " + (what.namef('xref))) + ":"); aliases = what.command_aliases(); if (aliases) { for a in (aliases) { line = " " + pad(("\"" + (a[1])) + "\"", ((.linelen()) - 10) / 2); .tell(((line + " => \"") + (a[2])) + "\""); } } else { .tell(" <none>"); } .tell("---"); . method _tell arg what; var conn, line; if (type(what) == 'list) { for line in (what) ._tell(line); } else { for conn in (connections) conn.send(what); } . method add_filter arg filter, [position]; if ((!(sender().has_ancestor($filters))) && (!(.is_writable_by(sender())))) throw(~perms, "%O does not have permission to remove filters.", sender()); // do this in three steps, first make sure the posistion is valid, // then check for it already, then figure its insert position. position = [@position, 'first][1]; if (!(position in ['last, 'first])) throw(~type, "Posistion types must be one of: 'last, 'first."); // does it exist? If so remove it. if (filter in filters) filters = setremove(filters, filter); // figure position if (position == 'last) position = listlen(filters) + 1; else if (position == 'first) position = 1; filters = insert(filters, position, filter); . method del_filter arg filter; if ((!(sender().has_ancestor($filters))) && (!(.is_writable_by(sender())))) throw(~perms, "%O does not have permission to remove filters.", sender()); if (filters) { filters = setremove(filters, filter); return; } else { throw(~nofilters, "You do not have any tell filters."); } . method wrap_cmd arg com, how; var filters; .perms(sender(), 'this); if (!(how in ["on", "off"])) return .tell("! You can either turn line wrapping `on' or `off'"); filters = .filters(); if (how == "on") { if (filters && ($wrap_filter in filters)) return .tell("! You already have line wrapping on.."); .add_filter($wrap_filter); return .tell("Line wrapping turned on."); } else { if (filters && (!($wrap_filter in filters))) return .tell("! You dont have line wrapping turned on."); .del_filter($wrap_filter); return .tell("Line wrapping turned off."); } . method filters .perms(sender()); return filters; . method tell_traceback arg traceback, [args]; var tt, name, eargs, error, str; // tt = tell_traceback || ['verbose, 0, "! "]; str = [@args, ""][1]; eargs = [@args, 0, 0][2]; error = [@args, 0, 0, 0][3]; tt = ['verbose, -1, "! "]; switch (tt[1]) { case 'verbose: traceback = $parse.traceback(traceback, tt[2], tt[3], error); if (args) name = (| $list.to_english($list.map(args, 'namef, 'ref)) |); if (!name) name = "Object"; .tell(strsub(traceback[1], "%O", name)); .tell(sublist(traceback, 2)); default: .tell(("! Internal error processing \"" + str) + "\", contact an administrator."); } . method set_tell_traceback arg which, [lines]; .perms(sender(), 'manager); if (!(which in ['verbose, 'brief, 'none])) throw(~type, "Which style must either be 'verbose, 'brief, or 'none."); if (lines && (type(lines[1]) != 'integer)) throw(~type, "You must specify the max lines as an integer."); if (!lines) lines = 0; else lines = lines[1]; tell_traceback = [which, lines]; . method namef arg [args]; if (!args) args = [['name]]; // first check for shortcuts, if so re-call this method correctly. if ((args[1]) == 'nactivity) { if (.activity()) args = [['name], " (", ['activity], ")"] + sublist(args, 2); else args = [['name]] + sublist(args, 2); } if ((args[1]) == 'titled) { if (.title()) args = [['name], ", ", ['title]] + sublist(args, 2); else args = [['name]] + sublist(args, 2); } return pass(@args); . method get_prompt return prompt; . method set_prompt arg what; .perms(sender(), 'this); prompt = what; . method prompt_cmd arg com, [args]; .perms(sender(), 'this); if (!args) args = [""]; .set_prompt(args[1]); .tell(("Prompt set as \"" + (args[1])) + "\""); . method password_cmd arg com, [args]; var syn; (> .perms(sender(), 'this) <); syn = com + " <old password> <new password>"; args = explode(@args); if ((listlen(args) < 2) || (listlen(args) > 2)) $parse.tell_error("Not enough arguments specified (note: passwords cannot contain spaces).", syn); if (!(.check_password(args[1]))) $parse.tell_error("Sorry.", syn); catch any { .set_password(args[2]); } with handler { $parse.tell_error((traceback()[1])[2], syn); } .tell("Password changed."); . method set_title arg str; .perms(sender(), 'manager); if (strlen(str) > 30) throw(~type, "Titles must be under 30 characters."); title = str; . method watch_logins_cmd arg com, args; args = explode(args); if (!args) return .tell("You must specify someone to watch (logging in/out)."); if ((args[1]) in ["all", "everybody", "everyone"]) { .set_watch_logins(1); .tell("You are now listening to login messages from everybody."); } else if ((args[1]) in ["none", "noone"]) { .set_watch_logins(0); .tell("You are now ignoring login messages."); } else { .tell("nothing else on this command is progged yet."); } . method delimited_tell arg text; var conn; // will adjust perms etc later. for conn in (.connections()) conn.enh_tell([text]); . method match_context arg str; return context[str]; . method context return context; . method match_environment arg str; var match, gend; match = (> pass(str) <); gend = (| match.gender() |); if (gend) context = dict_add(context, gend.pronoun('po), match); return match; . method non_terminated_tell arg text; var conn; if (.setting("terminated-tell")) { for conn in (.connections()) conn.enh_tell([text]); } else { .tell(text); } . method set_name arg new_name, [ignore]; var old_name, part, sname; (> .perms(sender(), 'manager) <); // so it doesnt bomb on .set_dbref if ((.name()) == new_name) return; if ($user_db.valid_name(new_name)) old_name = .name(); sname = $string.strip(new_name, $user_db.stripped_characters()); catch any { pass(new_name); $user_db.key_changed(old_name, new_name); .set_dbref(tosym("user_" + sname)); } with handler { (| pass(old_name) |); rethrow(error()); } . method find_object_nice arg str, [args]; var match; catch any { match = .find_object(str, @args); } with handler { .tell("! " + ((traceback()[1])[2])); throw(~stop, "", 'no_traceback); } return match; . method find_object arg str, [args]; var trace, match; // comprehensive matching method. // args define what to match. if (!args) args = ['environment]; while (args) { switch (args[1]) { case 'environment: match = (| .match_environment(str) |); case 'user: match = (| $user_db.find(str) |); case 'grasp: match = (| $object.to_dbref(str) |); } if (match) return match; args = delete(args, 1); } throw(~objnf, ("No object found by the reference \"" + str) + "\"."); . method creation_time return creation_time; . method age_cmd arg com, user; var person, time; .perms(sender(), 'parser); person = (| $user_db.find(user) |); if (!person) { person = (| .match_environment(user) |); if (!person) return .tell(("No person can be found by the name \"" + user) + "\"."); } time = person.creation_time(); .tell(((person.namef()) + " was created on ") + ($time.ldate(time))); .tell(((((person.gender()).pronoun('psc)) + " is ") + ($time.elapsed(time() - time, 'long))) + " old."); . method spawn_cmd arg com, args; var syn, new_obj, moved, name, parent, builder; (> .perms(sender(), 'this) <); syn = com + " <parent> [named|called] <new object name>"; args = explode(args); builder = $builder in (.ancestors()); if ("named" in args) args = setremove(args, "named"); if ("called" in args) args = setremove(args, "named"); if (!args) $parse.tell_error("No arguments specified.", syn); else if ((listlen(args) == 1) && (!builder)) $parse.tell_error("You must specify both the parent object and the name of the new object.", syn); parent = args[1]; parent = .match_env_nice(parent, syn); // users shouldn't be creating non VR objs. if ((!(parent.has_ancestor($thing))) && (!builder)) { .tell(("Only programmers are allowed to spawn non VR objects (anything which isn't descended from " + ($thing.namef('ref))) + ")."); return; } name = sublist(args, 2).to_string(); catch any { new_obj = parent.spawn(); if (name) { if (!(new_obj.has_ancestor($named))) .tell("Object is not descended from $named."); else (> new_obj.set_name(name) <); } moved = (| new_obj.move_to(this()) |); .tell(((("Object " + (new_obj.namef('ref))) + " spawned from ") + (parent.namef('ref))) + "."); } with handler { $parse.tell_error((traceback()[1])[2], syn); } . method _prose_done arg text, obj, which; .perms(sender(), 'this); (> obj.set_prose(which, text) <); which = tostr(which); .tell(((($string.capitalize(which)) + " prose description for ") + (obj.namef('ref))) + " set."); . method prose_cmd arg cmd, args; var syn, which, obj, prose, long; (> .perms(sender()) <); syn = cmd + " [-long|-short] <object>"; args = $parse.options(args); obj = (args[1]).to_string(); if (args[2]) { // We'll only take the first flag, too bad. args = dict_keys(args[2])[1]; long = match_template("l?ong", args); } if (long) which = 'long; else which = 'short; if (!obj) $parse.tell_error("No object specified.", syn); obj = .match_env_nice(obj); if (!(obj.has_ancestor($described))) $parse.tell_error((obj.namef('ref)) + " is not a describeable object!", syn); if (!(| obj.perms(this()) |)) $parse.tell_error(("You do not have permission to write the prose description for " + (obj.namef('ref))) + ".", syn); if (which == 'short) prose = [.prompt("Enter line for short prose: ")]; else prose = .read("Enter text for long prose (end with a period or abort with `@abort`):"); if (prose == 'aborted) return; if ((prose[1]) == "@abort") return .tell("Aborted."); (> obj.set_prose(which, prose) <); which = tostr(which); .tell(((($string.capitalize(which)) + " prose description for ") + (obj.namef('ref))) + " set."); . method status_cmd arg com, [args]; var line, s; (> .perms(sender(), 'this) <); .tell(((("Name: " + ($motd.server_name())) + ", ") + ($motd.server_title())) + "."); .tell("Startup time: " + ($time.date($sys.server_info('startup_time)))); .tell((" (" + ($time.to_english(time() - ($sys.server_info('startup_time))))) + " ago)"); .tell("Last backup time: " + ($time.date($sys.server_info('last_backup)))); .tell((" (" + ($time.to_english(time() - ($sys.server_info('last_backup))))) + " ago)"); .tell("Driver: " + ($sys.server_info('driver_version, 'long))); .tell("Core: " + ($sys.server_info('core_version, 'long))); s = $sys.status(); .tell(((("Driver execution time: " + ($time.to_english(s[1]))) + " seconds (") + tostr(s[2])) + " microsecs)"); .tell(((("System execution time: " + ($time.to_english(s[3]))) + " seconds (") + tostr(s[4])) + " microsecs)"); .tell(("Max resident set size utilized: " + tostr(s[5])) + " bytes"); .tell("Integral shared text size: " + tostr(s[6])); .tell("Integral shared memory size: " + tostr(s[7])); .tell("Integral unshared data size: " + tostr(s[8])); .tell("Integral unshared stack size: " + tostr(s[9])); .tell("Page reclaims: " + tostr(s[10])); .tell("Page Faults: " + tostr(s[11])); .tell("Number of times swapped: " + tostr(s[12])); .tell("Block input operations: " + tostr(s[13])); .tell("Block output operations: " + tostr(s[14])); .tell("IPC messages sent: " + tostr(s[15])); .tell("IPC messages received: " + tostr(s[16])); .tell("Signals delivered: " + tostr(s[17])); .tell("Voluntary context switches: " + tostr(s[18])); .tell("In-voluntary context switches: " + tostr(s[19])); . method del_command_alias arg alias; (> .perms(sender()) <); (> pass(alias) <); if ((!(.command_aliases())) && ($command_aliases_parser in (.parsers()))) { .tell("Removing $command_aliases_parser from your list of parsers."); .del_parser($command_aliases_parser); } . method add_command_alias arg alias, actual; (> .perms(sender()) <); (> pass(alias, actual) <); if ((.command_aliases()) && (!($command_aliases_parser in (.parsers())))) { .tell("Adding $command_aliases_parser to your list of parsers.."); .add_parser($command_aliases_parser, 'first); } . method logout_connection arg connection; if ((sender() != this()) || (definer() != caller())) throw(~perm, "Invalid access to private method."); .tell($string.center(("* * * " + ($integer.n_to_nth(listlen(.connections()) + 1))) + " Logout sucessful * * *", .linelen())); . method tell_ctext arg ctext, originator; var output, type; type = (.setting("content-type")) || "text/plain"; output = ctext.translate_to(type); .tell(output); . method rehash_cmd arg cmd; .tell("Rehashing commands in your environment..."); .rehash_command_environment(); . method description arg actor, [exclude]; var out, obj, contents, line; out = (> pass(actor, @exclude) <); contents = .contents(); line = ((.gender()).pronoun('psc)) + " is "; out = [@out, (line + ((.activity()) || "awake")) + "."]; if (!contents) { out = [@out, ((.gender()).pronoun('psc)) + " is holding nothing."]; } else { out = [@out, ((.gender()).pronoun('psc)) + " is holding:"]; for obj in (contents) out = [@out, " " + (obj.namef())]; } return out; . method _who_at_place arg str; var place, thing, who, args; (> .perms(sender(), 'this) <); // This should actually be done with a global place dictionary and // a local place dictionary for each user. place = $place.match_descendants(str); if (!place) { .tell(("I do not know where \"" + str) + "\" is."); return 0; } who = []; for thing in (place.contents()) { if (thing.has_ancestor($user)) who = [@who, thing]; } if (!who) { .tell(("Nobody is in " + (place.namef())) + "."); return 0; } args = [who, "Users in " + (place.namef())]; args = [@args, [['namef, 'titled], ['time_poll]]]; args = [@args, ["Name", "Times (idle)"], [1, 1]]; return args; . method _who_is arg [args]; var person, p, who; (> .perms(sender(), 'this) <); who = []; args = ($string.explode_english_list(@args)) || []; for p in (args) { catch any { person = $user_db.find(p); } with handler { switch (error()) { case ~ambig: .tell(((("The name \"" + p) + "\" can match any of: ") + ($list.to_english($list.map((traceback()[1])[3], 'namef)))) + "."); default: .tell(("I don't know who \"" + p) + "\" is."); } continue; } who = [@who, person]; } if (!who) return 0; return [who, (listlen(who) == 1) ? "User" | "Users"]; . method _who_programmers arg args, opts; var out, progs, p, x, t, all; (> .perms(sender(), 'this) <); progs = []; opts = dict_keys(opts); all = "all" in opts; if (args && (!all)) { for p in (args) { x = $user_db.find(p); if (!x) .tell(("I don't know who \"" + p) + "\" is."); else progs = [@progs, x]; } t = (("Programmer" + listlen(progs)) == 1) ? "" | "s"; } else if (all) { t = "All Programmers"; progs = $programmer.descendants(); progs = setremove(progs, $admin); } else { t = "Connected Programmers"; for p in ($user_db.connected()) { if (p.has_ancestor($programmer)) progs = [@progs, p]; } } if (!progs) return 0; return [progs, t]; . method _who_admins arg args, opts; var out, admins, a, x, t, all; (> .perms(sender(), 'this) <); admins = []; opts = dict_keys(opts); all = "all" in opts; if (args && (!all)) { for a in (args) { x = $user_db.find(a); if (!x) .tell(("I don't know who \"" + a) + "\" is."); else admins = [@admins, x]; } t = (("Admin" + listlen(admins)) == 1) ? "" | "s"; } else if (all) { t = "All Admins"; admins = $sys.admins(); } else { t = "Connected Admins"; for a in ($user_db.connected()) { if (a.has_ancestor($admin)) admins = [@admins, a]; } } if (!admins) return 0; return [admins, t]; . method _who_short var user, tmp, who, namestr, total; (> .perms(sender(), 'this) <); who = []; total = listlen($user_db.connected()); .tell((("Currently connected users (total: " + tostr(total)) + ((total == 1) ? " person" | " people")) + "):"); for user in ($user_db.connected()) { namestr = (((((" " + (user.namef())) + " (") + ($time.elapsed(user.connected_at()))) + " ") + ($time.dhms(user.idle_seconds()))) + ")"; who = [@who, namestr]; if (tmp < (strlen(namestr) + 2)) tmp = strlen(namestr) + 2; } .tell($list.columnize(who, (.linelen()) / (tmp + 1), " ", .linelen())); . method remember_cmd arg cmd, str; if (str == "here") { .remember_place(.location()); .tell(("Remembering " + ((.location()).name())) + "."); } else { // Eventually you may want to remember people for some reason, // for now just say something vague and maybe they will think // it did something -B .tell("Ok."); } . method remember_place arg place; (> .perms(sender(), 'this) <); if (type(place) != 'dbref) throw(~type, "Place must be submitted as an object."); // because it is not initialized (and shoudn't be) if (!remembered_places) remembered_places = []; if (place in remembered_places) return; remembered_places = [@remembered_places, place]; . method forget_place arg place; (> .perms(sender(), 'this) <); if (type(place) != 'dbref) throw(~type, "Place must be submitted as an object."); remembered_places = setremove(remembered_places, place); . method remembered_places (> .perms(sender(), 'this) <); return remembered_places || []; . method remembered_cmd arg cmd, str; var line; (> .perms(sender(), 'this) <); if (str != "places") { .tell("You can only currently remember \"places\"."); return; } if (!(.remembered_places())) return .tell("You do not remember any place."); // now is a good a time as any... .validate_remembered_places(); .tell("Remembered Places:"); for line in (((.remembered_places()).map('name)).lcolumnize((.linelen()) - 2)) .tell(" " + line); . method forget_cmd arg cmd, str; (> .perms(sender(), 'this) <); if (str == "here") { .forget_place(.location()); .tell(("Forgetting " + ((.location()).name())) + "."); } else { // Eventually you may want to remember people for some reason, // for now just say something vague and maybe they will think // it did something -B .tell("Ok."); } . method idle_time arg [args]; var idle; args = [@args, 'dhms][1]; idle = .idle_seconds(); if ((connected_at < 0) || (idle < 30)) return ""; switch (args) { case 'dhms: return $time.dhms(idle, 'long); case 'elapsed: return $time.elapsed(idle); case 'seconds: return idle; } . method connected_time arg [args]; args = [@args, 'dhms][1]; if (connected_at < 0) return "Last on: " + ctime(abs(connected_at)); switch (args) { case 'dhms: return $time.dhms(time() - connected_at, 'long); case 'elapsed: return $time.elapsed(time() - connected_at); case 'seconds: return time() - connected_at; } . method whereis_cmd arg cmd, who; var user, u; who = (who && (who.explode_english_list())) || []; if (who && ((who[1]) == "is")) who = delete(who, 1); if (!who) $parse.tell_error("You must specify somebody."); for user in [1 .. listlen(who)] { u = (| $user_db.find(who[user]) |); if (!u) { .tell(("I don't know who \"" + (who[user])) + "\" is."); who = replace(who, user, 0); } else { who = replace(who, user, u); } } for user in (who) { if (user) .tell(((user.name()) + " is in ") + ((user.location()).name('def))); } . method validate_remembered_places var place; (> .perms(sender(), 'this) <); for place in (remembered_places) { if (!valid(place)) remembered_places = setremove(remembered_places, place); } . method terminated_tell return (| (settings[$user])["terminated-tell"] |) || "text/plain"; . method new_connection arg addr, port; var line; (> .perms(caller(), $connection) <); connections = connections + [sender()]; if (listlen(connections) == 1) .login(sender()); else .login_again(sender()); line = ("CONNECT " + tostr(sender() in connections)) + " ("; line = (line + (((.parents())[1]).dbref())) + ") : "; line = (((line + (.dbref())) + " <") + (sender().address())) + "> "; $sys.log(line); . method connection_going_away arg addr, port; var con, line; (> .perms(caller(), $connection) <); con = sender() in connections; connections = setremove(connections, sender()); if (!connections) .logout(sender()); else .logout_connection(sender()); connections = setremove(connections, sender()); line = ("DISCONNECT " + tostr(sender() in connections)) + " ("; line = (line + (((.parents())[1]).dbref())) + ") : "; line = (((line + (.dbref())) + " <") + (sender().address())) + "> "; $sys.log(line); . method read arg [args]; var text, output, head, tail; if (!(.connections())) return 'not_connected; if (((.connections())[1]).is_reading()) return 'engaged; head = [@args, "Now receiving input, enter \".\" to finish or \"@abort\" to abort."][1]; tail = [@args, "** Aborted **; Text thrown away.", "** Aborted **; Text thrown away."][2]; if (head) .tell(head); output = ((.connections())[1]).start_reading('multiple); if ((output == 'aborted) && tail) .tell(tail); return output; . method read_line arg [args]; var line, abort_msg, head; if (!(.connections())) return 'not_connected; if (((.connections())[1]).is_reading()) return 'engaged; head = [@args, ""][1]; abort_msg = [@args, "** Aborted **", "** Aborted **"][2]; if (head) .tell(head); line = ((.connections())[1]).start_reading('one); if ((line == 'aborted) && abort_msg) .tell(abort_msg); return line[1]; . method prompt arg prompt, [abort_msg]; .non_terminated_tell(prompt); return (> .read_line("", @abort_msg) <); . method short_description arg actor, [exclude]; var out, obj, contents, line, p, wearing; out = (> pass(actor, @exclude) <); contents = .contents(); wearing = .wearing(); p = (.gender()).pronoun('psc); line = p + " is "; out = [@out, (line + ((.activity()) || "awake")) + "."]; if (!contents) out = [@out, p + " is holding nothing."]; else out = [@out, (p + " is holding ") + (contents.map_to_english('namef))]; if (!wearing) out = [@out, p + " is wearing nothing!"]; else out = [@out, (p + " is wearing ") + (wearing.map_to_english('name))]; return out; . method ways_cmd arg cmd; (> .perms(caller(), 'this) <); .tell((.location()).visible_exits_formatted(this(), 'long)); . method describe_cmd arg cmd, str; var args, syn, what, desc; (> .perms(sender(), 'this) <); syn = cmd + " <what> as <description>"; args = match_template("* as *", str); if (!args) $parse.tell_error("You may also use \"@prose\".", syn); what = .match_env_nice(args[1]); desc = args[3]; catch any { what.set_prose('short, [desc]); } with handler { .tell((traceback()[1])[2]); return; } .tell(("Short prose description for " + (what.namef('ref))) + " set."); . method gender_cmd arg cmd, gender; var genders; (> .perms(sender(), 'this) <); genders = [$gender_female, $gender_male, $gender_neuter, $gender_plural]; if (!gender) { .tell(("Syntax: `" + cmd) + " <gender>`"); .tell("Available Genders: " + ((genders.map('name)).to_english())); .tell(("You are currently a gender of " + ((.gender()).name())) + "."); } else { gender = gender in (genders.map('name)); if (!gender) { .tell("Gender must be one of: " + (genders.to_english())); } else { .set_gender(genders[gender]); .tell(("Gender set to " + ((.gender()).name())) + "."); .tell(("Pronouns: " + (((((.gender()).pronouns()).values()).sublist(1, 5)).to_english())) + "."); } } . method content_type return (| (settings_data[$user])["content-type"] |) || "text/plain"; .