/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: spells.cc,v 1.13.2.29 2000/07/03 06:20:30 aasen Exp $
// $Revision: 1.13.2.29 $  $Author: aasen $ $Date: 2000/07/03 06:20:30 $

//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//

/* spells.cc:  My first try at coding spells.  These are quite messy
    code-wise, but served as templates to second generation spells
    (see the other files) */

#include "commands.h"
#include "command2.h"
#include "command3.h"
#include <stdio.h>
#include "misc.h"
#include "misc2.h"
#include "battle.h"
#include "classes.h"
#include "spells.h"
#include "skills.h"
#include "ez_spll.h"
#include "spells2.h"
#include "dam_spll.h"
#include "pet_spll.h"
#include "rm_spll.h"
#include "trv_spll.h"
#include <PtrArray.h>
#include "SkillSpell.h"
#include "clients.h"


int get_mana_cost(int spell_num) {
   return SSCollection::instance().getSS(spell_num).getManaCost();
}

int get_mana_cost(int spell_num, critter& pc) {
   float pl, mana_cost=SSCollection::instance().getSS(spell_num).getManaCost();

   if (pc.isPc() && ((pl = (float)get_percent_lrnd(MANA_SKILL_NUM, pc)) > -1))
      mana_cost-=mana_cost*(pl/900.0);
   
   return (int)mana_cost;
}


void rem_effects_crit(int spell_num, critter &pc, short do_msg) {
   String buf(100);

   if (spell_num == ARMOR_SKILL_NUM) {  
     pc.AC -= ARMOR_EFFECT;
     pc.SPEL_RESIS -= ARMOR_EFFECT_M;
     if (do_msg)
       show("You feel more vulnerable.\n", pc);
   }//if
   else if (spell_num == MAGIC_SHIELD_SKILL_NUM) {
      pc.AC -= MAGIC_SHIELD_AC_EFFECT;
      pc.SPEL_RESIS -= MAGIC_SHIELD_SAC_EFFECT;
     if (do_msg)
       show("Your magical shield dissipates.\n", pc);
   }//if
   else if (spell_num == FAERIE_FIRE_SKILL_NUM) {
     pc.AC -= FAERIE_FIRE_AC_AUGMENTATION;
     if (do_msg)
       show("You stop glowing with an eerie purplish glow.\n", pc);
   }//if
   else if (spell_num == POISON_SKILL_NUM) {
     pc.HP_REGEN -= POISON_HP_REGEN_AUGMENTATION;
     pc.MA_REGEN -= POISON_MA_REGEN_AUGMENTATION;
     pc.MV_REGEN -= POISON_MV_REGEN_AUGMENTATION;
     if (do_msg)
       show("Your bowels no longer scream in pain!", pc);
   }//if
   else if (spell_num == WEB_SKILL_NUM) {
     pc.MV_REGEN -= WEB_MV_REGEN_AUGMENTATION;
     pc.DEX -= WEB_DEX_AUGMENTATION;
     if (do_msg)
       show("You finally work your way out of the web.\n", pc);
   }//if
   else if (spell_num == SHADOWS_BLESSING_SKILL_NUM) {
     pc.AC -= SHADOWS_BLESSING_EFFECT;
     if (do_msg)
       show("Your protective shadows fade away.\n", pc);
   }//if
   else if (spell_num == DETECT_MAGIC_SKILL_NUM) {
     if (pc.pc) {
       pc.PC_FLAGS.turn_off(18);
       if (do_msg)
         show("You can no longer detect magical auras.\n", pc);
     }//if
   }//if
   else if (spell_num == DETECT_HIDDEN_SKILL_NUM) {
     pc.SEE_BIT &= ~(4);
     if (do_msg)
       show("You no longer detect hidden things.\n", pc);
   }//if
   else if (spell_num == INFRAVISION_SKILL_NUM) {
     pc.SEE_BIT &= ~(1);
     if (do_msg)
       show("You can no longer see in the dark.\n", pc);
   }//if
   else if (spell_num == DETECT_INVISIBILITY_SKILL_NUM) {
     pc.SEE_BIT &= ~(2);
     if (do_msg)
       show("You no longer detect invisible things.\n", pc);
   }//if
   else if (spell_num == WEAKEN_SKILL_NUM) {
     pc.STR -= WEAKEN_EFFECT;
     if (do_msg)
       show("You feel stronger!\n", pc);
   }//if
   else if (spell_num == SLEEP_SKILL_NUM) {
     pc.CRIT_FLAGS.turn_off(15);
     wake(pc);
   }//if
   else if (spell_num == FLESH_TO_STONE_SKILL_NUM) {
     pc.CRIT_FLAGS.turn_off(14);
     unpetrify(pc, do_msg); //more dire effects??
   }//if
   else if (spell_num == FLY_SKILL_NUM) {
     pc.CRIT_FLAGS.turn_off(3);
     lose_fly(pc, do_msg); //more dire effects??
   }//if
   else if (spell_num == ENTANGLE_SKILL_NUM) {
     pc.MV_REGEN -= ENTANGLE_MV_REGEN_AUGMENTATION;
     pc.DEX -= ENTANGLE_DEX_AUGMENTATION;
     if (do_msg)
       show("You finally work your way out of the entanglement.\n", pc);
   }//if
   else if (spell_num == FIREPROOF_SKILL_NUM) {
     pc.HEAT_RESIS -= FIRE_PROOF_EFFECT;
     if (do_msg)
       show("You feel less protected from heat.\n", pc);
   }//if
   else if (spell_num == STRENGTH_SKILL_NUM) {
     pc.STR -= STRENGTH_EFFECT;
     if (do_msg)
       show("You feel weaker.\n", pc);
   }//if
   else if (spell_num == HASTE_SKILL_NUM) {
     pc.ATTACKS--;
     if (do_msg)
       show("You lose a little quickness.\n", pc);
   }//if
   else if (spell_num == PFE_SKILL_NUM) {
     pc.CRIT_FLAGS.turn_off(24);
     if (do_msg)
       show("You no longer feel so protected.\n", pc);
   }//if
   else if (spell_num == PFG_SKILL_NUM) {
     pc.CRIT_FLAGS.turn_off(25);
     if (do_msg)
       show("You no longer feel so protected.\n", pc);
   }//if
   else if (spell_num == DIVINE_PROTECTION_SKILL_NUM) {
     pc.AC -= DIVINE_PROTECTION_EFFECT;
     if (do_msg)
       show("A divine force quits protecting you.\n", pc);
   }//if
   else if (spell_num == STONE_SKIN_SKILL_NUM) {
     pc.DEX -= STONE_SKIN_EFFECT_DEX;
     pc.DAM_REC_MOD -= STONE_SKIN_EFFECT_DRM;
     if (do_msg)
       show("Your skin softens.\n", pc);
   }//if
   else if (spell_num == BLINDNESS_SKILL_NUM) {
     pc.SEE_BIT |= 1024;
     if (do_msg)
       show("A veil of darkness is lifted from your eyes.\n", pc);
   }//if
   else if (spell_num == ABSORB_BLOWS_SKILL_NUM) {
     if (do_msg)
       show("Your interdimensional lattice frays and falls apart.\n", pc);
   }//if
   else if (spell_num == PRISMATIC_GLOBE_SKILL_NUM) {
     pc.AC -= PRISMATIC_GLOBE_EFFECT_AC;
     pc.MOV -= PRISMATIC_GLOBE_EFFECT_MOV;
     if (do_msg)
       show("Your prismatic shield folds in upon itself and dissappears.\n",
            pc);
   }//if
   else if (spell_num == SANCTUARY_SKILL_NUM) {
     pc.DAM_REC_MOD -= SANCTUARY_EFFECT_DRM;
     if (do_msg)
       show("Your protective light fades.\n", pc);
   }//if
   else if (spell_num == BIND_WOUND_SKILL_NUM) {
     pc.HP_REGEN -= BIND_WOUND_EFFECT;
     if (do_msg)
       show("Your bandage wears away.\n", pc);
   }//if
   else if (spell_num == BLESS_SKILL_NUM) {
     pc.HIT -= BLESS_EFFECTS;
     if (do_msg)
       show("You feel slightly less blessed in the eyes of your lord.\n", pc);
   }//if
   else if ((spell_num == CHARM_SKILL_NUM) || 
            (spell_num == MASS_CHARM_SKILL_NUM)) {
     follow(1, &NULL_STRING, pc, do_msg);
   }//if
   else if (spell_num == INVISIBILITY_SKILL_NUM) {
      pc.show("Your cloak of invisibility fades away.\n");
      pc.VIS_BIT &= ~2;
   }//if
   else {
      Sprintf(buf, "ERROR:  rem_effects_crit DEFAULT: spll# [%i] %s.\n",
              spell_num,
              (const char*)(SSCollection::instance().getNameForNum(spell_num)));
      mudlog.log(ERROR, buf);
   }//switch
}// rem_effects_crit()


void rem_effects_obj(int spell_num, object &obj) {
  String buf(100);

  if (spell_num == RUNE_EDGE_SKILL_NUM) {
     obj.OBJ_DAM_DICE_SIDES -= RUNE_EDGE_EFFECTS;
  }//if
  else if ((spell_num == FROST_BLADE_SKILL_NUM) ||
           (spell_num == FIRE_BLADE_SKILL_NUM)) {
    ; //do nothing, losing spell is enough
  }//if
  else if (spell_num == INVISIBILITY_SKILL_NUM) {
    obj.OBJ_VIS_BIT &= ~2;
  }
  else if (spell_num == WIZARD_EYE_SKILL_NUM) {
     Sprintf(buf, "%S is no longer sending you visions.\n", obj.getName());
     obj.obj_proc->w_eye_owner->show(buf);
     obj.obj_proc->w_eye_owner->pc->w_eye_obj = NULL; //pc not looking at it anymore.
     obj.obj_proc->w_eye_owner = NULL; //object not owned.
  }
  else {
    Sprintf(buf, "ERROR:  rem_effects_obj, not supported, spll# [%i] %s.\n",
            spell_num, (const char*)(SSCollection::instance().getNameForNum(spell_num)));
    mudlog.log(ERROR, buf);
  }//else
}// rem_effects_obj()


void rem_effects_door(int spell_num, door& dr, room& rm1,
                      room& rm2, short do_msg) {
  String buf(100);
  
  if (spell_num == FIREWALL_SKILL_NUM) {
     if (do_msg) {
        show_all("The flames on the exit die down.\n", rm1);
        show_all("The flames on the exit die down.\n", rm2);
     }//if
  }//if
  else if (spell_num == DISTORTION_WALL_SKILL_NUM) {
    if (do_msg) {
      show_all("The distortion field fades.\n", rm1);
      show_all("The distortion field fades.\n", rm2);
    }//if
  }//if
  else {
     Sprintf(buf, "ERROR:  rem_effects_door, spll# [%i] %s.\n", spell_num, 
             (const char*)(SSCollection::instance().getNameForNum(spell_num)));
     mudlog.log(ERROR, buf);
  }//else
}// rem_effects_door()
 

void rem_effects_room(int spell_num, room &rm, short do_msg) {
   String buf(100);

   if (spell_num == ILLUMINATE_SKILL_NUM) {
     rm.checkLight(do_msg);
   }//if
   else {
     Sprintf(buf, 
             "ERROR:  spell_num(%i) out of range in rem_effects_room.\n",
             spell_num);
     mudlog.log(ERROR, buf);
   }//else
}// rem_effects_room()


void do_firewall_effects(critter& pc, int& is_dead) {
   String buf(100);
   is_dead = FALSE;

   if (pc.isMob()) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_firewall_effects.\n");
      return;
   }//if

   exact_raw_damage(d(10,5), FIRE, pc);

   if (pc.HP < 0) {
      emote("is burned to death!!", pc, ROOM, TRUE);
      show("You have been burned to death!\n", pc);
      agg_kills_vict(NULL, pc);
      is_dead = TRUE;
   }//if
   else {
      is_dead = FALSE;
      show("OUCH!!  You are singed as you enter.\n", pc);
      emote("momentarily catches on fire!", pc, ROOM, TRUE);
   }//else
}//do_firewall_effects(critter&


int do_distortion_wall_effects(critter& pc, int& is_dead, int sanity) {
   String buf(100);
   int retval;

   if (pc.isMob()) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_distortion_wall_effects.\n");
      is_dead = FALSE;
      return -1;
   }//if

   show("**WOW**, as you step into the next room you encounter a strange
silvery curtain of....energy!\n", pc);
   emote("blinks out of sight!", pc, ROOM, TRUE);
   retval = relocate_within_zone(pc, is_dead, sanity, FALSE);
   emote("materializes in front of you!", pc, ROOM, TRUE); //in new room now
   return retval;
}//do_distortion_wall_effects


void do_cast_fireball(critter& vict, critter& agg, int is_canned, int lvl) {
   String buf(100);
   short do_join_in_battle = TRUE;
   short do_fatality = FALSE;
   int spell_num = FIREBALL_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, agg);
 
   /*  Check for: lost concentration, did_hit, !mag room    */
   /*  Do: damage to vict, mana from agg, messages to all involved, */
   /*      increment pause_count, */

   if (room_list[agg.getCurRoomNum()].isHaven()) {
      show(NOT_IN_HAVEN_MSG, agg);
      return;
   }//if

   if ((room_list[agg.getCurRoomNum()].isNoPK()) && 
       (vict.pc && agg.pc)) { 
      show(NO_PK_HERE_MSG, agg);
      return;
   }//if

   if (is_canned) {
      if (did_spell_hit(vict, FIRE, agg, lvl, TRUE)) {
         vict.HP -= d(4, 20) + 
                lvl - (int)((100.0 / (vict.HEAT_RESIS + 100)) * 20);
         agg.PAUSE += 1;   // increment pause_count
         if (&vict == &agg) {
            if (vict.HP < 0) {
               show("You burn the flesh from your bones!\n", agg);
               Sprintf(buf, "burns the flesh from %s living bones!\n",
                       get_his_her(agg));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
               do_fatality = TRUE;
            }//if
            else {
               show("You give yourself a taste of life after death!\n", 
                    agg);
               Sprintf(buf, "blasts %s with %s crimson inferno.\n", 
                      get_himself_herself(vict), 
                      get_his_her(agg));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
            }//else
            do_join_in_battle = FALSE;
         }//if
         else {
            if (vict.HP < 0) {
               Sprintf(buf, "You burn the flesh from %S's living bones!!\n",
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
               Sprintf(buf, 
                   "%S burns the flesh from your once living bones!\n",
                   name_of_crit(agg, vict.SEE_BIT));
               show(buf, vict);
               Sprintf(buf, "burns the flesh from %S's living bones!\n",
                       name_of_crit(vict, ~0));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
               do_fatality = TRUE;
            }//if
            else {
               Sprintf(buf, "You give %S a taste of life after death!\n", 
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
               Sprintf(buf, "%S gives you a brief taste of hell!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
               buf.Cap();
               show(buf, vict);
               Sprintf(buf, "blasts %S with %s crimson inferno.\n", 
                      name_of_crit(vict, ~0), 
                      get_his_her(agg));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
            }//else
         }//else
      }//if did_hit
      else { //missed
         agg.PAUSE += 1;   // increment pause_count
         if (&agg == &vict) {
            show("You miss yourself with your sulpherous inferno.\n", agg);
            Sprintf(buf, "misses %s with %s fireball.\n", 
                    get_himself_herself(vict),
                    get_his_her(vict));
            emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
            do_join_in_battle = FALSE;
         }//if
         else {
            Sprintf(buf, "You miss %S with your fireball.\n", 
                    name_of_crit(vict, agg.SEE_BIT));
            show(buf, agg);

            Sprintf(buf, "%S narrowly misses you with a fireball!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
            buf.Cap();
            show(buf, vict);
 
            Sprintf(buf, "misses %S with %s fireball!\n", 
                       name_of_crit(vict, ~0), 
                       get_his_her(agg));
            emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
         }//else
      }//else, missed with canned magic   
   }//if canned
   else { //not canned 
      if (!lost_concentration(agg, spell_num)) { 
         if (&agg == &vict) {
            show("It would be stupid to try to burn yourself!!\n", agg);
            return;
         }//if
         if (did_spell_hit(agg, FIRE, vict)) {
            exact_raw_damage(d(8, agg.LEVEL), FIRE, vict, agg);
            if (vict.HP < 0) {
               Sprintf(buf, "You burn the flesh from %S's living bones!!\n",
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
               Sprintf(buf, 
                   "%S burns the flesh from your once living bones!\n",
                   name_of_crit(agg, vict.SEE_BIT));
               show(buf, vict);
               Sprintf(buf, "burns the flesh from %S's living bones!\n",
                       name_of_crit(vict, ~0));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
               do_fatality = TRUE;
            }//if
            else {
               Sprintf(buf, "You give %S a taste of life after death!\n", 
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
               Sprintf(buf, "%S gives you a brief taste of hell!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
               buf.Cap();
               show(buf, vict);
               Sprintf(buf, "blasts %S with %s crimson inferno.\n", 
                      name_of_crit(vict, ~0), 
                      get_his_her(agg));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE);
            }//else not fatality
         }//if did_hit
         else { //missed
            exact_raw_damage(d(3, agg.LEVEL) + agg.LEVEL, FIRE, vict, agg);
            if (vict.HP < 0) {
               Sprintf(buf, "You burn the flesh from %S's living bones!!\n",
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
               Sprintf(buf, 
                   "%S burns the flesh from your once living bones!\n",
                   name_of_crit(agg, vict.SEE_BIT));
               show(buf, vict);
               Sprintf(buf, "burns the flesh from %S's living bones!\n",
                       name_of_crit(vict, ~0));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE, &vict);
               do_fatality = TRUE;
            }//if
            else {
               Sprintf(buf, "You singe %S with your fireball.\n", 
                       name_of_crit(vict, agg.SEE_BIT));
               show(buf, agg);
  
               Sprintf(buf, "%S singes you with a fireball!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
               buf.Cap();
               show(buf, vict);
 
               Sprintf(buf, "singes %S with %s fireball!\n", 
                       name_of_crit(vict, ~0), 
                       get_his_her(agg));
               emote(buf, agg, room_list[agg.getCurRoomNum()], TRUE, &vict);
            }//else no fatality
         }//missed
         agg.MANA -= spell_mana;
         agg.PAUSE += 1;   // increment pause_count
      }//if !lost concentration
      else { //lost concentration
         show(LOST_CONCENTRATION_MSG_SELF, agg);

         emote("obviously forgot something!\n", agg, 
               room_list[agg.getCurRoomNum()], TRUE);
 
         agg.MANA -= spell_mana / 2;
         agg.PAUSE += 1; 
      }//else lost concentration
   }//else !canned

   if (do_join_in_battle && !HaveData(&vict, agg.IS_FIGHTING)) {
      join_in_battle(agg, vict);
   }//if

   if (do_fatality) {
      if (vict.mob && vict.MOB_FLAGS.get(16)) {
         vict.MOB_FLAGS.turn_off(16);
      }
      agg_kills_vict(&agg, vict);
   }//if
}//do_cast_fireball
 

void cast_fireball(int i_th, const String* victim, critter& pc) {
   critter* vict = NULL;
   int spell_num = FIREBALL_SKILL_NUM;

   if (victim->Strlen() == 0) 
      vict = Top(pc.IS_FIGHTING);
   else 
      vict = ROOM.haveCritNamed(i_th, victim, pc);
   if (!vict) {
      show("Whom do you wish to barbeque??\n", pc);
      return;
   }//if
   if (vict->isMob()) {
      vict = mob_to_smob(*vict, pc.getCurRoomNum(), TRUE, i_th,
              victim, pc.SEE_BIT);
   }//if

   if (!ok_to_do_action(vict, "KMSN", spell_num, pc)) {
     return;
   }//if
   
   if (!(vict = check_for_diversions(*vict, "SGM", pc)))
     return;                                                       
                 /* all checks have been passed, lets do it */

   do_cast_fireball(*vict, pc, FALSE, 0);
}//cast_fireball


void cast_summon(int i_th, const String* targ, critter& pc) {
   int spell_num = SUMMON_SKILL_NUM;
   String buf(100);

   critter* vict = have_crit_named(pc_list, i_th, targ,
                                   pc.SEE_BIT, ROOM);

   if( config.newSummon)
   {
      int rm_num;

      if (!vict) {
       vict = have_crit_named(linkdead_list, i_th, targ,
                 pc.SEE_BIT, ROOM);
      }

      if (vict) {
       rm_num = vict->getCurRoomNum();
      }
      else {
          vict = room::haveCritNamedInWorld(i_th, targ, pc.SEE_BIT, rm_num);
      }
   }

   if (!vict) {
      show("You don't see that person!\n", pc);
      return;
   }//if

   if (!ok_to_do_action(vict, "KMSNB", spell_num, pc)) {
      return;
   }//if

   if (vict->isImmort() && (vict->getLevel() > pc.getLevel())) {
      pc.show("You wish (and you suddenly feel hungry for your efforts!)!!\n");
      if (pc.HUNGER > 0) {
         pc.HUNGER = 0; //cause I'm evil!! --Ben
      }
      return;
   }

   if (ROOM.isNoMagEntry()) {
      pc.show("You can't magically transport someone to this room!\n");
      return;
   }
                 /* all checks have been passed, lets do it */

   do_cast_summon(*vict, pc, FALSE, 0);  //does no error checking
}//cast_summon



void do_cast_summon(critter& vict, critter& pc, int is_canned, int lvl) {
   String buf(100);
   short do_affects = FALSE;
   int spell_num = SUMMON_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, pc);

   int lost_con = FALSE;
   int did_hit = TRUE;

   if (!is_canned)
      lvl = pc.LEVEL;
   
   if (is_canned || (!(lost_con = lost_concentration(pc, spell_num)) &&
                     (did_hit = did_spell_hit(pc, SUMMON, vict)))){ 
      do_affects = TRUE;
      if (!is_canned)
         pc.MANA -= spell_mana;
   }//else !canned
   else if (lost_con) {
      show(LOST_CONCENTRATION_MSG_SELF, pc);
      
      emote(LOST_CONCENTRATION_MSG_OTHER, pc, ROOM, FALSE);
      if (!is_canned)
         pc.MANA -= spell_mana / 2;
   }//else lost concentration
   else {
      Sprintf(buf, "You failed to summon %S.\n", 
              name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);
      
      Sprintf(buf, "%S tried but failed to summon you!\n", 
              name_of_crit(pc, vict.SEE_BIT));
      show(buf, vict);
      
      Sprintf(buf, "fails to summon %S.", name_of_crit(vict, ~0));
      emote(buf, pc, ROOM, TRUE, &vict);
      if (!is_canned)
         pc.MANA -= spell_mana;
   }//else
   
   if (do_affects) {
      if (!mob_can_enter(vict, ROOM, FALSE)) {
         show("That person can't enter this room!\n", pc);
         return;
      }//if
      
      if (vict.getCurRoom()->isNoMagExit()) {
         pc.show("That person's area is impervious to your spell.\n");
         return;
      }

      Sprintf(buf, "%S opens a portal above your head and yanks you through!\n",
              name_of_crit(pc, vict.SEE_BIT));
      buf.Cap();
      show(buf, vict);
      
      Sprintf(buf, "is suddenly yanked through a portal that opens over %s head!",
              get_his_her(vict));
      emote(buf, vict, room_list[vict.getCurRoomNum()], TRUE); 
      
      Sprintf(buf, "has been summoned by %S.", name_of_crit(pc, ~0));
      emote(buf, vict, ROOM, TRUE);

      int is_dead;
      vict.doGoToRoom(pc.getCurRoomNum(), NULL, NULL, is_dead,
                      vict.getCurRoomNum(), 1); //vict is always a PC
      
   }//if do_affects
   pc.PAUSE += 1; 

   // RJY [Trice] attempt to slap on ending tags
   if( vict.isPc() && vict.isInBattle() ) {
      if (vict.isUsingClient()) {
         show(CTAG_END_BATTLE(vict.whichClient()), vict);
      }
      else if (vict.isUsingColor()) {
         show(*(vict.getDefaultColor()), vict);
      }
   }
}//do_cast_summon
 

void cast_passdoor(int i_th, const String* drr, critter& pc) {
   int spell_num = PASSDOOR_SKILL_NUM;
   door* dr = door::findDoor(ROOM.DOORS, i_th, drr, pc.SEE_BIT, ROOM);

   if (!dr) {
      show("Which door do you wish to pass?\n", pc);
      return;
   }//if

   if (!dr->isClosed()) {
      show("It isn't even closed!\n", pc);
      return;
   }//if

   if (dr->isMagLocked()) {
      show("You can feel a power emanating from the door which would make", pc);
      show("your spell fail horribly!\n", pc);
      return;
   }//if

   if (dr->isNoPassdoor()) {
      pc.show("This door is imbued with properties that block your spell!\n");
      return;
   }

   if (!ok_to_do_action(NULL, "KMSNB", spell_num, pc)) {
     return;
   }//if

   if (!(mob_can_enter(pc, room_list[abs(dr->destination)], TRUE)))
     return;

   do_cast_passdoor(*dr, pc, FALSE, 0);  //does no error checking
}//cast_passdoor


void do_cast_passdoor(door& dr, critter& vict, int is_canned, int lvl) {
   String buf(100);
   short do_affects = FALSE;
   int spell_num = PASSDOOR_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, vict);

   if (!is_canned)
      lvl = vict.LEVEL;

   if (vict.isMob()) {
      if (mudlog.ofLevel(WRN)) {
         mudlog << "WARNING:  MOB in do_cast_passdor." << endl;
      }
      return;
   }//if   


   int lost_con = TRUE;

   if (is_canned || !(lost_con = lost_concentration(vict, spell_num))) { 
      do_affects = TRUE;
      if (!is_canned)
         vict.MANA -= spell_mana;
   }//else !canned
   else { //lost con
      show(LOST_CONCENTRATION_MSG_SELF, vict);     
      emote(LOST_CONCENTRATION_MSG_OTHER, vict, 
            room_list[vict.getCurRoomNum()], FALSE);
      if (!is_canned)
         vict.MANA -= spell_mana / 2;
   }//else lost concentration
   
   if (do_affects) {
      show("You briefly step into another dimension!\n", vict);
      emote("steps into another dimension.", vict,
            room_list[vict.getCurRoomNum()], TRUE); 
      
      int is_dead;
      vict.doGoToRoom(abs(dr.destination), NULL, NULL, is_dead,
                      vict.getCurRoomNum(), 1);
      
      if (!is_dead) {
         emote("steps back into your dimension.", vict,
               room_list[vict.getCurRoomNum()], TRUE);
      }
   }//if do_affects
   vict.PAUSE += 1;   // increment pause_count
}//do_cast_passdoor

void cast_tammuz(int i_th, const String* victim, critter& pc) {
   int spell_num = TAMMUZ_SKILL_NUM;
   critter* vict = NULL;
   if (victim->Strlen() == 0)
     vict = &pc;
   else {
     vict = ROOM.haveCritNamed(i_th, victim, pc);
   }//else

   if (!vict) {
     show("Transport who?\n", pc);
     return;
   }//if

   if (!ok_to_do_action(vict, "KMSNB", spell_num, pc)) {
     return;
   }//if

   do_cast_tammuz(*vict, pc, FALSE, 0);  //does no error checking
}//cast_tammuz


void do_cast_tammuz(critter& vict, critter& pc, int is_canned, int lvl) {
   String buf(100);
   short do_affects = FALSE;
   int spell_num = TAMMUZ_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, pc);

   if (!is_canned)
     lvl = pc.LEVEL;

   int lost_con = TRUE;

   if (pc.isMob()) {
      if (mudlog.ofLevel(WRN)) {
         mudlog << "WARNING:  MOB in do_cast_tammuz." << endl;
      }
      return;
   }//if

   if (pc.getCurRoom()->isNoMagExit()) {
      vict.show("You cannot leave this place by magical means!\n");
      return;
   }
   
   if (is_canned || !(lost_con = lost_concentration(pc, spell_num))) { 
      do_affects = TRUE;
      if (!is_canned)
        pc.MANA -= spell_mana;
   }//else !canned
   else { //lost con
      show(LOST_CONCENTRATION_MSG_SELF, pc);     
      emote(LOST_CONCENTRATION_MSG_OTHER, pc, ROOM, FALSE);
      if (!is_canned)
         pc.MANA -= spell_mana / 2;
   }//else lost concentration
   
   if (do_affects) {
      show("The world shimmers!\n", vict);
      emote("grows plaid and disappears.", vict,
            room_list[vict.getCurRoomNum()], TRUE); 
      
      int is_dead;
      vict.doGoToRoom(config.tammuzRoom, NULL, NULL, is_dead,
                      vict.getCurRoomNum(), 1);

      if (!is_dead) {
         emote("blinks into existence.", vict, room_list[vict.getCurRoomNum()],
               TRUE);
      }//if

   }//if do_affects
   vict.PAUSE += 1;   // increment pause_count
}//do_cast_tammuz

void cast_recall(int i_th, const String* victim, critter& pc) {
   int spell_num = RECALL_SKILL_NUM;
   critter* vict = NULL;
   if (victim->Strlen() == 0)
     vict = &pc;
   else {
     vict = ROOM.haveCritNamed(i_th, victim, pc);
   }//else

   if (!vict) {
     show("Recall who?\n", pc);
     return;
   }//if

   if (!ok_to_do_action(vict, "KMSN", spell_num, pc)) {
     return;
   }//if

   do_cast_recall(*vict, pc, FALSE, 0);  //does no error checking
}//cast_recall


void do_cast_recall(critter& vict, critter& pc, int is_canned, int lvl) {
   String buf(100);
   short do_affects = FALSE;
   int spell_num = RECALL_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, pc);

   if (!is_canned)
     lvl = pc.LEVEL;

   int lost_con = TRUE;

   if (pc.isMob()) {
      if (mudlog.ofLevel(WRN)) {
         mudlog << "WARNING:  MOB in do_cast_recall." << endl;
      }
      return;
   }//if

   if (vict.isNPC()) {
      pc.show("You cannot recall NPC players.\n");
      return;
   }

   if (pc.getCurRoom()->isNoMagExit()) {
      vict.show("You cannot leave this place by magical means!\n");
      return;
   }
   
   if (is_canned || !(lost_con = lost_concentration(pc, spell_num))) { 
      do_affects = TRUE;
      if (!is_canned)
        pc.MANA -= spell_mana;
   }//else !canned
   else { //lost con
      show(LOST_CONCENTRATION_MSG_SELF, pc);     
      emote(LOST_CONCENTRATION_MSG_OTHER, pc, ROOM, FALSE);
      if (!is_canned)
         pc.MANA -= spell_mana / 2;
   }//else lost concentration
   
   if (do_affects) {
      show("The world shimmers!\n", vict);
      emote("grows translucent and disappears.", vict,
            room_list[vict.getCurRoomNum()], TRUE); 
      
      int is_dead;
      vict.doGoToRoom(config.recallRoom, NULL, NULL, is_dead,
                      vict.getCurRoomNum(), 1);

      if (!is_dead) {
         emote("blinks into existence.", vict, room_list[vict.getCurRoomNum()],
               TRUE);
      }//if

   }//if do_affects
   vict.PAUSE += 1;   // increment pause_count
}//do_cast_recall
 

void cast_teleport(int i_th, const String* targ, critter& pc) {
   int spell_num = TELEPORT_SKILL_NUM;
   String buf(100);

    critter* vict = have_crit_named(pc_list, i_th, targ, pc.SEE_BIT, ROOM);


   if( config.newTeleport)
   {

      int rm_num;

      if (!vict) {
       vict = have_crit_named(linkdead_list, i_th, targ,
                     pc.SEE_BIT, ROOM);
    }

    if (vict) {
        rm_num = vict->getCurRoomNum();
    }
    else {
         vict = room::haveCritNamedInWorld(i_th, targ, pc.SEE_BIT, rm_num);
    }

    if (!vict) {
         show("That person is not to be found.\n", pc);
           return;
    }//if
   }

   if (!ok_to_do_action(NULL, "KMSN", spell_num, pc)) {
     return;
   }//if

   if( config.newTeleport)
   {
              do_cast_teleport(*vict, pc, FALSE, 0);  //does no error checking
   }
   else
   {
              do_cast_teleport(pc, pc, FALSE, 0);  //does no error checking
   }

}//cast_teleport


void do_cast_teleport(critter& vict, critter& pc, int is_canned, int lvl) {
   String buf(100);
   int new_room_num = FALSE;
   short done = FALSE, do_affects = FALSE;
   int spell_num = TELEPORT_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, pc);

   //log("in do_cast_teleport\n");

   if (!is_canned)
     lvl = pc.LEVEL;

   int lost_con = TRUE;

   if (pc.getCurRoom()->isNoMagExit()) {
      vict.show("You cannot leave this place by magic means!\n");
      return;
   }
   if( config.newTeleport )
   {
              if (vict.getCurRoom()->isNoMagEntry()) {
                      pc.show("You can't magically transport to that room!\n");
                  return;
        }
   }

   if (is_canned || !(lost_con = lost_concentration(pc, spell_num))) { 
      do_affects = TRUE;
      if (!is_canned)
              pc.MANA -= spell_mana;
   }//else !canned
   else { //lost con
      show(LOST_CONCENTRATION_MSG_SELF, pc);
     
      emote(LOST_CONCENTRATION_MSG_OTHER, pc, 
           room_list[pc.getCurRoomNum()], FALSE);
      if (!is_canned)
         pc.MANA -= spell_mana / 2;
   }//else lost concentration

   if (do_affects) {
      show("The world shimmers!\n", vict);
      emote("grows translucent and disappears.", vict,
            room_list[pc.getCurRoomNum()], TRUE); 

      int sanity = 0;
      while (!done) {
         if (sanity++ > 10) {
            if (mudlog.ofLevel(DBG)) {
               mudlog << "WARNING:  Sanity check failed in do_cast_teleport."
                      << "  vict:  " << *(name_of_crit(vict, ~0)) << endl;
            }
            emote("disappears briefly and then shimmers back into existence.",
                  vict, room_list[pc.getCurRoomNum()], TRUE);

            break;
         }


            if( config.newTeleport)
            {
               int is_dead;

                       new_room_num = vict.getCurRoomNum();
                    if ((mob_can_enter(pc, room_list[new_room_num], FALSE)) &&
                       (!room_list[new_room_num].isNoMagEntry())) {
                                       done = TRUE;
                                       emote("shimmers into existence.", vict,
                               room_list[vict.getCurRoomNum()], TRUE);
                                       pc.doRemoveFromBattle();
                                       pc.doGoToRoom(vict.getCurRoomNum(), NULL, NULL,is_dead, pc.getCurRoomNum(), 1);
                               if (is_dead)
                               return;
                       }//if
                }
                else
                {
               int is_dead;

               new_room_num = d(1, Cur_Max_Room_Num);
               if ((mob_can_enter(pc, room_list[new_room_num], FALSE)) &&
               (!room_list[new_room_num].isNoMagEntry())) {
                       done = TRUE;
                      emote("shimmers into existence.", vict,
                       room_list[pc.getCurRoomNum()], TRUE);
                       pc.doRemoveFromBattle();
                      pc.doGoToRoom(new_room_num, NULL, NULL, is_dead,
                             pc.getCurRoomNum(), 1);
               if (is_dead)
                               return;
               }//if
            }
      }//while

      vict.doRemoveFromBattle();
   }//if do_affects
   vict.PAUSE += 1;   // increment pause_count
    // RJY [Trice] attempt to slap in ending battle TAGS
 if( pc.isInBattle() )
 {
   if (pc.isUsingClient()) {
          show(CTAG_END_BATTLE(pc.whichClient()), pc);
   }
   else if (pc.isUsingColor()) {
          show(*(pc.getDefaultColor()), pc);
   }
 }
}//do_cast_teleport
 


void cast_poison(int i_th, const String* victim, critter& pc) {
   critter* vict = NULL;
   int spell_num = POISON_SKILL_NUM;

   if (victim->Strlen() == 0) 
      vict = Top(pc.IS_FIGHTING);
   else 
      vict = ROOM.haveCritNamed(i_th, victim, pc);
   if (!vict) {
      show("Who do you wish to poison??\n", pc);
      return;
   }//if

   if (vict->isMob()) {
      vict = mob_to_smob(*vict, pc.getCurRoomNum(), TRUE, i_th,
                          victim, pc.SEE_BIT);
   }//if
 
   if (!ok_to_do_action(vict, "KMSNV", spell_num, pc)) {
     return;
   }//if
  
   do_cast_poison(*vict, pc, FALSE, 0);  //does no error checking
}//cast_poison


void do_cast_poison(critter& vict, critter& agg, int is_canned, int lvl) {
   String buf(100);
   short do_effects = FALSE;
   short do_join_in_battle = TRUE;
   int spell_num = POISON_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, agg);
 

   if (!is_canned)
      lvl = agg.LEVEL;

   if (is_canned) {
      if (did_spell_hit(vict, CRONIC, agg, lvl, TRUE)) {
         do_effects = TRUE;

         if (&vict == &agg) {
            show("You feel sick!\n", vict);
            emote("turns green and looks quite sick.", agg, 
                  room_list[agg.getCurRoomNum()], TRUE); 
            do_join_in_battle = FALSE;
         }//if
         else {
            Sprintf(buf, "You poison %S!\n", 
                       name_of_crit(vict, agg.SEE_BIT));
            show(buf, agg);
            Sprintf(buf, "%S has poisoned you!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
            buf.Cap();
            show(buf, vict);
            Sprintf(buf, "%S poisons %S.\n", 
                      name_of_crit(agg, ~0), name_of_crit(vict, ~0));
            buf.Cap();
            show_all_but_2(agg, vict, buf, room_list[agg.getCurRoomNum()]);
         }//else
      }//if did_hit
      else { //missed
         if (&agg == &vict) {
            show("You can't even manage to poison yourself.\n", agg);
            do_join_in_battle = FALSE;
         }//if
         else {
            Sprintf(buf, "You fail to poison %S.\n", 
                    name_of_crit(vict, agg.SEE_BIT));
            show(buf, agg);

            Sprintf(buf, "%S fails to poison you!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
            buf.Cap();
            show(buf, vict);
         }//else
         agg.PAUSE += 1;   // increment pause_count
      }//else, missed with canned magic   
   }//if canned
   else {//not canned 
      if (&agg == &vict) {
         show("You would feel stupid if you poisoned yourself on purpose.\n",
              agg);
         return;
      }//if
      if (!lost_concentration(agg, spell_num)) { 
         if (did_spell_hit(agg, CRONIC, vict)) {
            do_effects = TRUE;

            Sprintf(buf, "You poison %S!\n", 
                       name_of_crit(vict, agg.SEE_BIT));
            show(buf, agg);
            Sprintf(buf, "%S poisons you!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
            buf.Cap();
            show(buf, vict);
         }//if did_hit
         else { //missed
            Sprintf(buf, "You fail to poison %S.\n", 
                       name_of_crit(vict, agg.SEE_BIT));
            show(buf, agg);

            Sprintf(buf, "%S tries and fails to poison you!\n", 
                       name_of_crit(agg, vict.SEE_BIT));
            buf.Cap();
            show(buf, vict);
 
         }//missed
         agg.MANA -= spell_mana;
         agg.PAUSE += 1;   // increment pause_count
      }//if ! lost concentration
      else { //lost concentration
         show(LOST_CONCENTRATION_MSG_SELF, agg);

         emote(LOST_CONCENTRATION_MSG_OTHER, agg, *(agg.getCurRoom()), TRUE);
 
         agg.MANA -= spell_mana / 2;
         agg.PAUSE += 1; 
      }//else
   }//else !canned

   if (do_effects) {
      stat_spell_cell* sp;

      Cell<stat_spell_cell*> cll(vict.affected_by);
      while ((sp = cll.next())) {
         if (sp->stat_spell == spell_num) {
            sp->bonus_duration += (int)((float)(lvl) / 3.0);
            return;
         }//if
      }//while

      Put(new stat_spell_cell(spell_num, lvl/3), vict.affected_by);
      vict.HP_REGEN += POISON_HP_REGEN_AUGMENTATION;
      vict.MV_REGEN += POISON_MV_REGEN_AUGMENTATION;
      vict.MA_REGEN += POISON_MA_REGEN_AUGMENTATION;
   }//if

   if (do_join_in_battle && !HaveData(&vict, agg.IS_FIGHTING)) {
      join_in_battle(agg, vict);
   }//if
}//do_cast_poison


void cast_illuminate(critter& pc) {
   int spell_num = ILLUMINATE_SKILL_NUM;

   if (!ok_to_do_action(NULL, "KMSN", spell_num, pc)) {
     return;
   }//if

   do_cast_illuminate(ROOM, pc, FALSE, 0);  //does no error checking
}//cast_illuminate


void do_cast_illuminate(room& rm, critter& agg, int is_canned,
                        int lvl) {
   int spell_num = ILLUMINATE_SKILL_NUM;
   int spell_mana = get_mana_cost(spell_num, agg);
   String buf(100);
   short do_effects = FALSE;
 
   if (room_list[agg.getCurRoomNum()].isNoMagic()) {
      show(NOT_IN_NOMAG_RM_MSG, agg);
      return;
   }//if

   if (!is_canned)
      lvl = agg.LEVEL;

   agg.PAUSE += 1; 

   if (is_canned) {
      do_effects = TRUE;
      show("You enlighten the room!\n", agg); 
      emote("enlightens the room.", agg, rm, TRUE); 
   }//if canned
   else {//not canned 
      if (!lost_concentration(agg, spell_num)) { 
         do_effects = TRUE;
         show("You enlighten the room!\n", agg); 
         emote("enlightens the room.", agg, rm, TRUE); 
         agg.MANA -= spell_mana;
      }//if ! lost concentration
      else { //lost concentration
         show(LOST_CONCENTRATION_MSG_SELF, agg);
         emote(LOST_CONCENTRATION_MSG_OTHER, agg, rm, TRUE);
         agg.MANA -= spell_mana / 2;
      }//else
   }//else !canned

   if (do_effects) {
      mudlog.log(DBG, "Doing illuminate effects.\n");
      stat_spell_cell* sp;

      Cell<stat_spell_cell*> cll(rm.affected_by);
      while ((sp = cll.next())) {
         if (sp->stat_spell == spell_num) {
            sp->bonus_duration += (int)((float)(lvl) / 2.0);
            return;
         }//if
      }//while

      obj_ptr_log << "NOTE " << rm.getIdNum() << " " << &rm
                  << "Adding to affected_rooms bcause of illuminate." << endl;

      affected_rooms.gainData(&rm); //add to global affected list so
                                     //spell can wear off eventually
      Put(new stat_spell_cell(spell_num, lvl/2), rm.affected_by);
      rm.setVisBit(rm.getVisBit() & ~1);  //make it light
   }//if
}//do_cast_illuminate



//******************************************************************//
///**************   auxillary spell/skill functions   *************///
//******************************************************************//


int has_all_prereqs(int skill_num, critter& pc) {
   Cell<int> cll(SSCollection::instance().getSS(skill_num).prereqs);
   int tmp;
   int retval;

   while ((tmp = cll.next())) {
     if (pc.SKILLS_KNOWN.Find(tmp, retval)) {
       if (retval < 50)
         return FALSE;
     }//if
     else
       return FALSE;
   }//while

   return TRUE;
}//has_all_prereqs

void update_skills(critter& pc) {
   int key;
   if (pc.SKILLS_KNOWN.Min(key)) {
      update_skill(key, pc);
      while (pc.SKILLS_KNOWN.Next(key)) {
         update_skill(key, pc);
      }//while
   }//if
}//update_skills


void update_skill(int last_learned, critter& pc) {
   
   if (!pc.pc) {
      return;
   }//if

   if (get_percent_lrnd(last_learned, pc) < 50) {
      return;
   }

   if (!check_l_range(last_learned, 0, NUMBER_OF_SKILL_SPELLS, pc, FALSE)) {
      mudlog.log(ERROR,
                 "ERROR:  last_learned out of range, gain_spells_skills!!\n");
      return;
   }//if

   Cell<int> cll(SSCollection::instance().getSS(last_learned).enables);
   int tmp;
   while ((tmp = cll.next())) {
     if (has_all_prereqs(tmp, pc) && (get_percent_lrnd(tmp, pc) == -1)) {
        pc.SKILLS_KNOWN.Insert(tmp, 1);
        if (tmp == WEAPON_MASTERY_SKILL_NUM)
           pc.DAM++;
        else if (tmp == HONOR_CODE_SKILL_NUM)
           pc.WIS++;
        else if (tmp == LEADERSHIP_SKILL_NUM)
           pc.CHA++;
        else if (tmp == QUICKFOOT_SKILL_NUM)
           pc.DEX++;
        else if (tmp == WRESTLING_SKILL_NUM)
           pc.BH_DICE_COUNT++;
// This needs to be done in do_battle(), otherwise +1 attack items only work
// for people with at least 1% in second attack.
//        else if (tmp == SECOND_ATTACK_SKILL_NUM)
//           pc.ATTACKS++;
        else if (tmp == CLIMBING_SKILL_NUM)
           pc.CRIT_FLAGS.turn_on(5);
        else if (tmp == DUAL_WIELD_SKILL_NUM)
           pc.CRIT_FLAGS.turn_on(16);
        else if (tmp == LOGIC_SKILL_NUM)
            pc.CHA--; //logical people are boring!!
        else if (tmp == MARTIAL_ARTS_SKILL_NUM) {
           pc.BH_DICE_COUNT++;
           pc.BH_DICE_SIDES += 2;
        }//martail arts
     }//if
   }//while
}//gain_spells_skills


short lost_concentration(critter& agg, int spell_num) {
   int percent_lrned = 0, i;

   //   log("In lost_concentration\n");

   if (agg.pc) {
     agg.SKILLS_KNOWN.Find(spell_num, percent_lrned);
   }//if
   else { //not a pc
      percent_lrned = 50 + (2 * agg.LEVEL);
   }// else

   i = (int)(((float)percent_lrned / 50.0) * 
     (float)(agg.WIS + agg.INT + agg.LEVEL + 130));

   return (d(1, 100) >= d(1, i));
}//lost_concentration


int relocate_within_zone(critter& pc, int& is_dead, int sanity, int do_msgs) {
   if (sanity > 20) {
      mudlog << "ERROR:  sanity check failed in relocate_within_zone."
             << endl;
      is_dead = FALSE;
      return FALSE;
   }

   int zn = ROOM.getZoneNum();

   int begin_rm = ZoneCollection::instance().elementAt(zn).getBeginRoomNum();
   int end_rm = ZoneCollection::instance().elementAt(zn).getEndRoomNum();
   int count = 0;
   int new_room_num;

   while (TRUE) {   
      new_room_num = begin_rm + d(1, (end_rm - begin_rm));
      if (count++ > 15) 
         new_room_num = pc.getCurRoomNum();

      if (mob_can_enter(pc, room_list[new_room_num], FALSE)) {
         pc.doGoToRoom(new_room_num, NULL, NULL, is_dead, pc.getCurRoomNum(),
                       sanity, do_msgs);
         return TRUE;
      }//if

      if (count++ > 15) {
         is_dead = FALSE;
         return FALSE; //should never get here I think
      }
   }//while
}//relocate_within_zone