Login Watcher (#109)(an instance of Generic Feature Object made by Dredful)     This meter seems to be plugged into the heart of the MOO. With wizardly influence, it tells people (if they wish to know) when players log in or out of the MOO. This feature has help, naturally: help #109. Go to location of this object, Features Feature Object. HELP MANUAL:      This feature will notify you when people login or logout. To use it, `@addfeature #109' and then type `@login on'. If you wish to only watch specific people log in or out, see the @interesting verb below to create a list.            To customize the messages the login watcher dumps to you, make a property on      yourself called .login_watcher ... this should contain a string containing your      message, with substitutions.       Login Watcher - time dobject - date       w - day of week visitor - name of player       # - object number of player       m - message (connected or disconnected)       c - number of connected players      For a message of "Dredful connected at 12:45, for 42 users online.", set your      .login_watcher property to "visitor m at Login Watcher, for c users online."            The default message is: "< m: visitor. Total: c >" VERB SOURCE CODE: @login:
"Usage: @login on/off";
"";
"When on, you'll see logins/logoffs. Turn it off to stop watching.";
if (argstr == "on")
if (player in this.users)
player:tell("You are already watching logins/logoffs.");
else
this.users = {@this.users, player};
player:tell("You will now see logins/logoffs.");
endif
elseif (argstr == "off")
this.users = setremove(this.users, player);
player:tell("You will no longer see logins/logoffs.");
else
player:tell_lines($code_utils:verb_documentation());
endif
.
broadcast: "broadcast(LIST tell_connect:
if (caller != #0)
return E_PERM;
endif
arrival = args[1];
if (this.users)
this.thinks_connected = setadd(this.thinks_connected, arrival);
message = {1, arrival, length(connected_players())};
to_tell = this:get_list(arrival);
this:broadcast(to_tell, message);
endif
.
tell_disconnect:
if (caller != #0)
return E_PERM;
endif
departure = args[1];
if (this.users)
this.thinks_connected = setremove(this.thinks_connected, departure);
"length(connected_players())-1 since connected_players() isn't updated until
:disfunc is complete";
numb = length(connected_players());
numb = args[2] ? numb - 1 | numb;
message = {0, departure, numb};
to_tell = this:get_list(departure);
this:broadcast(to_tell, message);
endif
.
updating:
if (!$perm_utils:controls(player, this))
return E_PERM;
endif
while (this.running)
before = this.thinks_connected;
now = connected_players();
"Only check for case it thinks more are connected than truly are. Aren't interested
in case when more are connected now than it thinks. Since $login is foolproof. It's
unwatched disconnects we're worried about.";
if (discrep = $set_utils:diff(before, now))
for person in (discrep)
this:tell_disconnect(person, 0);
endfor
endif
this.thinks_connected = now;
suspend(this.update_interval);
endwhile
.
@inter*esting @uninter*esting: " - @interesting get_list:
if (caller != this)
return E_PERM;
endif
who = args[1];
newlist = setremove(this.users, who);
for person in (this.interesting_only)
if (!(this:check_interesting(person, who) == 1))
newlist = setremove(newlist, person);
endif
endfor
return $set_utils:intersection(newlist, connected_players());
.
check_interesting:
"check_interesting(OBJ player1, OBJ player2) => is player2 in player1's list?";
if (caller != this)
return E_PERM;
endif
who = args[1];
tester = args[2];
inters = this:get_inter(who);
if (inters[2][2])
return (tester in inters[2][2]) && 1;
else
"Something's messed up. This case shouldn't occur.";
return -1;
endif
.
get_inter:
if (caller != this)
return E_PERM;
endif
who = args[1];
isinter = (who in this.interesting_only) && 1;
if (fnd = $list_utils:assoc(who, this.interesting))
if (dead = $set_utils:diff(fnd[2], this:remove_invalids(fnd[2])))
this:set_inter(who, dead, 0);
fnd = $list_utils:assoc(who, this.interesting);
endif
endif
return {isinter, fnd};
.
set_inter:
"adds or removes to list: set_inter(OBJ who, LIST newpeople, BOOL add/remove)";
if (caller != this)
return E_PERM;
endif
who = args[1];
new = args[2];
flag = args[3];
found = $list_utils:iassoc(who, this.interesting);
if (flag)
if (new)
if (found)
for person in (new)
this.interesting[found][2] = setadd(this.interesting[found][2], person);
endfor
else
this.interesting = {@this.interesting, {who, new}};
endif
else
if (found)
this.interesting = listdelete(this.interesting, found);
endif
endif
else
if (found)
for person in (new)
this.interesting[found][2] = setremove(this.interesting[found][2], person);
endfor
endif
endif
.
feature_remove:
who = args[1];
if ((caller != who) || (caller_perms() != this.owner))
return E_PERM;
endif
this.users = setremove(this.users, who);
this.interesting_only = setremove(this.interesting_only, who);
if (f = $list_utils:iassoc(who, this.interesting))
this.interesting = listdelete(this.interesting, f);
endif
.
message:
":message(1|0 connect|disconnect, OBJ personnel change, NUM total connected, OBJ
who is being told)";
if (caller != this)
return E_PERM;
endif
mesg = args[1] ? "connected" | "disconnected";
change = args[2];
numb = args[3];
who = args[4];
base = $object_utils:has_property(who, "login_watcher") ? who.login_watcher | this.message;
subs = {{"%t", who:ctime(who, time())[12..19]}, {"%m", mesg}, {"%#", tostr(change)},
{"%n", change.name}, {"%c", tostr(numb)}, {"%d", $time_utils:ddmmyy(time())}, {"%w",
$time_utils:day(time())}};
return $string_utils:substitute(base, subs);
.
remove_invalids:
people = args[1];
for p in (people)
if (!is_player(p))
people = setremove(people, p);
endif
endfor
return people;
.
PROPERTY DATA:       thinks_connected       running       users       update_interval       interesting       interesting_only       message |