Generic user This object determines the behavior of user. Informational public methods: doing() Get doing string for who list connected_at() Return connection time last_command_at() Return time of last input check_password(str) True if str crypts to password match_environment(s) Return nearby object matching s local_to_environment(obj) True if obj is nearby connections() List of connection objects Public methods to perform actions: tell(s) Write string to user Owner methods: set_name(s) Set name set_doing(s) Set doing string set_password(str) Set password to crypt(str) parse_command(str) Execute input line str Protected methods: did_move(obj, place) Notification of completed move System object methods: login() Perform login actions Server methods: disconnect() Indicates disconnection parse(s) Indicates input line Commands: who_cmd("@who") Display a who listing doing_cmd("@doing", s) Set doing message quit_cmd("@quit") Log out help_on_cmd("help", topic, "on", obj) Get help on a topic on an object help_cmd("help", str) Get help parent proto_user object user var root name 'user var user password 0 var user doing 0 var user connected_at 0 var user last_command_at 0 var user editor 0 var user editor_method 0 var user connections 0 method init_user if (caller() != $root) throw(~perm, "Caller is not $root."); password = "*"; doing = ""; connected_at = 0; last_command_at = 0; editor = 0; editor_method = 0; connections = []; $user_db.user_created(); . method uninit_user var conn; if (caller() != $root) throw(~perm, "Caller is not $root."); for conn in (connections) (| conn.user_going_away() |); password = 0; doing = 0; editor = 0; editor_method = 0; connections = 0; $user_db.user_going_away(); . method set_vr_name arg new_name; var old_name; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); if (" " in new_name) throw(~spaces, "Space in new name."); if ((| $user_db.find_user(new_name) |)) throw(~duplicate, "Duplicate user name."); old_name = .vr_name(); (> pass(new_name) <); $user_db.user_changed_name(old_name); . eval var err; .initialize(); .add_command("@who", 'who_cmd); .add_command("@doing *", 'doing_cmd); .add_command("@quit", 'quit_cmd); .add_command("i?nventory", 'inventory_cmd); .add_command("p?age * with *", 'page_cmd); .add_command("sample_edit *", 'sample_edit_cmd); . method spawn arg [args]; if (!$sys.is_admin(sender())) throw(~perm, "Sender is not an admin."); return (> pass(@args) <); . method will_move arg mover, place; (> pass(mover, place) <); if (!place.has_ancestor($room)) throw(~perm, "Players can only move into rooms."); . method doing return doing; . method set_doing arg s; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); if (type(s) != 'string) throw(~type, "Argument not a string."); doing = s; . method connected_at return connected_at; . method last_command_at return last_command_at; . method tell arg what; var line, conn; if (type(what) == 'list) { for line in (what) .tell(line); } else { for conn in (connections) conn.tell(what); } . method set_password arg str; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); 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 parse_line arg s; if (caller() != $connection) throw(~perm, "Caller is not $connection."); // Don't let regular users see stack traces. catch any { last_command_at = time(); while (s && s[1] == " ") s = substr(s, 2); if (!s) return; return .parse_command(s); } with handler { .tell("Internal error processing command: " + s); } . method parse_command arg str; var cmd, loc, result, i, j, templates, template, word, fields, obj, verb_info; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); // Are we editing? if (editor) { if (substr(str, 1, 1) == "<") { str = substr(str, 2); if (!str) return; } else { result = editor.handle_editor_command(str); switch (result[1]) { case 'not_done: editor = result[2]; case 'abort: editor = 0; case 'done: .(editor_method)(result[2]); } return; } } // Check commands on this. cmd = .match_command(str); if (cmd) return .(cmd[1])(@cmd[2]); // Check commands on location. loc = .location(); cmd = loc.match_command(str); if (cmd) { loc.(cmd[1])(@cmd[2]); return; } // Try exit names. for obj in (loc.exits()) { if (str == obj.vr_name()) { obj.go_through(); return; } } // Resort to verb cache. templates = $verb_cache.templates(); catch ~objnf, ~verbnf { for template in (templates) { fields = match_template(strsub(template, "%this", "*"), str); if (type(fields) != 'list) continue; j = 1; for word in (explode(template)) { if (word == "%this") { obj = sender().match_environment(fields[j]); verb_info = obj.verb_info(template); if (verb_info[2] != 'remote && !.local_to_environment(obj)) .tell("You cannot do that from here."); else obj.(verb_info[1])(@fields); return; } else if (word == "*=*") { j = j + 2; } else { j = j + 1; } } } } with handler { switch (error()) { case ~objnf: .tell("I don't see \"" + error_arg() + "\" here."); case ~verbnf: .tell("You can't do that to that object."); } return; } // No luck. .tell("I don't understand that."); . method connection_logged_in arg addr, port; if (caller() != $connection) throw(~perm, "Caller is not $connection."); connections = connections + [sender()]; if (listlen(connections) == 1) .login(sender()); else .login_again(sender()); . method connection_gone arg addr, port; if (caller() != $connection) throw(~perm, "Caller is not $connection."); connections = setremove(connections, sender()); if (!connections) .logout(sender()); connections = setremove(connections, sender()); . method login arg connection; var loc; if (sender() != this() || definer() != caller()) throw(~perm, "Invalid access to private method."); $user_db.user_connected(); .tell("* * * Connected * * *"); connected_at = time(); last_command_at = time(); loc = .location(); (| loc.did_connect() |); (| loc.look_cmd("look") |); . method login_again arg connection; if (sender() != this() || definer() != caller()) throw(~perm, "Invalid access to private method."); last_command_at = time(); connection.tell("* * * Already connected * * *"); . method logout arg connection; if (sender() != this() || definer() != caller()) throw(~perm, "Invalid access to private method."); $user_db.user_disconnected(); (| .location().did_disconnect() |); . method connections return connections; . method connected disallow_overrides; return connections ? 1 | 0; . method who_cmd arg dummy; var user, seconds, namestr, constr, idlestr, n, doing; if (sender() != this()) throw(~perm, "Sender not this."); .tell("User Name On For Idle " + $sys.doing_poll()); for user in ($user_db.connected_users()) { namestr = pad(user.vr_name(), 14) + " "; // Put together the string for connect time. seconds = time() - user.connected_at(); if (seconds > 86400) { constr = tostr(seconds / 86400); constr = constr + "d"; } else { constr = ""; } constr = pad(constr, -3); seconds = seconds % 86400; constr = constr + " " + pad(tostr(seconds / 3600), -2, "0"); constr = constr + ":" + pad(tostr((seconds % 3600) / 60), -2, "0"); // Put together the string for idle time. seconds = time() - user.last_command_at(); if (seconds > 86400) idlestr = tostr(seconds / 86400) + "d"; else if (seconds > 3600) idlestr = tostr(seconds / 3600) + "h"; else if (seconds > 60) idlestr = tostr(seconds / 60) + "m"; else idlestr = tostr(seconds) + "s"; idlestr = pad(idlestr, -3) + " "; // Get doing and truncate if neccessary. doing = user.doing(); if (strlen(doing) > 46) doing = substr(doing, 1, 46); // Display the resulting line. .tell(namestr + constr + " " + idlestr + doing); } n = listlen($user_db.connected_users()); if (n == 1) .tell("One user logged in."); else .tell(tostr(n) + " users logged in."); . method doing_cmd arg dummy, s; if (sender() != this()) throw(~perm, "Sender not this."); .set_doing(s); .tell("Set."); . method quit_cmd arg dummy; if (sender() != this()) throw(~perm, "Sender not this."); return 'disconnect; . method inventory_cmd arg dummy; var i; if (sender() != this()) throw(~perm, "Sender not this."); .tell("Carrying:"); for i in (.contents()) .tell(" " + i.vr_name()); . method page_cmd arg dummy1, recipient, dummy2, message; var user; if (sender() != this()) throw(~perm, "Sender not this."); catch ~usernf { user = $user_db.find_user(recipient); if (!(user in $user_db.connected_users())) { .tell(user.vr_name() + " is not connected."); return; } user.tell(.vr_name() + " pages: " + message); .tell("You page \"" + message + "\" to " + user.vr_name() + "."); } with handler { .tell(recipient + " is not the name of a user."); } . method sample_edit_cmd arg dummy, str; editor = $editor_class.new([str]); editor_method = 'sample_edit_done; . method sample_edit_done arg text; .tell("Sample edit finished:"); .tell(text); .