Dump of #27777 (Self-Cleaning Room) @create $room named Self-Cleaning Room:Self-Cleaning Room @prop #27777."trigger_delay" 20 rc @prop #27777."delay" 3600 rc @prop #27777."remove_object_msg" "The housekeeper arrives to remove %[tcurrent_names] from %t." rc @prop #27777."trashtimes" {} r @prop #27777."trashobjects" {} r @prop #27777."current_names" "nothing" r @prop #27777."ejected" {} r #49853 @prop #27777."maximum_players" 50 rc @prop #27777."idle_max" 300 rc @prop #27777."being_shoved" {} r #49853 @prop #27777."self_cleaning" 0 r "#27777.("entrances") => E_PERM (Permission denied) "#27777.("exits") => E_PERM (Permission denied) "#27777.("key") => E_PERM (Permission denied) ;;#27777.("aliases") = {"Self-Cleaning Room"} ;;#27777.("description") = "This room optionally keeps itself relatively free of garbage. If this.self_cleaning is set, nonplayer objects which are not present in .residents are only allowed to remain for this.delay seconds (default one hour). This is not perfect; it uses :enterfunc as its trigger instead of forking. Messages: @remove_object gets printed to everyone in the room when an object is ejected. [Note kluge: instead of %n to describe the object being removed, use %[tcurrent_names]; this is so multiple items will be mentioned correctly in one message.]. @self-clean commandline verb toggles self cleaning, :set_self_cleaning permits programmatic shift." ;;#27777.("object_size") = {11115, 1141286549} @verb #27777:"enterfunc" this none this @program #27777:enterfunc pass(@args); if (!this.self_cleaning) return; endif item = args[1]; now = time(); if (this:litterp(item)) if (loc = item in this.trashobjects) this.trashtimes[loc] = now; else this.trashobjects = {@this.trashobjects, item}; this.trashtimes = {@this.trashtimes, now}; endif else this:check_if_too_full(item); endif ejectables = {}; deleteables = {}; for i in [1..length(this.trashobjects)] item = this.trashobjects[i]; if ((!valid(item)) || (!this:litterp(item))) "Maybe a player who connected, no longer litter."; "Also, if a !valid object gets in here, we're in trouble and better flush it."; deleteables = {@deleteables, item}; elseif (this:flush_item_now(i, now)) ejectables = {@ejectables, item}; endif endfor for x in (deleteables) this:deleteitem(x); endfor if (ejectables) fork (this.trigger_delay) for x in (ejectables) if (x.location == this) this:eject_basic(x); else ejectables = setremove(ejectables, x); if (x in this.trashobjects) this:deleteitem(x); endif endif this.current_names = $string_utils:english_list($list_utils:map_verb(ejectables, "title")); endfor if (ejectables) this:announce_all($string_utils:pronoun_sub(this.remove_object_msg)); endif endfork endif . @verb #27777:"exitfunc" this none this @program #27777:exitfunc if (callers()[1][1..4] != {#-1, "move", #-1, #-1}) return E_PERM; endif pass(@args); if (this.self_cleaning) this:deleteitem(args[1]); endif . @verb #27777:"eject eject_basic" this none this rxd #89987 @program #27777:eject set_task_perms($wiz_utils:random_wizard()); if (caller in {this, this.owner}) if (this.self_cleaning) x = args[1]; if (x.location == this) this.ejected = setadd(this.ejected, x); fork (this.delay * 5) this.ejected = setremove(this.ejected, x); endfork endif endif return pass(@args); else return E_PERM; endif . @verb #27777:"remove_object_msg" this none this @program #27777:remove_object_msg return this.(verb); . @verb #27777:"litterp" this none this rx @program #27777:litterp item = args[1]; if (item == this.owner) return 0; elseif (is_player(item) && (!(item in this.residents))) "nonresident idling players are litter, even if sessile"; return (typeof(idle_seconds(item)) == ERR) && ((time() - item.last_disconnect_time) > 300); else "non-resident objects are litter"; return !(item in this.residents); endif . @verb #27777:"acceptable" this none this @program #27777:acceptable "Modified 10/19/98 by TheCat to exclude sleeping players who don't belong."; what = args[1]; if ((this.self_cleaning && (ticks_left() < 15000)) && ((what in this.ejected) || this:litterp(what))) "If less than 15000 ticks, we are either a spammy command line task, or, more likely, a suspended or forked task trying to auto-return. Deny those."; result = 0; elseif ((is_player(what) && (!$object_utils:connected(what))) && (!this:basic_accept_for_abode(what))) result = 0; else result = pass(@args); endif return result; . @verb #27777:"deleteitem" this none this @program #27777:deleteitem if (caller != this) return E_PERM; endif item = args[1]; if (loc = item in this.trashobjects) this.trashobjects = listdelete(this.trashobjects, loc); this.trashtimes = listdelete(this.trashtimes, loc); endif . @verb #27777:"too_full" this none this rxd #49853 @program #27777:too_full max = this.maximum_players; cp = connected_players(); for x in (this.contents) if (x in cp) if ((max = max - 1) < 0) return 1; endif endif endfor return 0; . @verb #27777:"most_idle_player" this none this rx @program #27777:most_idle_player idler = #-1; time = 0; for x in (this.contents) if (idle_seconds(x) > time) time = idle_seconds(idler = x); endif endfor return time && {idler, time}; . @verb #27777:"shove_out" this none this rxd #49853 @program #27777:shove_out "shove_out(who, ..disallowed destinations...)"; "since this can move people, requires permissions"; if ((caller != this) && (!caller_perms().wizard)) return E_PERM; endif who = args[1]; msg = args[2]; poss_exits = this.exits; while (poss_exits) exit = poss_exits[random(length(poss_exits))]; poss_exits = setremove(poss_exits, exit); if ((!(exit.dest in args)) && exit.dest:acceptable(who)) break; else exit = 0; endif endwhile if (typeof(exit) != OBJ) return 0; endif player = who; this:shove_through_exit(exit, msg); return 1; . @verb #27777:"check_if_too_full" this none this rxd #49853 @program #27777:check_if_too_full item = args[1]; if (is_player(item) && this:too_full()) if ((who = this:most_idle_player()) && (who[2] > this.idle_max)) this:shove_out(who[1], {"", "It's awfully crowded in here to idle... you decide to go somewhere else less noisy.", ""}); elseif (ents = $set_utils:intersection(this.entrances, $list_utils:slice(callers()))) if (item.location == this) this:shove_out(item, {"", "It's too crowded in here, and you decide to explore a little.", ""}, @$list_utils:map_property(ents, "source")); endif endif endif . @verb #27777:"shove_through_exit" this none this rxd #67 @program #27777:shove_through_exit if (caller != this) return E_PERM; endif fork (0) who = player; if (who.location != this) "don't do it, not here"; return; endif exit = args[1]; dest = exit.dest; set_task_perms(player); who:tell_lines(args[2]); if (who.location == this) exit:move(who); endif if (who.location == this) "the 'eject' makes sure that they don't auto-return, and they also move"; this:eject_basic(who); endif endfork fork (1) "REALLY get them out of here, dang it! In case they killed the above task"; if (player.location == this) this:eject_basic(player); dobj = player; this:announce_all_but({player}, this:oejection_msg()); endif endfork . @verb #27777:"flush_item_now" this none this @program #27777:flush_item_now "args[1] is an index into this.trashobjects"; "args[2] is now, so we don't have to recalculate it for every single item."; "Returns 1 if item should be flushed now, else 0."; index = args[1]; now = args[2]; return (now - this.trashtimes[index]) > this.delay; . @verb #27777:"forget_trash" this none this @program #27777:forget_trash "This verb clears the record of litter in this room, and should be called after changing this.self_cleaning from 1 to 0."; if ((caller == this) || $perm_utils:controls(caller_perms(), this)) this.trashtimes = {}; this.trashobjects = {}; endif . @verb #27777:"@self-clean" any any none rxd @program #27777:@self-clean "If no args, toggle state. Else turn self-cleaning on or off"; "+x so you can call it on generics to toggle."; if ($perm_utils:controls(valid(caller_perms()) ? caller_perms() | player, this)) switch = argstr ? argstr | "toggle"; if (this.self_cleaning) if ((switch == "toggle") || (switch == "off")) this:set_self_cleaning(0); this:forget_trash(); player:tell(this:title() + " is no longer self cleaning."); elseif (switch == "on") player:tell("Self-cleaning is already on."); else player:tell("Try this instead: @self-clean off"); endif else if ((switch == "toggle") || (switch == "on")) this:set_self_cleaning(1); player:tell("Self-cleaning turned on."); elseif (switch == "off") player:tell("Self-cleaning is already on."); else player:tell("Try this instead: @self-clean on"); endif endif else player:tell("Permission denied."); endif . @verb #27777:"set_self_cleaning" this none this @program #27777:set_self_cleaning if ((caller == this) || $perm_utils:controls(caller_perms(), this)) return this.self_cleaning = args[1]; else return E_PERM; endif . "***finished***