/
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: skills.cc,v 1.11.2.19 2000/06/28 01:34:29 greear Exp $
// $Revision: 1.11.2.19 $  $Author: greear $ $Date: 2000/06/28 01:34:29 $

//
//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
//

//*********************** skills.cc ********************//

#include "misc.h"
#include "misc2.h"
#include "classes.h"
#include "spells.h"
#include "battle.h"
#include "skills.h"
#include "commands.h"
#include "batl_prc.h"
#include "socials.h"
#include "social2.h"
#include <PtrArray.h>
#include "load_wld.h"
#include "SkillSpell.h"


int track(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

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

   int p_lrnd = get_percent_lrnd(TRACK_SKILL_NUM, pc);

   if (p_lrnd == 0) {
      pc.show(CS_TRACK_DUH);
      return -1;
   }

   /* check for miss on skill */
   if ((d(1, p_lrnd) * 4) < d(1,100)) {
      Sprintf(buf, "You sense a trail to the %S.\n", 
              door_list[d(1,8)].names.peekFront());
      show(buf, pc);
      return 0;
   }//if


   if (!victim) {
      mudlog.log(ERROR, "ERROR:  NULL(s) sent to track().\n");
   }//if
   else if (pc.isMob()) {
      mudlog.log(ERROR, "ERROR:  mob trying to track..\n");
   }//if
   else if (pc.POS != POS_STAND) {
      show("You must be standing in order to track.\n", 
            pc);
   }//if
   else if (!pc.IS_FIGHTING.isEmpty()) {
      show("You can't track while you're fighting!!\n", pc);
   }//if
   else if (!victim->Strlen()) {
      show("Track who??\n", pc);
   }//if
   else { //ok, should be good to go 
      int znum = pc.getCurZoneNum();
      int in_room;
      // this fn sets in_room btw.
      crit_ptr = room::haveCritNamedInZone(ZoneCollection::instance().elementAt(znum),
                                           i_th, victim, pc.SEE_BIT, in_room);
      if (!crit_ptr) {
        show("That person is not found in these parts.\n", pc);
      }//if
      else {
        if (pc.getCurRoomNum() == in_room) {
          show("You're already here!\n", pc);
        }//if
        else {
          List<int> path;
          path_from_a_to_b(pc.getCurRoomNum(), in_room, path);

          /*log("TRACK:  HERE IS PATH.\n");
          Cell<int> tcll(path);
          int tint;
          while (tint = Next(tcll)) {
            Sprintf(buf, "TRACK:  %i ", tint);
            log(buf);
          }//while
          */

          if (path.isEmpty()) {
             show("You can't get there from here!\n", pc);
          }//if
          else {
             Cell<door*> cll(ROOM.DOORS);
             door* ptr;
             path.popFront(); //get rid of first one
             while ((ptr = cll.next())) {
                if (abs(ptr->destination) == path.peekFront()) {
                   Sprintf(buf, "You sense a trail leading %S.\n", 
                           direction_of_door(*ptr));
                   show(buf, pc);
                   return 0;
                }//if
             }//while
             Sprintf(buf, "TRACK:  no exit to this room:  %i\n",
                     path.peekFront());
             //log(buf);
             show(buf, pc);
          }//else got some kinda path
        }//else not already in same room
      }//else found a crit ptr
   }//else, good to go
   return -1;
}//track


int trip(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

   if (!victim->Strlen()) {
      if (!(crit_ptr = pc.IS_FIGHTING.peekFront())) {
         show("Trip who?\n", pc);
         return -1;
      }//if
   }//if
   else {
      crit_ptr = ROOM.haveCritNamed(i_th, victim, pc.SEE_BIT);
   }//if

   if (crit_ptr) {

      if (crit_ptr == &pc) {
        show("You trip over your own two feet!\n", pc);
        return 0;
      }//if

      if (crit_ptr->isMob()) {
         crit_ptr = mob_to_smob(*crit_ptr, pc.getCurRoomNum(),
                                TRUE, i_th, victim, pc.SEE_BIT);
      }//if

      if (!ok_to_do_action(crit_ptr, "SVPFA", -1, pc)) {
         return -1;
      }//if

      if (!(crit_ptr = check_for_diversions(*crit_ptr, "GM", pc)))
         return -1;

      return do_trip(*crit_ptr, pc);
   }//if
   else {
     show("Trip who??\n", pc);
   }//else
   return -1;
}//trip


int do_trip(critter& vict, critter& pc) {
   String buf(100);
   short do_fatality = FALSE;


   if ((vict.isMob()) || (pc.isMob())) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_trip.\n");
      return -1;
   }//if

   if (!pc.IS_FIGHTING.haveData(&vict)) {
      join_in_battle(pc, vict);
   }//if

   if (skill_did_hit(pc, TRIP_SKILL_NUM, vict)) {
      pc.PAUSE += 2; //increment pause_count
      exact_raw_damage(d(4, 5), NORMAL, vict, pc);
      vict.PAUSE += d(1,3);
      vict.setPosn(POS_SIT);


      Sprintf(buf, "trips %S.", name_of_crit(vict, ~0));
      emote(buf, pc, ROOM, TRUE, &vict);
      Sprintf(buf, "%S trips you!\n", name_of_crit(pc, vict.SEE_BIT));
      buf.Cap();
      show(buf, vict);
      Sprintf(buf, "You trip %S!\n", name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);

      if (vict.HP < 0) {
        Sprintf(buf, "breaks %s neck as %s hits the ground!! ***CRACK***\n",
                get_his_her(vict), get_he_she(vict));
        emote(buf, vict, ROOM, TRUE);
        do_fatality = TRUE;
      }//if fatality
   }//if
   else {  //missed
      Sprintf(buf, "You nimbly dodge %S's attempt to trip you!\n",
              name_of_crit(pc, vict.SEE_BIT));
      show(buf, vict);

      Sprintf(buf, "dodges %S's attempt to trip %s.",
              name_of_crit(pc, ~0), get_him_her(vict));
      emote(buf, vict, ROOM, TRUE, &pc);

      Sprintf(buf, "%S dodges your attempt to trip %s.\n",
                 name_of_crit(vict, pc.SEE_BIT), get_him_her(vict));
      show(buf, pc);

      pc.PAUSE += 2; //increment pause_count
   }//else
   if (do_fatality) {
      agg_kills_vict(&pc, vict);
   }//if
   return 0;
}//do_trip()


int steal(int i_th, const String* obj, int j_th, const String* victim,
          critter& pc) {
   critter* crit_ptr = NULL;
   object* objptr = NULL;
   int gold = FALSE;

   String buf(100);

   crit_ptr = ROOM.haveCritNamed(j_th, victim, pc.SEE_BIT);

   if (crit_ptr) {
      if (crit_ptr == &pc) {
        show("There's a bright idea!\n", pc);
        return 0;
      }//if

      if (crit_ptr->isMob()) {
         crit_ptr = mob_to_smob(*crit_ptr, pc.getCurRoomNum(), TRUE,
                                i_th, victim, pc.SEE_BIT);
      }//if

      if (!ok_to_do_action(crit_ptr, "mSVPF", -1, pc)) {
         return -1;
      }//if

      if (!obj->Strlen() || (strcasecmp(*obj, "gold") == 0)) {
        gold = TRUE;
      }//if
      else {
        objptr = have_obj_named(crit_ptr->inv, i_th, obj, pc.SEE_BIT,
                                ROOM);      
      }//else
      return do_steal(objptr, *crit_ptr, pc, gold);
   }//if
   else {
     show("Steal from who??\n", pc);
   }//else
   return -1;
}//steal


int do_steal(object* obj, critter& vict, critter& pc, 
              short steal_gold = FALSE) {
   String buf(100);
   int amt;


   if (!vict.isImmort() && skill_did_hit(pc, STEAL_SKILL_NUM, vict)) {
      if (obj && !obj_get_by(*obj, pc, TRUE, TRUE)) {
         return -1;
      }
      /* it worked */
      pc.PAUSE += 1; //increment pause_count
      if (obj) {
         vict.loseInv(obj);
         pc.gainInv(obj);
         /* no explicit penalties if you don't get caught! */
         
         Sprintf(buf, "You successfully lift %S from %S!\n",
                 long_name_of_obj(*obj, pc.SEE_BIT),
                 name_of_crit(vict, pc.SEE_BIT));
         show(buf, pc);
      }//if an object
      else if (steal_gold) {
         pc.GOLD += (amt = (d(1,vict.GOLD) / 4));
         vict.GOLD -= amt;
         /* no explicit penalties if you don't get caught! */
         
         Sprintf(buf, "You successfully lift %i coins from %S!\n",
                 amt, name_of_crit(vict, pc.SEE_BIT));
         show(buf, pc);
      }//if
      else { //!gold AND !obj, bad guess!!
         show(
            "You snoop around undetected, but don't find what you're looking for!\n",
            pc);
         return 0;
      }//else
      return 0;
   }//if
   else {  //got caught!!!
      
      Sprintf(buf, "%S catches you with your hands on %s things!!\n",
              name_of_crit(vict, pc.SEE_BIT), get_his_her(vict));
      show(buf, pc);
      
      Sprintf(buf, "is caught trying to steal from %S.\n",
              name_of_crit(vict, ~0));
      emote(buf, pc, ROOM, TRUE, &vict);
      
      Sprintf(buf, "You catch %S with %s hands in your pockets!.\n",
              name_of_crit(pc, vict.SEE_BIT), get_his_her(pc));
      show(buf, vict);
      

      if (!vict.pc) {
         if (!vict.mob->proc_data || (vict.mob->getBenevolence() < 5)) {
            /* gonna be a whuppin! */
            do_hit(pc, vict); //start battle
         }//
         else {
            sob(1, &NULL_STRING, vict, room_list[vict.getCurRoomNum()]);
         }//else
      }//if
      else {
         if (pc.pc) { //P_STEAL
            pc.PC_FLAGS.turn_on(20);
         }//if
      }//else
      return -1;
   }//else
   return -1;
}//do_steal


int kick(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

   if (!victim->Strlen()) {
      if (!(crit_ptr = pc.IS_FIGHTING.peekFront())) {
         show("Kick who?\n", pc);
         return -1;
      }//if
   }//if
   else {
      crit_ptr = ROOM.haveCritNamed(i_th, victim, pc.SEE_BIT);
   }//if

   if (crit_ptr) {

      if (crit_ptr == &pc) {
         show("You kick yourself for your stupidity!\n", pc);
         Sprintf(buf, "kicks %s.", get_himself_herself(pc));
         emote(buf, pc, ROOM, TRUE);
         return 0;
      }//if

      if (crit_ptr->isMob()) {
         crit_ptr = mob_to_smob(*crit_ptr, pc.getCurRoomNum(), TRUE,
                                i_th, victim, pc.SEE_BIT);
      }//if

      if (!ok_to_do_action(crit_ptr, "SVPF", -1, pc)) {
         return -1;
      }//if

      if (!(crit_ptr = check_for_diversions(*crit_ptr, "GM", pc)))
         return -1;

      return do_kick(*crit_ptr, pc);
   }//if
   else {
      show("Kick who??\n", pc);
   }//else
   return -1;
}//kick


int do_kick(critter& vict, critter& pc) {
   String buf(100);
   short do_fatality = FALSE;


   if ((vict.isMob()) || (pc.isMob())) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_kick.\n");
      return -1;
   }//if

   if (!pc.IS_FIGHTING.haveData(&vict)) {
      join_in_battle(pc, vict);
   }//if

   if (skill_did_hit(pc, KICK_SKILL_NUM, vict)) {

      pc.PAUSE += d(1,2); //increment pause_count
      float d1 = (((float)(pc.STR)) * (float)(pc.getLevel()) + 5.0) / 60.0;
      exact_raw_damage(d((int)d1, 5), NORMAL, vict, pc);
      vict.PAUSE += d(1,3);

      if (vict.HP < 0) {
         Sprintf(buf, "kicks in %S's temple with %s foot!!\n", 
                 name_of_crit(vict, ~0), get_his_her(pc));
         emote(buf, pc, ROOM, TRUE, &vict);
         Sprintf(buf, 
                 "You see %S's foot racing straight for your temple...\n",
                 name_of_crit(pc, vict.SEE_BIT));
         show(buf, vict);
         Sprintf(buf, 
                 "You crush %S's temple with your round-house kick!!\n",
                 name_of_crit(vict, pc.SEE_BIT));
         show(buf, pc);
         do_fatality = TRUE;
      }//if fatality
      else {
         Sprintf(buf, "%S kicks you in the chest!\n",
                 name_of_crit(pc, vict.SEE_BIT));
         buf.Cap();
         show(buf, vict);

         Sprintf(buf, "You kick %S.\n", name_of_crit(vict, vict.SEE_BIT));
         show(buf, pc);

         Sprintf(buf, "kicks %S!\n", name_of_crit(vict, ~0));
         emote(buf, pc, ROOM, TRUE, &vict);
      }//else
   }//if
   else {  //missed
      Sprintf(buf, "kicks mightily at %S, missing by a foot!\n",
              vict.getName());
      emote(buf, pc, ROOM, FALSE, &vict);

      Sprintf(buf, "%S narrowly misses your head with %s foot!\n", 
              name_of_crit(pc, vict.SEE_BIT), get_his_her(pc));
      buf.Cap();
      show(buf, vict);

      Sprintf(buf, "You miss a kick at %S's head.\n",
              name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);

      pc.PAUSE += 2; //increment pause_count
   }//else
   if (do_fatality) {
      agg_kills_vict(&pc, vict);
   }//if
   return 0;
}//do_kick()


int bash(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

   if (!victim->Strlen()) {
      if (!(crit_ptr = Top(pc.IS_FIGHTING))) {
         show("Bash who?\n", pc);
         return -1;
      }//if
   }//if
   else {
      crit_ptr = ROOM.haveCritNamed(i_th, victim, pc.SEE_BIT);
   }//if

   if (crit_ptr) {

      if (crit_ptr == &pc) {
         show("You shouldn't be bashing yourself..\n", pc);
         return -1;
      }//if

      if (crit_ptr->isMob()) {
         crit_ptr = mob_to_smob(*crit_ptr, pc.getCurRoomNum(), TRUE, i_th, victim,
                                pc.SEE_BIT);
      }//if

      if (!ok_to_do_action(crit_ptr, "SVPFA", -1, pc)) {
         return -1;
      }//if

      if (!(crit_ptr = check_for_diversions(*crit_ptr, "GM", pc)))
         return -1;

      return do_bash(*crit_ptr, pc);
   }//if
   else if (door* dptr = door::findDoor(ROOM.DOORS, i_th, victim,
                pc.SEE_BIT, ROOM))
      return do_bash(*dptr, pc);
   else
      pc.show(CS_NO_CAN_SEE);
   return -1;
}//bash


int do_bash(door& vict, critter& pc) { //bash for doors
   String buf(100);

   if (pc.isMob()) {
      if (mudlog.ofLevel(ERROR)) {
         mudlog << "ERROR:  MOB sent to do_bash, name:  " 
                << *(name_of_crit(pc, ~0)) << "  address:  " << &pc << endl;
      }

      return -1;
   }//if

   if (!vict.dr_data->door_data_flags.get(2)) {
      show("It isn't even closed.\n", pc);
      return -1;
   }//if

   if (!vict.dr_data->door_data_flags.get(3)) {
      show("Its not locked, just open it!\n", pc);
      return -1;
   }//if

   if (!vict.dr_data->door_data_flags.get(7)) {
      show("You nearly break your hand on the door.  It doesn't budge!\n",
                pc);
      Sprintf(buf, 
        "nearly breaks %s hand on the door.  It doesn't budge!",
         get_his_her(pc));
      emote(buf, pc, ROOM, TRUE);
   }//if
   else if (d(1, 100) < get_percent_lrnd(BASH_SKILL_NUM, pc)) {
      Sprintf(buf, "You bust down the %S.\n", name_of_door(vict,
                pc.SEE_BIT));
      show(buf, pc);
      vict.dr_data->door_data_flags.turn_off(2);
      vict.dr_data->door_data_flags.turn_off(5);
      Sprintf(buf, "busts open the %S!\n", name_of_door(vict, ~0));
      emote(buf, pc, ROOM, TRUE);
   }//else
   else {
      Sprintf(buf, "The %S gives a little as you hit it.\n",
                name_of_door(vict, pc.SEE_BIT));
      show(buf, pc);
      Sprintf(buf, "budges the %S with %s hit.\n", name_of_door(vict, ~0),
                get_his_her(pc));
      emote(buf, pc, ROOM, TRUE);
   }//else  
   
   pc.PAUSE += d(2,2); //increment pause_count
   return 0;
}//do_bash()//door



int do_bash(critter& vict, critter& pc) {
   String buf(100);
   short do_fatality = FALSE;

   if ((vict.isMob()) || (pc.isMob())) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_bash.\n");
      return -1;
   }//if

   if (!pc.IS_FIGHTING.haveData(&vict)) {
      join_in_battle(pc, vict);
   }//if

   if (skill_did_hit(pc, BASH_SKILL_NUM, vict)) {

      pc.PAUSE += d(1,3); //increment pause_count
      exact_raw_damage(d(pc.STR/2, 5) + pc.DEX/2, NORMAL, vict, pc);
      vict.PAUSE += d(1,3);

      if (vict.HP < 0) {
         Sprintf(buf, "crushes the skull of %S with %s fist!!\n", 
                 name_of_crit(vict, ~0), get_his_her(pc));
         emote(buf, pc, ROOM, TRUE, &vict);
         Sprintf(buf, 
          "The last thing you feel is %S's fist caving in your temple!!\n",
          name_of_crit(pc, vict.SEE_BIT));
         show(buf, vict);
         Sprintf(buf, 
          "With a mighty blow of your fist you crush %S's skull.\n",
          name_of_crit(vict, pc.SEE_BIT));
         show(buf, pc);
         do_fatality = TRUE;
      }//if fatality
      else {
         Sprintf(buf, "%S rings your bell!\n",
                 name_of_crit(pc, vict.SEE_BIT));
         buf.Cap();
         show(buf, vict);

         Sprintf(buf, "You bash %S!\n", name_of_crit(vict, vict.SEE_BIT));
         show(buf, pc);

         Sprintf(buf, "bashes %S!\n", name_of_crit(vict, ~0));
         emote(buf, pc, ROOM, TRUE, &vict);
      }//else
   }//if
   else {  //missed
      Sprintf(buf, "nearly falls on %s butt trying to hit %S!\n",
              get_his_her(pc), vict.getName());
      emote(buf, pc, ROOM, FALSE, &vict);

      Sprintf(buf, "%S takes a big swing at you but misses!\n", 
                 name_of_crit(pc, vict.SEE_BIT));
      buf.Cap();
      show(buf, vict);

      Sprintf(buf, "You try to bash %S but fall on your ass!\n",
                 name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);

      pc.PAUSE += d(2,2); //increment pause_count
      return -1;
   }//else
   if (do_fatality) {
      agg_kills_vict(&pc, vict);
   }//if
   return 0;
}//do_bash()


int block(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

   if (!victim->Strlen()) {
      if (!(crit_ptr = Top(pc.IS_FIGHTING))) {
         show("Block who?\n", pc);
         return -1;
      }//if
   }//if
   else {
      crit_ptr = ROOM.haveCritNamed(i_th, victim, pc.SEE_BIT);
   }//if

   if (crit_ptr) {
     if (!pc.IS_FIGHTING.haveData(crit_ptr)) {
       show("You aren't fighting that person.\n", pc);
       return -1;
     }//if

     if (!ok_to_do_action(crit_ptr, "PFA", -1, pc)) {
        return -1;
     }//if

     return do_block(*crit_ptr, pc);
   }//if
   else if (door* dptr = door::findDoor(ROOM.DOORS, i_th, victim,
                pc.SEE_BIT, ROOM))
      return do_block(*dptr, pc);
   else
      pc.show(CS_NO_CAN_SEE);
   return -1;
}//block


int do_block(critter& vict, critter& pc) {
   String buf(100);

   if ((vict.isMob()) || (pc.isMob())) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_block.\n");
      return -1;
   }//if

   if (!HaveData(&vict, pc.IS_FIGHTING)) {
      return -1;
   }//if

   if (skill_did_hit(pc, BLOCK_SKILL_NUM, vict)) {
      pc.PAUSE += d(1,3); //increment pause_count
      vict.CRIT_FLAGS.turn_on(21); //now is blocked

      Sprintf(buf, "You block %S.\n", name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);
      Sprintf(buf, "blocks %S.", name_of_crit(vict, ~0));
      emote(buf, pc, ROOM, TRUE, &vict);
      Sprintf(buf, "%S blocks you.\n", name_of_crit(pc, vict.SEE_BIT));
      show(buf, vict);
      return 0;
   }//if
   else {  //missed
      show("You miss the block.\n", pc);
      emote("misses the block.", pc, ROOM, TRUE, &vict);
      Sprintf(buf, "%S tries but fails to block you.\n", 
              name_of_crit(pc, vict.SEE_BIT));
      show(buf, vict);
      return -1;
   }//else
}//do_block()



int do_block(door& vict, critter& pc) {
   String buf(100);

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

   if (ROOM.isHaven() || ROOM.isNoPK()) {
     show("Aggression is not allowed here.\n", pc);
     return -1;
   }//if

   if (!pc.IS_FIGHTING.isEmpty()) {
     show("You can't block an entrance while fighting.\n", pc);
     return -1;
   }//if

   if (vict.dr_data->door_data_flags.get(14)) {
     show("Someone is already blocking that door!\n", pc);
     return -1;
   }//if

   if (d(1, 100) < get_percent_lrnd(BLOCK_SKILL_NUM, pc)) {
      Sprintf(buf, "You start blocking the %S.\n", name_of_door(vict,
                pc.SEE_BIT));
      show(buf, pc);
      vict.dr_data->door_data_flags.turn_on(14);
      vict.crit_blocking = &pc;
      Sprintf(buf, "starts blocking the %S!\n", name_of_door(vict, ~0));
      emote(buf, pc, ROOM, TRUE);
      return 0;
   }//else
   else {
     pc.PAUSE += d(1, 2); //increment pause_count
     show(
    "You can't find a suitable spot, maybe if you tried a little harder.\n",
          pc);
   }//else      
   return -1;
}//do_block()//door


int claw(int i_th, const String* victim, critter& pc) {
   critter* crit_ptr;
   String buf(100);

   if (pc.EQ[9] && pc.EQ[10]) {
      show("You don't have a free hand!\n", pc);
      return -1;
   }//if

   if (!victim->Strlen()) {
      crit_ptr = Top(pc.IS_FIGHTING);
   }//if
   else {
      crit_ptr = ROOM.haveCritNamed(i_th, victim, pc.SEE_BIT);
   }//if

   if (crit_ptr) {

      if (crit_ptr == &pc) {
         show("You shouldn't be clawing yourself..\n", pc);
         return -1;
      }//if

      if (crit_ptr->isMob()) {
         crit_ptr = mob_to_smob(*crit_ptr, pc.getCurRoomNum(),
                                TRUE, i_th, victim, pc.SEE_BIT);
      }//if

      if (!ok_to_do_action(crit_ptr, "SVPF", -1, pc)) {
         return -1;
      }//if

      if (!(crit_ptr = check_for_diversions(*crit_ptr, "GM", pc)))
         return -1;

      return do_claw(*crit_ptr, pc);

   }//if
   else 
      show("Claw who?\n", pc);
   return -1;
}//claw


int do_claw(critter& vict, critter& pc) {
   String buf(100);
   short do_fatality = FALSE;

   mudlog.log(TRC, "In do_claw.\n");

   if ((vict.isMob()) || (pc.isMob())) {
      mudlog.log(ERROR, "ERROR:  MOB sent to do_claw.\n");
      return -1;
   }//if

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

   pc.PAUSE += d(1,3); //increment pause_count

   if (skill_did_hit(pc, CLAW_SKILL_NUM, vict)) {

      exact_raw_damage((d(pc.STR/2, 5) + pc.LEVEL), NORMAL, vict);

      if (vict.HP < 0) {
         Sprintf(buf, "rips %S's throat out with %s %s!!\n", 
                 name_of_crit(vict, ~0), get_his_her(pc),
                 (pc.RACE == AVIAN ? "deadly talons" : "curled hand"));
         emote(buf, pc, ROOM, TRUE);
         Sprintf(buf, 
                 "You are supprised to see %S holding your larynx!!\n",
                 name_of_crit(pc, vict.SEE_BIT));
         show(buf, vict);
         Sprintf(buf, 
                 "You rip out %S's larynx with a quick swipe of your %s.\n",
                 name_of_crit(vict, pc.SEE_BIT),
                 (pc.RACE == AVIAN ? "deadly talons" : "curled hand"));
         show(buf, pc);
         do_fatality = TRUE;
      }//if fatality
      else {
         Sprintf(buf, 
                "%S's %s leave bloody streaks across your body!\n",
                 name_of_crit(pc, vict.SEE_BIT),
                 (pc.RACE == AVIAN ? "deadly talons" : "fingers" ));
         buf.Cap();
         show(buf, vict);

         Sprintf(buf, 
                 "Your %s leave bloody streaks across %S's body!\n", 
                 (pc.RACE == AVIAN ? "deadly talons" : "fingers"),
                 vict.getName(pc));
         show(buf, pc);

         Sprintf(buf, "claws %S with %s %s!\n",
                 name_of_crit(vict,~0), get_his_her(pc),
                 (pc.RACE == AVIAN ? "dedly talons" : "curled hand"));
         emote(buf, pc, ROOM, TRUE);
      }//else
   }//if
   else {  //missed
      Sprintf(buf, "%S takes a big swipe at you but misses!\n", 
                 name_of_crit(pc, vict.SEE_BIT));
      buf.Cap();
      show(buf, vict);

      Sprintf(buf, "You try to claw %S but narrowly miss.\n",
             name_of_crit(vict, pc.SEE_BIT));
      show(buf, pc);
      return -1;
   }//else
   if (do_fatality) {
      agg_kills_vict(&pc, vict);
   }//if
   return 0;
}//do_claw()


int construct(critter& pc, short do_mob = FALSE) {
   String buf(100);
   object* toolbox, *ptr, *item1, *item2, *item3, *item4, *item5;
   Cell<object*> cll;
   //   log("In construct.\n");

   item1 = item2 = item3 = item4 = item5 = NULL;

   if (!pc.pc && !do_mob) //no ordering pets to do yer dirty-work
      return -1;

   if (!ok_to_do_action(NULL, "mBFPSK", CONSTRUCT_SKILL_NUM, pc)) {
      return -1;
   }

   pc.inv.head(cll);
   toolbox = NULL;
   while ((ptr = cll.next())) {
      if (ptr->OBJ_FLAGS.get(64)) { //if a toolbox
         toolbox = ptr;
         break;
      }//if
   }//while

   if (!toolbox) {
      show("You must have a toolbox in order to construct something.", 
           pc);
      return -1;
   }//if

   if (toolbox->inv.isEmpty()) {
      show("You need components in your toolbox to work with!\n", 
           pc);
      return -1;
   }//if

                /* found a tool box, make sure its clear of junk */
   toolbox->inv.head(cll);
   while ((ptr = cll.next())) {
      if (!(ptr->OBJ_FLAGS.get(67))) {
         Sprintf(buf, "%S is not a component to any construction.\n",
                 &(ptr->short_desc));
         buf.Cap();
         show(buf, pc);
         show("You have to have a clean toolbox in order to work!!\n", 
              pc);
         return -1;
      }//if
      if (ptr->OBJ_LEVEL > pc.LEVEL) {
         Sprintf(buf, "%S is too advanced for you to work with it.\n",
                 &(ptr->short_desc));
         buf.Cap();
         show(buf, pc);
         show("You must remove it from your work ", pc);
         show("area before you can continue.\n", pc);
         return -1;
      }//if
   }//while

   ptr = Top(toolbox->inv);

   if (!ptr->obj_proc) {
      Sprintf(buf, "ERROR:  %S is COMPONENT w/NULL obj_proc.\n", 
              &(ptr->short_desc));
      mudlog.log(ERROR, buf);
      return -1;
   }//if
   if (!ptr->obj_proc->construct_data) {
      Sprintf(buf, "ERROR:  %S is COMPONENT w/NULL construct_data.\n", 
              &(ptr->short_desc));
      mudlog.log(ERROR, buf);
      return -1;
   }//if

                  /* check for all components available */
   if (check_l_range(ptr->COMPONENT_ITEM1, 1, NUMBER_OF_ITEMS, pc, 
                     FALSE)) {
      if (!(item1 = have_obj_numbered(toolbox->inv, 1, 
                                      ptr->COMPONENT_ITEM1, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to construct %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM1].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM2, 1, NUMBER_OF_ITEMS, pc, 
                     FALSE)) {
      if (!(item2 = have_obj_numbered(toolbox->inv, 1, 
                                      ptr->COMPONENT_ITEM2, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to construct %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM2].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM3, 1, NUMBER_OF_ITEMS, pc, 
                     FALSE)) {
      if (!(item3 = have_obj_numbered(toolbox->inv, 1, 
                                      ptr->COMPONENT_ITEM3, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to construct %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM3].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM4, 1, NUMBER_OF_ITEMS, pc, 
                     FALSE)) {
      if (!(item4 = have_obj_numbered(toolbox->inv, 1, 
                                      ptr->COMPONENT_ITEM4, pc.SEE_BIT, ROOM))) { 
         Sprintf(buf, "You need %S in order to construct %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM4].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM5, 1, NUMBER_OF_ITEMS, pc, 
                     FALSE)) {
      if (!(item5 = have_obj_numbered(toolbox->inv, 1, 
                                      ptr->COMPONENT_ITEM5, pc.SEE_BIT, ROOM))) { 
         Sprintf(buf, "You need %S in order to construct %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM5].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

                /*  have all items and levels are compatable */

   int targ_num = ptr->COMPONENT_TARG;
   // NOTE:  Can't use ptr after this, because it might be deleted!!!

   if (item1) {
      toolbox->loseInv(item1);
      drop_eq_effects(*item1, pc, FALSE, FALSE);
      recursive_init_unload(*item1, 0);
      if (item1->isModified()) {
         delete item1;
         item1 = NULL;
      }//if
   }//if
   
   if (item2) {
      toolbox->loseInv(item2);
      drop_eq_effects(*item2, pc, FALSE, FALSE);
      recursive_init_unload(*item2, 0);
      if (item2->isModified()) {
         delete item2;
         item2 = NULL;
      }//if
   }//if
   
   if (item3) {
      toolbox->loseInv(item3);
      drop_eq_effects(*item3, pc, FALSE, FALSE);
      recursive_init_unload(*item3, 0);
      if (item3->isModified()) {
         delete item3;
         item3 = NULL;
      }//if
   }//if
   
   if (item4) {
      toolbox->loseInv(item4);
      drop_eq_effects(*item4, pc, FALSE, FALSE);
      recursive_init_unload(*item4, 0);
      if (item4->isModified()) {
         delete item4;
         item4 = NULL;
      }//if
   }//if
   
   if (item5) {
      toolbox->loseInv(item5);
      drop_eq_effects(*item5, pc, FALSE, FALSE);
      recursive_init_unload(*item5, 0);
      if (item5->isModified()) {
         delete item5;
         item5 = NULL;
      }//if
   }//if
   
   if (skill_did_hit(pc, CONSTRUCT_SKILL_NUM, pc)) {
      toolbox->gainInv(&(obj_list[targ_num]));
      recursive_init_loads(obj_list[targ_num], 0);
      Sprintf(buf, "You have successfully constructed %S in %S.\n",
              obj_list[targ_num].getLongName(),
              toolbox->getLongName());
      show(buf, pc);
   }//if skill_did_hit, ie if pc knew it well enuf not to fail
   else {
      show("You fiddle with your components, but all you can seem to", pc);
      show(" do is bugger them up completely.\n", pc);
   }//else
   pc.PAUSE += 4;
   return 0;
}//construct()



int concoct(critter& pc, short do_mob = FALSE) {
   String buf(100);
   object* cauldron, *ptr, *item1, *item2, *item3, *item4, *item5;
   Cell<object*> cll;
   //   log("In concoct.\n");

   if (!pc.pc && !do_mob) //no ordering pets to do yer dirty-work
     return -1;

   item1 = item2 = item3 = item4 = item5 = NULL;

   if (!ok_to_do_action(NULL, "mBFPSK", BREW_SKILL_NUM, pc)) {
      return -1;
   }

   pc.inv.head(cll);
   cauldron = NULL;
   while ((ptr = cll.next())) {
      if (ptr->OBJ_FLAGS.get(65)) { //if a cauldron
         cauldron = ptr;
         break;
      }//if
   }//while

   if (!cauldron) {
      show("You must have a cauldron in order to brew something.", 
           pc);
      return -1;
   }//if

   if (IsEmpty(cauldron->inv)) {
      show("You need ingredients in your cauldron to brew with!\n", 
           pc);
      return -1;
   }//if

                /* found a cauldron, make sure its clear of junk */
   cauldron->inv.head(cll);
   while ((ptr = cll.next())) {
      if (!(ptr->OBJ_FLAGS.get(68))) { //concoct component
         Sprintf(buf, 
             "%S will certainly distort the properties of your brew.  ",
             &(ptr->short_desc));
         buf.Cap();
         show(buf, pc);
         show("You'd better take it out.\n", pc);
         return -1;
      }//if
      if (ptr->OBJ_LEVEL > pc.LEVEL) {
         Sprintf(buf, "You do not yet fully comprehend the power of %S.\n",
                 &(ptr->short_desc));
         buf.Cap();
         show(buf, pc);
         show("Until you better understand it, you shouldn't include", pc);
         show(" it in your cauldron.\n", pc);
         return -1;
      }//if
   }//while

   ptr = Top(cauldron->inv);

   if (!ptr->obj_proc) {
      Sprintf(buf, "ERROR:  %S is COMPONENT w/NULL obj_proc.\n", 
             &( ptr->short_desc));
      mudlog.log(ERROR, buf);
      return -1;
   }//if
   if (!ptr->obj_proc->construct_data) {
      Sprintf(buf, "ERROR:  %S is COMPONENT w/NULL construct_data.\n", 
              &(ptr->short_desc));
      mudlog.log(ERROR, buf);
      return -1;
   }//if

                  /* check for all components available */
   if (check_l_range(ptr->COMPONENT_ITEM1, 1, NUMBER_OF_ITEMS, pc, 
       FALSE)) {
      if (!(item1 = have_obj_numbered(cauldron->inv, 1, 
                   ptr->COMPONENT_ITEM1, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to brew %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM1].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM2, 1, NUMBER_OF_ITEMS, pc, 
       FALSE)) {
      if (!(item2 = have_obj_numbered(cauldron->inv, 1, 
                   ptr->COMPONENT_ITEM2, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to brew %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM2].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM3, 1, NUMBER_OF_ITEMS, pc, 
       FALSE)) {
      if (!(item3 = have_obj_numbered(cauldron->inv, 1, 
                   ptr->COMPONENT_ITEM3, pc.SEE_BIT, ROOM))) {
         Sprintf(buf, "You need %S in order to brew %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM3].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM4, 1, NUMBER_OF_ITEMS, pc, 
       FALSE)) {
      if (!(item4 = have_obj_numbered(cauldron->inv, 1, 
                   ptr->COMPONENT_ITEM4, pc.SEE_BIT, ROOM))) { 
         Sprintf(buf, "You need %S in order to brew %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM4].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   if (check_l_range(ptr->COMPONENT_ITEM5, 1, NUMBER_OF_ITEMS, pc, 
       FALSE)) {
      if (!(item5 = have_obj_numbered(cauldron->inv, 1, 
                   ptr->COMPONENT_ITEM5, pc.SEE_BIT, ROOM))) { 
         Sprintf(buf, "You need %S in order to brew %S.\n",
                 &(obj_list[ptr->COMPONENT_ITEM5].short_desc),
                 &(obj_list[ptr->COMPONENT_TARG].short_desc));
         show(buf, pc);
         return -1;
      }//if
   }//if

   int targ_num = ptr->COMPONENT_TARG;
   // NOTE:  Can't use ptr after this, because it might be deleted!!!

                /*  have all items, and levels are compatable */

   if (item1) {
      cauldron->loseInv(item1);
      drop_eq_effects(*item1, pc, FALSE);
      recursive_init_unload(*item1, 0);
      if (item1->isModified()) {
         delete item1;
         item1 = NULL;
      }//if
   }//if
   
   if (item2) {
      cauldron->loseInv(item2);
      drop_eq_effects(*item2, pc, FALSE);
      recursive_init_unload(*item2, 0);
      if (item2->isModified()) {
         delete item2;
         item2 = NULL;
      }//if
   }//if
   
   if (item3) {
      cauldron->loseInv(item3);
      drop_eq_effects(*item3, pc, FALSE);
      recursive_init_unload(*item3, 0);
      if (item3->isModified()) {
         delete item3;
         item3 = NULL;
      }//if
   }//if
   
   if (item4) {
      cauldron->loseInv(item4);
      drop_eq_effects(*item4, pc, FALSE);
      recursive_init_unload(*item4, 0);
      if (item4->isModified()) {
         delete item4;
         item4 = NULL;
      }//if
   }//if
   
   if (item5) {
      cauldron->loseInv(item5);
      drop_eq_effects(*item5, pc, FALSE);
      recursive_init_unload(*item5, 0);
      if (item5->isModified()) {
         delete item5;
         item5 = NULL;
      }//if
   }//if
   
   if (skill_did_hit(pc, BREW_SKILL_NUM, pc)) {
      pc.gainInv(&(obj_list[targ_num]));
      recursive_init_loads(obj_list[targ_num], 0);
      Sprintf(buf, "You have successfully brewed %S.\n",
              &(obj_list[targ_num].short_desc));
      show(buf, pc);
   }//if skill_did_hit, ie if pc knew it well enuf not to fail
   else {
      show("You try to remember the recipe, but you must have", pc);
      show(" forgotten something because this stuff stinks and your ", pc);
      show("ingredients are ruined!!\n", pc);
   }//else
   pc.PAUSE += 4;
   return 0;
}//concoct()


int scribe(const String* spell, critter& pc, short do_mob = FALSE) {
   String buf(100);
   object* pen, *parchment; 
   int spell_num;

   /* default is that mob's can't scribe, ie no 'ordering' them to scribe */
   if (!pc.pc && !do_mob)
     return -1;

   //   log("In scribe.\n");

        // level of spell can't be higher than parchment level 
        // and or pen level.
        // Can only scribe spells the pc knows of course, unless its 
        // a SMOB
        // Must be wielding pen
        // Must be holding parchment
        // Resulting scroll goes to inventory

   if (spell->Strlen() == 0) {
      show("Please specify which spell you wish to scribe.\n", pc);
      return -1;
   }//if

   if (!ok_to_do_action(NULL, "mBFPr", spell_num, pc)) {
      return -1;
   }

   pen = pc.EQ[9];
   if (!pen || !pen->OBJ_FLAGS.get(66)) {
      show("You must be wielding a pen in order to scribe.\n", pc);
      return -1;
   }//if

                // pen is valid, check for parchment //

   parchment = pc.EQ[10];
   if (!parchment || !parchment->OBJ_FLAGS.get(69)) {
      show("You must be holding a parchment in order to scribe.\n", pc);
      return -1;
   }//if

                // parchment and pen are valid, check on spell //

   spell_num = SSCollection::instance().getNumForName(*spell);
   if (spell_num == -1) {
      show("That spell is in need of research.\n", pc);
      return -1;
   }//if

   /* does pc know the spell?? */

   int p_learned = get_percent_lrnd(spell_num, pc);
   if (p_learned == -1) {
     show("You don't know of that spell.\n", pc);
     return -1;
   }//if

                // have valid spell number, now check levels

   int spell_lvl = SSCollection::instance().getSS(spell_num).getMinLevel();
   
   if (spell_lvl > pen->OBJ_LEVEL) {
      show("Your pen is too weak to convey such magic.\n", pc);
      return -1;
   }//if

   if (spell_lvl > parchment->OBJ_LEVEL) {
      show("Your parchment cannot hold such strong words of magic.\n", pc);
      return -1;
   }//if

            // have all items, levels are compatable //
   int scroll_num;
   if (!lost_concentration(pc, spell_num)) {
      if ((scroll_num = SSCollection::instance().getSS(spell_num).getScrollNum()) != -1) {

         recursive_init_unload(*(pc.EQ[10]), 0);
         remove_eq_effects(*(pc.EQ[10]), pc, FALSE, FALSE, 10);
         if (pc.EQ[10]->isModified()) 
            delete pc.EQ[10];
         pc.EQ[10] = NULL; //no more parchment

         pc.gainInv(&(obj_list[scroll_num]));

         recursive_init_loads(obj_list[scroll_num], 0);

         Sprintf(buf, "You have successfully scribed %S.\n",
              &(obj_list[scroll_num].short_desc));
         show(buf, pc);
         pc.MANA -= get_mana_cost(spell_num, pc);
         pc.PAUSE += 4;
      }//if
      else { //scroll object not created yet
         Sprintf(buf, "ERROR:  need to create scroll for spell:  %i.\n",
                 spell_num);
         mudlog.log(ERROR, buf);
         show("As you finish the last phrase the parchement grows hot and",
              pc);
         show(" bursts into flame.\nThis spell just doesn't take to paper", 
              pc);
         show(" very well!\n", pc);
         if (pc.EQ[10]->isModified()) 
            delete pc.EQ[10];
         pc.EQ[10] = NULL; //no more parchment
      }//else
   }//if !lost concentration, if he/she knew it well enuf
   else {
      show("You suddenly lose your train of thought, and as you mark", pc);
      show(" through that last line, you know the parchment is useless.\n",
           pc);
      if (pc.EQ[10]->isModified()) 
         delete pc.EQ[10];
      pc.EQ[10] = NULL; //no more parchment
      pc.PAUSE += 4;
      pc.MANA -= (get_mana_cost(spell_num, pc) / 2);
   }//else
   return 0;
}//scribe()



///*********************************************************************///
//************************ auxillary functions **************************//
///*********************************************************************///


short did_spell_hit(const critter& agg, const int spell_type,
                    const critter& vict, int lvl = -1, 
                    short is_canned = FALSE) {

  int j = 100;
  switch (spell_type)
     {
     case NORMAL:
        j = vict.AC;
        break;
     case FIRE: case D_BREATH:
        j =  vict.HEAT_RESIS;
        break;
     case ICE:
        j = vict.COLD_RESIS;
        break;
     case ELECTRICITY:
        j = vict.ELEC_RESIS;
        break;
     case CRONIC:
        j = ((18 - vict.CON) * 5 + 25);
        break;
     case AGILITY:
        j = ((18 - vict.DEX) * 5 + 25);
        break;
     case COERCION:
     case CHARM:
        j = ((18 - vict.INT) * 5 + 25);
        if (agg.ALIGN < -850)
           j += (int)((float)j * .25);
        else if (agg.ALIGN > 250)
           j += (int)((float)j * ((float)agg.ALIGN / 4000.0));
        break;
     default:
        if (mudlog.ofLevel(ERROR)) {
           mudlog << "ERROR:  default in did_spell_hit, spelltype:  "
                  << spell_type << endl;
        }
        j = 100;
     }//switch   
  
  j += vict.SPEL_RESIS; //gen resistance to spells
      
  if (is_canned) {
    j -= (vict.LEVEL - lvl) * 10;
  }//if
  else {
    j -= (vict.LEVEL - agg.LEVEL) * 10;
  }//else

  j += 200; 

  if (j < 0)
    j = 0;
  else if (j > 400)
    j = 400;

  if ((spell_type == COERCION) || (spell_type == CHARM)) {
     if (vict.getLevel() > agg.getLevel()) {
        return FALSE;
     }
  }

  return (d(1, 75) < d(1, j));
}//did_spell_hit


short skill_did_hit(critter& agg, int spell_num, critter& vict) {
   int percent_lrnd = 0;

   if (agg.pc) {
      agg.SKILLS_KNOWN.Find(spell_num, percent_lrnd);
   }//if
   else { //else not a pc
      int foo = (agg.getLevel() - SSCollection::instance().getSS(spell_num).getMinLevel());
      if (foo > 0) {
         percent_lrnd = max((50 + (foo * 15)), 100);
      }
      else {
         percent_lrnd = 10;
      }
   }//else
   
   if ((spell_num == CONSTRUCT_SKILL_NUM) || (spell_num == BREW_SKILL_NUM))
     return (d(1, 100) < d(1, (percent_lrnd * 2 + 2 * (agg.DEX + agg.INT))));

   else if ((spell_num == BODYSLAM_SKILL_NUM) ||
            (spell_num == HURL_SKILL_NUM))
     return (d(1, vict.CRIT_WT_CARRIED) < d(1, percent_lrnd + agg.STR * 10));
   else if ((spell_num == BACKSTAB_SKILL_NUM) ||
            (spell_num == CIRCLE_SKILL_NUM)) {
      int rnd1 = d(1, (agg.HIT * 3 + agg.DEX * 5 + agg.LEVEL * 2));
      int rnd2  = d(1, (2 * vict.DEX + vict.LEVEL + max(-vict.AC / 2,  25)));
      return (((float)(rnd1) * (float)(percent_lrnd) / 100.0) >
              ((float)(rnd2)));
   }
   else {
     return (d(1, ((agg.HIT + agg.DEX + 2 * agg.LEVEL) * (percent_lrnd / 4))) >
             d(1, ((vict.DEX + 2 * vict.LEVEL) * 15)));
   }
}//skill_did_hit


int sneak(critter& pc, int smob_too = FALSE) {
   String buf(100);
   
   if (pc.isMob())
      return -1; //no MOB's allowed!!
   
   if (!smob_too && !pc.pc) {
      return -1;
   }//if 
   
   
   if (pc.isFrozen()) {
      show("You are too frozen to do anything.\n", pc);
      return -1;
   }//if
   
   if (pc.CRIT_FLAGS.get(17)) {
      pc.CRIT_FLAGS.turn_off(17);
      show("You stop sneaking around.\n", pc);
   }//if
   else {
      if (get_percent_lrnd(SNEAK_SKILL_NUM, pc) > 0) {
         pc.CRIT_FLAGS.turn_on(17);
         show("You start sneaking.\n", pc);
      }//if
      else {
         show("You couldn't sneak up on a sleeping Ogrue!!\n", pc);
      }//else
   }//else, not sneaking right now
   return 0;
}//sneak


int hide(critter& pc, int smob_too = FALSE) {
   String buf(100);

   if (pc.isMob())
      return -1; //no MOB's allowed!!
   
   if (!smob_too && !pc.pc) {
      return -1;
   }//if 
   
   if (pc.isFrozen()) {
      show("You are too frozen to hide.\n", pc);
      return -1;
   }//if
   
   if (pc.CRIT_FLAGS.get(22)) {
      pc.CRIT_FLAGS.turn_off(22);
      show("You stop hiding.\n", pc);
   }//if
   else {
      if (get_percent_lrnd(HIDE_SKILL_NUM, pc) > 0) {
         pc.CRIT_FLAGS.turn_on(22);
         show("You start hiding.\n", pc);
      }//if
      else {
         show("You are not skilled in this stealthy art!!\n", pc);
      }//else
   }//else, not hiding right now
   return 0;
}//hide

/*  Basically, just hide for rangers. */
int blend(critter& pc, int smob_too = FALSE) {
   String buf(100);

   if (pc.isMob())
      return -1; //no MOB's allowed!!
   
   if (!smob_too && !pc.pc) {
      return -1;
   }//if 
   
   if (pc.isFrozen()) {
      show("You are too frozen to hide.\n", pc);
      return -1;
   }//if
   
   if (pc.CRIT_FLAGS.get(22)) {
      pc.CRIT_FLAGS.turn_off(22);
      show("You step out of hiding.\n", pc);
   }//if
   else {
      if (get_percent_lrnd(BLEND_SKILL_NUM, pc) > 0) {
         pc.CRIT_FLAGS.turn_on(22);
         show("You blend into the background.\n", pc);
      }//if
      else {
         show("You are not skilled in this stealthy art!!\n", pc);
      }//else
   }//else, not hiding right now
   return 0;
}//blend
          

int scan(critter& pc) {

   if (!ok_to_do_action(NULL, "KSPF", SCAN_SKILL_NUM, pc)) {
      return -1;
   }//if

   return ROOM.doScan(pc);
}//scan