Dump of #59933 (Generic Weapon Spell Focus)

@create #82 named Generic Weapon Spell Focus:Generic Weapon Spell Focus,weapon spell focus,spell focus,focus
@prop #59933."default_cast_msg" "%N %<waves> %p arms and %<mutters> weird syllables." rc
@prop #59933."db" #328 r
"#59933.("bonus") => E_PERM (Permission denied)
"#59933.("visible_spells") => E_PERM (Permission denied)
"#59933.("no_imp") => E_PERM (Permission denied)
"#59933.("dodgable") => E_PERM (Permission denied)
"#59933.("parryable") => E_PERM (Permission denied)
"#59933.("slowness") => E_PERM (Permission denied)
"#59933.("parry") => E_PERM (Permission denied)
"#59933.("attack") => E_PERM (Permission denied)
"#59933.("pen") => E_PERM (Permission denied)
"#59933.("dam") => E_PERM (Permission denied)
"#59933.("skill") => E_PERM (Permission denied)
;;#59933.("pierce") = 0
"#59933.("max_str_bonus") => E_PERM (Permission denied)
"#59933.("can_degrade") => E_PERM (Permission denied)
"#59933.("track_usage") => E_PERM (Permission denied)
;;#59933.("manufactured") = 820783482
;;#59933.("worth") = -1
;;#59933.("condition") = 100
;;#59933.("use_spell_msg_db") = 1
;;#59933.("odrop_failed_msg") = "%<tries> to drop %t but fails!"
;;#59933.("odrop_succeeded_msg") = "%<drops> %t."
;;#59933.("otake_succeeded_msg") = "%<picks> up %t."
"#59933.("key") => E_PERM (Permission denied)
;;#59933.("aliases") = {"Generic Weapon Spell Focus", "weapon spell focus", "spell focus", "focus"}
;;#59933.("description") = "A generic instrument of destuction, albiet one crackling with magickal potential."
;;#59933.("object_size") = {19508, 1141286561}

@verb #59933:"check_casting" this none this
@program #59933:check_casting
":check_casting(OBJ caster character, OBJ target character, OBJ spell) => boolean Can caster manage to cast spell?";
if (!(rpg = $local.rpg):trusted(caller_perms()))
  return E_PERM;
elseif (this.location != (by = args[1]))
  rpg:playertell(by, "You don't have the ", this.name, ".");
elseif (!valid(doll = rpg:get_doll(by)))
  rpg:playertell(by, "You don't know how to cast spells. . . perhaps the Bovine Illuminati could help.");
elseif (!(this in doll.wielding))
  rpg:playertell(by, "You must wield the ", this.name, " first.");
elseif ((!`caller.no_know ! E_PROPNF => 0') && (doll.(args[3].aliases[1]) <= 0))
  rpg:playertell(by, "You don't know that spell.");
elseif (p = doll:cannot_cast())
  return rpg:playertell(by, (typeof(p) == STR) ? p | "You're paralyzed and find casting spells impossible.");
elseif (!doll.hands)
  rpg:playertell(by, "My god! You have no hands and must cast! What a shame that you can't do that.");
elseif (!this:check_casting_location(by))
  rpg:playertell(by, "The etheric flow of magick seems to be cut off to your location; you are unable to cast spells.");
elseif (`player.location:sleeping(player) ! E_VERBNF, E_PERM')
  rpg:playertell(player, "You dream of being a great magus.");
elseif (!doll:long_enough())
  rpg:playertell(by, ((("Your " + this.name) + " fizzles due to lack of energy.  It will take at least ") + tostr(max(1, (doll.last_attack - time()) + rpg.gm_lag))) + " seconds to recover.");
  kill_task(task_id());
elseif (is_player(by) && (`idle_seconds(by) ! ANY => 1000' > 300))
  rpg:playertell(by, "Try casting spells while you're actually at the keyboard, eh?");
  kill_task(task_id());
elseif (((length(callers()) > 1) && (!rpg:trusted(callers()[2][3]))) && (callers()[2][1..2] != {$match_utils, "match_verb"}))
  raise(E_PERM);
else
  doll.last_attack = time();
  return 1;
endif
"Profane 22-DEC-95 2000EST -- Added.";
"Irin Thu Feb  6 19:15:45 1997 PST -- Added idle check.  Wonder where the heck it went.";
"Profane 25-APR-97 1402PST -- added location check";
"Profane 18-MAY-97 1521PDT -- disallow programmtic spell calls by non-trusted.";
"Profane (#30788) - Sun Oct 19 08:49:42 1997 PDT - added check for having hands";
"Profane (#30788) - Tue Mar 20, 2001 - Allow calls via $match_utils:match_verb so e.g. `firebolt blah with 2nd blah' will work.";
.

@verb #59933:"check_live_target" this none this
@program #59933:check_live_target
":check_live_target(OBJ caster character, [OBJ target, OBJ spell, NUM boolean peaceful]) => doll of target || $nothing.  For spells that want one living target.";
return this.db:(verb)(@args);
"THX (#105941) - Wed May 10, 2000 - Moved the guts of this verb to $local.rpg.magic_db.";
.

@verb #59933:"check_object_target" this none this
@program #59933:check_object_target
":check_object_target(OBJ caster character, [STR target]) => OBJ target. Designed for spells who take an inanimate object as a target.";
{by, ?tstr = dobjstr, @rest} = args;
(rpg = $local.rpg):secure();
stuff = rpg:trusted_verb(where = by.location, "visible") ? where:visible() | where.contents;
target = $match_utils:match(tstr, stuff);
if ($command_utils:object_match_failed(target, tstr))
elseif (!(where in {tloc = target.location, `tloc.location ! ANY => tloc'}))
  rpg:playertell(player, "You can't affect ", target.name, " from where you are.");
elseif (((tloc != where) && rpg:trusted_verb(tloc, "visible")) && (!(target in tloc:visible())))
  rpg:playertell(player, "The ", target:title(), " seems to be protected by its containment.");
elseif (((!rpg.object_db:is_monster(target)) && (!$object_utils:isa(target, rpg.thing))) && (!((target.owner in rpg.gms) && $object_utils:has_verb(target, "receive_" + callers()[1][2]))))
  rpg:playertell(player, "My God!  ", target:titlec(), " seems to be immune to Illuminati magick.");
else
  return target;
endif
return $nothing;
"Profane 22-DEC-95 2014EST -- Added.";
"THX 20-MAR-1997 -- Added a hook to let gms hide equipment in containers and cleaned up a bit.";
.

@verb #59933:"check_multiple_live_targets" this none this
@program #59933:check_multiple_live_targets
":check_multiple_live_targets(OBJ caster character, [STR target]) => LIST of dolls. For spells that want to affect more than one living character at once.";
if ((rpg = $local.rpg):trusted(caller_perms()))
  {by, ?tstr = dobjstr, ?spell = $nothing, ?peaceful = 0} = args;
  words = setremove($list_utils:remove_duplicates($string_utils:words(tstr)), "and");
  targets = {};
  if ((!words) || (words == {"all"}))
    targs = setremove(rpg:find_chars(by.location)[1], by);
    targs = setremove(targs, rpg:get_doll(by).mounted);
    for dude in (targs)
      if (valid(arf = this:check_live_target(by, dude)))
        targets = setadd(targets, arf);
      endif
    endfor
  else
    for try_ in (words)
      try_ = (try_[length(try_)] == ",") ? try_[1..length(try_) - 1] | try_;
      who = this:check_live_target(by, try_, spell, peaceful);
      targets = valid(who) ? setadd(targets, who) | targets;
    endfor
  endif
  if (!targets)
    rpg:playertell(by, "Erm, you've managed to pick no living targets.");
  endif
  return targets;
else
  return E_PERM;
endif
"Profane 22-DEC-95 2022EST -- Added";
"Profane (#30788) - Wed Jan 10, 2001 - `all' does not include your mount.";
.

@verb #59933:"casting_msg" this none this rx
@program #59933:casting_msg
":casting_msg(OBJ caster character, OBJ spell || STR property name, OBJ target) => STR message for casting spell.";
"Targets can be characters, LRPG objects, or lists of characters. We check to see if we've been passed a character's doll, and convert target to the character in that case, otherwise leave it alone.  Lists will get converted to title_list's down below";
{by, spell, target} = args;
target = (typeof(target) != LIST) ? valid(`target.character ! E_PROPNF, E_INVIND') ? target.character | target | target;
spell = (typeof(spell) == OBJ) ? spell.aliases[1] | spell;
if ($local.rpg:is_monster(by))
  if (by in {target, target.character})
    mesgs = ((((by.(spell + "_cast_self_msg") || by.(spell + "_cast_msg")) || by.default_self_cast_msg) || by.default_cast_msg) || this.default_self_cast_msg) || this.default_cast_msg;
  else
    mesgs = (by.(spell + "_cast_msg") || by.default_cast_msg) || this.default_cast_msg;
  endif
else
  if (by in {target, target.character})
    mesgs = ((this.(spell + "_cast_self_msg") || this.(spell + "_cast_msg")) || this.default_self_cast_msg) || this.default_cast_msg;
  else
    mesgs = this.(spell + "_cast_msg") || this.default_cast_msg;
  endif
endif
msg = (typeof(mesgs) == LIST) ? $list_utils:random_element(mesgs) | mesgs;
msg = strsub(msg, "%[focus]", this.name);
if (typeof(target) != LIST)
  names = target.name;
else
  dudes = `$list_utils:map_prop(target, "character") ! E_TYPE, E_PROPNF => target';
  names = $string_utils:title_list(dudes);
endif
msg = strsub(msg, "%[target]", names);
return msg;
"Profane 22-DEC-95 2026EST -- Added";
"StarDancer 24-DEC-95 -- removed call to pronoun_sub, 'cause it's in :say_action already.";
"StarDancer 24-DEC-95 -- added code ta 'low for lists a strings inna `_msg' prop.";
"StarDancer 31-JUL-96 -- replaced call to $string_utils:substitute with strsub, and set dobj = target in :spell";
.

@verb #59933:"check_casting_loc*ation" this none this
@program #59933:check_casting_location
":check_casting_location([OBJ caster character]) => return true if the caster is an acceptable location to cast spells (i.e. in an RPG-type room.)";
{?who = player} = args;
return $local.rpg:is_rpg_room(who.location);
.

@verb #59933:"may_cast" this none this
@program #59933:may_cast
":may_cast(doll, spell) => Allowed to cast the spell.";
{doll, spell} = args;
if (this in `doll.character.gaglist ! E_PROPNF, E_PERM => {}')
  return 0;
endif
return 1;
.

@verb #59933:"pay_cost" this none this
@program #59933:pay_cost
":pay_cost(doll, spell, skillobj, costdiv) => Pay the cost of casting a spell.  Separated from :spell to shrink the thing down a bit, and so we don have to maintain so many copies of :spell. -- Irin";
{doll, spell, skill, cost} = args;
if (caller == this)
  doll:check_ins(skill.sane / cost);
  "args[1]:check_ins(args[3].sane / args[4]);";
endif
.

@verb #59933:"bonus" this none this
@program #59933:bonus
":bonus(by, target, spell) => bonus of this foci on casting.";
return this.(verb);
.

@verb #59933:"sing_spell" this none this
@program #59933:sing_spell
{by, spell, target} = args;
songs = `this.(spell + "_lyrics") ! ANY => 0';
if (songs && (song = songs[random($)]))
  {rpg, loc} = {$local.rpg, by.location};
  for dude in (loc)
    if (is_player(dude) && rpg.options:get(`rpg:get_doll(dude).rpg_options ! E_INVIND', "lyrics"))
      rpg:playertell_lines(dude, song);
    endif
  endfor
endif
"Mooshie (#106469) - Fri Dec 12, 1997 - Let caster see lyrics.";
.

@verb #59933:"hidden_verbs" this none this
@program #59933:hidden_verbs
{who} = args;
if (!valid(doll = (rpg = $local.rpg):get_doll(who)))
  doll = rpg.doll;
endif
prev = pass(@args);
for spell in (this.visible_spells)
  try
    {spellname, skillname, objdef} = spell;
    `arglist = verb_args(objdef, spellname) ! ANY => {}';
    if ((arglist != {}) && (!doll.(skillname)))
      prev = {@prev, {objdef, spellname, verb_args(objdef, spellname)}};
    endif
  except v (ANY)
    "Ignore 'em";
  endtry
endfor
return prev;
.

@verb #59933:"spell" this none this
@program #59933:spell
":spell(OBJ caster character, OBJ|LIST target, OBJ spell, [NUM qual modifier, NUM (true|false) peaceful, OBJ skill object]";
"+ [ANY extra arguments to pass to spell verb on #328]) -- call spell on magic database if all is well.";
(rpg = $local.rpg):secure();
{by, target, spell, ?mod = 0, ?peaceful = 0, ?skillobj = spell, @extra_args} = args;
target = valid(x = rpg:get_doll(target)) ? x | target;
if (typeof(spell) == OBJ)
  spell = spell.aliases[1];
elseif (typeof(skillobj) != OBJ)
  skillobj = rpg:match_skill(skillobj);
  if (!valid(skillobj))
    raise(E_INVARG, "Spell focus was passed incorrect spell object: " + tostr(`args[6] ! E_RANGE => spell'));
  endif
endif
loc = by.location;
doll = rpg:get_doll(by);
peaceful = peaceful ? peaceful | rpg.magic_db:is_peaceful_spell(doll, target, spell);
self_cast = (`loc.peaceful ! ANY' || (doll == target)) && ((spell in rpg.magic_db.self_cast_difficult) ? random(3) - 1 | (!(spell in rpg.magic_db.self_cast_allowed)));
mod = mod + this:bonus(by, target, spell);
if (!this:may_cast(doll, spell))
  return;
endif
rpg:playertell(by, "You try to cast ", (spell in skillobj.aliases) ? skillobj:title() | $string_utils:capitalize(spell), ".");
(dobj == $failed_match) && (dobj = `target.character ! ANY => $nothing');
rpg:say_action(`caller:casting_msg(by, spell, target) ! ANY => this:casting_msg(by, spell, target)', by);
if ((!peaceful) && is_player(by))
  rpg.magic_db.sc_recovery_effect:add(doll);
  doll:write_misc_note("spell recover", time() + ((2 * skillobj.slow) / 5));
endif
qual = 0;
if (rpg:trusted_verb(loc, "magic_effect"))
  if (typeof(effect = `loc:magic_effects(doll, qual, skillobj, target) ! E_VERBNF, E_PERM => loc:magic_effect(doll, qual, skillobj, target)') != NUM)
    return effect;
  endif
  qual = qual - effect;
endif
qual = qual + skillobj:resolve(by, (mod - skillobj.diff) - ((length(doll.aggressor) - 1) * 15), self_cast || `caller.no_imp ! ANY => this.no_imp');
this:sing_spell(by, spell, target);
if (typeof(effect = doll:casting_effects(doll, target, qual, skillobj)) != NUM)
  return effect;
elseif ((qual = qual - effect) <= 0)
  rpg:rpg_announce_all(loc, "Nothing happens.");
  if (qual < -50)
    rpg:playertell(by, "Disturbed demons buffet your mind.  You feel like your soul is being put through the wringer.");
    this:pay_cost(doll, spell, skillobj, 1);
  else
    this:pay_cost(doll, spell, skillobj, 3);
  endif
else
  this.db:(spell)(doll, target, qual, skillobj, @extra_args);
  this:pay_cost(doll, spell, skillobj, 1);
endif
if (!peaceful)
  "Target/targets become aggressors.  Then they get a chance to nail caster.  No more hail freebies.";
  targets = (typeof(target) == LIST) ? target | {target};
  for t in (targets)
    if ((parent(t) == rpg.doll) && (t != doll))
      if (is_player(char = t.character))
        add = t in rpg.pcs;
      else
        char:set_last_attacker(by);
        add = char.alive;
      endif
      if (add)
        (t in doll.aggressor) || doll:first_blood(by, char);
        t.aggressor = setadd(t.aggressor, by);
        doll.aggressor = setadd(doll.aggressor, char);
      endif
    endif
  endfor
  (by.location == loc) && (`loc.peaceful ! ANY' || doll:invite(skillobj.slow));
endif
"Profane (#30788) - Sat Aug  1, 1998 - Add bit for self_cast -- casting spells on yourself == no improvement of skills";
"Profane (#30788) - Mon Aug 24, 1998 - No skill improve for casting in `peaceful' rooms.";
"Mooshie (#106469) - Wed Feb 10, 1999 - I moved the location's :magic_effect check before the :resolve. This way rooms that disallow spells won't let people macro away casting spells in them.";
"THX (#105941) - Mon Jun 26, 2000 - Check that by.location == loc before even thinking about calling doll:invite().";
"THX (#105941) - Sat Apr 14, 2001 - Put an explicit check into the loop that adds targets into the aggressors property after the spell runs.  If the thing has died, we really don't want to add it to aggressors or it'll screw up first_blood stuff.";
.

@verb #59933:"check_live_target(obsolete)" this none this
@program #59933:check_live_target(obsolete)
":check_live_target(OBJ caster character, [OBJ target, OBJ spell, NUM boolean peaceful]) => doll of target || $nothing. For spells that want one living target.";
{by, ?tstr = dobjstr, ?spell = $nothing, ?peaceful = 0} = args;
(rpg = $local.rpg):secure();
"by = args[1];";
"tstr = (length(args) > 1) ? tostr(args[2]) | dobjstr;";
"peaceful = (length(args) > 3) ? args[4] | 0;";
tstr = tostr(tstr);
target = valid(x = by:my_match_object(tstr)) ? x | dobj;
{loc, mdb, odb} = {by.location, rpg.magic_db, rpg.object_db};
no_target = ((!valid(target)) || (target.location != loc)) && (target != loc);
if (no_target && (spell in mdb.range_spells))
  exits = loc:exits();
  what = {};
  for x in (exits)
    while (`valid(x.succ_exit) ! ANY')
      x = x.succ_exit;
    endwhile
    if (odb:is_missile_exit(x))
      what = {@what, @x.dest.contents};
    endif
  endfor
  target = $match_utils:match(tstr, what);
  if (target in what)
    no_target = 0;
  endif
elseif (no_target && valid(`target = loc:match_for_spell(by, tstr, spell, peaceful) ! ANY => $nothing'))
  (loc.owner in rpg.gms) && (no_target = 0);
endif
caster = rpg:get_doll(by);
doll = rpg:get_doll(target);
peaceful = peaceful ? peaceful | mdb:is_peaceful_spell(caster, doll, spell);
if (no_target)
  rpg:playertell(by, "I don't see any `", tstr, "' here.");
elseif (!valid(doll))
  verbname = "receive_" + spell.aliases[1];
  (`rpg:trusted_verb(target, verbname) ! E_INVIND => 0' && target:(verbname)(dobj, spell)) || rpg:playertell(by, "My God! ", target.name, " seems to be immune to Illuminati magic.");
elseif (((!peaceful) && is_player(target)) && ((!$object_utils:connected(target)) || ((idle_seconds(target) > rpg.idle_threshold) && ((time() - doll.last_attack) > rpg.idle_threshold))))
  rpg:playertell(by, "Hold your magic!  By the edict of the great wizard, bystanders must not be molested.");
elseif (((((!peaceful) && is_player(target)) && (target != player)) && (!(target in caster.aggressor))) && rpg.rpg_options:get(caster.rpg_options, "peacenik"))
  rpg:playertell(by, "Whoa!  You don't really want to commit violence upon your fellow human beings, do you?  Even if it is ", target:title(), ".  After all, love is the most powerful weapon.  Play nice, now.");
else
  return doll;
endif
return $nothing;
"Profane 22-DEC-95 2008EST -- Added.";
"THX (#105941) - Sun May 31, 1998 - Scatter assignment.  Checking for custom receive_\"spell\" on !alive targets too.";
"Profane (#30788) - Mon Jul  6, 1998 - uncommented the bit about setting tstr- a plain scatter dun hack it. Also error trap receive_* call";
"Profane (#30788) - Wed Apr 21, 1999 - check new peacenik option";
"THX (#105941) - Mon Jan  3, 2000 - Commented the tstr length(args) stuff and replaced with a tostr().  Put in  some stuff to check peaceful for the peacenik stuff.";
"THX (#105941) - Tue Mar  7, 2000 - Added a check for \"range_spells\" ... maybe we can make some spells work through missile-transmitting exits.";
.

@verb #59933:"eggie" this none this
@program #59933:eggie
if (this == #14197)
  this:set_aliases({"rotten egg", "egg"});
endif
.

"***finished***