Dump of #258 Dungeon

@create #1610 named Generic Dungeon Room:Generic Dungeon Room,Dungeon Room
@prop #258."transparency_support" 0 rc
@prop #258."free_exit" 0 rc
@prop #258."player_all_verbs" {} rc
;;#258.("player_all_verbs") = {"drop", "throw", "give", "hand", "wear", "remove", "wield", "unwield", "sheathe", "sling", "put", "insert"}
@prop #258."room_all_verbs" {} rc
;;#258.("room_all_verbs") = {"get", "take"}
@prop #258."gripe_recipients" {} rc
;;#258.("gripe_recipients") = {#4044}
@prop #258."magic_effect" 0 r
@prop #258."blessed_exit" 0 r
@prop #258."accept_rpg_teleport" 0 rc
"#258.("misc_notes") => E_PERM (Permission denied)
"#258.("magic_effects") => E_PERM (Permission denied)
"#258.("combat_effects") => E_PERM (Permission denied)
"#258.("unannounced") => E_PERM (Permission denied)
@prop #258."teleport_object" #-1 r
@prop #258."teleport_task" 0 r
@prop #258."forgiving" {} r
"#258.("allowed_exits") => E_PERM (Permission denied)
;;#258.("dawn_msg") = ""
;;#258.("night_msg") = ""
;;#258.("dusk_msg") = ""
;;#258.("day_msg") = ""
;;#258.("free_entry") = 0
"#258.("entrances") => E_PERM (Permission denied)
"#258.("exits") => E_PERM (Permission denied)
;;#258.("ctype") = 5
"#258.("key") => E_PERM (Permission denied)
;;#258.("aliases") = {"Generic Dungeon Room", "Dungeon Room"}
;;#258.("object_size") = {72473, 1141286558}

@verb #258:"acceptable" this none this
@program #258:acceptable
{what} = args;
{rpg, owner, loc} = {$local.rpg, what.owner, what.location};
if (rpg.player_start:is_banned(owner) || (!rpg.player_start:is_not_banned(what)))
  return 0;
elseif (is_player(what))
  if ((what != owner) && (!rpg.guests_allowed))
    return 0;
  elseif ((loc in {$mail_editor, $note_editor}) && (this == loc.original[what in loc.active]))
    if (((valid(doll = rpg:get_doll(what)) && ((note = doll:read_misc_note("last_room")) != E_PROPNF)) && (note == this)) || (what in rpg.gms))
      return 1;
    endif
    valid(doll) && rpg:log_error(tostr("Apparent hacked entry attempt by ", $string_utils:nn(what), " from ", $string_utils:nn(loc), " to ", $string_utils:nn(this), ".  Callers: ", toliteral(callers(1))));
  endif
endif
return ((pass(what) || (owner in rpg.gms)) || ($object_utils:contains(this, what) && ($object_utils:isa(what, rpg.thing) || rpg.object_db:is_monster(what)))) || ((what == this.teleport_object) && (task_id() == this.teleport_task));
"Removed my insertion of $local.rpg:trust(0) since it seems to allow all entries from any room with an :accept verb higher than this one.";
"Mooshie (#106469) - Sun Oct 12 00:09:02 1997 PDT - Added teleport object/task check. Set by :bless_for_teleport ";
"THX (#105941) - Thu Jan 27, 2000 - Allow players back in from $mail_editor and $note_editor.";
"THX (#105941) - Sun Mar 18, 2001 - changed the is_rpg call to is_monster temporarily.";
"THX (#105941) - Sun May  6, 2001 - Removed temporary acceptance of hacked $editor origins after catching a few exploiters.  Now it just goes to pass(what).";
.

@verb #258:"l*ook" any any any rxd
@program #258:look
"look [at] thing -- Take a gander at something.";
rpg = $local.rpg;
string = (prepstr == "at") ? iobjstr | dobjstr;
what = string ? this:match(string) | this;
if (valid(doll = rpg:get_doll(player)) && (msg = doll:cannot_see()))
  rpg:playertell(player, msg);
elseif (!$command_utils:object_match_failed(what, string))
  what:look_self();
  if (valid(rpg:get_doll(what)) && is_player(what))
    rpg:look_health(what);
    rpg:look_gear(what);
  endif
endif
"Quinn 01-AUG-93 0812-ET: Hacked to recognise 'at', and to use :object_match_failed.";
"Profane (#30788) - Wed Feb 14, 2001 - support for cannot_see";
.

@verb #258:"enterfunc" this none this
@program #258:enterfunc
if (!(rpg = $local.rpg):trusted_efunc())
  return E_PERM;
endif
{thing} = args;
pass(thing);
if ((thing in rpg.pcs) && is_player(thing))
  rpg.usage_meter:add_user(thing);
endif
theEntrance = this:identify_entrance(thing);
this:notify_arrival(thing, theEntrance);
if (valid(doll = (rpg = $local.rpg):get_doll(thing)))
  min = 999;
  for y in (doll.aggressor)
    if (valid(y) && (y.location == this))
    else
      doll.aggressor = setremove(doll.aggressor, y);
    endif
  endfor
  for q in (setremove(thing.location.contents, thing))
    if (valid(z = rpg:get_doll(q)) && ((poss = z.act) < min))
      min = poss;
    endif
  endfor
  if (min < 999)
    doll.act = min;
    "fork (0)";
    "  doll:invite(doll:get_att(\"slowness\") / 2, {-1});";
    "endfork";
  else
    clear_property(doll, "act");
  endif
endif
"New silent 'port detection:";
if ((theEntrance in this:entrances()) || ((thing == this.teleport_object) && (task_id() == this.teleport_task)))
elseif ((((this:free_entry(thing) && (rpg.gm_lag < rpg.idle_threshold)) && (!(thing.owner in rpg.gms))) && valid(thing)) && (parent(thing) != $garbage))
  task = task_id();
  this.unannounced = setadd(this.unannounced, {task, thing});
  fork (3)
    "Fork, because porting announces messages after the moveto; our code in announce* will remove the task from the .unannounced_property if it's not a silent port.";
    if (i = {task, thing} in this.unannounced)
      this:announce_all(thing.name, " teleports in, `silently.'");
      (this.owner in rpg.gms) && this:exitshock(thing);
      this.unannounced = listdelete(this.unannounced, i);
      if (parent(this).unannounced == this.unannounced)
        clear_property(this, "unannounced");
      endif
    endif
  endfork
endif
"Profane 5-OCT-97 -- new code for silent entry detection.";
"Mooshie (#106469) - Fri Jan  2, 1998 - Added some security, a little de-ticking. Will de-tick much more later, this is a mess.";
"Mooshie (#106469) - Sat Aug 28, 1999 - Added a call to the RPG usage meter.";
.

@verb #258:"forgive" any none none rxd
@program #258:forgive
rpg = $local.rpg;
cp = caller_perms();
if (((cp != player) && valid(cp)) && (!rpg:trusted(cp)))
  return player:tell("See G_M about remote calls to the '", verb, "' verb.");
elseif (!valid(doll = rpg:get_doll(player)))
  return player:tell("As a peaceful person, you hold no grudges.");
elseif (valid(attempt = this:match(dobjstr)))
  dobj = attempt;
elseif ($command_utils:object_match_failed(dobj, dobjstr))
  return;
endif
if (!valid(fdoll = rpg:get_doll(dobj)))
  doll.aggressor = setremove(doll.aggressor, dobj);
  return player:tell(dobj.name, " is no threat to you.");
endif
for n in (this.forgiving)
  if ((n[1] == dobj) && (n[2] == player))
    doll.aggressor = setremove(doll.aggressor, dobj);
    fdoll.aggressor = setremove(fdoll.aggressor, player);
    player:tell("You break off combat with ", dobj.name, ".");
    dobj:tell("You break off combat with ", player.name, ".");
    return rpg:rpg_announce_all_but(this, {player, dobj}, player.name, " and ", dobj.name, " break off combat with each other.");
  elseif (`(n[1].location != this) || (n[2].location != this) ! ANY => 1')
    this.forgiving = setremove(this.forgiving, n);
  endif
endfor
if (player in fdoll:aggressor())
  this.forgiving = setadd(this.forgiving, {player, dobj});
  is_player(dobj) ? dobj:tell(player.name, " forgives you and wishes to cease combat.  If you wish to break off, type 'forgive ", player.name, "', and all will be forgiven.") | dobj:notify_forgive(player);
  player:tell("You offer to break off combat with ", dobj.name, ".");
  rpg:rpg_announce_all_but(this, {player, dobj}, player.name, " offers to break off the combat with ", dobj.name, ".");
elseif (dobj in doll:aggressor())
  doll.aggressor = setremove(doll.aggressor, dobj);
  player:tell("You break off combat with ", dobj.name, ".");
  is_player(dobj) ? dobj:tell(player.name, " breaks off combat with you.") | dobj:notify_forgive(player);
  rpg:rpg_announce_all_but(this, {player, dobj}, player.name, " breaks off combat with ", dobj.name, ".");
else
  player:tell("There is no conflict between you and ", dobj.name, ".  There is nothing to forgive.");
endif
.

@verb #258:"hate" any none none rxd
@program #258:hate
rpg = $local.rpg;
doll = rpg:get_doll(player);
what = this:match(dobjstr);
if ($match_utils:object_match_failed(what, dobjstr))
elseif (!valid(doll))
  player:tell("As a peaceful person, you hold no grudges.");
elseif (what == player)
  player:tell("If you hate yourself that much, why not MOOicide?");
elseif ((callers() && is_player(player)) && (!(caller_perms() in rpg.grand_masters)))
  rpg:log_error((((((("Player " + $string_utils:nn(player)) + " made to hate using +x nature of verb: ") + $string_utils:nn(caller)) + " owned by ") + tostr(`$string_utils:nn(caller.owner) ! ANY')) + "  :  ") + toliteral(callers()));
elseif (!doll:legal_target(what))
  return;
elseif (!(what in rpg.pcs))
  player:tell("You nurse your grudge against ", what.name, ".");
else
  player:tell("You nurse your grudge against ", what.name, ".");
  (what in doll.aggressor) || doll:first_blood(player, what);
  (what.location == player.location) && (doll.aggressor = setadd(doll.aggressor, what));
endif
"Hydros (#106189) Thu Aug 11, 2005 - Added a call to :legal_target.";
.

@verb #258:"tell_contents" this none this
@program #258:tell_contents
{contents, ctype} = args;
if (this.dark)
  return;
elseif (ctype != 5)
  pass(contents, ctype);
  return;
endif
pcs = (rpg = $local.rpg).pcs;
people = things = {};
for q in (contents)
  if ((q in pcs) || is_player(q))
    this:hide(q) || (people = listappend(people, q));
  else
    things = listappend(things, q);
  endif
endfor
if (things)
  rpg:playershow(player, "You see ", $string_utils:english_list($list_utils:map_verb(things, "title")), " here.");
endif
if (people)
  rpg:playershow(player, $string_utils:english_list($list_utils:map_verb(people, "title")), (length(people) == 1) ? " is" | " are", " here.");
endif
"THX 13-Apr-1997 -- Scatter assignment and de-ticked.  Should be nice and fast now.";
.

@verb #258:"exitfunc" this none this rx
@program #258:exitfunc
"Penalise for illegal exit, clear aggressor and action properties, and remove object from the aggressor lists of everyone still in the room.";
{who} = args;
if ((!(rpg = $local.rpg):trusted_efunc()) || ((caller != this) && (!$perm_utils:controls(caller_perms(), who))))
  return E_PERM;
elseif (valid(who) && (parent(who) != $garbage))
  pass(who);
else
  return;
endif
if (this:exit_ok(who))
  "... they've left via a normal route ...";
else
  this:exitshock(who);
endif
odb = rpg.object_db;
if (valid(doll = rpg:get_doll(who)))
  ("lighting" in this.room_data) && this:relight(doll, 0);
  ("tavern" in this.room_data) && odb.natweap_db:remove_natweap(doll, odb.pirate_brawling);
  clear_property(doll, "aggressor");
  clear_property(doll, "act");
  if (is_player(who))
    doll:write_misc_note("last_room", this);
    if (valid(doll.duelee))
      if ((ddoll = rpg:get_doll(doll.duelee)).duelee == who)
        "Fled a duel.";
        winner = doll.duelee;
        fork (0)
          for dude in ($set_utils:union(#15870:active_players(), {who, winner}))
            if (rpg.rpg_options:get(`rpg:get_doll(dude).rpg_options ! E_INVIND => {}', "APB"))
              rpg:playertell(dude, winner:titlec(), " has defeated ", who:title(), " in a duel to the death! ", who:title(), " has fled like a cowardly dog!");
            endif
          endfor
        endfork
        clear_property(ddoll, "duelee");
      endif
      clear_property(doll, "duelee");
    endif
  endif
endif
for pair in (this.forgiving)
  if (who in pair)
    (this.forgiving = setremove(this.forgiving, pair)) || clear_property(this, "forgiving");
  endif
endfor
(length(this.contents) < 33) && this:notify_exit(who, this:identify_exit(who, 0));
((((!valid(loc = who.location)) || (odb:is_rpg_room(loc) || odb:is_rpg_room(loc.location))) || (parent(loc) == $generic_editor)) || (loc in {`who.home ! ANY => $nothing', rpg.player_start})) || ((who in rpg.pcs) && who:tell("You have just exited the LambdaRPG."));
"Profane (#30788) - Sat Nov  8 23:13:41 1997 PST - readded call to notify_exit, where'd it go?";
"Mooshie (#106469) - Fri Jan  2, 1998 - Moved the for loop that removes exiter from aggressor lists to :notify_exit, so we don't duplicate the for loop. Also replaced :secure_stack security with :trusted_efunc.";
"THX (#105941) - Sat Nov  7, 1998 - Only call :notify_exit() if there are fewer than 50 objects in the room.";
"THX (#105941) - Sat Mar 31, 2001 - Added a hack for the room lighting stuff.";
"THX (#105941) - Mon Apr 30, 2001 - Added a misc_note that tracks the player's last RPG room location for validating a return from the kids of $generic_editor.";
"THX (#105941) - Wed May 30, 2001 - Added a loop to clean out the .forgiving property.";
"Profane (#30788) - Thu May 31, 2001 - announce fleeing of duels, reset duelee prop";
.

@verb #258:"exits" this none this rxd #78
@program #258:exits
if ((callers()[1][3] in #46.gms) || (callers()[1][1] == this))
  return this.exits;
else
  return {};
endif
.

@verb #258:"dests" this none this rxd #78
@program #258:dests
if (callers()[1][3] in #46.gms)
  v = {};
  for k in (this:exits())
    z = k;
    while ($object_utils:isa(z, #566))
      z = z.succ_exit;
    endwhile
    if ($object_utils:isa(z, $exit))
      v = listappend(v, z.dest);
    endif
  endfor
  return v;
else
  return {};
endif
.

@verb #258:"exit_ok" this none this
@program #258:exit_ok
"You can teleport from a room your owner owns, from one that's free_exit, or if you're a GM's object.";
rpg = $local.rpg;
{what} = args;
theExit = this:identify_exit(what, 1);
"this:notify_exit(what, theExit);";
if (((this:free_exit(what) || (theExit in this:exits())) || (what.owner == this.owner)) || (what.owner in rpg.gms))
  return 1;
elseif (`parent(theExit) ! E_INVARG' == $generic_editor)
  return 0;
else
  ca = callers();
  index = 0;
  while (ca[index = index + 1][1..2] == {this, "exitfunc"})
  endwhile
  while (ca[index = index + 1][1..2] == {what, "moveto"})
  endwhile
  for res in (ca[index..$])
    if (res[3] in rpg.gms)
      return 1;
    elseif ((!res[3]) in rpg.exporters)
      return 0;
    endif
  endfor
  return 0;
endif
"Profane (#30788) - Fri Jan  2, 1998 - commented out call to notify_exit; since it should be done in exitfunc anyway.";
"THX (#105941) - Thu Oct  7, 1999 - Tweaked this for speed and passed a 1 to this:identify_exit().";
.

@verb #258:"same_time" this none this
@program #258:same_time
(rpg = $local.rpg):secure();
if (this.transparency_support)
  {dungeon, missile_exit, o_u} = {rpg.dungeon, rpg.object_DB.PARENT_missile_exit[1], $object_utils};
  where = setadd(args, this);
  e = this:exits();
  d = this:dests();
  for k in [1..length(e)]
    if (o_u:isa(e[k], missile_exit) && (!(d[k] in where)))
      where = o_u:isa(d[k], dungeon) ? d[k]:same_time(@where) | {@where, d[k]};
    endif
  endfor
  return where;
else
  return {this};
endif
.

@verb #258:"announce_all_but" this none this
@program #258:announce_all_but
{exclude, @announce} = args;
rpg = $local.rpg;
for t in (this.contents)
  if (t in exclude)
  elseif (valid(doll = rpg:get_doll(t)) && doll:cannot_hear())
  else
    try
      t:tell(@announce);
    except (ANY)
      "Ignore listener with bad :tell";
      continue t;
    endtry
  endif
endfor
"New silent entry detection:";
if ((this.unannounced && (i = $list_utils:iassoc(task_id(), this.unannounced))) && index(tostr(@announce), this.unannounced[i][2].name))
  this.unannounced = listdelete(this.unannounced, i);
endif
"Quinn 13-OCT-93 0116: Added .transparency_support check before all that ancestry snooping.  Made one call to ancestors instead of several :isas.  Changes should speed up :announce* calls and make tracebacks less frequent.";
"Profane 5-OCT-97 -- new code for silent entry detection.";
"THX (#105941) - Fri Jun 29, 2001 - Copied the old code to #258:announce_all_but(old) and removed the transparency support (which no-one was using apparently).  Added exclusion of dolled objects that :cannot_hear().  Changed to the actual tells in this verb.  Otherwise we just end up going through .contents all over again.";
"Profane (#30788) - Fri Mar  8, 2002 - tighten up the detection, make them have their name in the message.";
.

@verb #258:"missile_dests" this none this
@program #258:missile_dests
if (!$local.rpg:trusted(caller_perms()))
  return E_PERM;
endif
who = args[1];
where = {this};
e = this:exits();
d = this:dests();
for k in [1..length(e)]
  if (($object_utils:isa(e[k], #16049) || $object_utils:isa(e[k], #16050)) && e[k]:is_missile_channel_for(who))
    where = listappend(where, d[k]);
  endif
endfor
return where;
.

@verb #258:"moveto" this none this
@program #258:moveto
return ($local.rpg:trusted(caller_perms()) || (args[1] == $nothing)) && pass(@args);
.

@verb #258:"block" any any any
@verb #258:"identify_exit" this none this
@program #258:identify_exit
{what, ?loc_if_no_exit = 0} = args;
exits = this:exits();
for entry in (callers()[3..$])
  if (entry[1] in exits)
    return entry[1];
  endif
endfor
return loc_if_no_exit ? what.location | $nothing;
.

@verb #258:"identify_entrance" this none this
@program #258:identify_entrance
entrances = this:entrances();
for entry in (callers()[3..$])
  if (entry[1] in entrances)
    return entry[1];
  endif
endfor
return $nothing;
"Mooshie (#106469) - Fri Jan 18, 2002 - This verb used to return callers()[$][1] - the 'this' of the last call. This really didn't make sense, and :identify_exit returns $nothing uniformly if no exit was used to leave. Changed it to return $nothing.";
.

@verb #258:"entrances" this none this rxd #78
@program #258:entrances
if ((callers()[1][3] in #46.gms) || (callers()[1][1] == this))
  return this.entrances;
else
  return {};
endif
.

@verb #258:"contents" this none this
@program #258:contents
if ((contents = this.contents) && $list_utils:assoc("look_self", callers(), 2))
  pcs = $local.rpg.pcs;
  for t in (contents)
    if (t in pcs)
      this:hide(t) && (contents = setremove(contents, t));
    endif
  endfor
endif
return contents;
.

@verb #258:"old_missile_dests" this none this
@program #258:old_missile_dests
if (!$local.rpg:trust())
  return E_PERM;
endif
who = args[1];
where = {this};
e = this:exits();
d = this:dests();
for k in [1..length(e)]
  if ($object_utils:isa(e[k], #16049) && e[k]:is_missile_channel_for(who))
    where = listappend(where, d[k]);
  endif
endfor
return where;
.

@verb #258:"notify_arrival" this none this
@program #258:notify_arrival
":notify_arrival(OBJ player, OBJ entrance_used)";
{who, entrance} = args;
if (caller == this)
  rpg = $local.rpg;
  if (valid(doll = rpg:get_doll(who)))
    doll.valid_pkp_targets = doll.INvalid_pkp_targets = {};
    for effobj in (doll.move_effects)
      if (`effobj.owner in rpg.gms ! ANY')
        fork (0)
          rpg:trusted_verb(effobj, "enter_effect") && effobj:enter_effect(who, this, entrance);
        endfork
      else
        doll:setremove_att("move_effects", effobj);
      endif
    endfor
  endif
  for object in (this.contents)
    rpg:s_i_f_i_n();
    if (rpg:trusted_verb(object, verb))
      object:(verb)(who, entrance);
    endif
  endfor
endif
return;
"Irin -- Hardcode so that non-creature objects get notified.";
"Passes to the Adventurer's Database (#46), which notifies each object in this location of the given event.";
"Mooshie (#106469) - Fri Jan 18, 2002 - Added move effects support.";
"Mooshie (#106469) - Fri Jan 18, 2002 - Changed this:contents() call to this.contents at the top of the :notify_arrival loop.";
"#46:check_notification(this:contents(), verb, args);";
"Mooshie (#106469) - Fri Jan 18, 2002 - Commented out this call to :check_notification, which duplicates the for-loop above.";
"Hydros (#106189) - Wed Jul 13, 2005 - As the RPG gets bigger, it gets tickier.  Added forks in a couple of spots to avoid tick-outs we've been having.";
"Hydros (#106189) - Tue, Aug 9, 2005 - Changed one of the forks to a suspending call. We were getting odd E_VERBNF tracebacks.";
"Hydros (#106189) - Thu Sep 8, 2005 - Added a clearing of the .[IN]valid_pkp_targets props. Using these props helps to reduce ticks in $local.rpg.death_db.pkp_effect:check_for_pk().";
.

@verb #258:"visible" this none this
@program #258:visible
"A more intelligent handling of `all' and `everything' matching.";
"This version is tailored for the RPG, only returning kids of Adventure Gear (#517).";
objects = pass(@args);
pcs = (rpg = $local.rpg).pcs;
for q in (objects)
  if (q in pcs)
    this:invisible(q) && (objects = setremove(objects, q));
  endif
endfor
if (!(dobjstr in {"all", "everything"}))
  return objects;
endif
q_u = rpg.user_utils.quinn;
thing = rpg.thing;
fvrb = q_u:cutr(callers(), 1)[1][2];
if (fvrb in this.room_all_verbs)
  objects = q_u:class_list(this.contents, thing);
elseif (fvrb in this.player_all_verbs)
  objects = q_u:class_list((args ? args[1] | player).contents, thing);
else
  objects = q_u:class_list(objects, thing);
endif
rpg:s_i_n();
return objects;
.

@verb #258:"@rpg-gripe" any from this
@program #258:@rpg-gripe
$mail_editor:invoke(this.gripe_recipients, "@rpg-gripe", "@gripe: " + tostr(args[1]));
.

@verb #258:"magic_effects" this none this
@program #258:magic_effects
":magic_effects(OBJ caster doll, NUM spell quality, OBJ spell skill, OBJ target doll) => check the room for any mystickal effects that would influence casting.";
"A non-numeric return value will stop the casting cold; a numeric return value will be subtracted from spell quality.";
"Newly hacked to check .magic_effects for a list of extra effects that could be added to a room by gms who don't own the room.";
rpg = $local.rpg;
rpg:secure();
{caster, qual, spell, target} = args;
effect = 0;
for effobj in (this.magic_effects)
  if (rpg:trusted_verb(effobj, "magic_effect"))
    try
      e = effobj:magic_effect(@args);
    except x (ANY)
      this.magic_effects = setremove(this.magic_effects, effobj);
      e = 0;
      dude = $nothing;
      while ((!valid(dude)) && valid(parent(effobj)))
        if (info = `verb_info(effobj, "magic_effect") ! ANY')
          dude = info[1];
        else
          effobj = parent(effobj);
        endif
      endwhile
      $mail_agent:send_message(this, effobj.owner, "Error reported", ($string_utils:from_value(x, 1, 5) + " ") + tostr(effobj));
    endtry
    if (typeof(e) != NUM)
      return e;
    else
      effect = effect + e;
    endif
  else
    this.magic_effects = setremove(this.magic_effects, effobj);
  endif
endfor
"OK, add in the room's own effect:";
try
  e = this:magic_effect(@args);
except x (ANY)
  this.magic_effects = setremove(this.magic_effects, this);
  e = 0;
  dude = $nothing;
  while ((!valid(dude)) && valid(parent(this)))
    if (info = `verb_info(this, "magic_effect") ! ANY')
      dude = info[1];
    else
      this = parent(this);
    endif
  endwhile
  $mail_agent:send_message(this, this.owner, "Error reported", ($string_utils:from_value(x, 1, 5) + " ") + tostr(this));
endtry
if (typeof(e) != NUM)
  return e;
else
  effect = effect + e;
endif
return effect;
"Mooshie (#106469) - Fri Oct 10 01:25:41 1997 PDT - moved typeof(e) check inside of :trusted_verb to avoid E_VARNF tbs.";
.

@verb #258:"set_value" this none this
@program #258:set_value
":set_value(STR property_name, value) -- Sets this.(property_name) to `value'";
{att, val} = args;
(rpg = $local.rpg):secure();
if ((caller_perms() in {this.owner, rpg.owner}) || (att in {"combat_effects", "magic_effects"}))
  return this.(att) = val;
else
  return E_PERM;
endif
"Mooshie (#106469) - Mon Jan 19, 1998 - Re-wrote. Same thing, but faster.";
"Profane (#30788) - Sun Aug 30, 1998 - what was the point of 2 perm checks?";
"THX (#105941) - Thu Jul 15, 1999 - The second check only allows other gamemasters to change magic_effects and combat_effects.";
.

@verb #258:"get_value" this none this
@program #258:get_value
$local.rpg:secure();
{att} = args;
return this.(att);
"Mooshie (#106469) - Mon Jan 19, 1998 - Re-wrote. Same thing, but faster.";
.

@verb #258:"obvious_exits" this none this rx
@program #258:obvious_exits
"Hacked to check for an :obvious verb as well as the standard property.";
exits = {};
for exit in (this:exits())
  if ($code_utils:verb_or_property(exit, "obvious"))
    exits = setadd(exits, exit);
  endif
endfor
return exits;
"Quinn 10-AUG-93 0748: Added.";
.

@verb #258:"exitshock" this none this rx
@program #258:exitshock
":exit_penalty(who) -- Penalise player for unauthorised teleport from an RPG room.";
{who} = args;
(rpg = $local.rpg):secure();
{owner, gms} = {this.owner, rpg.gms};
for what in ({who, @$object_utils:all_contents(who)})
  rpg:s_i_f_i_n();
  if ((valid(doll = rpg:get_doll(what)) && (is_player(what) || what.alive)) && (what.owner != owner))
    aggressors = doll.aggressor;
    "These aggressors may not be in the same room ... e.g., archers.";
    clear_property(doll, "aggressor");
    for t in (this.contents)
      (t in aggressors) || ((valid(tdoll = rpg:get_doll(t)) && (who in tdoll.aggressor)) && (aggressors = {@aggressors, t}));
    endfor
    compound = 1;
    deserted_players = {};
    for t in (setremove(aggressors, who))
      compound = compound + 1;
      if ((is_player(t) && (t in connected_players())) && (!(t in gms)))
        compound = compound + 1;
        deserted_players = {@deserted_players, t};
      endif
    endfor
    rpg:playertell(what, "The inherent implausibility of your exit briefly distorts your consciousness.");
    if (!is_player(what))
      doll:check_ins(10 + random(45 * compound));
    else
      doll:check_ins(10 + random(45 * compound));
      doll.last_attack = doll.last_attack + (4 + compound);
      doll:write_misc_note("teleport lag", doll.last_attack);
      doll:clear_good_spells();
      deserted_players && this:exitslam(doll, deserted_players);
    endif
  endif
endfor
"THX1138 (#105941) - Mon Jun 15, 1998 - Added a splurge to time out beneficial spells if the player exits the LRPG using LambdaMOO teleportation.";
"Hannibal (#104762) - Tue July 24, 2001 - Removed connected check for exitslam.";
.

@verb #258:"free_exit" this none this
@program #258:free_exit
return this.(verb);
.

@verb #258:"bless_exit" this none this
@program #258:bless_exit
":bless_exit(what)";
"Bless exit from this room by the given object, during THIS task.";
"A 'blessed' exit avoids the mental fatigue of other teleportation.";
if ($local.rpg:trusted(caller_perms()))
  this.blessed_exit = {args[1], task_id()};
else
  return E_PERM;
endif
.

@verb #258:"look_self" this none this
@program #258:look_self
"Temporary :look_effects() for showing storms active in the area.";
pass(@args);
rpg = $local.rpg;
if (storms = rpg.magic_db:print_storms(this))
  player:tell_lines(storms);
endif
melee = duels = {};
visible = this:contents();
for t in (this.contents)
  if (valid(doll = rpg:get_doll(t)))
    for r in (doll.view_effects)
      if (look = `r:look_msg(doll) ! E_VERBNF => ""')
        player:tell(look);
      endif
    endfor
    if ((valid(doll.duelee) && (`(ddoll = rpg:get_doll(doll.duelee)).duelee ! E_INVIND' == t)) && (!(t in $list_utils:flatten(duels))))
      if (((doll.last_attack + 300) < time()) || ((`ddoll.last_attack ! E_INVIND => 0' + 300) < time()))
        "Duelist idled out.";
        rpg:tell_damage(t, "Your duel has timed out, and has been rendered null and void.");
        rpg:tell_damage(doll.duelee, "Your duel has timed out, and has been rendered null and void.");
        clear_property(doll, "duelee");
        clear_property(ddoll, "duelee");
      else
        duels = {@duels, {t, doll.duelee}};
      endif
    elseif (doll.aggressor)
      (t in visible) && (melee = {@melee, t:title()});
    endif
  endif
endfor
for pair in (duels)
  player:tell(pair[1]:titlec(), " and ", pair[2]:title(), " are engaged in a duel to the death!");
endfor
(length(melee) > 1) && player:tell($string_utils:english_list(melee), " are engaged in ", {"fierce", "brutal", "vicious", "heated", "savage"}[random($)], " combat.");
"Miles 26-Aug-1995 -- Added.";
.

@verb #258:"make_fertile" this none this
@program #258:make_fertile
":make_fertile() -- Temporarily toggles the 'f' bit, allowing GMs (and not builders in general) to create a child of adventure gear.  To be used as follows:";
";;#equipment:make_fertile();return player:_create(#equipment)";
"Where '#equipment' is the number of the object you're wanting to create.  The blank object returned will be your child.  Congratulations, Mommy.";
if ($local.rpg:trusted(caller_perms()))
  if (!this.f)
    this.f = 1;
    fork (0)
      this.f = 0;
    endfork
  endif
  return this.f;
endif
"Quinn 09-JUL-93 0343: Changed :trust call to :trusted(caller_perms()); Updated comment lines;  eliminated check for ownership in first 'if'.  Let it crash if a kid not owned by GM uses the parent; Now returns status of f-bit.";
.

@verb #258:"_eject" this none this
@program #258:_eject
":_eject -- called from $local.rpg:die to eject loser players who have @refused moves from G_M";
{who} = args;
$local.rpg:secure();
this:bless_exit(who);
this:eject_basic(who);
.

@verb #258:"say" any any any rxd
@program #258:say
doll = (rpg = $local.rpg):get_doll(player);
if (valid(doll) && (p = doll:cannot_talk()))
  return player:tell((typeof(p) == STR) ? p | "You're paralyzed and find it impossible to talk.");
endif
try
  if (is_player(player) || `player.yeller ! ANY => 0')
    player:tell("You say, \"", argstr, "\"");
    this:announce_all_but({player}, player.name, " ", $gender_utils:get_conj("says", player), ", \"", argstr, "\"");
  else
    player:tell("You say: \"", argstr, "\"");
    rpg:rpg_announce_all_but(this, {player}, player.name, " ", $gender_utils:get_conj("says", player), ", \"", argstr, "\"");
  endif
except (ANY)
  "Don't really need to do anything but ignore the idiot who has a bad :tell";
endtry
.

@verb #258:"match_exit" this none this rx
@program #258:match_exit
rpg = $local.rpg;
if (valid(p = pass(@args)))
  if ((caller == this) || (caller in rpg.object_db.walking_features))
    if (this:sleeping(player))
      rpg:playertell(player, "In your dreams, you yearn to travel.");
      kill_task(task_id());
    elseif (this:resting(player))
      this:stand(player);
    endif
  endif
  c = callers();
  while (c[1][1..2] == {this, verb})
    c = c[2..$];
  endwhile
  "i.e. strip out any child versions of this verb";
  if (((c[1][1] == this) && rpg:trusted(c[1][3])) && (m = (doll = rpg:get_doll(player)):cannot_walk()))
    "i.e. ONLY do the paralysis crap if match_exit is called by a trusted verb... let non-trusted verbs match_exits, because match_exit can be called non-VR, e.g. by FO's";
    "Thus we prevent people from getting stamina checks via the overloaded combat effect by calling @rose, for example.";
    (length(callers()) < 7) && rpg:playertell(player, (typeof(m) == STR) ? m | "You're paralyzed.  You aren't going to be doing much moving around.");
    return $failed_match;
  elseif (p in rpg.object_db.bad_exits)
    return $failed_match;
  endif
endif
return p;
"Profane (#30788) - Mon Mar  5, 2001 - change security bits.";
"THX (#105941) - Tue Apr  3, 2001 - Upgraded to do sleeping-refusal and auto-standing here rather than in #49444:east.  Cleaned up quite a bit.";
.

@verb #258:"initialize" this none this
@program #258:initialize
owner = (rpg = $local.rpg).owner;
if ((!(this.owner in rpg.gms)) && (!(parent(this) in rpg.object_DB.OBJ_player_ownable_room)))
  callers = callers();
  fork (0)
    msg = {$string_utils:nn(player), toliteral(callers), ((($string_utils:nn(this) + " ") + $string_utils:nn(parent(this))) + " ") + ctime()};
    $mail_agent:send_message(owner, {owner}, "Player has created child of #258", msg);
  endfork
endif
return pass(@args);
.

@verb #258:"sleep doze nap snooze rest sit crash slump collapse yawn snore search wake stand rise pray chant" none none none
@program #258:sleep
"A catch all verb that help the rpg room look smarter by not saying \"I don't understand that.\" all the time.";
if (!((caller in {player, this, this.location}) && (player.location == this)))
  return E_PERM;
endif
if (verb in {"sleep", "doze", "nap", "snooze", "rest", "sit", "crash", "slump", "collapse"})
  player:tell("You can't seem to get comfortable here.");
elseif (verb == "yawn")
  player:tell("You yawn.");
elseif (verb in {"snore", "wake"})
  player:tell("You aren't sleeping here.");
elseif (verb in {"stand", "rise"})
  player:tell("You aren't resting here.");
elseif (verb == "search")
  player:tell("You make a quick search of the room and find nothing hidden.");
else
  player:tell("This isn't a good place to ", verb, ".");
endif
.

@verb #258:"all_contents" this none this
@program #258:all_contents
"Copied from object utilities (#3669):all_contents by Hacker (#18105) Wed Jul  2 06:37:05 1997 PDT";
"all_contents(object)";
"Return a list of all objects contained (at some level) by object.";
for y in (res = args[1].contents)
  y.contents && (res = {@res, @this:all_contents(y)});
endfor
return res;
.

@verb #258:"read_misc_note" this none this
@program #258:read_misc_note
":read_misc_note(name)";
"Much as the same verb on the voodoo doll. In fact, the same verb.";
"View a miscellaneous note on the voodoo doll.";
$local.rpg:secure();
{index} = args;
for elm in (this.misc_notes)
  {elm1, elm2} = elm;
  if (elm1 == index)
    return elm2;
  endif
endfor
return E_PROPNF;
.

@verb #258:"write_misc_note" this none this
@program #258:write_misc_note
":write_misc_note(name, value)";
"As per the vebr on #74";
if (!$local.rpg:trusted(caller_perms()))
  return E_PERM;
elseif (length(args) != 2)
  return E_ARGS;
endif
notes = this.misc_notes;
index = args[1];
for i in [1..length(notes)]
  if (notes[i][1] == index)
    this.misc_notes[i][2] = args[2];
    return i;
  endif
endfor
this.misc_notes = listappend(notes, args);
return length(notes) + 1;
.

@verb #258:"erase_misc_note" this none this
@program #258:erase_misc_note
":erase_misc_note(name)";
"Remove a miscellaneous note from the room.";
if (!$local.rpg:trusted(caller_perms()))
  return E_PERM;
endif
notes = this.misc_notes;
index = args[1];
for i in [1..length(notes)]
  if (notes[i][1] == index)
    this.misc_notes = listdelete(notes, i);
    size = length(notes) - 1;
    if (size == 0)
      clear_property(this, "misc_notes");
    endif
    return size;
  endif
endfor
return E_PROPNF;
.

@verb #258:"combat_effects" this none this
@program #258:combat_effects
":combat_effect(DOLL by, DOLL target, OBJ weapon) => check the room for any wierd effects which would impede/assist the attacker.";
"A non-numeric return value will stop the swing cold; a numeric return value will be subtracted from attack quality.";
"Newly hacked to check .combat_effects for a list of extra effects that could be added to a room by gms who don't own the room.";
rpg = $local.rpg;
rpg:secure();
{by, target, weapon} = args;
effect = 0;
for effobj in (this.combat_effects)
  if (rpg:trusted_verb(effobj, "combat_effect"))
    try
      e = effobj:combat_effect(@args);
    except x (ANY)
      this.combat_effects = setremove(this.combat_effects, effobj);
      e = 0;
      dude = $nothing;
      while ((!valid(dude)) && valid(parent(effobj)))
        if (info = `verb_info(effobj, "combat_effect") ! ANY')
          dude = info[1];
        else
          effobj = parent(effobj);
        endif
      endwhile
      $mail_agent:send_message(this, effobj.owner, "Error reported", ($string_utils:from_value(x, 1, 5) + " ") + tostr(effobj));
    endtry
  else
    this.combat_effects = setremove(this.combat_effects, effobj);
  endif
  if (typeof(e) != NUM)
    return e;
  else
    effect = effect + e;
  endif
endfor
"OK, add in the room's own effect:";
try
  e = this:combat_effect(@args);
except x (ANY)
  this.combat_effects = setremove(this.combat_effects, this);
  e = 0;
  dude = $nothing;
  while ((!valid(dude)) && valid(parent(this)))
    if (info = `verb_info(this, "combat_effect") ! ANY')
      dude = info[1];
    else
      this = parent(this);
    endif
  endwhile
  $mail_agent:send_message(this, this.owner, "Error reported", ($string_utils:from_value(x, 1, 5) + " ") + tostr(this));
endtry
if (typeof(e) != NUM)
  return e;
else
  effect = effect + e;
endif
return effect;
.

@verb #258:"bless_for_teleport" this none this
@program #258:bless_for_teleport
"Usage: bless_for_teleport(OBJ thing)";
"Sets this room to allow the same task to teleport an object in.";
if (!$local.rpg:trusted(caller_perms()))
  return E_PERM;
endif
{what} = args;
this.teleport_object = what;
this.teleport_task = task_id();
"Mooshie (#106469) - Sun Oct 12 00:06:40 1997 PDT - Added.";
.

@verb #258:"notify_exit" this none this
@program #258:notify_exit
"Passes to the Adventurer's Database (#46), which notifies each object in this location of the given event.";
":notify_exit(OBJ player, OBJ exit_used)";
{who, exit} = args;
if (caller == this)
  gms = (rpg = $local.rpg).gms;
  if (valid(doll = rpg:get_doll(who)))
    for effobj in (doll.move_effects)
      if (`effobj.owner in gms ! ANY')
        fork (0)
          rpg:trusted_verb(effobj, "exit_effect") && effobj:exit_effect(who, this, exit);
        endfork
      else
        doll:setremove_att("move_effects", effobj);
      endif
    endfor
  endif
  for object in (this.contents)
    if (valid(doll = rpg:get_doll(object)) && doll.aggressor)
      doll.aggressor = setremove(doll.aggressor, who);
      doll.valid_pkp_targets = setremove(doll.valid_pkp_targets, who);
      doll.INvalid_pkp_targets = setremove(doll.INvalid_pkp_targets, who);
    endif
    if (rpg:trusted_verb(object, verb))
      fork (0)
        object:(verb)(who, exit);
      endfork
    endif
  endfor
endif
return;
"Profane (#30788) - Sat Dec  5, 1998 - error trap the calls.";
"Mooshie (#106469) - Fri Jan 18, 2002 - Added move effects support.";
"Hydros (#106189) - Wed Jul 13, 2005 - As the RPG gets bigger, it gets tickier.  Added forks in a couple of spots to avoid tick-outs we've been having.";
"Hydros (#106189) - Tue Oct 4, 2005 - Added clearing of .[IN]valid_pkp_targets props to aid the new PKProtection system.";
.

@verb #258:"att*ack hit ki*ll" any none none rxd
@program #258:attack
"attack <target>";
"attack <target>'s <bodypart>";
rpg = $local.rpg;
if ((((!valid(cp = caller_perms())) || rpg:trusted(cp)) || ((caller == this) || (caller in rpg.vacuum.monsters))) || (!is_player(player)))
  if (parsed = $match_utils:parse_possessive_reference(dobjstr))
    {dobjstr, where} = parsed;
  else
    where = "";
  endif
  if (valid(doll = rpg:get_doll(player)))
    for t in (doll.aggressor)
      (t.location == this) || (doll.aggressor = setremove(doll.aggressor, t));
    endfor
    if (dobjstr)
      "... do nothing ... ";
    elseif (agg = doll.aggressor)
      dobjstr = tostr(agg[random($)]);
    else
      rpg:playertell(player, "Who (or what) are you trying to hit?");
      return;
    endif
    if (w = doll:wielding())
      {first, @weaps} = w;
      return first:hit(dobjstr, "with", tostr(first), weaps, where);
    else
      rpg:playertell(player, "You are unarmed.");
      return E_INVIND;
    endif
  else
    rpg:playertell(player, "Your feeble attacks have no effect upon ", dobj.name, ". Perhaps you should consider being trained with the Bovine Illuminati.");
    return E_INVARG;
  endif
else
  return E_PERM;
endif
.

@verb #258:"he*al sl*ow re*call li*felink unl*ink mindp*robe de*press st*ealskill pa*cify unw*all fo*rcewall bar*kskin di*spel har*den hai*l ices*hell waterw*hip conj*ure sum*mon sto*rm sti*nkcloud pr*edict heat charm*foe hold*foe raven*fear bi*ting_cloud haste acidr*ain appr*aise poi*son tang*le gly*ph ca*lm minds*hock sha*tter mag*icfist rune reverse*missiles det*ect windw*all ench*ant rot fireb*olt viper*_bite unviper backf*ire unbar*k unbac*kfire petals wound drain compost triage beguile mergestorm stoneflesh blade*barrier unblade*barrier daggers*torm parch chill unreverse resurrect dirge fort*ify haw*thorn anim*ate" any any any rxd
@program #258:heal
"Copied from Generic Dungeon Room (#258):firebolt [verb author Grand_Master (#2693)] at Mon Sep 12 17:39:10 2005 PDT";
rpg = $local.rpg;
mdb = rpg.magic_db;
if (callers() && ((caller != this) && (!(caller in rpg.vacuum.monsters))))
  rpg:secure();
endif
"fiddle with the arguments given so they'll match.";
test = $string_utils:parse_command((verb + " ") + argstr);
true_dobjstr = dobjstr;
if (!prepstr)
  test[6][2] = {@test[6][2], "with/using", "out of/from inside/from"};
endif
"First, see short-circuit if the player is trying to call the exact verb on the exact object specified:";
if ((((dobj != this) && valid(dobj)) && $match_utils:match_verb(verb, dobj, args)) || (valid(iobj) && $match_utils:match_verb(verb, iobj, args)))
  "such was the case, so we can stop now.";
  return;
endif
"If a preposition isn't given, we just let the verb match `from' and `with' the prepositions used for casting from the focus directly.";
"Iobj is always the focus, which we set down below.";
"Dobj takes some more fiddling, and depends on the focus being used, so we fiddle it below.";
"determine the full name of the verb we want:";
spells = verb_info(rpg.dungeon, verb)[3];
spells = " " + $string_utils:strip_chars(spells, "*");
match = match(spells, ("%<%(" + verb) + "%(%w%|_%)*%)%>");
try
  spell = substitute("%1", match);
except (E_INVARG)
  "No match at all.";
  player:tell("The spellcasting shortcut verb can't seem to figure out which spell \"", verb, "\" refers to.");
  return;
endtry
"Now find what objects it's on.";
doll = rpg:get_doll(player);
stuff = valid(iobj) ? {iobj} | {};
"if the player gave an iobj (which will be a focus), we check that one first";
stuff = {@stuff, @`doll:wielding() ! ANY => {}', @`doll:wearing() ! ANY => {}'};
"then we check held/worn stuff.";
"Now we see which of these things is a focus for the requested spell.";
candidates = {};
wrong_prep = {};
for thingy in (stuff)
  if (verbloc = $object_utils:has_callable_verb(thingy, spell))
    if (verb_args(verbloc[1], spell)[2] in test[6][2])
      candidates = setadd(candidates, thingy);
    else
      "This bit is in case of failure, so we can explain syntax.";
      wrong_prep = setadd(wrong_prep, thingy);
    endif
  endif
endfor
"now try and call the spell verb";
for focus in (candidates)
  "$match_utils:match_verb needs iobjstr and prepstr set for it to work, so we set them here, per which focus we are trying.";
  iobjstr = tostr(iobj = focus);
  focus_args = verb_args($object_utils:has_callable_verb(focus, spell)[1], spell);
  prepstr = $code_utils:short_prep(focus_args[2]);
  "Fiddling with dobj is necessary for $match_utils:match_verb to call verbs with a `none' dobj argument.";
  if (!true_dobjstr)
    "Player did not specify a dobj, so we make some assumptions.";
    if (focus_args[1] != "none")
      if (spell in {@mdb.peaceful_spells, @mdb.self_default_spells})
        "assume player as target for peaceful spells.";
        dobjstr = tostr(dobj = player);
      elseif (doll.aggressor)
        "Hostile spell, pick a random aggressor";
        dobjstr = tostr(dobj = doll.aggressor[random($)]);
      else
        "Casting hostile spell with no aggressor. dork.";
        dobjstr = "";
        dobj = $nothing;
      endif
    else
      "The player did not give us a dobj, but we might have set it in trying to match a verb without a `none' dobj argument, so unset it here.";
      dobjstr = "";
      dobj = $nothing;
    endif
  elseif ((dobj == focus) && (focus_args[1] == "none"))
    dobjstr = "";
    dobj = $nothing;
  endif
  if ($match_utils:match_verb(spell, focus, {}))
    "bingo, a match";
    return;
  endif
endfor
"Ok, now try to explain the problem:";
if (wrong_prep)
  $command_utils:explain_syntax(wrong_prep[1], verb, args);
else
  player:tell("You try to cast ", `rpg:match_skill(spell):title() ! E_INVIND => verb', ", but realize you lack the proper focus.");
endif
.

@verb #258:"emote" any any any rxd
@program #258:emote
doll = (rpg = $local.rpg):get_doll(player);
if (valid(doll) && (p = doll:cannot_emote()))
  return player:tell((typeof(p) == STR) ? p | "You're paralyzed and find it impossible to emote anything.");
endif
argstr = (argstr && (argstr[1] == ":")) ? argstr[2..$] | (" " + argstr);
if (is_player(player))
  " this:show_all_but({`this:sleeping() ! E_VERBNF'}, player.name, argstr)";
  this:show_all_but(`this:sleeping() ! E_VERBNF', player.name, argstr);
else
  player:tell("You emote: ", player.name, argstr);
  rpg:rpg_show_all_but(this, {player, @`this:sleeping() ! E_VERBNF => {}'}, player.name, argstr);
endif
.

@verb #258:"exitclean" this none this
@program #258:exitclean
(rpg = $local.rpg):secure();
{doll} = args;
n = 0;
for t in (sch = doll.schedule)
  {what, effect, time, various} = t;
  n = n + 1;
  if (effect in {"unwind", "unwall", "unbark", "unstone"})
    doll.schedule[n][3] = time();
  elseif (effect == "unspeed")
    if (various[1] > doll.slowness)
      "They're hasted...";
      doll.schedule[n][3] = time();
    endif
  endif
endfor
.

@verb #258:"notify_player" this none this rxd #58142
@program #258:notify_player
if (caller == $local.rpg)
  {who, msg} = args;
  (who.location == this) && notify(who, msg);
else
  return E_PERM;
endif
.

@verb #258:"detect_magic_msg" this none this
@program #258:detect_magic_msg
"Returns messages displayed when a player successfully casts detect in this room.";
{bydoll, qual} = args;
(rpg = $local.rpg):secure();
msg = {};
for d in (setremove(this.magic_effects, this))
  if ($object_utils:has_callable_verb(d, "detect_magic_msg"))
    msg = {@msg, @(typeof(f = d:detect_magic_msg(bydoll, qual)) == LIST) ? f | {f}};
  endif
endfor
if (oset = (typeof(temp = this:read_misc_note("g&r")) == LIST) ? temp | {})
  "revise the list, take out expired glyphs&runes etc.";
  grset = $list_utils:build_alist(oset, 3);
  for d in (grset)
    if (time() > d[3])
      grset = setremove(grset, d);
    endif
  endfor
  if (!grset)
    rpg.magic_db.gr_combat_effect:remove_effect(this);
    return msg;
  endif
  if ((length(grset) * 3) != length(oset))
    this:write_misc_note("g&r", $list_utils:flatten(grset));
  endif
  gset = rset = {};
  for d in (grset)
    if (d[2] < 0)
      gset = {@gset, d};
    else
      rset = {@rset, d};
    endif
  endfor
  if (qual > 100)
    "say what they are, their strength, when they expire.";
    msg = {@msg, "Your powerfully enhanced vision reveals much about the glowing magical energies upon the ground:"};
    for d in (grset)
      f = abs(d[2]);
      if (f > 50)
        stren = "A pulsing and brightly throbbing ";
      elseif (f > 25)
        stren = "A solidly glowing ";
      else
        stren = "A flickering ";
      endif
      msg = {@msg, tostr(stren, d[1].name, (d[2] < 0) ? " glyph " | " rune ", "will expire in ", $time_utils:english_time(d[3] - time()), ".")};
    endfor
    return msg;
  elseif (qual > 75)
    "say what the glyphs and runes are, and a qualifier indicating their strength";
    nmsg = "Your enhanced vision reveals";
    for d in (grset)
      f = abs(d[2]);
      if (f > 50)
        stren = "a pulsing and brightly throbbing ";
      elseif (f > 25)
        stren = "a solidly glowing ";
      else
        stren = "a flickering ";
      endif
      nmsg = nmsg + tostr(((d == grset[$]) && (length(grset) > 1)) ? " and " | " ", stren, d[1].name, (d[2] < 0) ? " glyph," | " rune,");
    endfor
    nmsg[$] = " ";
    return {@msg, nmsg + "etched into the ground here."};
  elseif (qual > 50)
    "say what the glyphs and runes are";
    nmsg = "Your enhanced vision reveals";
    for d in (grset)
      nmsg = nmsg + tostr(((d == grset[$]) && (length(grset) > 1)) ? " and " | " ", $string_utils:a_or_an(d[1].name), " ", d[1].name, (d[2] < 0) ? " glyph," | " rune,");
    endfor
    nmsg[$] = " ";
    return {@msg, nmsg + "etched into the ground here."};
  elseif (qual > 25)
    "say #glyphs and #runes";
    return {@msg, tostr("Your enhanced vision reveals ", gset ? tostr($string_utils:english_number(length(gset)), " glyph", (length(gset) > 1) ? "s " | " ") | "", (gset && rset) ? "and " | "", rset ? tostr($string_utils:english_number(length(rset)), " rune", (length(gset) > 1) ? "s " | " ") | "", "etched into the ground here.")};
  else
    "just say total # glyphs&runes";
    return {@msg, tostr("Your enhanced vision reveals ", (length(grset) > 1) ? $string_utils:english_number(length(grset)) + " glyphs and/or runes" | "a glyph or rune", " etched into the ground here.")};
  endif
else
  return msg;
endif
"Dred 2-12-99: Created new spell result.";
"Copied from Perceiving the Powers of Magic (#476):detect_magic_msg(room) by Dred (#49925) Tue Feb 16 06:13:51 1999 PST";
.

@verb #258:"hide" this none this
@program #258:hide
{what} = args;
if (valid(doll = $local.rpg:get_doll(what)))
  for t in (doll.view_effects)
    if (`t:hide_from_tell_contents(what) ! E_VERBNF')
      return 1;
    endif
  endfor
endif
return 0;
.

@verb #258:"disfunc" this none this rd
@program #258:disfunc
if ((((cp = caller_perms()) == player) || $perm_utils:controls(cp, player)) || (caller == this))
  if (((player in $local.rpg.pcs) && (player == player.owner)) && (!(player in $local.rpg.gms)))
    this:announce_all_but({player}, $string_utils:pronoun_sub("%N %<has> disconnected.", player));
  else
    pass(@args);
  endif
endif
.

@verb #258:"identify_exit(old)" this none this
@program #258:identify_exit(old)
lenc = length(ca = callers());
for entry in (ca[3..lenc])
  if (entry[1] in this:exits())
    return entry[1];
  endif
endfor
return $nothing;
return args[1].location;
.

@verb #258:"say(old)" any any any rxd
@program #258:say(old)
doll = $local.rpg:get_doll(player);
if (valid(doll) && (p = doll:cannot_talk()))
  return player:tell((typeof(p) == STR) ? p | "You're paralyzed and find it impossible to talk.");
endif
try
  is_player(player) && player:tell("You say, \"", argstr, "\"");
  this:announce_all_but({player}, player.name, " ", $gender_utils:get_conj("says", player), ", \"", argstr, "\"");
except (ANY)
  "Don't really need to do anything but ignore the idiot who has a bad :tell";
endtry
.

@verb #258:"emote(old)" any any any rxd
@program #258:emote(old)
doll = (rpg = $local.rpg):get_doll(player);
if (valid(doll) && (p = doll:cannot_emote()))
  return player:tell((typeof(p) == STR) ? p | "You're paralyzed and find it impossible to emote anything.");
endif
argstr = (argstr && (argstr[1] == ":")) ? argstr[2..$] | (" " + argstr);
if (is_player(player))
  this:announce_all_but({}, player.name, argstr);
else
  player:tell("You emote: ", player.name, argstr);
  rpg:rpg_announce_all_but(this, {player}, player.name, argstr);
endif
.

@verb #258:"exitshock(old)" this none this rx
@program #258:exitshock(old)
":exit_penalty(who) -- Penalise player for unauthorised teleport from an RPG room.";
{who} = args;
(rpg = $local.rpg):secure();
owner = this.owner;
for what in ({who, @$object_utils:all_contents(who)})
  rpg:time_stop(1);
  if ((valid(doll = rpg:get_doll(what)) && (is_player(what) || what.alive)) && (what.owner != owner))
    aggressors = doll.aggressor;
    for t in (this.contents)
      (t in aggressors) || ((valid(tdoll = rpg:get_doll(t)) && (who in tdoll.aggressor)) && (aggressors = {@aggressors, t}));
    endfor
    compound = 1;
    for t in (aggressors)
      compound = (compound + 1) + is_player(t);
    endfor
    rpg:playertell(what, "The inherent implausibility of your exit briefly distorts your consciousness.");
    if ((connected = what in connected_players()) || (!is_player(what)))
      doll:check_ins(10 + random(45 * compound));
    endif
    if (connected)
      doll.last_attack = (doll.last_attack + 4) + compound;
      doll:clear_good_spells();
    endif
    clear_property(doll, "aggressor");
  endif
endfor
"THX1138 (#105941) - Mon Jun 15, 1998 - Added a splurge to time out beneficial spells if the player exits the LRPG using LambdaMOO teleportation.";
.

@verb #258:"exitslam" this none this
@program #258:exitslam
{doll, mob} = args;
if (`this.arena ! E_PROPNF => 0')
  "Combat Arena: fight is not to-the-death so don't penalize.";
elseif (caller == this)
  rpg = $local.rpg;
  vowed = rpg.user_utils.ogwul:vowed(doll);
  if (((note = doll:read_misc_note("first_blood")) != E_PROPNF) || vowed)
    {char, puzzles, result} = {doll.character, rpg.puzzle_log, 0};
    if (note)
      for t in (note)
        {who, time} = t;
        if ((who in mob) && (time > time()))
          puzzles:add_solved(char, verb);
          result = result + 1;
        endif
      endfor
    else
      puzzles:add_solved(char, verb);
      result = result + 1;
    endif
    if (result || vowed)
      {object_db, losses, su} = {rpg.object_db, {}, $string_utils};
      hits = severity = puzzles:has_solved(char, verb);
      rpg.object_db.exitslam_effect:add(doll);
      doll:write_misc_note("exitslam", time() + (99 * severity));
      contents = $object_utils:all_contents(char);
      severity = min(severity, length(contents));
      for t in (contents)
        rpg:s_i_f_i_n();
        if (((length(losses) < severity) && object_db:is_thing(t)) && (!t:keep_at_death(char)))
          losses = {@losses, t.name};
          t:moveto(this);
        endif
      endfor
      rpg:rpg_announce_all_but(this, {char}, "In ", char.pp, " haste to leave, ", char.name, " teleports out without using LambdaRPG methods and leaves behind ", char.pp, " ", eng_list = su:english_list(losses), "!");
      rpg:playertell(char, "In your haste to get away from ", su:english_list($list_utils:map_prop(mob, "name")), ", you become distracted while using teleportation techniques that aren't LambdaRPG methods and lose control of your ", eng_list, "!");
      rpg:rpg_announce_all_but(this, {char}, char.name, "'s equipment clatters to the ground.");
      fork (0)
        $mail_agent:send_message(rpg.owner, rpg.object_db.confess, (su:nn(this) + ":") + verb, {((((su:nn(char) + " lost a ") + eng_list) + " whilst escaping from ") + su:nn(mob)) + " after initiating the combat (or having vowed to escape using only themely means).", ("This player has been affected " + tostr(hits)) + " times to date."});
      endfork
    endif
  endif
endif
.

@verb #258:"sc*ore health ht co*ndition" this none this
@program #258:score
"THX (#105941) - Thu Mar 16, 2000 - Interrupts the 'sc' on the Bovine FO to check sleeping players.";
(rpg = $local.rpg):secure();
if (!dobjstr)
  dobj = player;
elseif (valid(dobj))
  "gotcha";
else
  dobj = player:my_match_object(dobjstr);
endif
dobj = toobj(dobj);
if (valid(doll = rpg:get_doll(dobj)))
  for t in ({"inj", "ins", "fat"})
    (doll.(t) < 0) && (doll.(t) = 0);
  endfor
endif
if (player in rpg.gms)
elseif (`player.location:sleeping(player) ! ANY => 0')
  return player:tell(rpg.user_utils.thx1138:sleeping_score(dobj));
endif
rpg.gm_feature.gm_utils:score(dobj);
"THX (#105941) - Mon Dec 18, 2000 - Put an ugly bloody hack in to catch negative injury, fatigue, or sanity scores before continuing.";
.

@verb #258:"hidden_verbs" this none this
@program #258:hidden_verbs
{who} = args;
prev = pass(who);
generic = (rpg = $local.rpg).dungeon;
if (!rpg:trusted(who))
  prev = {@prev, {generic, verb_info(generic, "sleep")[3], {"none", "none", "none"}}};
  prev = {@prev, {generic, verb_info(generic, "heal")[3], {"any", "any", "any"}}};
endif
return prev;
.

@verb #258:"setadd_exit setremove_exit" this none this
@program #258:setadd_exit
":setadd[remove]_exit(OBJ exit)  --  Adds/removes and exit to/from an RPG room _if_ the exit is in the room's .allowed_exits property.";
"If (room == exit.dest) then the exit is added/removed from room.entrances.  If (room == exit.source) then the exit is added/removed from room.exits.";
{exit} = args;
(rpg = $local.rpg):secure();
if (`exit.source ! ANY => $nothing' == this)
  slot = "exits";
elseif (`exit.dest ! ANY => $nothing' == this)
  slot = "entrances";
else
  raise(E_INVARG);
endif
if ((this.owner in rpg.gms) && (exit in this.allowed_exits))
  this.(slot) = index(verb, "add") ? setadd(this.(slot), exit) | setremove(this.(slot), exit);
else
  raise(E_PERM);
endif
"THX (#105941) - Thu Mar 23, 2000 - Added.";
.

@verb #258:"invisible" this none this
@program #258:invisible
{what} = args;
if (valid(doll = $local.rpg:get_doll(what)))
  for t in (doll.view_effects)
    if (`t:hide_from_visible(what) ! E_VERBNF')
      return 1;
    endif
  endfor
endif
return 0;
.

@verb #258:"match_exit(old)" this none this rx
@program #258:match_exit(old)
rpg = $local.rpg;
c = callers();
while (c[1][1..2] == {this, verb})
  c = c[2..$];
endwhile
"i.e. strip out any child versions of this verb";
"if (caller == this || caller_perms() in rpg.gms)";
if (valid(p = pass(@args)))
  if (((c[1][1] == this) && rpg:trusted(c[1][3])) && (m = (doll = rpg:get_doll(player)):cannot_walk()))
    "i.e. ONLY do the paralysis crap if match_exit is called by a trusted verb... let non-trusted verbs match_exits, because match_exit can be called non-VR, e.g. by FO's";
    "Thus we prevent people from getting stamina checks via the overloaded combat effect by calling @rose, for example.";
    (length(callers()) < 7) && player:tell((typeof(m) == STR) ? m | "You're paralyzed.  You aren't going to be doing much moving around.");
    return $failed_match;
  elseif (p in rpg.object_db.bad_exits)
    return $failed_match;
  else
    return p;
  endif
else
  return p;
endif
"else";
"  return $failed_match;";
"endif";
"Profane (#30788) - Mon Mar  5, 2001 - change security bits.";
.

@verb #258:"_eject(old)" this none this
@program #258:_eject(old)
":_eject -- called from #46:die to eject loser players who have @refused moves from G_M";
if ($local.rpg:trusted(caller_perms()))
  this:eject_basic(args[1]);
endif
.

@verb #258:"duel" any any any
@program #258:duel
rpg = $local.rpg;
if (player.location != this)
  rpg:playertell(player, "No remote dueling, sorry.");
elseif (!valid(doll = rpg:get_doll(player)))
  rpg:playertell(player, "Duel how?  You need to get illuminated first.  Try #88.");
elseif ($command_utils:object_match_failed(target = this:match(argstr), argstr))
elseif (target == player)
  rpg:playertell(player, "... Try the termination centre.");
elseif (!is_player(target))
  rpg:playertell(player, "You can only duel other players.");
elseif (player.owner != player)
  rpg:playertell(player, "Duelling as a guest?  What a pansy; get a real character first!");
elseif (target.owner != target)
  rpg:playertell(player, "Dueling guests?  What fun is that?  Forget it.");
elseif (!valid(tdoll = rpg:get_doll(target)))
  rpg:playertell(player, target.name, " does not seem to be enlightened; therefore you cannot duel ", target.po, ".");
elseif (player.location != target.location)
  rpg:playertell(player, "You're not in the same place as ", target.name, ".");
elseif (valid(doll.duelee))
  if (doll.duelee == target)
    if (tdoll.duelee == player)
      rpg:playertell(player, "Um, you and ", target.name, " are already dueling.");
    else
      rpg:playertell(player, "You have already challenged ", target.name, " to a duel to the death.");
    endif
  else
    if (`rpg:get_doll(doll.duelee).duelee ! E_INVIND' == player)
      rpg:playertell(player, "You're currently dueling ", doll.duelee.name, "; one duel at a time.");
    else
      rpg:playertell(player, "You've just challenged ", doll.duelee.name, " to a duel, finish that one first.");
    endif
  endif
elseif ((valid(who = tdoll.duelee) && valid(`rpg:get_doll(tdoll.duelee).duelee ! E_INVIND => $nothing')) && (who != player))
  rpg:playertell(player, target.name, " is currently engaged in a duel with ", who.name, "; wait until they've finished.");
elseif (setremove(tdoll.aggressor, player))
  rpg:playertell(player, target.name, " seems occupied with another combat at the moment.  Maybe try again later, or ask them to break off all combat.");
elseif (teammates = rpg.user_utils.quinn:class_list(doll.armour_effects, rpg.doll))
  rpg:playertell(player, "You'll have to unteam with ", $string_utils:english_list($list_utils:map_prop($list_utils:map_prop(teammates, "character"), "name")), " before you can engage in a duel.");
elseif (teammates = rpg.user_utils.quinn:class_list(tdoll.armour_effects, rpg.doll))
  rpg:playertell(player, target.name, " will have to unteam with ", $string_utils:english_list($list_utils:map_prop($list_utils:map_prop(teammates, "character"), "name")), " before you can engage ", target.po, " in a duel.");
elseif (tdoll.duelee == player)
  "Accepting duel.";
  doll.duelee = target;
  rpg:tell_damage(player, "You accept ", target.name, "'s duel to the death! FIGHT!");
  rpg:tell_damage(target, player.name, " accepts your duel to the death! FIGHT!");
  rpg.owner.duelers = {@rpg.owner.duelers, {player, target, time()}};
  doll.last_attack = time();
  tdoll.last_attack = time();
else
  "Initiating";
  doll.duelee = target;
  rpg:tell_damage(player, "You have challenged ", target.name, " to a duel to the death!");
  rpg:tell_damage(target, player.name, " has challenged you to a duel to the death! Type `duel ", player.name, "' to accept or `decline ", player.name, "' to refuse.");
endif
"Hydros (#106189) - Tue Nov 1, 2005 - Added check for target's location matching that of player.";
.

@verb #258:"decline" any any any
@program #258:decline
rpg = $local.rpg;
"decline <player> => declines a duel to the death that player has challenged you to.";
if (player.location != this)
  rpg:playertell(player, "No remote dueling (or un-dueling), sorry.");
elseif (!valid(doll = rpg:get_doll(player)))
  rpg:playertell(player, "Um dude, no one could duel you even if they wanted, stop being so paranoid.");
elseif ($command_utils:object_match_failed(target = this:match(argstr), argstr))
elseif (!valid(tdoll = rpg:get_doll(target)))
  rpg:playertell(player, "Um, ", target.name, " couldn't duel you even if ", `target.ps ! ANY => "it"', " wanted to; stop being so paranoid.");
elseif ((doll.duelee == target) && (tdoll.duelee == player))
  rpg:playertell(player, "Hey, you already accepted the duel. No declining now.");
elseif (tdoll.duelee != player)
  rpg:playertell(player, target.name, " has not offered to duel you, so you're safe.");
else
  tdoll.duelee = $nothing;
  rpg:tell_damage(player, "You decline ", target.name, "'s duel to the death.");
  rpg:tell_damage(target, player.name, " has declined your offer to duel to the death.");
endif
.

@verb #258:"announce_all_but(old)" this none this
@program #258:announce_all_but(old)
rpg = $local.rpg;
if (this.transparency_support && (((rpg.thing in (anc = rpg:parents(caller))) || (rpg.doll in anc)) || (rpg.monster in anc)))
  for k in (this:same_time())
    k:(verb)(@args);
  endfor
else
  pass(@args);
endif
"New silent entry detection:";
if (i = $list_utils:iassoc(task_id(), this.unannounced))
  this.unannounced = listdelete(this.unannounced, i);
endif
"Quinn 13-OCT-93 0116: Added .transparency_support check before all that ancestry snooping.  Made one call to ancestors instead of several :isas.  Changes should speed up :announce* calls and make tracebacks less frequent.";
"Profane 5-OCT-97 -- new code for silent entry detection.";
.

@verb #258:"announce_all" this none this
@program #258:announce_all
this:announce_all_but({}, @args);
"THX (#105941) - Fri Jun 29, 2001 - Added.";
.

@verb #258:"announce" this none this
@program #258:announce
this:announce_all_but({player}, @args);
"THX (#105941) - Fri Jun 29, 2001 - Added.";
.

@verb #258:"show_all_but" this none this
@program #258:show_all_but
{exclude, @announce} = args;
rpg = $local.rpg;
for t in (this.contents)
  if (t in exclude)
  elseif (valid(doll = rpg:get_doll(t)) && doll:cannot_see())
  else
    try
      t:tell(@announce);
    except (ANY)
      "Ignore listener with bad :tell";
      continue t;
    endtry
  endif
endfor
"New silent entry detection:";
if (this.unannounced && (i = $list_utils:iassoc(task_id(), this.unannounced)))
  this.unannounced = listdelete(this.unannounced, i);
endif
"THX (#105941) - Fri Jun 29, 2001 - Added.";
.

@verb #258:"show" this none this
@program #258:show
this:show_all_but({player}, @args);
"THX (#105941) - Fri Jun 29, 2001 - Added.";
.

@verb #258:"show_all" this none this
@program #258:show_all
this:show_all_but({}, @args);
"THX (#105941) - Fri Jun 29, 2001 - Added.";
.

"***finished***