Dump of #19051 (Generic Skill Object)

@create $root_class named Generic Skill Object:Generic,Skill,Object
@prop #19051."dependant" {} r
;;#19051.("dependant") = {{}, {}}
@prop #19051."learn" 10 r
@prop #19051."encumbrance" 0 r
@prop #19051."insanity" 0 r
@prop #19051."injury" 0 r
@prop #19051."fatigue" 0 r
@prop #19051."dep_names" {} r
@prop #19051."neg_deps" {} r
@prop #19051."neg_dep_names" {} r
@prop #19051."max_level" 25 r
@prop #19051."caps" {} r
@prop #19051."cap_names" {} r
@prop #19051."cap_boost_mult" 1 r
@prop #19051."enc_ins_inj_fat" {} rc
;;#19051.("enc_ins_inj_fat") = {0, 0, 0, 0}
@prop #19051."improve_learn_ok" 1 rc
@prop #19051."improve_task" 264748148 r
"#19051.("queue") => E_PERM (Permission denied)
@prop #19051."move_dependent" 0 r
"#19051.("key") => E_PERM (Permission denied)
;;#19051.("aliases") = {"Generic", "Skill", "Object"}
;;#19051.("description") = "An indicator of skill in some nameless area."
;;#19051.("object_size") = {15902, 1141286561}

@verb #19051:"resolve" this none this
@program #19051:resolve
":resolve(<OBJ character>, <NUM modifier to resolve>, [FLAG no_improve], [OBJ permissions]) => NUM result of skill roll for character, with modfier added on.";
"The no_improve flag, if given and true, prevents the doll's skill improvement routine from being called at all.";
"The permissions argument overrides the regular perm check for gm probationary status in deciding whether or not to call the doll's improve routine.";
if (caller_perms() in (rpg = $local.rpg).gms)
  {char, mod, ?no_imp = 0, ?perms = caller_perms()} = args;
  if (valid(doll = rpg:get_doll(char)))
    no_imp = no_imp || (valid(doll.duelee) && (`rpg:get_doll(doll.duelee).duelee ! E_INVIND' == doll.character));
    res = rpg:roll(doll:total(this) + mod) - (pen = this:penalty(doll));
    res = this:slowness_mod(res - this:stinkcloud_pen(doll), doll);
    ic = this:slowness_mod(max(20, random(180) - 60), doll) - pen;
    if (no_imp)
      "... don't call improve ...";
    else
      if ((res > -20) && (res < ic))
        (perms in rpg.probation) || this:check_improve(doll);
      endif
      this:track_usage();
    endif
    doll.last_action = time();
    return res;
  else
    return -200;
  endif
else
  return 100 - random(200);
  "Return some random nonsensical number, just so prospective GMs can practice with resolves and not get E_TYPEs from an E_PERM.";
endif
.

@verb #19051:"moveto" this none this
@program #19051:moveto
{where} = args;
if ($local.rpg:is_grandmaster(caller_perms()) || caller_perms().wizard)
  return pass(where);
else
  return E_PERM;
endif
.

@verb #19051:"penalty" this none this
@program #19051:penalty
{doll} = args;
if (caller == this)
  return ((((4 + (this.injury * doll.inj)) + (this.insanity * doll.ins)) + (this.fatigue * doll.fat)) + ((this.encumbrance * doll:encumbrance()) / 3)) / min(25, doll.end || 15);
endif
return 0;
"THX (#105941) - Mon Mar 29, 1999 - subst /10/(doll.end || 15)/2";
.

@verb #19051:"property_name" this none this
@program #19051:property_name
"Return the corresponding property name on $local.rpg.doll.";
return this.aliases[1];
.

@verb #19051:"initialize" this none this rx
@program #19051:initialize
if ((caller == this) || $perm_utils:controls(caller_perms(), this))
  this:moveto($local.rpg.skills);
  $quota_utils:object_bytes(this);
  return pass(@args);
else
  return E_PERM;
endif
"Profane 13-DEC-95 1126 EST -- $quota:utils:object_size.";
.

@verb #19051:"recycle" this none this rx
@program #19051:recycle
if ((caller == this) || $perm_utils:controls(caller_perms(), this))
  propname = this:property_name();
  delete_property($local.rpg.doll, propname);
  delete_property($local.rpg.skills, propname);
  return pass(@args);
else
  return E_PERM;
endif
.

@verb #19051:"description" this none this
@program #19051:description
"Return the description, plus a line detailing which skills affect this one.";
deps = this.dependant;
atts = deps[1];
skills = deps[2];
if (atts || skills)
  depstr = (((this:title() + " is a skill directly influenced by ") + (atts ? "the attributes " + $string_utils:title_list(atts) | "")) + (skills ? ((atts ? ", and " | "") + "the skill(s) ") + $string_utils:title_list(skills) | "")) + ".";
else
  depstr = this:title() + " is a basic attribute.";
endif
return {@(typeof(base = pass(@args)) == LIST) ? base | {base}, depstr};
"DR 10-APR-94 -- Tweaked the spacing in 'the skills'.";
.

@verb #19051:"tell_stats" this none this
@program #19051:tell_stats
stats = properties($local.RPG.skill_object);
player:tell($string_utils:centre(this.name, 40, "-"));
dep = this.dependant;
player:tell("Dependant Attributes: ", $string_utils:nn(dep[1], "", "None"));
player:tell("Dependant     Skills: ", $string_utils:nn(dep[2], "", "None"));
player:tell("");
for pn in (setremove(stats, "dependant"))
  player:tell($string_utils:left(pn, 18), ": ", $string_utils:print(this.(pn)));
endfor
player:tell($string_utils:space(40, "-"));
.

@verb #19051:"stinkcloud_pen*alty" this none this
@program #19051:stinkcloud_penalty
":stinkcloud_penalty(<OBJ doll>) => NUM penalty that doll should have to a resolve roll for being under the influence of stinkcloud";
{doll} = args;
rpg = $local.rpg;
if ((rpg.magic_db.sc_combat_effect in doll.view_effects) && (data = doll:read_misc_note("stinkcloud")))
  if (caller != this)
    "Return some random nonsensical number, just so prospective GMs can practice with resolves and not get E_TYPEs from an E_PERM.";
    return 99 - random(200);
  endif
  {qual, time} = data;
  qual = (qual > 0) ? qual | 0;
  cloud_pen = min(max((time - time()) + (qual * toint(sqrt(tofloat(qual)))), 1), qual);
  if ((rpg.skills.shock:resolve(doll, -cloud_pen) >= 0) || ((time() - time) > 1200))
    doll:erase_misc_note("stinkcloud");
    rpg.magic_db.sc_combat_effect:remove(doll);
    rpg:playertell(doll.character, "You have finally recovered from the effects of the stinking cloud.");
    cloud_pen = 0;
  else
    if (random(4) == 1)
      rpg:playertell(doll.character, "You are still reeling from the effects of the stinking cloud. . .");
      rpg:say_action("%N %<hacks> and %<wheezes>.", doll.character);
    endif
  endif
  return cloud_pen;
endif
return 0;
"Irin Mon Sep  9 17:15:12 1996 PDT -- replaced $math_utils:sqrt() with sqrt().  Set max penalty to equal quality.";
"THX 18-FEB-1997 - tossed in scatters where appropriate to kill list indexings.  Cleaned up a bit.";
"Profane (#30788) - Tue Jan 13, 1998 - simplify security";
"THX (#105941) - Wed Jun 13, 2001 - Put security check inside the check for stinkcloud presence and checked for stinkcloud effect in doll.view_effects before doll:read_misc_note(\"stinkcloud\").  This saves ~100 ticks for every single resolve call!  But we should still get rid of this hack.";
.

@verb #19051:"fake_resolve pseudoresolve" this none this
@program #19051:fake_resolve
":fake_resolve(<OBJ character>, <NUM modifier to resolve>, [NUM skill score,LIST dependant, NUM learn, NUM encumbrance pen, NUM insanity pen, NUM injury pen, NUM fatigue pen]) => As a regular resolve, but allows you to pass parameters for various penalty bits.";
if (!$local.rpg:trusted(caller_perms()))
  return 100 - random(200);
elseif (!valid(doll = $local.rpg:get_doll(args[1])))
  return E_INVARG;
else
  mod = args[2];
  l = length(args);
  score = (l > 2) ? args[3] | doll.(this:property_name());
  dependant = (l > 3) ? args[4] | this.dependant;
  learn = (l > 4) ? args[5] | this.learn;
  insanity = (l > 5) ? args[6] | this.insanity;
  injury = (l > 6) ? args[7] | this.injury;
  fatigue = (l > 7) ? args[8] | this.fatigue;
  total = score;
  for dep_att in (dependant[1])
    total = total + doll.(dep_att.aliases[1]);
  endfor
  for dep_att in (dependant[2])
    total = total + doll:total(dep_att);
  endfor
  pen = ((((4 + (injury * doll.inj)) + (insanity * doll.ins)) + (fatigue * doll.fat)) + ((encumbrance * doll:encumbrance()) / 10)) / 10;
  res = $local.rpg:roll((total + mod) - pen);
  res = res - this:stinkcloud_pen(doll);
  doll.last_action = time();
  return res;
endif
.

@verb #19051:"cap" this none this
@program #19051:cap
"#19051:cap(doll) => returns maximum value that the skill can have, for purposes of $local.rpg.doll:improve.";
$local.rpg:secure();
if (cn = this.cap_names)
  {doll} = args;
  top = 0;
  for c in (cn)
    top = max(top, doll.(c));
  endfor
  return top;
else
  return this.max_level;
endif
"Each skill has a list of cap names.  These are compiled by #34595:update_skills, when skills are changed.  Each skill has an individual cap, and each one depends on either its own cap, or if it has none, the caps of all skills higher on it in the hierarchy.  Thus, melee is based on CAPmelee, while rapier is capped by CAPsword and CAPweap1.  Somebody come up with a less obscure method.  Please! ;) -- Irin.";
.

@verb #19051:"improve_learn_ok" this none this
@program #19051:improve_learn_ok
return this.(verb);
.

@verb #19051:"slowness_mod" this none this
@program #19051:slowness_mod
"Makes it more difficult to improve if you're hasted. Easier of slowed.";
"I realize the code is a bit of an eye-sore. So, what it does is take the first argument, `res' and will halve it for a slowness of 2 and make it half again its original value for a slowness of 18. Those are the min and max values and everything in-between is proportionate. A slowness of 10 would be unchanged.";
{res, doll} = args;
if (caller == this)
  return toint(tofloat(res) * doll.slowness_mod);
else
  return res;
endif
"Mooshie (#106469) - Fri Dec 26, 1997 - Added. I hope I never have to look back on this and wonder how I was doing it.";
"Mooshie (#106469) - Thu Feb  5, 1998 - Faster version. :set_att now hooks .slowness modifications and sets .slowness_mod appropriately.";
.

@verb #19051:"check_improve" this none this
@program #19051:check_improve
":check_improve(OBJ doll)";
{doll} = args;
(rpg = $local.rpg):secure();
who = doll.character;
if ((`idle_seconds(who) ! ANY => -1' < 0) && (!(who.owner in rpg.gms)))
  raise(E_PERM, "No skill improvement for disconnected players.");
elseif (this.move_dependent && doll:stymied())
  return;
endif
root = $code_utils:verb_loc();
root.queue = {@root.queue, {doll, this, callers()}};
"Okay, we're basically checking if the improve_task has ended, or suspended in someone else's queue here.  I.e., some idiot player's :tell verb.";
if ((!$code_utils:task_valid(root.improve_task)) || (`task_stack(root.improve_task) ! ANY' == E_PERM))
  fork z (0)
    root:do_improve();
  endfork
  root.improve_task = z;
endif
.

@verb #19051:"do_improve" this none this
@program #19051:do_improve
":do_improve()";
(rpg = $local.rpg):secure();
root = $code_utils:verb_loc();
while (root.queue && (root.improve_task == task_id()))
  {doll, skill, callers} = root.queue[1];
  root.queue = root.queue[2..$];
  if (`doll.(skill.aliases[1]) || 1 ! ANY')
    doll:improve(skill, 0, callers);
  endif
  rpg:s_i_f_i_n();
endwhile
.

@verb #19051:"track_usage" this none this
@program #19051:track_usage
return;
.

@verb #19051:"penalty_trusted" this none this
@program #19051:penalty_trusted
{doll} = args;
$local.rpg:secure();
return this:penalty(doll);
.

@verb #19051:"stinkcloud_pen(old)" this none this
@program #19051:stinkcloud_pen(old)
":stinkcloud_penalty(<OBJ doll>) => NUM penalty that doll should have to a resolve roll for being under the influence of stinkcloud";
if (caller != this)
  "Return some random nonsensical number, just so prospective GMs can practice with resolves and not get E_TYPEs from an E_PERM.";
  return 99 - random(200);
else
  {doll} = args;
  rpg = $local.rpg;
  if (data = doll:read_misc_note("stinkcloud"))
    {qual, time} = data;
    qual = (qual > 0) ? qual | 0;
    cloud_pen = min(max((time - time()) + (qual * toint(sqrt(tofloat(qual)))), 1), qual);
    if ((rpg.skills.shock:resolve(doll, -cloud_pen) >= 0) || ((time() - time) > 1200))
      doll:erase_misc_note("stinkcloud");
      rpg.magic_db.sc_combat_effect:remove(doll);
      rpg:playertell(doll.character, "You have finally recovered from the effects of the stinking cloud.");
      cloud_pen = 0;
    else
      if (random(4) == 1)
        rpg:playertell(doll.character, "You are still reeling from the effects of the stinking cloud. . .");
        rpg:say_action("%N %<hacks> and %<wheezes>.", doll.character);
      endif
    endif
    return cloud_pen;
  endif
endif
"Irin Mon Sep  9 17:15:12 1996 PDT -- replaced $math_utils:sqrt() with sqrt().  Set max penalty to equal quality.";
"THX1138 18-FEB-1997 - tossed in scatters where appropriate to kill list indexings.  Cleaned up a bit.";
"Profane (#30788) - Tue Jan 13, 1998 - simplify security";
.

"***finished***