baglady (#71)

(an instance of generic programmer made by Hacker)

     A rather lost soul, wandering around the streets of the city picking up and dropping off various things that she seems to find useful. At least those items she finds interesting for a short while. She's wearing old rags that might have been pretty once. Now they are covered in dirt, much like her face, as she seems to be more interested in her possessions than herself.

baglady is carrying Shaman.

Go to location of this object, Hovel.


baglady owns south north Hovel


VERB SOURCE CODE:

look_self:
player:tell_lines(this:description());
if (this.location == this.home)
    player:tell($string_utils:pronoun_sub("%S % propped up on the bed, playing 
with some old dusty toys.", this));
else
    player:tell($string_utils:pronoun_sub("%S % moving around from place to place, 
picking up stray items.", this));
endif
.


cleanup:
"$housekeeper:cleanup([insist]) => clean up player's objects. Argument is 'up' or 
'up!' for manually requested cleanups (notify player differently)";
if (caller_perms() != this)
    return E_PERM;
endif
for object in (this.clean)
    x = object in this.clean;
    if (this.requestors[x] == player)
        if (result = this:replace(object, @args))
            player:tell(result, ".");
        endif
    endif
    $command_utils:suspend_if_needed(0);
endfor
player:tell("The baglady has finished moving your objects around.");
.


replace:
"replace the object given to its proper spot (if there is one).";
object = args[1];
insist = (length(args) > 1) && args[2];
notify(this, tostr("cleaning ", object, " task ", task_id(), " insist ", insist));
i = object in this.clean;
if (!i)
    return tostr(object, " is not on the ", this.name, "'s cleanup list");
endif
place = this.destination[i];
if (!(($recycler:valid(object) && ($recycler:valid(place) || (place == #-1))) && 
(!(object.location in this.recycle_bins))))
    "object no longer valid (recycled or something), remove it.";
    this.clean = listdelete(this.clean, i);
    this.requestors = listdelete(this.requestors, i);
    this.destination = listdelete(this.destination, i);
    return tostr(object) + " is no longer valid, removed from cleaning list";
endif
oldloc = loc = object.location;
if (object.location == place)
    "already in its place";
    return "";
endif
requestor = this.requestors[i];
if (insist != "up!")
    for thing in (object.contents)
        if (thing:is_listening())
            return ((("Not returning " + object.name) + " because ") + thing.name) 
+ " is inside";
        endif
        $command_utils:suspend_if_needed(0);
    endfor
    if (valid(loc) && (loc != $limbo))
        if (loc:is_listening())
            return ((("Not returning " + object.name) + " because ") + loc.name) 
+ " is holding it";
        endif
        for y in (loc:contents())
            if ((y != object) && y:is_listening())
                return (((("Not returning " + object.name) + " because ") + y.name) 
+ " is in ") + loc.name;
            endif
            $command_utils:suspend_if_needed(0);
        endfor
    endif
endif
if (valid(place) && (!place:acceptable(object)))
    return (place.name + " won't accept ") + object.name;
endif
requestor:tell("As you requested, the baglady moves ", $string_utils:nn(object), 
" from ", $string_utils:nn(loc), " to ", $string_utils:nn(place), ".");
if ($object_utils:has_verb(loc, "announce_all_but"))
    loc:announce_all_but({requestor, object}, "At ", requestor.name, "'s request, 
the ", this.name, " shuffles in, picks up ", object.name, " and shuffles off with 
", ($object_utils:has_property(object, "po") && (typeof(object.po) == STR)) ? object.po 
| "it", ".");
endif
this:moveit(object, place, requestor);
if ((loc = object.location) == oldloc)
    return (object.name + " wouldn't go; ") + ((!place:acceptable(object)) ? (" perhaps 
" + $string_utils:nn(place)) + " won't let it in" | ((" perhaps " + $string_utils:nn(loc)) 
+ " won't let go of it"));
endif
object:tell("The baglady picks you up and drops you off a short time later.");
if ($object_utils:isa(loc, $room))
    loc:announce_all_but({object}, "At ", requestor.name, "'s request, the baglady 
shuffles in, deposits ", object:title(), " and leaves.");
else
    loc:tell("You notice a baglady shuffle in, give you ", object:title(), " and 
leave.");
endif
return "";
.


cleanup_list:
if (args)
    if (!valid(who = args[1]))
        return;
    endif
    player:tell(who.name, "'s personal cleanup list:");
else
    who = 0;
    player:tell("Baglady's complete cleanup list:");
endif
player:tell("------------------------------------------------------------------");
printed_anything = 0;
objs = this.clean;
reqs = this.requestors;
dest = this.destination;
for i in [1..length(objs)]
    $command_utils:suspend_if_needed(2);
    req = reqs[i];
    ob = objs[i];
    place = dest[i];
    if (((who == 0) || (req == who)) || (ob.owner == who))
        if (!valid(ob))
            player:tell($string_utils:left(tostr(ob), 7), $string_utils:left("** 
recycled **", 50), "(", req.name, ")");
        else
            player:tell($string_utils:left(tostr(ob), 7), $string_utils:left(ob.name, 
26), "=>", $string_utils:left(tostr(place), 7), place.name || "nowhere", " (", req.name, 
")");
        endif
        printed_anything = 1;
    endif
endfor
if (!printed_anything)
    player:tell("** The baglady has nothing in her cleanup list.");
endif
player:tell("------------------------------------------------------------------");
.


add_cleanup:
if (!$perm_utils:controls(caller_perms(), this))
    return E_PERM;
endif
what = args[1];
if ((what < #1) || (!valid(what)))
    return "invalid object";
endif
who = (length(args) > 1) ? args[2] | player;
where = (length(args) > 2) ? args[3] | what.location;
if ($object_utils:isa(who, $guest))
    return tostr("Guests can't use the ", this.name, ".");
endif
if (!is_player(who))
    return tostr("Non-players can't use the ", this.name, ".");
endif
if (!valid(where))
    return tostr("The ", this.name, "doesn't know how to find ", where, " in order 
to put away ", what.name, ".");
endif
if (is_player(what))
    return ("The " + this.name) + " doesn't do players.";
endif
for x in (this.eschews)
    if ($object_utils:isa(what, x[1]))
        ok = 0;
        for y in [3..length(x)]
            if ($object_utils:isa(what, x[y]))
                ok = 1;
            endif
        endfor
        if (!ok)
            return tostr("The ", this.name, " doesn't do ", x[2], "!");
        endif
    endif
endfor
if ($object_utils:has_callable_verb(where, "litterp") ? where:litterp(what) | ((where 
in this.public_places) && (!(what in where.residents))))
    return tostr("The ", this.name, " won't litter ", where.name, "!");
endif
if (i = what in this.clean)
    if ((!this:controls(i, who)) && valid(this.destination[i]))
        return tostr(this.requestors[i].name, " already asked that ", what.name, 
" be kept at ", this.destination[i].name, "!");
    endif
    this.requestors[i] = who;
    this.destination[i] = where;
else
    this.clean = {what, @this.clean};
    this.requestors = {who, @this.requestors};
    this.destination = {where, @this.destination};
endif
return tostr("The ", this.name, " will keep ", what.name, " (", what, ") at ", valid(where) 
? ((where.name + " (") + tostr(where)) + ")" | where, ".");
.


remove_cleanup:
if (!$perm_utils:controls(caller_perms(), this))
    return E_PERM;
endif
what = args[1];
who = (length(args) > 1) ? args[2] | player;
if (i = what in this.clean)
    if (!this:controls(i, who))
        return tostr("You may remove an object from the ", this.name, " list only 
if you own the object, the place it is kept, or if you placed the original cleaning 
order.");
    endif
    this.clean = listdelete(this.clean, i);
    this.destination = listdelete(this.destination, i);
    this.requestors = listdelete(this.requestors, i);
    return tostr(what.name, " (", what, ") removed from cleanup list.");
else
    return tostr(what.name, " not in cleanup list.");
endif
.


controls:
"does player control entry I?";
i = args[1];
who = args[2];
if ((who in {this.owner, @this.owners}) || who.wizard)
    return "Yessir.";
endif
i = args[1];
cleanable = this.clean[i];
if (this.requestors[i] == who)
    return "you asked for the previous result, you can change this one.";
elseif (((who == cleanable.owner) || (!valid(dest = this.destination[i]))) || (who 
== dest.owner))
    return "you own the object or the place where it is being cleaned to, or the 
destination is no longer valid.";
else
    return "";
endif
.


continuous:
"start the housekeeper cleaning continuously. Kill any previous continuous";
"task. Not meant to be called interactively.";
if (!$perm_utils:controls(caller_perms(), this))
    return E_PERM;
endif
if ($code_utils:task_valid(this.task))
    kill_task(this.task);
    this.task = 0;
endif
fork taskn (0)
    while (1)
        for x in (this.clean)
            fork (0)
                this:replace(x);
            endfork
            suspend(this.testing ? 2 | this:time());
        endfor
        suspend(5);
        this:litterbug();
    endwhile
endfork
this.task = taskn;
.


litterbug:
for room in (this.public_places)
    for thingy in (room.contents)
        suspend(10);
        if (((thingy.location == room) && this:is_litter(thingy)) && (!this:is_watching(thingy, 
$nothing)))
            "if it is litter and no-one is watching";
            fork (0)
                this:send_home(thingy);
            endfork
            suspend(0);
        endif
    endfor
endfor
.


is_watching:
return valid(thing = args[1]) && thing:is_listening();
.


send_home:
if (caller != this)
    return E_PERM;
endif
litter = args[1];
littering = litter.location;
this:ejectit(litter, littering);
home = litter.location;
if ($object_utils:isa(home, $room))
    home:announce_all("A ", this.name, " shuffles in, deposits ", litter:title(), 
" and leaves.");
else
    home:tell("You notice a ", this.name, " shuffle in, give you ", litter:title(), 
" and leave.");
endif
if ($object_utils:has_callable_verb(littering, "announce_all_but"))
    littering:announce_all_but({litter}, "A ", this.name, " shuffles in, picks up 
", litter:title(), " and then leaves.");
endif
.


moveit:
"Wizardly verb to move object with requestor's permission";
if (caller != this)
    return E_PERM;
else
    set_task_perms(player = args[3]);
    return args[1]:moveto(args[2]);
endif
.


ejectit:
"this:ejectit(object,room): Eject args[1] from args[2].  Callable only by housekeeper's 
quarters verbs.";
if (caller == this)
    args[2]:eject(args[1]);
endif
.


is_object_cleaned:
what = args[1];
if (!(where = what in this.clean))
    return 0;
else
    return {this.destination[where], this.requestors[where]};
endif
.


is_litter:
thingy = args[1];
for x in (this.litter)
    if ($object_utils:isa(thingy, x[1]) && (!$object_utils:isa(thingy, x[2])))
        return 1;
    endif
endfor
return 0;
.


init_for_core:
if (caller_perms().wizard)
    this.password = "Impossible password to type";
    this.litter = {};
    this.public_places = {};
    this.requestors = {};
    this.destination = {};
    this.clean = {};
    this.eschews = {};
    this.recycle_bins = {};
    this.cleaning = #-1;
    this.task = 0;
    this.owners = {#2};
    pass(@args);
endif
.


clean_status:
count = 0;
for i in (this.requestors)
    if (i == player)
        count = count + 1;
    endif
    $command_utils:suspend_if_needed(1);
endfor
player:tell("Number of items in cleanup list: ", tostr(length(this.clean)));
player:tell("Number of items you requested to be tidied: ", tostr(count));
player:tell("Number of requestors: ", tostr(length($list_utils:remove_duplicates(this.requestors))));
player:tell("Time to complete one cleaning circuit: ", $time_utils:english_time(length(this.clean) 
* this:time()));
.


is_cleaning:
"return a string status if the hosuekeeper is cleaning this object";
cleanable = args[1];
info = this:is_object_cleaned(cleanable);
if (info == 0)
    return tostr(cleanable.name, " is not cleaned by the ", this.name, ".");
else
    return tostr(cleanable.name, " is kept tidy at ", info[1].name, " (", info[1], 
") at ", info[2].name, "'s request.");
endif
.


time:
"Returns the amount of time to suspend between objects while continuous cleaning.";
"Currently set to try to complete cleaning circuit in one hour, but not exceed one 
object every 20 seconds.";
return max(20, 3600 / length(this.clean));
.


acceptable:
return caller == this;
.


idle_suffix:
return "";
.



PROPERTY DATA:
      recycle_bins
      owners
      cleaning
      litter
      eschews
      public_places
      task
      requestors
      destination
      clean
      testing