***A dump of the Adventurers Database (#46) on March 6th

@create $room named Adventurers Database:Adventurers,Database,rpg
@prop #46."recycler" #4489 rc
@prop #46."seconds_min" 1 rc
@prop #46."ticks_min" 5000 rc
@prop #46."exporters" {} rc
@prop #46."sheet_level" {} rc
;;#46.("sheet_level") = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2}
@prop #46."sheet_atts" {} rc
;;#46.("sheet_atts") = {#19148, #19184, #19226, #19230, #19231, #19235, #19243, #19316, #19343, #19804, #107205, #57444, #5781, #75899, #25257, #5784, #9080, #7565, #7144, #7096, #6232, #32762, #6175, #10590, #6178, #6176, #95126, #29862, #75056, #6499, #6451, #6357, #7689, #32774, #32783, #105206, #1587, #40790, #19988, #19989, #83399, #60852, #76229, #7790, #87015, #7607, #32775, #6531, #32761, #32781, #32755, #9064, #9092, #67571, #29441, #18671, #46377, #10887, #7127, #86906, #80069, #41175, #37142, #60016, #53375, #112382, #14725, #104445, #12289, #74835, #65756, #101109, #74932, #87759, #66624, #74393, #9097, #101146, #78716, #89057, #32773, #54026, #79154, #6564, #108033, #98619, #18688, #104447, #59643, #17251, #11401, #68846, #108598, #62036, #6275, #32771, #41289, #70784, #81055, #9903, #10923, #69062, #73102, #117341, #85976, #99395, #102024, #55012, #45809, #20936, #16045, #57478, #75817, #93140, #83431, #34688, #97757, #71258, #8108, #22707, #52130, #56377, #109701, #49020, #110969, #14497, #71490, #24840, #19856, #19835, #32039, #24330, #17076, #4649, #24346, #34155, #81749, #67393, #89199, #24345, #25664, #50023, #66562, #4631, #2763, #4728, #32776, #32779, #32780, #32778}
@prop #46."gms" {} rc
;;#46.("gms") = {#2693, #34876, #43860, #21077, #19845, #37972, #58456, #49397, #61219, #93228, #47818, #106488, #77500, #105941, #106469, #106487, #104762, #46102, #98232, #82267, #87516, #45216, #49925, #68, #7003, #3118, #540, #14, #89395, #63546, #50222, #31829, #1449, #100806, #108850, #117389, #100337, #116601, #119377, #30788, #106189, #50367, #102427, #112369, #114701}
@prop #46."costs" {} rc
;;#46.("costs") = {1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8, 9, 10, 11, 13, 15, 17, 20, 24, 29, 35, 42, 50, 999999}
@prop #46."dolls" {} rc
;;#46.("dolls") = {#1390, #3734, #3787, #4004, #4052, #4320, #8078, #18659, #23825, #18806, #31931, #41833, #41849, #32854, #28038, #29022, #51009, #26184, #51775, #17620, #16403, #52611, #24130, #51988, #53172, #20523, #26738, #29404, #13502, #31489, #49887, #52310, #54064, #29919, #29454, #24620, #47855, #57735, #41153, #27441, #55068, #37347, #34390, #50892, #56269, #55824, #48060, #21835, #3741, #16735, #31791, #51744, #61229, #35881, #62807, #44094, #67379, #73513, #71231, #73510, #32602, #55763, #3345, #69302, #68814, #4144, #72773, #4515, #72786, #65369, #65060, #84167, #12424, #61774, #13011, #89508, #75264, #88792, #80245, #56639, #90355, #97224, #97238, #97252, #97312, #28961, #97049, #9742, #66136, #58410, #100848, #52999, #51620, #70640, #71119, #91803, #8384, #3259, #33402, #5048, #2058, #71253, #69416, #57870, #8986, #10173, #52437, #8355, #76993, #93782, #87663, #60721, #13007, #60793, #28617, #96270, #11776, #43431, #76087, #97067, #93189, #47568, #101475, #88576, #92765, #82789, #98895, #23270, #49937, #58286, #7384, #79705, #61532, #94754, #67546, #68745, #5830, #62033, #27734, #81317, #48400, #96845, #67302, #55891, #14643, #3018, #56519, #95273, #75107, #84951, #102052, #58764, #77749, #16177, #11573, #70513, #86454, #70577, #71689, #81184, #89210, #70665, #97793, #60332, #103196, #11390, #100994, #64275, #106869, #104279, #54518, #10967, #64372, #7252, #35371, #77636, #90875, #84464, #5285, #46616, #79618, #94369, #7016, #2209, #51123, #92230, #3358, #30279, #100360, #5779, #30459, #107885, #96550, #73705, #48507, #70680, #64213, #111936, #22572, #55147, #5481, #59247, #61608, #57116, #103345, #9667, #13399, #91479, #92788, #17078, #101379, #112995, #96378, #1774, #81683, #90308, #16131, #100567, #21336, #13268, #72274, #102501, #45276, #20943, #55357, #2451, #2968, #75149, #27411, #11013, #100451, #50965, #74106, #113709, #90364, #54015, #87720, #79702, #62888, #94490, #108023, #113734, #109951, #34523, #72092, #111137, #74217, #24275, #90345, #88834, #56196, #79809, #24128, #82014, #69378, #91346, #14632, #74421, #59917, #91199, #105335, #53073, #24997, #49788, #115292, #95432, #28881, #70317, #90064, #45671, #86258, #6081, #59886, #69599, #8133, #94127, #95797, #36083, #87587, #98130, #90278, #67703, #110533, #104471, #111301, #17205, #98551, #103275, #104097, #19373, #108585, #113324, #81738, #14838, #75010, #110106, #38031, #4983, #115206, #96826, #63856, #83645, #91704, #86628, #10665, #49440, #61244, #55074, #53506, #74171, #102229, #4639, #63496, #78129, #90245, #81004, #66939, #50103, #106063, #89890, #89586, #45020, #101620, #108070, #45811, #42571, #112392, #109476, #71435, #75337, #72443, #67261, #114815, #67054, #11881, #81613, #73519, #55237, #107040, #68208, #18661, #98202, #112144, #87184, #69325, #115783, #111669, #99985, #4483, #2196, #82434, #43655, #14872, #10979, #96002, #94749, #89957, #17158, #10575, #102797, #104858, #118737, #23337, #99442, #103917, #22747, #97414, #107893, #106110, #109650, #116641, #66998, #33188, #106922, #53362, #92393, #16934, #94986, #91987, #78355, #55692, #93739, #54636, #72766, #112030, #62438, #54350, #52180, #113398, #44125, #16987, #114998, #116651, #2372, #69105, #84307, #51599, #38771, #44228, #68157, #114841, #106644, #58013, #101796, #100826, #54097, #51681, #33090, #54696, #93524, #118953, #55854, #68010, #58066, #115296, #55743, #88022, #15784, #57440, #52320, #68798, #71789, #17717, #53195, #81299, #55604, #89543, #80521, #118571, #82542, #91963, #9717, #113883, #111442, #59409, #97819, #8316, #94875, #51734, #94539, #4527, #68957, #102921, #115158, #3563, #112537, #14455, #92158, #51008, #94516, #63401, #16854, #86550, #103069, #46615, #9672, #11018, #113478, #56037, #61118, #90708, #95535, #108341, #66475, #12479, #74840, #88091, #59230, #64608, #116141, #50663, #65583, #77575, #121683, #107937, #66179, #96670, #75154, #84499, #3287, #32357, #11576, #83138, #121608, #105308, #15518, #74538, #12683, #40508, #69004, #60716, #57485, #14477, #76745, #59743, #81052, #37054, #51551, #13510, #16030, #114345, #114057, #59143, #58642, #95925, #118662, #64397, #119861, #11627, #60300, #72869, #103087, #113891, #47803, #87403, #114568, #66655, #72891, #117227, #104892, #59405, #31779, #120441, #43634, #72919, #96467, #15459, #109749, #51438, #98444, #16091, #52573, #10683, #108779, #81028, #86117, #65990, #43906, #117434, #113951, #97838, #85215, #70184, #102058, #39780, #14719, #71780, #112148, #56573, #121552, #8138, #105311, #30397, #60227, #76286, #71226, #103636, #4861, #9482, #73621, #54553, #56827, #111764, #54073, #111037, #114949, #117103, #72339, #58323, #26020, #80566, #120726, #91855, #58884, #57419, #95226, #119842, #23545, #65069, #15514, #116092, #110222}
@prop #46."attdeps" {} rc
;;#46.("attdeps") = {{{}, {"ohswd"}}, {{"agl", "agl", "agl", "pcn", "agl"}, {}}, {{"end", "end", "end", "wil", "end"}, {}}, {{}, {"melee"}}, {{"agl", "str", "agl"}, {}}, {{}, {"ohhfw"}}, {{}, {"melee"}}, {{}, {"melee"}}, {{}, {"thhft"}}, {{}, {"ohswd"}}, {{}, {"melee"}}, {{}, {"melee"}}, {{"melee", "agl", "pcn", "str"}, {}}, {{}, {"shield"}}, {{"int", "wil", "int"}, {}}, {{}, {"magic"}}, {{}, {"fire"}}, {{}, {"thhft"}}, {{"agl", "str", "wil", "agl", "str"}, {}}, {{"wil", "wil", "int", "wil", "pcn"}, {}}, {{"str", "agl", "end", "str"}, {}}, {{}, {"thhft"}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {}}, {{}, {"ecto"}}, {{}, {"gadget"}}, {{"dex", "int", "pcn"}, {}}, {{}, {"ecto"}}, {{"agl", "str", "pcn"}, {}}, {{}, {"throw"}}, {{}, {"climb"}}, {{}, {"ohswd"}}, {{}, {"melee"}}, {{}, {"natweap"}}, {{}, {"natweap"}}, {{}, {"natweap"}}, {{"ohswd"}, {"kat"}}, {{"thswd"}, {"kat"}}, {{}, {"climb"}}, {{}, {}}, {{}, {"knives"}}, {{}, {"magic"}}, {{}, {"time"}}, {{}, {"magic"}}, {{}, {"force"}}, {{}, {"melee"}}, {{"ohhfw"}, {"baxe"}}, {{"thhft"}, {"baxe"}}, {{"dex", "pcn", "dex", "int"}, {}}, {{}, {"drive"}}, {{}, {"bike"}}, {{}, {"fire"}}, {{}, {"magic"}}, {{}, {"life"}}, {{}, {"knives", "melee"}}, {{}, {"longarms"}}, {{}, {"missiles"}}, {{"dex", "pcn", "dex"}, {}}, {{}, {"missiles"}}, {{}, {"drawbow"}}, {{}, {}}, {{}, {"spear"}}, {{}, {"javelin", "throw"}}, {{}, {"javelin", "melee"}}, {{}, {"missiles"}}, {{}, {"handguns"}}, {{"pcn", "wil", "pcn"}, {}}, {{}, {"observe"}}, {{}, {"observe"}}, {{}, {"throw"}}, {{"app", "wil", "emp"}, {}}, {{}, {"convince"}}, {{}, {"convince"}}, {{}, {"trick"}}, {{}, {"dagger", "throw"}}, {{}, {"dagger", "melee"}}, {{}, {"ohswd"}}, {{}, {"thhft"}}, {{}, {"fire"}}, {{}, {"gadget"}}, {{"dex", "emp", "wil"}, {}}}
@prop #46."atts" {} rc
;;#46.("atts") = {"brswd", "dodge", "shock", "ohswd", "melee", "club", "ohhfw", "thhft", "tclub", "rap", "kat", "thswd", "shield", "kites", "magic", "fire", "firebolt", "staff", "climb", "sanity", "swim", "scyth", "str", "end", "dex", "agl", "int", "emp", "wil", "pcn", "app", "gadget", "throw", "furn", "wclim", "scim", "natweap", "claw", "tenta", "teeth", "kat1", "kat2", "tclimb", "knives", "dagger", "time", "slow", "force", "forcewall", "baxe", "baxe1", "baxe2", "drive", "heat", "life", "heal", "sai", "crossbow", "longarms", "missiles", "drawbow", "longbow", "spear", "javelin", "javelin_throw", "javelin_melee", "handguns", "revolver", "observe", "notice", "search", "star", "convince", "persuade", "trick", "pray", "dagger_throw", "dagger_melee", "machete", "pick", "storm", "lockpick", "spellsing", "thieving", "teleport", "charm", "recall", "pacify", "stamina", "brawl", "moofu", "magic_theory", "creo", "intellego", "muto", "perdo", "rego", "corporem", "ignem", "vim", "animalem", "mentem", "aquam", "herbam", "imagonem", "terram", "depress", "calm_winds", "shatter", "windwall", "stinkcloud", "predict", "whip", "harden", "enchant", "biting_cloud", "barkskin", "hail", "lifelink", "stealskill", "mindprobe", "waterwhip", "iceshell", "dispel", "claim", "auram", "shocking_grasp", "unarmed", "greatsword", "summon"}
@prop #46."pcs" {} rc
;;#46.("pcs") = {#1381, #3730, #3777, #4002, #4048, #1214, #8077, #17777, #19044, #4418, #13573, #4981, #10249, #16104, #21598, #15458, #7057, #5632, #26608, #35896, #52165, #40259, #2955, #42381, #53178, #53798, #45991, #31020, #45622, #40379, #40890, #51765, #51082, #44015, #55272, #6527, #8953, #50841, #36198, #20474, #48474, #22224, #7686, #39500, #16410, #53941, #53978, #22055, #51809, #57159, #56543, #61004, #9096, #102, #62858, #56299, #33020, #73468, #73054, #71798, #73373, #72883, #32401, #79574, #79214, #4142, #8954, #8952, #85990, #4677, #29929, #4375, #4186, #74798, #77819, #83797, #33931, #1383, #93374, #67730, #7151, #94799, #41501, #26450, #21252, #97587, #95558, #90796, #61620, #63670, #66635, #365, #819, #820, #1453, #2805, #2992, #3048, #3094, #3098, #3764, #3032, #3760, #3956, #4049, #4050, #7965, #10441, #11966, #2230, #15844, #15907, #15908, #15990, #12689, #86696, #103632, #73404, #58625, #87886, #88892, #83242, #8891, #1112, #20800, #1092, #69439, #66341, #104015, #98531, #1285, #1298, #1355, #1338, #1348, #1091, #1011, #76667, #87453, #1798, #1251, #9799, #9365, #7744, #75947, #52869, #4713, #1742, #6113, #5003, #4688, #12763, #1178, #1179, #79322, #1987, #2705, #2605, #41330, #15884, #63530, #52868, #6
>> Network buffer overflow: 993 lines of output to you have been lost <<
else
  wielding_msg = s_u:pronoun_sub(("  %S %<is> wielding " + s_u:title_list(wielding)) + ".", who);
endif
player:tell(wearing_msg + wielding_msg);
if (special)
  player:tell(s_u:from_list(special, "  "));
endif
"Quinn 31-JUL-93 2247-ET: Re-written to use modern core verbs; minor changes to variable choice; inclusion of ALL things wielded if more than 2";
"Quinn 10-AUG-93 0226-ET: Hacked to print 'only' hand instead of 'primary' if the character has only one hand.";
"Quinn 12-AUG-94 1418-ET: Check :hide_from_look_gear returning true, and do not show weapon if so.  Messages now support verb conj/plural players, and are more informative, including support for natural weapons.  Remove !rpg_thing equipment.";
"Quinn 12-AUG-94 1554-ET: Added :look_gear_msg verb check for special display of certain equipment.";
"Quinn 26-SEP-94 0938-ET: Stuck .crest in shield:look_gear_msg.  Items MUST define a :hide_from_look_gear returning true if they wish to be excluded from the mundane listing, even if they define a :look_gear_msg.";
"StarDancer 10-NOV-94 0035-ET: Added a `armed with' msg for monsters who's .animal prop is set 'cause most animals don have hands.";
"Profane 22-JUN-96 0018EST -- Added hook for custom verb on monsters";
.

@verb #46:"approve_att_change" this none this rx
@program #46:approve_att_change
":log_att_change(player, {doll, attribute, new_value}, callers)";
"Return E_PERM if the given attribute change should not be permitted.";
"(Right now this is used only to log stat changes.  Set 'logging_att_changes' to the log length desired.)";
if (caller_perms() == this.owner)
  {who, info, stack} = args;
  {doll, att, val} = info;
  if (is_player(char = doll.character) && ((char in this.fishy) || ((abs(val - doll.(att)) > 20) && (att != "inj"))))
    if ((att in this.no_log_atts) || ((who in this.gms) && (char in this.gms)))
      "... do nothing ...";
      "Since practically every time ya move, .act gets set, let's filter it out.";
    elseif ((len = this.logging_att_changes) > 1)
      log = listinsert(this.att_change_log, {time(), who, info, stack ? stack | callers()}, 1);
      log = log[1..min($, len)];
      this.att_change_log = log;
    endif
  endif
  {prog, object} = stack[1][3..4];
  if (((prog in this.probation) || (object in this.banned_from_mod)) || (att in this.unsettable_values))
    return E_PERM;
  endif
  return 1;
else
  return E_PERM;
endif
.

@verb #46:"view_att_log" this none this
@program #46:view_att_log
if (!(caller_perms() in {@this.grand_masters, @this.spies}))
  return E_PERM;
else
  return {this.fishy, this.att_change_log};
endif
.

@verb #46:"add_doll" this none this
@program #46:add_doll
"  add_doll(OBJ character, OBJ doll) -> BOOLEAN success  may suspend";
"Adds doll to this.dolls and character to this.pcs, associated with";
"each other.  The character may not have another doll already registered.";
if (!this:trusted(caller_perms()))
  return E_PERM;
endif
character = args[1];
doll = args[2];
if (((!$object_utils:isa(doll, this.doll)) || (doll.character != character)) || (character in this.pcs))
  return E_INVARG;
endif
$command_utils:suspend_if_needed(this.gm_lag);
this.pcs = {@this.pcs, character};
this.dolls = {@this.dolls, doll};
return 1;
"June 28, 1995 -- Slither, first version";
.

@verb #46:"rm_pc" this none this
@program #46:rm_pc
"  rm_pc(OBJ pc) => OBJ doll  may suspend";
"Removes the (pc/doll) pair from this.pcs/this.dolls lists.  Returns";
"the removed doll.";
if ((caller == this) || this:trusted(caller_perms()))
  this:s_i_n();
  pos = args[1] in this.pcs;
  if (pos)
    dolls = this.dolls;
    this.pcs = listdelete(this.pcs, pos);
    this.dolls = listdelete(dolls, pos);
    return dolls[pos];
  else
    return E_INVARG;
  endif
else
  return E_PERM;
endif
"June 28, 1995 -- Slither, first version";
.

@verb #46:"rm_doll" this none this
@program #46:rm_doll
"  rm_doll(OBJ doll) => OBJ pc   may suspend";
"Removes the (pc/doll) pair from this.pcs/this.dolls lists.  Returns";
"the removed RPG character.";
{doll} = args;
this:secure();
this:s_i_n();
pos = doll in this.dolls;
if (!pos)
  return $object_utils:isa(doll, this.doll) ? 1 | E_INVARG;
endif
pcs = this.pcs;
this.dolls = listdelete(this.dolls, pos);
this.pcs = listdelete(pcs, pos);
return pcs[pos];
"June 28, 1995 -- Slither, first version";
.

@verb #46:"reap_protect_pc" this none this
@program #46:reap_protect_pc
" :reap_protect_pc(OBJ pc, NUM time, OBJ gm, STR comment) => BOOL changed";
"Keeps the player `pc' from having their doll reaped until after `time'.";
"`gm' should be the gm to contact about this, and `comment' allows one";
"to explain any unusual circumstances.  If the player is already protected,";
"then this call will replace the previous data.";
if (!this:trusted(caller_perms()))
  return E_PERM;
endif
pc = args[1];
time = args[2];
if (((length(args) != 4) || (!is_player(pc))) || (time < time()))
  return E_INVARG;
endif
olddata = this.reap_protected_pcs;
pos = pc in olddata[1];
if (pos)
  newpcs = olddata[1];
  newpcdata = olddata[2];
  newpcdata[pos] = listdelete(args, 1);
else
  newpcs = {@olddata[1], pc};
  newpcdata = {@olddata[2], listdelete(args, 1)};
endif
this.reap_protected_pcs = {newpcs, newpcdata};
return 1;
"July 31/95 Slither  -- first version";
.

@verb #46:"unreap_protect_pc" this none this
@program #46:unreap_protect_pc
"  :unreap_protect_pc(OBJ pc)";
"Removes any RPG reap protection for pc";
if (!this:trusted(caller_perms()))
  return E_PERM;
endif
pc = args[1];
data = this.reap_protected_pcs;
pos = pc in data[1];
if (pos)
  newpcs = listdelete(data[1], pos);
  newpcdata = listdelete(data[2], pos);
  this.reap_protected_pcs = {newpcs, newpcdata};
endif
"July 31/95 Slither  -- first version";
.

@verb #46:"is_reap_protected" this none this
@program #46:is_reap_protected
" :is_reap_protected(OBJ pc) => LIST data ";
"If pc is protected from the RPG reap, returns {time, gm, comment},";
"otherwise returns {}.  'time' is the time the pc is protected until,";
"and 'gm' is the gm to talk to about this, and 'comment' is any";
"comment that was provided about protecting this player.";
pc = args[1];
pos = pc in this.reap_protected_pcs[1];
if (pos)
  data = this.reap_protected_pcs[2][pos];
  if (data[1] < time())
    this:unreap_protect_pc(pc);
    return {};
  else
    return data;
  endif
else
  return {};
endif
"July 31/95 Slither -- first version";
.

@verb #46:"cleanse_reap_protected_pcs" this none this
@program #46:cleanse_reap_protected_pcs
" :cleanse_reap_protected_pcs()    may suspend";
"removes any invalid or useless entries from this.reap_protected_pcs";
for pc in (this.reap_protected_pcs[1])
  $command_utils:suspend_if_needed(10);
  if (!is_player(pc))
    "pc isn't a player anymore!";
    this:unreap_protect_pc(pc);
  else
    rpp = this.reap_protected_pcs;
    pos = pc in rpp[1];
    if (pos && (rpp[2][pos][1] < time()))
      "protection expired";
      this:unreap_protect_pc(pc);
    endif
  endif
endfor
return 1;
"July 31/95 Slither -- first version";
.

@verb #46:"reap_protected_pcs" this none this
@program #46:reap_protected_pcs
"  :reap_protected_pcs() =>  {LIST pcs, LIST pcdata}  may suspend";
"returns data on all the pcs that are protected from the RPG reap.";
"The data is in the following format:";
"  pcs is a list of all the protected pcs";
"  pcdata is a list such that pcdata[i] is the data about pcs[i],";
"    and pcdata[i] is in the format {time, gm, comment}, where";
"      time is the time the protection expires";
"      gm is the gm who is listed as being the person to ask about this,";
"      comment is any comment they made about this protection";
this:cleanse_reap_protected_pcs();
return this.reap_protected_pcs;
"July 31/95 Slither  -- first version";
.

@verb #46:"rpg_announce*_all" this none this
@program #46:rpg_announce_all
":rpg_announce(<OBJ location>, <LIST/STR args to pass to tell>) -> As a regular room:announce for location, but only spews to non-sleeping players.";
{where, @string} = args;
this:secure();
this:rpg_announce_all_but(where, (verb == "rpg_announce") ? {player} | {}, @string);
"THX1138 (#105941) - Sun Apr 19, 1998 - Changed code to send to this:rpg_announce_all_but() to save on maintaining identical code.";
.

@verb #46:"rpg_announce_all(older)" this none this
@program #46:rpg_announce_all(older)
":rpg_announce_all(<OBJ location>, <LIST/STR args to pass to tell>) -> As a regular room:announce for location, but only spews to non-sleeping players.";
{where, @string} = args;
this:rpg_announce_all_but(where, {}, @string);
"THX1138 (#105941) - Sun Apr 19, 1998 - Changed code to send to this:rpg_announce_all_but() to save on maintaining identical code.";
.

@verb #46:"is_rpg_room" this none this
@program #46:is_rpg_room
return this.object_db:(verb)(@args);
.

@verb #46:"is_monster" this none this
@program #46:is_monster
return this.object_db:(verb)(@args);
.

@verb #46:"rate_skill skill_rate" this none this
@program #46:rate_skill
":rate_skill(NUM score, NUM max possible score) => STR word rating of score compared with max";
{score, max} = args;
if ((score < 0) || (max < 1))
  return "subhuman";
else
  names = this.rate_words;
  point_spread = max / (length(names) - 3);
  if (point_spread)
    score = score / point_spread;
    score = score ? score | 1;
  else
    excess = (length(names) - max) - 3;
    names = names[1..($ - 3) - (excess - (excess / 2))];
    names = names[(excess / 2) || 1..$];
  endif
  score = (score > length(names)) ? length(names) | score;
  score = score ? score | 1;
  return names[score];
endif
.

@verb #46:"gmlist" this none this
@program #46:gmlist
rpg_helpers = #58390:group_members();
help_names = {};
for who in (rpg_helpers)
  help_names = (valid(who) && is_player(who)) ? {@help_names, $string_utils:nn(who)} | help_names;
endfor
return $string_utils:columnize(help_names, 3);
.

@verb #46:"rpg_lag" this none this
@program #46:rpg_lag
":rpg_lag() => How much are we delaying RPG actions to control lag?";
return this.gm_lag;
"THX July 23, 1998  - Bypass this dog's breakfast of Irin's code that uses scads of ticks.";
try
  if (q = queued_tasks())
    n = 1;
    while ((n <= length(q)) && (q[n][2] <= (time() - 1000000)))
      n = n + 1;
    endwhile
    a = q[n][2];
    if (a == 0)
      return this.min_command_interval;
    endif
    lag = min(time() - a, 3600);
    return max(this.min_command_interval, (10 * lag) / this.lag_standard);
  else
    return this.min_command_interval;
  endif
except x (ANY)
  return this.min_command_interval;
endtry
.

@verb #46:"restore_pc" this none this
@program #46:restore_pc
":restore_pc(who, doll) => restores doll to who, saving their other doll.";
{who, newdoll} = args;
this:secure();
{rpg_doll, player_start, death_db} = {this.doll, this.player_start, this.death_db};
if ((!is_player(who)) || (!$object_utils:isa(newdoll, rpg_doll)))
  return E_NACC;
endif
if (newdoll.character != who)
  return E_INVARG;
endif
if (n = newdoll in this.dolls)
  return E_NONE;
endif
if (n = who in this.pcs)
  this:save_doll(this.dolls[n]);
elseif ((!(caller in {this.magic_db, this.object_db.hack_db})) && player_start:is_banned(who))
  player:tell("Have the player to be restored go the the Initiation Chamber first.");
  return E_INVIND;
endif
if ((who in this.macro_users) && (caller_perms() != this.owner))
  return player:tell("Only Grand_Master can restore an indicted macro user.");
endif
banned = player_start.banned_for_life;
for t in (this.saved_dolls)
  if ((parent(t) != rpg_doll) || (t.character in banned))
    this.saved_dolls = setremove(this.saved_dolls, t);
  endif
endfor
this.pcs = {@this.pcs, who};
this.dolls = {@this.dolls, newdoll};
this.saved_dolls = setremove(this.saved_dolls, newdoll);
this.object_db.CAP_corrector:correct_doll(newdoll);
death_db.corpse_dolls = setremove(death_db.corpse_dolls, newdoll);
this.guild_db:restore_guilds(newdoll);
this.puzzle_log:restore_puzzles(newdoll);
for x in (newdoll.natural_weapons)
  this.object_db.natweap_db:remove_natweap(newdoll, x);
endfor
newdoll.resurrected = time();
return newdoll;
"THX 27-Mar-1997 -- Added splurge to remove newdoll from this.saved_dolls ... to save time for manually restoring PCs when searching through the list.";
"Profane 8-APR-97 1618PST -- return newdoll";
"Mooshie (#106469) - Tue Jan 13, 1998 - guild DB and puzzle log hook.";
"THX (#105941) - Mon Jan 26, 1998 - Added a blurb to clean out this.saved_dolls which needs to be done only occasionally.";
"THX (#105941) - Wed Feb 18, 1998 - Added a requirement that the player to be restored must already have a voodoo doll.  This will prevent banned players from using registered seconds.";
"THX (#105941) - Mon Nov  1, 1999 - Added a call to the CAP_corrector upon rebirth.";
"THX (#105941) - Fri Jun  1, 2001 - Allow hack_db to resurrect as well as magic_db.";
"Hannibal (#104762) - Wed July 25, 2001 - Set newdoll.resurrected to time().";
"Hydros (#106189) - Tue Mar 15, 2005 - Removed all natural weapons that might be lingering on the doll--because mailed fists were sticking around.";
.

@verb #46:"check_notification" this none this
@program #46:check_notification
this:secure();
return this.notifier:check_notification(@args);
"Route to RPG notifier.";
":check_notification(OBJ|LIST to_be_notified, STR notify_verb, LIST args)";
"The verb now accepts a list as an arg, no longer checks :get_doll, and justspews the data, ignoring whether its a valid doll OR object.";
if (!this:trusted(caller_perms()))
  return E_PERM;
endif
{x, verbname, argslist} = args;
if (verbname[1..7] != "notify_")
  return E_PERM;
endif
for object in ((typeof(x) == LIST) ? x | {x})
  if (this:is_monster(object))
    value = `object:(verbname)(@argslist) ! ANY';
  endif
endfor
"New check_notification hacked by Quinn 03-JAN-93.";
"Profane 13-APR-95 14:20EST - Added :trusted_verb check, thus adding 46 ticks per notify call..";
"THX 13-FEB-97: Version 1.8.0 update, de-ticked and removed Profane's grudging :trusted_verb check in favour of an is_monster check.";
.

@verb #46:"trusted_verb trusted_property" this none this rxd #58016
@program #46:trusted_verb
":trusted_verb/property(OBJ object, STR verbname | STR propname)";
"Return true if the indicated verb/property is owned by a player in $local.rpg.gms.  Return 0 if it is not, or an error if the arguments are invalid.";
"--WIZARDLY--";
{object, name} = args;
if (verb == "trusted_property")
  if ($object_utils:has_property(object, name))
    where = object;
  else
    return E_PROPNF;
  endif
else
  if (`{where} = $object_utils:has_callable_verb(object, name) ! ANY => 0')
    "... do nothing ... ";
  else
    return E_VERBNF;
  endif
endif
try
  {info, @extra} = (verb == "trusted_verb") ? verb_info(where, name) | property_info(where, name);
  return info in this.gms;
except error (ANY)
  return error[1];
endtry
"Copied from Grand_Master (#2693):trusted_verb Sun Oct  9 10:00:39 1994 PDT";
"Copied from Quinn (#19845):trusted_verb Sun Feb  6 16:02:53 1994 PST";
"Isagi 100894 11:00P Fixed feature that caused E_VERBNF to be returned if there was no verb, but there was a property.";
"THX1138 02-16-97 10:00EST - Got rid of needless assignments and handled everything with scatter assignments to improve readability and to reduce _indexing_ into lists that were _created_ a few lines previously.";
.

@verb #46:"secure" this none this
@program #46:secure
":secure() => raise E_PERM if we don't like the look of whoever called your verb (i.e., a builtin, or non-GM permed verb called you.)";
if (callers()[2][3] in this.gms)
  return;
endif
(caller_perms() in this.ex_gms) ? kill_task(task_id()) | raise(E_PERM, "RPG Security Violation!");
"Profane 1-APR-97 1708PST -- added bit for command-line verbs";
"Irin Thu Apr  3 12:33:06 1997 PST -- Unceremoniously sent the code for command-line verbs to #46:secure_x().  Thus saving 1 tick.";
"THX (#105941) - Fri Mar 23, 2001 - Added ex_gm check IFF the verb's about to raise an error.";
.

@verb #46:"secure_stack" this none this
@program #46:secure_stack
":secure_stack([trust builtin at end]) => Check if all calling verbs up to and incuding the first verb not of the same name and location are GM permed.  the optional argument, if true, means that we would trust a builtin to be the first caller in this.";
"The idea with this verb is to make just one security check for a whole bunch of callers.  Put the security check on the root verb (example, #258:enterfunc).  Then, all the other enterfuncs which call #258:enterfunc (example: #9505:enterfunc) can just 'pass(@args)' first.  We reach the root of the secure stack, make the security check, raise an error if it failed, otherwise all the code in the stack is secure.  Cool, huh?";
{?trust_builtin = 0} = args;
gms = this.gms;
callers = callers();
calling_object = callers[1][1];
calling_verb = callers[1][2];
for caller in (callers[2..$])
  if ((caller[1] == calling_object) && (caller[2] == calling_verb))
    if (caller[3] in gms)
    else
      raise(E_PERM, "RPG Security Violation.  Insecure stack verb.");
    endif
  elseif ((caller[3] in gms) || (((trust_builtin && caller[2]) && (caller[3] == #-1)) && (caller[4] == #-1)))
    return;
  else
    raise(E_PERM, "RPG Security Violation.  Insecure stack caller.");
  endif
endfor
.

@verb #46:"merge_dolls" this none this
@program #46:merge_dolls
":merge_dolls(new, old) => Merge stats on 'old' with 'new'.  Recycle 'old'.";
this:secure();
{new, old, ?numer = 2} = args;
doll = this.doll;
if ((((((parent(new) != doll) || (parent(old) != doll)) || (new.character != old.character)) || (!(old in this.saved_dolls))) || (!(new in this.dolls))) || (numer < 1))
  "Checking that all dolls and doll.characters are properly aligned, and that the mixing ratio is at least 1:1.";
  return E_INVARG;
endif
denom = numer + 1;
for skill in ($object_utils:descendants_suspended(this.skill_object))
  sk = skill.aliases[1];
  try
    hi = max(old.(sk), new.(sk));
    lo = min(old.(sk), new.(sk));
    new.(sk) = ((numer * hi) + lo) / denom;
  except (ANY)
    "darn.  Somebody made a skillobject without a prop on the doll.  Owell.";
  endtry
  $command_utils:suspend_if_needed(this.gm_lag);
endfor
this.guild_db:restore_guilds(old);
this.puzzle_log:restore_puzzles(old);
this.saved_dolls = setremove(this.saved_dolls, old);
return 1;
"Mooshie (#106469) - Tue Jan 13, 1998 - Restore old guild/puzzle info.";
.

@verb #46:"secure_x" this none this
@program #46:secure_x
":secure() => raise E_PERM if we don't like the look of whoever caller your verb (i.e., a builtin, or non-GM permed verb called you.";
if (`callers()[2][3] ! E_RANGE => player' in this.gms)
  return;
endif
raise(E_PERM, "RPG Security Violation!");
"Profane 1-APR-97 1708PST -- added bit for command-line verbs";
.

@verb #46:"sheet_text" this none this
@program #46:sheet_text
":sheet_text(OBJ doll, [NUM type of sheet]) -> LIST text containing info on who's skills and whatnot.";
"Types: 1 = Basic (words, left column only); 2 = Intermediate (words, no zeros), 3 = Advanced (words, all), 4 = Arcane (numbers, all)";
this:secure();
{doll, ?type = 1} = args;
if (parent(doll) != this.doll)
  raise(E_INVARG, "Error:  Non-doll passed to :sheet_text");
endif
who = doll.character;
{su, cu} = {$string_utils, $command_utils};
atts = this.sheet_atts;
lev = this.sheet_level;
text = {};
len = length(atts);
sec = su:space((type < 4) ? 12 | 25);
loc = 0;
q = 1;
fit = (type < 4) ? 12 | 3;
while (q <= len)
  cu:suspend_if_needed(lag = this.gm_lag, "Suspending the generation of ", who.name, "'s statistics.  Will resume shortly. [approx. ", lag, " seconds]");
  line = "";
  att = atts[q];
  val = doll.(att.aliases[1]);
  i = lev[q];
  if (((i == 0) || (type > 2)) || (val && (type > 1)))
    for x in [1..i]
      line = line + sec;
    endfor
    sum = doll:total(att);
    valword = (type < 4) ? this:rate_skill(val, 25) | tostr(val);
    sumword = (type < 4) ? this:rate_skill(sum, doll:potential_total(att)) | tostr(sum);
    line = ((((line + su:left((length(att.name) < 15) ? att.name | att.name[1..14], 15)) + (val ? su:right(valword, fit) | su:space(fit))) + " (") + su:right(sumword, fit)) + ") ";
  endif
  q = q + 1;
  if (line)
    text = {@text, line};
  endif
endwhile
return text;
"Profane 15-APR-97 1112PST -- hacked up old verb to create different versions.";
.

@verb #46:"slip_text" this none this
@program #46:slip_text
":slip_text(OBJ chracter) -> return list of text for a slip of parchment";
{who, ?type = 1} = args;
if (!this:trusted(caller_perms()))
  return E_PERM;
elseif (!this:trusted(caller.owner))
  caller.owner:tell("You may as well recycle ", $string_utils:nn(caller), ". You ain't gonna get anything out of it.");
  return E_PERM;
elseif (!valid(doll = this:get_doll(who)))
  return {"NO INFORMATION FOUND ON SUBJECT"};
elseif ((player in this.gms) || (this.gm_lag < this.idle_threshold))
  text = {tostr("Agent : ", crypt(caller.name), "--", caller), tostr("Date  : ", who:ctime() || ctime()), tostr("Player: ", who.name, " (", who, ")  Doll: ", doll, (who in this.gms) ? "  *** GameMaster ***" | ""), ""};
  text = {@text, @this:sheet_text(doll, type)};
  return text;
else
  return player:tell("The MOO is too busy to generate sheet stats at the moment.  Try when LambdaMOO is less lagged.");
endif
.

@verb #46:"get_att" none none none rxd
@program #46:get_att
{att} = args;
if (caller_perms() in this.gms)
  return (att in this.no_view) ? (caller_perms() in this.grand_masters) ? this.(att) | {} | `this.(att) ! ANY => {}';
else
  return E_PERM;
endif
.

@verb #46:"sample_lag" this none this
@program #46:sample_lag
if (!(caller_perms() in this.grand_masters))
  return E_PERM;
endif
lag = (time() - this.last_lag_sample) - 15;
this.lag_samples = {lag, @this.lag_samples[1..3]};
"Now compute the current lag and store it in a property, instead of computing it in :current_lag, which is called a hundred times a second.";
thislag = max(0, (time() - this.last_lag_sample) - this.lag_sample_interval);
if (thislag > 3600)
  "more than an hour, probably the lag sampler stopped";
  this.current_lag = 0;
else
  samples = this.lag_samples;
  sum = 0;
  cnt = 0;
  for x in (listdelete(samples, 1))
    sum = sum + x;
    cnt = cnt + 1;
  endfor
  this.current_lag = max(thislag, samples[1], samples[2], sum / cnt);
endif
fork (15)
  this:sample_lag();
endfork
this.last_lag_sample = time();
lag_samples = setremove(this.lag_samples, max(@this.lag_samples));
this.gm_lag = $login.checkpoint_in_progress + (min(240, max(@lag_samples, $login.current_lag / 2) / 4) * this.object_db.lag_beast.alive);
"THX 17-Jun-1997  -- Ripped this code offa $login and reconfigured for G_M's usage.";
"THX (#105941) - Tue Nov 17, 1998 - Added a line to truncate the largest of G_M's lag samples ... let's try to ignore transient spikes.  Also truncate the lag at 240 seconds which is backing off enough for bloody well anyone.";
"THX (#105941) - Wed Dec 20, 2000 - Added $login.checkpoint_in_progress straight in ... so His Eminence will back off an additional second during checkpoint.";
.

@verb #46:"gm_lag" this none this
@program #46:gm_lag
return this.gm_lag;
.

@verb #46:"check_doll" this none this
@program #46:check_doll
"Usage: check_doll(OBJ doll [, INT hands needed [, boolean sleeping ok? [, boolean resting ok? [, STR sleep msg [, STR rest msg [, STR not-enough hands msg ]]]]])";
{doll, ?hands = 0, ?sleeping = 0, ?resting = 0, ?sleep_msg = "You dream of doing great things.", ?rest_msg = "You should probably get off your can before trying that.", ?hand_msg = "You seem to have run out of hands necessary for that."} = args;
who = doll.character;
if (sleeping)
  if (resting)
    if (doll:long_enough())
      if (msg = doll.paralyzed)
        who:tell((typeof(msg) == STR) ? msg | "You're paralyzed. Knock it off.");
      elseif (is_player(who) && (`idle_seconds(who) ! ANY => 301' > 300))
        who:tell("Try doing that when you're actually at the keyboard, eh?");
      endif
    else
      who:tell("It will take at least ", tostr((doll.last_attack - time()) + rpg:rpg_lag()), " seconds to recover.");
    endif
  elseif (`who.location:resting() ! E_VERBNF => 0')
    who:tell(rest_msg);
  endif
elseif (`who.location:sleeping() ! E_VERBNF => 0')
  who:tell(sleep_msg);
endif
.

@verb #46:"trusted_efunc" this none this
@program #46:trusted_efunc
"Usage: trusted_efunc()";
"Called from an :exitfunc or :enterfunc to make sure that it's either a) being called legitimately from something moving in or out of the room, or b) being called by GM perms.";
if (length(calls = callers()) > 1)
  {it, name, prog, @rest} = calls[2];
  return ((it == caller) || (prog in this.gms)) || ((!valid(it)) && (name in {"move", "recycle"}));
endif
return 0;
.

@verb #46:"initiate_pc" this none this rxd #2487
@program #46:initiate_pc
"Check the bloodline of the player.  If E is ok, call this:def_pc().";
if (caller == (start = #88))
  {pc} = args;
  if ((pc in connected_players()) && (pc.location == start))
    banned = {@start.banned_for_life, @$list_utils:slice(start.banned, 1)};
    cr = $local.second_char_registry;
    all_chars = cr:is_shared_char(pc) ? cr:shared_owners(pc) | cr:all_chars(pc);
    for t in (all_chars)
      if (t in banned)
        if (pos = pc in this.pcs)
          this.pcs = listdelete(this.pcs, pos);
          this.dolls = listdelete(this.dolls, pos);
        endif
        return;
      endif
    endfor
    (pc in this.pcs) || this:def_pc(pc);
  endif
else
  return E_PERM;
endif
"Wizard permissions required.";
"THX1138 (#105941) - Mon Jan 26, 1998 - Added this code to prevent secondary characters of LRPG-banned characters from getting new dolls.";
"THX1138 (#105941) - Thu May 21, 1998 - subst /this.player_start/#88/ to prevent any chance of hacking the caller here.";
.

@verb #46:"trusted_fefunc" this none this
@program #46:trusted_fefunc
"Usage: trusted_fefunc()";
"Stands for trusted fertile efunc. Does the same thing as #332:secure_efunc, but is for use when called by a fertile room parent. It needs to check for :enterfunc/:exitfunc verbs defined on children, which adds ticks.";
if ((len = length(calls = callers())) > 2)
  original = callers[1][1];
  for call in (calls)
    {it, name, prog, @rest} = call;
    if ((prog in gms) || ((!valid(it)) && (name in {"move", "recycle"})))
      return 1;
    elseif (it != original)
      return 0;
    endif
  endfor
endif
return 0;
.

@verb #46:"log_error" this none this
@program #46:log_error
"Snagged from Irin (#106049):log_error Wed Mar 11 21:22:49 1998 PST";
"RPG:log_error(STR/LIST error) => Report some sort of funky error to appropriate parties.";
this:secure();
{error} = args;
error = (typeof(error) == LIST) ? error | {error};
error = {ctime(), $string_utils:nn(caller), $string_utils:nn(caller_perms()), @error};
this.errors = listappend(this.errors, error);
return;
if (length(this.errors) > 10)
  msg = {};
  for n in (this.errors)
    msg = {@msg, @n, ""};
  endfor
  $mail_agent:send_message(this, this.owner, "Some errors.", msg);
  this.errors = {};
endif
.

@verb #46:"fixpos" this none this
@program #46:fixpos
"$local.rpg version of ... $you:fixpos(string, pronoun)";
"This is horribly dwimmy.  E.g. %x's gets turned into your, %X's gets turned into Your, and %X'S gets turned into YOUR. --Nosredna";
{string, pronoun} = args;
if (!index(string, "'s"))
  return string;
endif
{prefix, letter} = {pronoun[1..$ - 1], pronoun[$]};
{lowercase, uppercase} = {"abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
upper = prefix + uppercase[index(lowercase, letter)];
allupper = upper + "'S";
upper = upper + "'s";
lower = (prefix + lowercase[index(lowercase, letter)]) + "'s";
return strsub(strsub(strsub(string, lower, "your", 1), upper, "Your", 1), allupper, "YOUR", 1);
"THX (#105941) - Thu Oct 12, 2000 - Copied this from Brack's (#90845) version of $you.";
.

@verb #46:"clean*_player_prop" this none this
@program #46:clean_player_prop
"Copied from THX_utils (#99799):clean by THX1138 (#105941) Wed May 20 11:17:02 1998 PDT";
"Verb cleans out props containing lists of players.   Doll-less and invalid objects are removed.";
"To get this to work for you, you need to copy this verb to your utilities.";
{object, property} = args;
if ((caller_perms() != (owner = this.owner)) || (property in {"dolls", "pcs"}))
  return E_PERM;
  "... special check to protect this.dolls and this.pcs from accidents ...";
endif
current = object.(property);
newlist = {};
for t in (current)
  if (valid(this:get_doll(t)))
    newlist = setadd(newlist, t);
  else
    owner:tell($string_utils:nn(t), " has no doll.");
  endif
endfor
object.(property) = newlist;
.

@verb #46:"pronoun_sub" this none this
@program #46:pronoun_sub
"Pronoun (and other things) substitution. See 'help pronouns' for details.";
"syntax:  $string_utils:pronoun_sub(text[,who[,thing[,location[,dobj[,iobj]]]]])";
"%s,%o,%p,%q,%r    => <who>'s pronouns.  <who> defaults to player.";
"%n,%d,%i,%t,%l,%% => <who>, dobj, iobj, <thing>, location and %";
"<thing> defaults to caller; <location> defaults to who.location";
"%S,%O,%P,%Q,%R, %N,%D,%I,%T,%L have corresponding capitalized substitutions.";
" %[#n], %[#d], ...  =>  <who>, dobj, etc.'s object number";
"%(foo) => <who>.foo and %(Foo) => <who>.foo capitalized. %[dfoo] => dobj.foo, etc..";
"%<foo> -> whatever <who> does when normal people foo. This is determined by calling :verb_sub() on the <who>.";
"%<d:foo> -> whatever <dobj> does when normal people foo.";
{string, ?who = player, ?thing = caller, ?where = $nothing, ?dobject = dobj, ?iobject = iobj} = args;
"if (caller != this)";
"  return E_PERM;";
"endif";
this:secure();
where = valid(where) ? where | (valid(who) ? who.location | where);
"set_task_perms($no_one);";
if (typeof(string) == LIST)
  plines = {};
  for line in (string)
    plines = {@plines, this:(verb)(line, who, thing, where)};
  endfor
  return plines;
endif
old = tostr(string);
new = "";
objspec = "nditl";
objects = {who, dobject, iobject, thing, where};
prnspec = "sopqrSOPQR";
prprops = {"ps", "po", "pp", "pq", "pr", "Ps", "Po", "Pp", "Pq", "Pr"};
oldlen = length(old);
while ((prcnt = index(old, "%")) && (prcnt < oldlen))
  s = old[k = prcnt + 1];
  if ((s == "<") && (gt = index(old[k + 2..$], ">")))
    "handling %<verb> ";
    gt = (gt + k) + 1;
    vb = old[k + 1..gt - 1];
    vbs = who;
    if ((length(vb) > 2) && (vb[2] == ":"))
      " %<d:verb>";
      vbs = objects[index(objspec, vb[1]) || 1];
      vb = vb[3..$];
    endif
    vb = $object_utils:has_verb(vbs, "verb_sub") ? vbs:verb_sub(vb) | this:(verb)(vb, vbs);
    new = (new + old[1..prcnt - 1]) + vb;
    k = gt;
  else
    cp_args = {};
    if (brace = index("([", s))
      if (!(w = index(old[k + 1..oldlen], ")]"[brace])))
        return new + old;
      else
        p = old[prcnt + 2..(k = k + w) - 1];
        if (brace == 1)
          "%(property)";
          cp_args = {who, p};
        elseif (p[1] == "#")
          "%[#n] => object number";
          s = (o = index(objspec, p[2])) ? tostr(objects[o]) | (("[" + p) + "]");
        elseif (!(o = index(objspec, p[1])))
          s = ("[" + p) + "]";
        else
          " %[dproperty] ";
          cp_args = {objects[o], p[2..w - 1], strcmp(p[1], "a") < 0};
        endif
      endif
    elseif (o = index(objspec, s))
      passed = is_player(objects[o]) ? "name" | "";
      cp_args = {objects[o], passed, strcmp(s, "a") < 0};
    elseif (w = index(prnspec, s, 1))
      cp_args = {who, prprops[w]};
    elseif (s == "#")
      s = tostr(who);
    elseif (s != "%")
      s = "%" + s;
    endif
    new = (new + old[1..prcnt - 1]) + ((!cp_args) ? s | ((typeof(sub = $string_utils:_cap_property(@cp_args)) != ERR) ? sub | (("%(" + tostr(sub)) + ")")));
  endif
  old = old[k + 1..oldlen];
  oldlen = oldlen - k;
endwhile
return new + old;
.

@verb #46:"say_action" this none this rx
@program #46:say_action
"$local.rpg:say_action(message [,who, thing, where, excluding whom, highlight whom])";
"announce 'message' with pronoun substitution as if it were just ";
"  $local.rpg:rpg_announce_all($string_utils:pronoun_sub(message, who, thing, where)); ";
"except that who (player), dobj, and iobj get modified messages, with the appropriate use of 'you' instead of their name.";
"who   default player";
"thing default object that called this verb";
"where default who.location";
"excluding default {}";
"highlighting default nobody (otherwise the argument given will see eir messages with `damage highlighting')";
"(This differs from $you:say_action in that only bystanding non-sleeping players will get messages.)";
{msg, ?who = player, ?thing = caller, ?where = who.location, ?excluding = {}, ?highlight = 0} = args;
if (where in this.silent_rooms)
  return;
endif
this:secure();
{s_u, you} = {$string_utils, $you};
if (typeof(msg) == LIST)
  tell = "";
  for x in (msg)
    tell = tell + ((typeof(x) == STR) ? x | x[random($)]);
  endfor
else
  tell = msg;
endif
spew = {tell, tell, tell};
if (i = highlight in {who, dobj, iobj})
  doll = this:get_doll(highlight);
  options = this.rpg_options;
  {start, finish} = options:get(doll.rpg_options, "highlighting") ? options:get(doll.rpg_options, "highlights") || options.highlights_default | {"", ""};
  spew[i] = tostr(start, tell, finish);
endif
this:playershow(who, this:pronoun_sub(this:fixpos(spew[1], "%n"), you, thing, where));
exclude = {dobj, who, iobj, @excluding};
for t in (where.contents)
  if ((t in exclude) || (!valid(tdoll = this:get_doll(t))))
  elseif (tdoll:cannot_see())
    exclude = {@exclude, t};
  elseif (tdoll:cannot_resolve())
    exclude = {@exclude, t};
    hazy = {@hazy, t};
  endif
endfor
this:s_i_n();
this:rpg_show_all_but(where, exclude, this:pronoun_sub(tell, who, thing, where));
if (hazy)
  {dstow, istow} = {dobj, iobj};
  ((dobj in this.pcs) || is_player(dobj)) && (dobj = this.somebody);
  this:rpg_show_all_but(where, $set_utils:diff(where.contents, hazy), this:pronoun_sub(tell, this.someone, thing, where));
  {dobj, iobj} = {dstow, istow};
endif
if ((`is_player(dobj) ! E_TYPE, E_INVIND' && (!(dobj in {who, @excluding}))) && (dobj.location == where))
  ddoll = this:get_doll(dobj);
  {dstow, istow} = {dobj, iobj};
  if (valid(ddoll) && ddoll:cannot_resolve())
    active = this.someone;
    ((iobj in this.pcs) || is_player(iobj)) && (iobj = this.somebody);
  else
    active = who;
  endif
  dobj = you;
  this:playershow(dstow, this:pronoun_sub(this:fixpos(spew[2], "%d"), active, thing, where));
  {dobj, iobj} = {dstow, istow};
endif
if ((`is_player(iobj) ! E_TYPE, E_INVIND' && (!(iobj in {who, dobj, @excluding}))) && (iobj.location == where))
  idoll = this:get_doll(iobj);
  {dstow, istow} = {dobj, iobj};
  if (valid(idoll) && idoll:cannot_resolve())
    active = this.someone;
    ((dobj in this.pcs) || is_player(dobj)) && (dobj = this.somebody);
  else
    active = who;
  endif
  iobj = you;
  this:playershow(istow, this:pronoun_sub(this:fixpos(spew[3], "%i"), active, thing, where));
  {dobj, iobj} = {dstow, istow};
endif
"Profane (#30788) - Tue Dec 30, 1997 - only do tells to dobj/iobj if they're players.";
"Mooshie (#106469) - Tue Jan  6, 1998 - Added `excluded' option. An update from $you.";
"THX (#105941) - Fri Jun 12, 1998 - Changed call from s_u:pronoun_sub to this:pronoun_sub everywhere and commented out old ugly hack for <who>.  This calls player.name instead of player:title which should save a few ticks and improve readability.";
"Profane (#30788) - Sat Jun 20, 1998 - hack for damage highlighting";
"Profane (#30788) - Sun Jun  4, 2000 - insert `yadda/location = where' conditions for spewing messages to iobj, dobj";
"THX (#105941) - Mon Jun 25, 2001 - Changed to exclude those who cannot see and alter the messages to those who cannot_resolve to Someone and Somebody Else.";
.

@verb #46:"rate*_weapon" this none this
@program #46:rate_weapon
"$local.rpg:rate*_weapon(OBJ weapon, [LIST {attacker, defender}])";
"=> rating";
"Rate an rpg weapon based on certain mathematical criteria.";
this:secure();
x = this.pcs[$];
{weap, ?foes = {x, x}} = args;
if (!$object_utils:isa(weap, this.weapon))
  return E_INVARG;
endif
{x, y} = foes;
boost = 20 - (10 * weap.hands);
if ($object_utils:has_verb(weap, "critical_hit") != {this.weapon})
  boost = boost + 15;
endif
if ($object_utils:has_verb(weap, "critical_miss") != {this.weapon})
  boost = boost - 7;
endif
basic = `(((min(weap:attack(x, y), 50) + max(-25, weap:parry(x, y, weap) / 3)) - max(-25, weap:dodgable(x, y))) - max(-25, weap:parryable(x, y))) - weap:slowness(x, y) ! ANY => 25';
expert = `(((weap:dam(x, y) + weap:special_damage(x, y)) + max(-5, weap:pierce(x, y))) - max(0, weap:pen(x, y))) + (30 / max(1, weap:con(x, y))) ! ANY => 25' + boost;
return abs(expert) * (expert + basic);
"@Moved from spiderknight (#348):rate by THX1138 (#105941) Mon Jul 13 08:25:54 1998 PDT";
.

@verb #46:"compare_opponents" this none this
@program #46:compare_opponents
this:secure();
{protag, antag} = args;
if (valid(pdoll = this:get_doll(protag)) && valid(adoll = this:get_doll(antag)))
  return {this:rank_pc(pdoll, protag, antag), this:rank_pc(adoll, antag, protag)};
else
  player:tell("Both arguments must be LambdaRPG participants.");
endif
.

@verb #46:"rank_pc" this none this
@program #46:rank_pc
if (caller == this)
  {doll, who, whoelse} = args;
  rank = weapon = 0;
  look_thru = doll.wielding ? doll.wielding | doll.natural_weapons;
  for t in (look_thru)
    temp = rank;
    rank = max(rank, max(1, this:rate_weapon(t, {who, whoelse}) / 55) * doll:total(t.skill));
    weapon = (temp == rank) ? weapon | t;
  endfor
  return {rank, weapon};
else
  return E_PERM;
endif
.

@verb #46:"has_saved_doll" this none this
@program #46:has_saved_doll
{?who = $nothing} = args;
doll = this.doll;
dolls = pcs = {};
for t in (this.saved_dolls)
  if (((valid(t) && (parent(t) == doll)) && `is_player(t.character) ! E_TYPE') && ((time() - t.last_action) < 2000000))
    dolls = {@dolls, t};
    pcs = {@pcs, t.character};
  else
    this.saved_dolls = setremove(this.saved_dolls, t);
  endif
endfor
return valid(who) ? (who in pcs) ? dolls[who in pcs] | $nothing | pcs;
.

@verb #46:"tell_damage" this none this
@program #46:tell_damage
"Usage: tell_damage(OBJ who, @STR damage strings)";
"Will highlight the damage string before sending it to the recipient--as appropriate.";
{who, @msg} = args;
if (valid(doll = this:get_doll(who)))
  this:secure();
  options = this.rpg_options;
  {start, finish} = options:get(doll.rpg_options, "highlighting") ? options:get(doll.rpg_options, "highlights") || options.highlights_default | {"", ""};
  this:playertell(who, start, @msg, finish);
endif
"THX (#105941) - Mon Jun  5, 2000 - Check that the doll is valid since improvement checks call this code too.";
.

@verb #46:"s_i_n" this none this rx
@program #46:s_i_n
if ((ticks_left() < 7500) || (seconds_left() < 2))
  {?long = this.gm_lag} = args;
  (caller_perms() == this.owner) && suspend(long);
endif
"suspends if ticks left is under 6000 or if secs left is under 2";
"THX (#105941) - Fri Jan  1, 1999 - This is G_M's version of $command_utils:suspend_if_needed().  NB: Use rpg:s_i_f_i_n() when doing conditional suspends in for-loops.";
.

@verb #46:"doll_exp" this none this
@program #46:doll_exp
":doll_exp(doll) -> Numeric representation of doll's overall LRPG experience.";
this:secure();
{doll, ?augment = 0} = args;
exp = 0;
if (valid(doll) && (parent(doll) == this.doll))
  skills = this.skills.contents;
  attributes = this.attributes;
  for skill in (skills)
    if (!(skill in attributes))
      exp = exp + (doll.(skill.aliases[1]) * skill.learn);
    endif
  endfor
  if (augment)
    exp = (exp * 2) * max(doll.magic_theory, doll.melee);
  endif
endif
return exp;
.

@verb #46:"s_i_f_i_n suspend_in_for_if_needed" this none this rx
@program #46:s_i_f_i_n
if ((ticks_left() < 2400) || (seconds_left() == 1))
  (caller_perms() == this.owner) && suspend(0);
endif
"suspends if ticks left is under 3600 or if secs left is under 1.";
"THX (#105941) - Fri Jan  1, 1999 - This version of :suspend_if_needed(0) is to be used in for-loops in the core if the effects required are fairly immediate.  In other words, this is a quick and dirty way of gaining some more ticks and seconds.";
.

@verb #46:"save_doll" this none this
@program #46:save_doll
this:secure();
{doll} = args;
if ((is_player(who = doll.character) && (who == who.owner)) && (parent(doll) == this.doll))
  saved = who in $list_utils:map_prop(this.saved_dolls, "character");
  if (saved)
    s_d = this.saved_dolls[saved];
    current = (this:doll_exp(doll) + (5 * doll.pot)) + (99 * $math_utils:sum($list_utils:map_arg(doll, "get_att", $list_utils:slice($list_utils:map_prop(this.attributes, "aliases"), 1))));
    test = (this:doll_exp(s_d) + (5 * s_d.pot)) + (99 * $math_utils:sum($list_utils:map_arg(s_d, "get_att", $list_utils:slice($list_utils:map_prop(this.attributes, "aliases"), 1))));
    if (current > test)
      this.saved_dolls[saved]:moveto(this.cemetery);
      this.saved_dolls = listdelete(this.saved_dolls, saved);
      "Only save ONE DOLL PER PLAYER, thank you drive through.";
      "Only save a new doll if it has more exp than the old one. Yes, this does not take into account basic stat fluctuations. deal.";
      saved = 0;
    endif
  endif
else
  return E_INVARG;
endif
this:s_i_n();
for weapon in (doll.wielding)
  weapon:do_unwield(who);
endfor
for armour in (doll.wearing)
  armour:do_remove(who);
endfor
doll.wielding = doll.wearing = {};
for item in (doll.schedule)
  if (item in doll.schedule)
    doll.schedule = setremove(doll.schedule, item);
    {q1, q2, time, q4} = item;
    this.toady:call_verb(q1, q2, {doll, @q4});
  endif
endfor
for item in (doll.claimed_objects)
  valid(`item.claimed_by ! ANY => $nothing') && item:unclaim_for(item.claimed_by);
endfor
doll.paralyzed = 0;
if (n = doll in this.dolls)
  this.dolls = listdelete(this.dolls, n);
  this.pcs = listdelete(this.pcs, n);
endif
doll:write_misc_note("Guilds", (guildb = this.guild_db):guilds_for(who));
guildb:reset_for(who);
puzzles = (puzzle_log = this.puzzle_log):solved(who);
times = {};
for puzzle in (puzzles)
  this:s_i_n();
  times = {@times, puzzle_log:has_solved(who, puzzle)};
endfor
doll:write_misc_note("Puzzles", {puzzles, times});
puzzle_log:reset_for(who);
if (doll == this.object_db.suit_doll)
  return;
elseif (saved)
  this.saved_dolls = {@this.saved_dolls, doll};
  this.death_db.corpse_dolls = setadd(this.death_db.corpse_dolls, doll);
else
  (who == this.owner) || (this.saved_dolls = listappend(setremove(this.saved_dolls, doll), doll));
  this.saved_dolls = {@this.saved_dolls[max(1, $ - 80)..$]};
endif
((doll in this.dolls) || (doll in this.saved_dolls)) || doll:moveto(this.cemetery);
"THX (#105941) - Sat Mar 21, 1998 - Still save macro users' dolls.  Prevent all but G_M from restoring in restore_pc instead.  Stop G_M from getting a doll saved .... waste of quota";
"Profane (#30788) - Mon Jan 11, 1999 - consider pot and att totals when deciding which doll to save.";
"THX (#105941) - Tue Nov  2, 1999 - Changed to temporarily save the doll associated with a corpse.  This doll will be removed by player_corpse:rot() if the player isn't resurrected first.";
"THX (#105941) - Mon Apr 16, 2001 - Put a hack in so that the doll associated with the suit of armour doesn't get into saved_dolls.";
.

@verb #46:"rpg_announce_all_but" this none this
@program #46:rpg_announce_all_but
":rpg_announce_all_but(<OBJ location>, <LIST things not to announce to>, <LIST/STR args to pass to tell>) -> As a regular room:announce_all_but for location, but only spews to non-sleeping players who are not in the exclude list.";
{where, exclude, @text} = args;
if (where in this.silent_rooms)
  return;
endif
this:secure();
"New silent entry detection:";
"if (i = `$list_utils:iassoc_new(task_id(), where.unannounced) ! ANY')";
"  where.unannounced = listdelete(where.unannounced, i);";
"endif";
text = (typeof(text) == LIST) ? text | {text};
exclude = {@exclude, @this.silent_players};
for dude in (where.contents)
  if (dude in connected_players())
    (dude in exclude) || this:playertell(dude, @text);
  elseif ((mon = `dude.tell_forward ! E_PROPNF => {}') && (dude.owner in this.gms))
    exclude = (valid(doll = dude.doll) && doll:cannot_hear()) ? setadd(exclude, dude) | exclude;
    for t in (mon)
      (dude in exclude) || t:tell("  (", dude.name, ") ", @text);
    endfor
  endif
endfor
"THX (#105941) - Mon Feb 15, 1999 - Changed call to where:notify_player() if caller_perms() are trusted.";
"THX (#105941) - Mon Jun 25, 2001 - Added a check for monitored monsters who cannot hear.";
.

@verb #46:"new_sheet" this none this
@program #46:new_sheet
":sheet(who, [about_what]) -- tell player numerical info about WHO's LRPG stats.";
if (!this:trust())
  return E_PERM;
endif
{who, ?what = 0} = args;
doll = this:get_doll(who);
if (doll == $nothing)
  player:tell("No such adventurer.");
  return;
endif
sheet = {};
sheet = {tostr("Player: ", who.name, " (", who, ")  Doll: ", doll, (who in this.gms) ? "  *** GameMaster ***" | "")};
sheet = {@sheet, ""};
suff = "";
s = "                      ";
atts = this.sheet_atts;
h = this.sheet_level;
if (what == "combat")
  atts = atts[1..55];
  h = h[1..55];
elseif (what == "magic")
  atts = atts[56..100];
  h = h[56..100];
elseif (what == "miscl")
  atts = atts[101..$];
  h = h[101..$];
endif
for q in [1..length(atts)]
  this:time_stop();
  z = doll.(atts[q].aliases[1]);
  if (z)
    zs = $string_utils:right(tostr(z), 2);
  else
    zs = "  ";
  endif
  if (suff == "")
    for k in [1..h[q]]
      suff = suff + s;
    endfor
  endif
  skill = this:match_skill(atts[q]);
  if (what == "magic")
    suff = ((((suff + $string_utils:left((length(skill.aliases[1]) < 13) ? skill.aliases[1] | skill.aliases[1][1..12], 13)) + zs) + " (") + $string_utils:right(tostr(doll:total(atts[q])), 3)) + ") ";
  else
    suff = ((((suff + $string_utils:left((length(skill.name) < 13) ? skill.name | skill.name[1..12], 13)) + zs) + " (") + $string_utils:right(tostr(doll:total(atts[q])), 3)) + ") ";
  endif
  if (q == length(atts))
    sheet = {@sheet, suff, ""};
  elseif ((h[q] == -2) && (h[q + 1] == 0))
    sheet = {@sheet, suff, ""};
    suff = "";
  elseif (h[q] != (h[q + 1] - 1))
    sheet = {@sheet, suff};
    suff = "";
  endif
endfor
sheet = {@sheet, tostr(who.name, " hates ", $string_utils:english_list($list_utils:map_prop(doll.aggressor, "name")), ". ", who.psc, " is in ", who.location.name, " (", who.location, ").")};
sheet = {@sheet, tostr("Physical Damage: ", doll.inj, "  Psychic Damage: ", doll.ins, " Experience: ", this:exp(who), (doll.size == 10) ? "" | ("  Size: " + tostr(doll.size)))};
player:tell_lines_suspended(sheet);
.

@verb #46:"parents" this none this
@program #46:parents
{what} = args;
ret = {};
while (valid(what = parent(what)))
  ret = {@ret, what};
endwhile
return ret;
"THX (#105941) - Wed Feb 24, 1999 - This is a bit speedier than $object_utils:ancestors() ... only for one object though.";
.

@verb #46:"is_fast_room" this none this
@program #46:is_fast_room
return $object_utils:isoneof(args[1], this.fast_rooms);
.

@verb #46:"rpg_announce_all_but(old)" this none this
@program #46:rpg_announce_all_but(old)
":rpg_announce_all_but(<OBJ location>, <LIST things not to announce to>, <@(LIST of STRs)/STR args to pass to tell>) -> As a regular room:announce_all_but for location, but only spews to non-sleeping players who are not in the exclude list.";
{where, exclude, @text} = args;
if (where in this.silent_rooms)
  return;
endif
text = (typeof(text) == LIST) ? text | {text};
exclude = {@exclude, @this.silent_players};
for dude in (where.contents)
  if (dude in connected_players())
    (dude in exclude) || dude:tell(@text);
  elseif ((mon = `dude.tell_forward ! E_PROPNF => {}') && (dude.owner in this.gms))
    for t in (mon)
      (dude in exclude) || t:tell("  (", dude.name, ") ", @text);
    endfor
  endif
endfor
for room in (`where.tell_forward ! E_PROPNF => {}')
  for dude in (room.contents)
    if (dude in connected_players())
      (dude in exclude) || dude:tell("  (from ", where.name, ") ", @text);
    endif
  endfor
endfor
"Profane 1-DEC-96 1229PST - s/is_player/connected_players, move exclusion check to conditional, added comment";
"THX (#105941) - Mon Apr 27, 1998 - Commented the Silent 'port stuff.  Let room:announce() handle it.  This verb is for speed.";
.

@verb #46:"playertell_lines" this none this
@program #46:playertell_lines
"Usage: playertell_lines(OBJ player, LIST|STR line(s) of text)";
"Sends all provided lines through this:playertell (to consolidate line-wrapping code and the like).";
this:secure();
{who, lines} = args;
(typeof(lines) != LIST) && (lines = {lines});
for line in (lines)
  this:playertell(who, line);
endfor
.

@verb #46:"train(old)" this none this
@program #46:train(old)
":train(player, attribute-list)";
"Attempt to improve each of player's attributes in 'attribute-list'.";
"=> E_NONE   if player isn't an Illuminatus.";
"=> E_QUOTA  if player has no potential.";
"=> n        where 'n' is the number of courses completed.";
this:secure();
{pc, atts} = args;
if (!valid(doll = this:get_doll(pc)))
  return E_NONE;
elseif (!(pot = doll.pot))
  return E_QUOTA;
endif
total = 0;
for attnam in (atts)
  "oldatt = doll.(attnam);";
  oldatt = doll:get_unmod_att(attnam);
  cost = this.costs[oldatt + 1];
  if ((!pot) || (cost > pot))
    return total;
  else
    doll.(attnam) = oldatt + 1;
    doll.pot = pot = doll.pot - cost;
    total = total + 1;
  endif
endfor
return total;
"Quinn 11-AUG-93 0645: Re-written w/comments; removed messages; return meaningful values; see Academy Room (#146@LMOO) for example interpretation of results.";
"THX 20-FEB-1997 -- Scatter assignment.  Whee.";
"Profane (#30788) - Wed May 19, 1999 - Use :unmod_att";
.

@verb #46:"fixpos(old)" this none this
@program #46:fixpos(old)
"Copied from Irin (#106049):fixpos Thu Mar 12 11:34:15 1998 PST";
{string, fix} = args;
up = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
down = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
allupper = "";
upper = "";
lower = "";
for n in [1..length(fix)]
  if ((i = fix[n] in up) || (i = fix[n] in up))
    upper = upper + up[i];
    lower = lower + down[i];
  else
    upper = upper + fix[n];
    lower = lower + fix[n];
  endif
endfor
allupper = upper + "'S";
upper = upper + "'s";
lower = lower + "'s";
return strsub(strsub(strsub(string, lower, "your", 1), upper, "Your", 1), allupper, "YOUR", 1);
.

@verb #46:"rm_doll(old)" this none this
@program #46:rm_doll(old)
"  rm_doll(OBJ doll) => OBJ pc   may suspend";
"Removes the (pc/doll) pair from this.pcs/this.dolls lists.  Returns";
"the removed RPG character.";
if (!this:trusted(caller_perms()))
  return E_PERM;
endif
doll = args[1];
$command_utils:suspend_if_needed(this.gm_lag);
pos = doll in this.dolls;
if (!pos)
  return $object_utils:isa(doll, this.doll) ? 1 | E_INVARG;
endif
pcs = this.pcs;
this.dolls = listdelete(this.dolls, pos);
this.pcs = listdelete(pcs, pos);
return pcs[pos];
"June 28, 1995 -- Slither, first version";
.

@verb #46:"do_reset" this none this
@program #46:do_reset
"Kill that guest's RPG doll, as appropriate.";
if (parent(caller) != $local.guest)
  return E_PERM;
elseif (valid(gdoll = this:get_doll(caller)))
  {odb, cemetery, loc} = {this.object_db, this.cemetery, caller.location};
  is_rpg = odb:is_rpg(loc);
  "drop RPG items only in dungeons. Nice and tidy";
  for item in (caller.contents)
    if (odb:is_corpse(item))
      item:moveto(this.cinder);
    elseif (odb:is_thing(item))
      dest = (is_rpg && loc:acceptable(item)) ? loc | cemetery;
      item:moveto(dest);
    endif
    this:s_i_f_i_n();
  endfor
  for person in ({@gdoll.aggressor, @valid(loc) ? loc.contents | {}})
    "clear aggressor lists";
    if (valid(pdoll = this:get_doll(person)))
      pdoll.aggressor = setremove(pdoll.aggressor, caller);
    endif
    this:s_i_f_i_n();
  endfor
  "kill the doll";
  this.recycler:_recycle(gdoll);
endif
"THX (#105941) - Mon Nov 27, 2000 - Added to replace the code on $local.guest:do_reset() that was antiquated.";
.

@verb #46:"secure(old)" this none this
@program #46:secure(old)
":secure() => raise E_PERM if we don't like the look of whoever called your verb (i.e., a builtin, or non-GM permed verb called you.)";
if (callers()[2][3] in this.gms)
  return;
  "if (callers()[$][4] == #1)";
  "  \"verb has gone thru huh processing; feature verb.\";";
  "  if ($set_utils:intersection($list_utils:slice(callers(), 3), setremove($list_utils:slice($local.rpg.player_start.banned, 1), $local.rpg.owner)))";
  "    \"Certain banned people like to make cheating/macro FOs. Sorry.\";";
  "    raise(E_PERM, \"RPG Security Violation!\");";
  "  endif";
  "endif";
endif
raise(E_PERM, "RPG Security Violation!");
"Profane 1-APR-97 1708PST -- added bit for command-line verbs";
"Irin Thu Apr  3 12:33:06 1997 PST -- Unceremoniously sent the code for command-line verbs to #46:secure_x().  Thus saving 1 tick.";
.

@verb #46:"is_alive" this none this rx
@program #46:is_alive
{doll} = args;
if (is_player(char = doll.character))
  return char in this.pcs;
endif
return char.alive;
.

@verb #46:"say_audio" this none this rx
@program #46:say_audio
"$local.rpg:say_audio(message [,who, thing, where, excluding whom, highlight whom])";
"announce 'message' with pronoun substitution as if it were just ";
"  $local.rpg:rpg_announce_all($string_utils:pronoun_sub(message, who, thing, where)); ";
"except that who (player), dobj, and iobj get modified messages, with the appropriate use of 'you' instead of their name.";
"who   default player";
"thing default object that called this verb";
"where default who.location";
"excluding default {}";
"highlighting default nobody (otherwise the argument given will see eir messages with `damage highlighting')";
"(This differs from $you:say_action in that only bystanding non-sleeping players will get messages.  This version added to handle audible messages ... blindness or deafness can now be a factor.)";
{msg, ?who = player, ?thing = caller, ?where = who.location, ?excluding = {}, ?highlight = 0} = args;
if (where in this.silent_rooms)
  return;
endif
this:secure();
{s_u, you} = {$string_utils, $you};
if (typeof(msg) == LIST)
  tell = "";
  for x in (msg)
    tell = tell + ((typeof(x) == STR) ? x | x[random($)]);
  endfor
else
  tell = msg;
endif
spew = {tell, tell, tell};
if (i = highlight in {who, dobj, iobj})
  doll = this:get_doll(highlight);
  options = this.rpg_options;
  {start, finish} = options:get(doll.rpg_options, "highlighting") ? options:get(doll.rpg_options, "highlights") || options.highlights_default | {"", ""};
  spew[i] = tostr(start, tell, finish);
endif
this:playertell(who, this:pronoun_sub(this:fixpos(spew[1], "%n"), you, thing, where));
exclude = {dobj, who, iobj, @excluding};
for t in (where.contents)
  if ((t in exclude) || (!valid(tdoll = this:get_doll(t))))
  elseif (tdoll:cannot_hear())
    exclude = {@exclude, t};
  elseif (tdoll:cannot_see() || tdoll:cannot_resolve())
    exclude = {@exclude, t};
    blind = {@blind, t};
  endif
endfor
this:rpg_announce_all_but(where, exclude, this:pronoun_sub(tell, who, thing, where));
if (blind)
  {dstow, istow} = {dobj, iobj};
  ((dobj in this.pcs) || is_player(dobj)) && (dobj = this.somebody);
  this:rpg_announce_all_but(where, $set_utils:diff(where.contents, blind), this:pronoun_sub(tell, this.someone, thing, where));
  {dobj, iobj} = {dstow, istow};
endif
if ((`(dobj in this.pcs) || is_player(dobj) ! E_TYPE, E_INVIND' && (!(dobj in {who, @excluding}))) && (dobj.location == where))
  ddoll = this:get_doll(dobj);
  if (valid(ddoll) && ddoll:cannot_hear())
  else
    {dstow, istow} = {dobj, iobj};
    if (valid(ddoll) && (ddoll:cannot_see() || ddoll:cannot_resolve()))
      active = this.someone;
      ((iobj in this.pcs) || is_player(iobj)) && (iobj = this.somebody);
    else
      active = who;
    endif
    dobj = you;
    this:playertell(dstow, this:pronoun_sub(this:fixpos(spew[2], "%d"), active, thing, where));
    {dobj, iobj} = {dstow, istow};
  endif
endif
if ((`is_player(iobj) ! E_TYPE, E_INVIND' && (!(iobj in {who, dobj, @excluding}))) && (iobj.location == where))
  idoll = this:get_doll(iobj);
  if (valid(idoll) && idoll:cannot_hear())
  else
    {dstow, istow} = {dobj, iobj};
    if (valid(idoll) && (idoll:cannot_see() || idoll:cannot_resolve()))
      active = this.someone;
      ((dobj in this.pcs) || is_player(dobj)) && (dobj = this.somebody);
    else
      active = who;
    endif
    iobj = you;
    this:playertell(istow, this:pronoun_sub(this:fixpos(spew[3], "%i"), active, thing, where));
    {dobj, iobj} = {dstow, istow};
  endif
endif
"THX (#105941) - Tue Jun  5, 2001 - Added.";
.

@verb #46:"playershow" this none this
@program #46:playershow
":playershow(OBJ who, STR or STRs @msg)  -   calls notify(who, tostr(@msg)) if who is a player and if who is in a descendant of $local.rpg.dungeon.";
(caller == this) || this:secure();
{who, @msg} = args;
where = who.location;
if (valid(doll = this:get_doll(who)) && doll:cannot_see())
  return;
elseif (is_player(who) && this:is_fast_room(where))
  msg = strsub(tostr(@msg), "xch_mudtext", "xch mudtext");
  if ((ll = who.linelen) > 0)
    for line in ($player:linesplit(msg, ll))
      where:notify_player(who, line);
    endfor
  else
    where:notify_player(who, msg);
  endif
else
  who:tell(@msg);
endif
"Mooshie (#106469) - Sat Oct  9, 1999 - Checking if 'caller == this' first should save indexing ticks for the many calls routed through :rpg_announce* verbs and :playertell_lines.";
.

@verb #46:"playertell" this none this
@program #46:playertell
":playertell(OBJ who, STR or STRs @msg)  -   calls notify(who, tostr(@msg)) if who is a player and if who is in a descendant of $local.rpg.dungeon.";
(caller == this) || this:secure();
{who, @msg} = args;
where = who.location;
if (is_player(who) && this:is_fast_room(where))
  msg = strsub(tostr(@msg), "xch_mudtext", "xch mudtext");
  if ((ll = who.linelen) > 0)
    for line in ($player:linesplit(msg, ll))
      where:notify_player(who, line);
    endfor
  else
    where:notify_player(who, msg);
  endif
else
  who:tell(@msg);
endif
"Mooshie (#106469) - Sat Oct  9, 1999 - Checking if 'caller == this' first should save indexing ticks for the many calls routed through :rpg_announce* verbs and :playertell_lines.";
.

@verb #46:"rpg_show_all_but" this none this
@program #46:rpg_show_all_but
":rpg_announce_all_but(<OBJ location>, <LIST things not to announce to>, <LIST/STR args to pass to tell>) -> As a regular room:announce_all_but for location, but only spews to non-sleeping players who are not in the exclude list.";
{where, exclude, @text} = args;
if (where in this.silent_rooms)
  return;
endif
this:secure();
"New silent entry detection:";
"if (i = `$list_utils:iassoc_new(task_id(), where.unannounced) ! ANY')";
"  where.unannounced = listdelete(where.unannounced, i);";
"endif";
text = (typeof(text) == LIST) ? text | {text};
exclude = {@exclude, @this.silent_players};
for dude in (where.contents)
  if (dude in connected_players())
    (dude in exclude) || this:playertell(dude, @text);
  elseif ((mon = `dude.tell_forward ! E_PROPNF => {}') && (dude.owner in this.gms))
    exclude = (valid(doll = dude.doll) && doll:cannot_see()) ? setadd(exclude, dude) | exclude;
    for t in (mon)
      (dude in exclude) || t:tell("  (", dude.name, ") ", @text);
    endfor
  endif
endfor
"THX (#105941) - Mon Feb 15, 1999 - Changed call to where:notify_player() if caller_perms() are trusted.";
"THX (#105941) - Mon Jun 25, 2001 - Added a check for monitored monsters who cannot see.";
.

@verb #46:"rpg_show*_all" this none this
@program #46:rpg_show_all
":rpg_show(<OBJ location>, <LIST/STR args to pass to tell>) -> As a regular room:show for location, but only spews to non-sleeping players.";
{where, @string} = args;
this:secure();
this:rpg_show_all_but(where, (verb == "rpg_show") ? {player} | {}, @string);
"THX (#105941) - Sun Jun 24, 2001 - Changed code to send to this:rpg_show_all_but() to save on maintaining identical code.";
.

@verb #46:"playerannounce" this none this
@program #46:playerannounce
":playerannounce(OBJ who, STR or STRs @msg)  -   calls notify(who, tostr(@msg)) if who is a player and if who is in a descendant of $local.rpg.dungeon.  Checks doll:cannot_hear() before proceeding.";
(caller == this) || this:secure();
{who, @msg} = args;
where = who.location;
if (valid(doll = this:get_doll(who)) && doll:cannot_hear())
  return;
elseif (is_player(who) && this:is_fast_room(where))
  msg = strsub(tostr(@msg), "xch_mudtext", "xch mudtext");
  if ((ll = who.linelen) > 0)
    for line in ($player:linesplit(msg, ll))
      where:notify_player(who, line);
    endfor
  else
    where:notify_player(who, msg);
  endif
else
  who:tell(@msg);
endif
"THX (#105941) - Mon Jul  2, 2001 - Added.";
.

@verb #46:"erase_all_saved_dolls_for" this none this
@program #46:erase_all_saved_dolls_for
"Removed all the back up voodoo dolls of `who' from this.saved_dolls.";
"Yeah, yeah, this scenario is rare, but possible.";
(rpg = $local.rpg):secure();
if (!(caller_perms() in this.grand_masters))
  return E_PERM;
else
  {who} = args;
  for x in (this.saved_dolls)
    rpg:s_i_f_i_n();
    if (`x.character ! E_PROPNF => $nothing' == who)
      this.saved_dolls = setremove(this.saved_dolls, x);
      this.dolls = setremove(this.dolls, x);
      "We also recycle the doll(s).";
      x:moveto(this.cemetery);
    endif
  endfor
endif
"Hydros (#106189) - Mon Mar 7, 2005 - Added.  Currently for use with Alaria (#35896):restore.";
.

@verb #46:"wizmove" this none this rxd #2487
@program #46:wizmove
"Copied from Hydros (#106189):wmove at Tue Apr 12 12:11:30 2005 PDT";
"A wizardly move for His Eminence's RPG.  Only specific objects, and specific verbs on those objects, are approved to call this, and these should be rare.";
"NOTE to GameMasters: to access this verb, contact Grand_Master, (or an incarnation thereof). This wizardly code is not to be taken lightly and His Eminence frowns on abuse of forced movement code--i.e., you taste crunchy with ketchup.";
"NB: If the teleported object is a player, e will receive RPG exitshock unless, after the move, you :announce eir name to the room, (e.g. `<moved.name> teleports in.').";
(rpg = $local.rpg):secure();
{moved, newloc} = args;
if (!rpg.object_db:is_rpg_room(moved.location))
  "Only callable while `moved' target is within the RPG.";
  return E_PERM;
else
  "Only specific verbs on specific objects can call this movement into play.";
  if ((x = $list_utils:assoc(caller, rpg.approved_wizmoves, 1)) && (callers()[1][2] == x[2]))
    "If move() fails for any reason, we simply eject them from the RPG (:eject_basic() being owned by Heathcliff somewhere down the line.)";
    `move(moved, newloc) ! E_RECMOVE, E_NACC => moved.location:_eject(moved)';
  else
    return E_PERM;
  endif
endif
"Hydros (#106189) - Tue Apr 12, 2005 - Added, soon to be owned by Nosredna (#2487).";
.

@verb #46:"respawn_non_pkp_pc" this none this
@program #46:respawn_non_pkp_pc
"Instantly respawn a non-PKP PC in eir .home. A perk for volunteering into the playerkilling realm.";
this:secure();
{doll} = args;
who = doll.character;
loc = who.location;
for item in ({@doll.aggressor, @valid(loc) ? loc.contents | {}})
  this:s_i_f_i_n();
  if (valid(them = this:get_doll(item)))
    them.aggressor = setremove(them.aggressor, who);
  endif
endfor
for t in (doll.armour_effects)
  if (parent(t) == this.doll)
    doll:remove_teammate(t);
    t:remove_teammate(doll);
  endif
endfor
doll.inj = 50 + random(25);
doll.ins = 50 + random(25);
doll.fat = 50 + random(25);
tot = 0;
costs = this.costs;
for att in (this.attributes)
  val = doll.(att.aliases[1]);
  for n in [1..min(val, 25)]
    tot = tot + costs[n];
  endfor
endfor
{lop, pop} = {600, 2};
if (tot > lop)
  for att in (this.attributes)
    a = att.aliases[1];
    if ((tot > (2 * lop)) || (random(pop) == 2))
      doll.(a) = min(max(doll.(a) - 1, 12 + random(5)), doll.(a));
    endif
  endfor
endif
if (doll.app > 11)
  doll.app = doll.app - 1;
endif
count = 0;
countlist = {};
for x in ($list_utils:randomly_permute(who.contents))
  if (this.object_db:is_thing(x))
    count = count + 1;
    if (`who.location:acceptable(x) ! ANY => 0')
      `x:moveto(who.location) ! ANY';
      countlist = setadd(countlist, x.name);
    endif
    if (count >= 3)
      break;
    endif
  endif
endfor
this.magic_db:teleport(doll, who.home, (rpcm = this.death_db.respawn_pc_msgs)[1], rpcm[2], rpcm[3], rpcm[4]);
if (countlist != {})
  who:tell(("You dropped your " + $string_utils:english_list(countlist)) + " where you died.");
endif
"Copied from Hydros (#106189):respawn_non_pkp_pc at Sun Oct 16 14:18:30 2005 PDT";
.

"***finished***