FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/


#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "magic.h"
#include "song.h"
#include "cabal.h"
#include "recycle.h"
#include "interp.h"
#include "s_skill.h"
#include "jail.h"
#include "bounty.h"

void lagprot_yell(CHAR_DATA* ch, CHAR_DATA* victim, int gsn, int shield)
{
  /* this composes the yells for differnt shields. */
  char buf[MIL];
 
  switch (shield)
    {
      /* PROTECTIVE SHIELD */
    case LAG_SHIELD_PROT:
      sprintf(buf, "Don't even think about trying to use %s on me, %s!",
	IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name,
	PERS(ch,victim));
      break;

      /* FORCE FIELD*/
    case LAG_SHIELD_FFIELD:
      sprintf(buf, "Your feeble %s cannot penetrate my forcefield %s!",
        IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name,
        PERS(ch,victim));
      break;

      /* ARMOR */
    case LAG_SHIELD_ARMOR:
      sprintf(buf, "Your feeble %s cannot penetrate my armor %s!",
        IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name,
        PERS(ch,victim));
      break;
  
      /* NON-CORPOREAL */
    case LAG_SHIELD_NONCORP:
      sprintf(buf, "You can't %s me %s you clumsy fool!",
        IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name,
        PERS(ch,victim));
      break;

      /* BALANCE */
    case LAG_SHIELD_BALANCE:
      /* IRON WILL */
    case LAG_SHIELD_IWILL:
      sprintf(buf, "Your %s is no match for my abilities %s!",
        IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name,
        PERS(ch,victim));
      break;

      /* DEFAULT */
    default:
      sprintf(buf, "Help! %s is trying to %s me!",
        PERS(ch,victim),
        IS_GEN(gsn)? effect_table[GN_POS(gsn)].name : skill_table[gsn].name);
    }//END SWITCH
    j_yell(victim,buf);
}


void lagprot_msg(CHAR_DATA* ch, CHAR_DATA* victim, int sn, int shield, bool fYell)
{
  /* does the different combat messages. */

  //3 message buffers to be displayed at the end.
  char to_char[MIL];
  char to_vict[MIL];
  char to_room[MIL];

  char* noun;
  char* verb_tch;
  char* verb_tvic;
  char* verb_trm;

  int verb_pos = lagattack_lookup(sn);

  if (verb_pos == -1)
    {
      bug("lagport_msg run with incorrect skill!", 0);
      return;
    }
  noun = lagattack_table[verb_pos].noun;
  verb_tch = lagattack_table[verb_pos].to_char;
  verb_tvic = lagattack_table[verb_pos].to_vict;
  verb_trm = lagattack_table[verb_pos].to_room;

  switch (shield)
    {
      /* PROTECTIVE SHIELD */
    case LAG_SHIELD_PROT:
      sprintf(to_char, "Your %s is ineffective as %s a protective shield.", noun, verb_tch);
      sprintf(to_vict, "$n's %s %s protective shield.",noun, verb_tvic);
      sprintf(to_room, "$n's %s %s $N's protective shield.",noun, verb_trm);
      break;

      /* FORCE FIELD*/
    case LAG_SHIELD_FFIELD:
      sprintf(to_char, "Your %s is ineffective as %s an elastic shield of force.", noun, verb_tch);
      sprintf(to_vict, "$n's %s %s force field.",noun, verb_tvic);
      sprintf(to_room, "$n's %s %s $N's force field.",noun, verb_trm);
      break;

      /* REFLECTIVE FIELD*/
    case LAG_SHIELD_RFIELD:
      sprintf(to_char, "Your %s is weakened as %s the reflective shield.", noun, verb_tch);
      sprintf(to_vict, "$n's %s %s reflective field.",noun, verb_tvic);
      sprintf(to_room, "$n's %s %s $N's reflective field.",noun, verb_trm);
      break;

      /* FORCE FIELD*/
    case LAG_SHIELD_ARMOR:
      sprintf(to_char, "Your %s is ineffective as %s the Juggernaut Plate.", noun, verb_tch);
      sprintf(to_vict, "$n's %s %s Juggernaut Plate.",noun, verb_tvic);
      sprintf(to_room, "$n's %s %s $N's Juggernaut Plate.",noun, verb_trm);
      break;
  
      /* NON-CORPOREAL */
    case LAG_SHIELD_NONCORP:
      sprintf(to_char, "Your %s is inneffective against $N.", noun);
      sprintf(to_vict, "$n's %s is usless against you.",noun);
      sprintf(to_room, "$N seems uneffected by $n's %s",noun);
      break;

      /* BALANCE */
    case LAG_SHIELD_BALANCE:
      /* IRON WILL */
    case LAG_SHIELD_IWILL:
      sprintf(to_char, lagattack_table[verb_pos].ba_char);
      sprintf(to_vict, lagattack_table[verb_pos].ba_vict);
      sprintf(to_room, lagattack_table[verb_pos].ba_room);
      break;
    }//END SWITCH

  //Upcase the first letter just in case.
  to_char[0] = UPPER(to_char[0]);
  to_vict[0] = UPPER(to_vict[0]);
  to_room[0] = UPPER(to_room[0]);

  //show messages
  act(to_char, ch, NULL, victim, TO_CHAR);
  act(to_vict, ch, NULL, victim, TO_VICT);
  act(to_room, ch, NULL, victim, TO_NOTVICT);

  if (fYell)
    lagprot_yell(ch, victim, sn, shield);
}//END


/* executes checks for lag protection */
/* returns type of shield that is on victim. */
int get_lagprot(CHAR_DATA* ch)
{
  int shield_type = LAG_SHIELD_NONE;

  //check if person has a shield first.
  if ( IS_AFFECTED2(ch, AFF_PROTECT_SHIELD) )
    shield_type = LAG_SHIELD_PROT;
  else if(is_affected(ch, gsn_forcefield))
    shield_type = LAG_SHIELD_FFIELD;
  else if(is_affected(ch, gen_ref_shield))
    shield_type = LAG_SHIELD_RFIELD;
  else if(is_armor_enhanced(ch) > ENHANCE_BASIC)
    shield_type = LAG_SHIELD_ARMOR;
  else if (is_affected(ch, gsn_iron_will)
     && ch->mana > 0)
    shield_type = LAG_SHIELD_IWILL;
  else if (is_affected(ch, gsn_mist_form))
    shield_type = LAG_SHIELD_NONCORP;
  else if (get_skill(ch, gsn_balance) > 1
	   && ch->class == gcn_monk
	   && is_empowered_quiet(ch,1)
	   && ch->mana > 0)
    shield_type = LAG_SHIELD_BALANCE;
  else if (get_skill(ch, gsn_balance) > 1
	   && ch->class == gcn_blademaster
	   && is_empowered_quiet(ch,1)
	   && ch->mana > 0)
    shield_type = LAG_SHIELD_BALANCE;
  return shield_type;
}

/* preforms ALL lagsshield checks, displays messges and yells */
/* set yell to TRUE to yell */
/* pass how good the bash attack was using chance */
/* Pass amount of lag by address as it is changed in the function */
/* pass damage by address as it is changed as well. */
/* pass if lag attack was successful or not by fSuccess (needed for skills that only work if hit like balance.)*/
   /* returns TRUE if cahracter was shielded. */

bool do_lagprot(CHAR_DATA* ch, CHAR_DATA* victim, int chance, int* do_dam, int* lag, int sn, bool fSuccess, bool fYell)
{
  int shield = LAG_SHIELD_NONE;
  int dam = *do_dam;
  int vic_lag = *lag;

  if ( (shield = get_lagprot(victim)) != LAG_SHIELD_NONE)
    {
      bool fProt = FALSE;	
      /* BALANCE */
      if (shield == LAG_SHIELD_BALANCE && fSuccess)
	{
	  if (number_percent() < get_skill(victim, gsn_balance))
	    {
	      if (sn == gsn_bash)
		{
		  check_improve(victim,gsn_balance,TRUE,60);
		  victim->mana -= URANGE(0,10, victim->mana);
		}
	      else if (sn == gsn_bodyslam)
		{
		  check_improve(victim,gsn_balance,TRUE,70);
		  victim->mana -= URANGE(0,15,victim->mana);
		}
	      else if (sn == gsn_grapple)
		{
		  check_improve(victim,gsn_balance,TRUE,40);
		  victim->mana -= URANGE(0,7,victim->mana);
		}
	      else if (sn == gsn_thrust)
		{
		  check_improve(victim,gsn_balance,TRUE,90);
		  victim->mana -= URANGE(0,18,victim->mana);
		}

	      else
		{
		  check_improve(victim,gsn_balance,TRUE,50);
		  victim->mana -= URANGE(0,10,victim->mana);
		}
	      fProt = TRUE;	
	      vic_lag = 0;
	    }
	}//END BALANCE
      /* IRON WILL */
      else if (shield == LAG_SHIELD_IWILL && fSuccess)
	{
	  if (number_percent() < 100 + (victim->level - ch->level) * 5)
	    {
	      if (sn == gsn_bash)
		victim->mana -= URANGE(0,20,victim->mana);
	      else if (sn == gsn_bodyslam)
		victim->mana -= URANGE(0,30,victim->mana);
	      else if (sn == gsn_grapple)
		victim->mana -= URANGE(0,15,victim->mana);
	      else if (sn == gsn_thrust)
		victim->mana -= URANGE(0,40,victim->mana);
	      else 
		victim->mana -= URANGE(0,20,victim->mana);
	      
	      fProt = TRUE;	
	      vic_lag = 0;
	    }
	}//END IRON WILL
      /* NORMAL SHIELDS */
      else if (shield == LAG_SHIELD_ARMOR)
	{
	  if (number_percent() < 25){
	    fProt = TRUE;	
	    vic_lag = 0;
	    dam = 0;
	  }
	}
      else if (shield == LAG_SHIELD_RFIELD)
	{
	  fProt = TRUE;	
          vic_lag = UMAX(PULSE_VIOLENCE, 2 * vic_lag / 3);
	  dam = dam / 2;
	}
      else if (shield == LAG_SHIELD_FFIELD)
	{
	  fProt = TRUE;	
          vic_lag = 0;
	  dam = 0;
	}
      else if (shield == LAG_SHIELD_PROT)
	{
	  fProt = TRUE;	
          vic_lag = 0;
	  dam = 0;
	}
      if (fProt)
	lagprot_msg(ch, victim, sn, shield, fYell);
      *lag = vic_lag;
      *do_dam = dam;
      return fProt;
    }//END LAGPROTECTION
  return FALSE;
}//end do_lagprot


void a_yell( CHAR_DATA *ch, CHAR_DATA *victim )
{
  char buf[MSL];
  if (ch == NULL || victim == NULL)
    return;
  if (ch->fighting != victim && victim->fighting != ch && (!IS_NPC(ch) || ch->master != NULL)){
    if (!IS_NPC(victim)){
      sprintf(buf,"%s attacked %s at %d", IS_NPC(ch) ? ch->short_descr : ch->name, 
	      victim->name,ch->in_room->vnum);
      log_string(buf);
      wiznet(buf,NULL,NULL,WIZ_FIGHTING,0,0);
      continuum(victim, CONTINUUM_ATTACK);
     
/* MURDER CRIME CHECK */
      if (ch->in_room && is_crime(ch->in_room, CRIME_MURDER, victim)){
	set_crime(ch, victim, ch->in_room->area, CRIME_MURDER);
	
	/* check of simulacra for justices */
	if (is_affected(ch, gsn_doppelganger)){
	  char buf[MIL];
	  sprintf( buf, "Warning! Someone seems to be masquerading as %s!",
		   PERS2(ch));
	  cabal_echo_flag( CABAL_JUSTICE | CABAL_HEARGUARD, buf );
	}
      }
/* ATTACKING JUSTICE IN LAWFUL AREA IS ALWAYS AN OBSTRUCTION */
      else if (victim->pCabal && IS_CABAL(victim->pCabal, CABAL_JUSTICE) && IS_AREA(ch->in_room->area, AREA_LAWFUL)){
	set_crime(ch, victim, ch->in_room->area, CRIME_OBSTRUCT);
      }
      /* CONTINENCY */
      check_contingency(ch, NULL, CONT_ATTACK);
      check_contingency(victim, NULL, CONT_ATTACKED);

    }//END PC CHECK
    else {
      bool fCrime = FALSE;
/* ASSAULT CRIME CHECK */
      if (ch->in_room && is_crime(ch->in_room, CRIME_ASSAULT, victim)){
	set_crime(ch, victim, ch->in_room->area, CRIME_ASSAULT);
	fCrime = TRUE;
      }
/* ATTACKING JUSTICE MOBS IN LAWFUL AREA IS ALWYAS A CRIME */
      else if (victim->pCabal && IS_CABAL(victim->pCabal, CABAL_JUSTICE) && IS_AREA(ch->in_room->area, AREA_LAWFUL)){
	set_crime(ch, victim, ch->in_room->area, CRIME_OBSTRUCT);
	fCrime = TRUE;
      }
/* attackign charmed mobs requiers a yell as well */
      else if (IS_NPC(victim) && IS_AFFECTED(victim, AFF_CHARM))
	fCrime = TRUE;

      if (IS_SET(victim->off_flags,GUILD_GUARD) && victim->pCabal && IS_CABAL(victim->pCabal, CABAL_JUSTICE)){
	sprintf(buf, "%s: Alert! The jail is being attacked!", ch->in_room->area->name);
	cabal_echo_flag( CABAL_JUSTICE, buf );
	sprintf(buf, "Alert! The jail is being attacked by %s!",PERS(ch,victim));
      }
      else if (IS_SET(victim->off_flags,GUILD_GUARD))
	sprintf(buf, "Alert! The guild is being attacked by %s!",PERS(ch,victim));
      else
	sprintf(buf, "Help! I'm being attacked by %s!",PERS(ch,victim));
      
      //mark the cabal capture item timer if this is a cabal guard and members present
      if (victim->pCabal)
	set_capture_item_timer( victim );
      if (fCrime){
	REMOVE_BIT(victim->comm,COMM_NOCHANNELS);
	REMOVE_BIT(victim->comm,COMM_NOYELL);
	j_yell(victim,buf);
	SET_BIT(victim->comm,COMM_NOYELL);
	SET_BIT(victim->comm,COMM_NOCHANNELS);
      }
    }//END NPC CHECK
  }
}

void do_gain(CHAR_DATA *ch, char *argument)
{
    char arg[MIL];
    CHAR_DATA *trainer;
    if (IS_NPC(ch))
	return;
    if (ch->class == gcn_adventurer){
      send_to_char("Adventurers cannot convert train and practice sessions.\n\r", ch);
      return;
    }
    for ( trainer = ch->in_room->people; trainer != NULL; trainer = trainer->next_in_room)
	if (IS_NPC(trainer) && IS_SET(trainer->act,ACT_GAIN))
	    break;
    if (trainer == NULL || !can_see(ch,trainer))
    {
	send_to_char("You can't do that here.\n\r",ch);
	return;
    }
    if (is_exiled(ch, trainer->in_room->area->vnum )){
      char buf[MIL];
      sprintf( buf, "No one in %s will deal with you %s!", trainer->in_room->area->name, PERS2(ch));
      do_say( trainer, buf );
      return;
    }
    one_argument(argument,arg);
    if (arg[0] == '\0')
    {
	do_say(trainer,"Pardon me?");
	return;
    }
    if (!str_prefix(arg,"convert"))
    {
	if (ch->practice < 10)
	{
            act("$N tells you '`2You are not yet ready.``'", ch,NULL,trainer,TO_CHAR);
	    return;
	}
        act("$N helps you apply your practice to training.", ch,NULL,trainer,TO_CHAR);
	ch->practice -= 10;
	ch->train +=1 ;
	return;
    }
    if (!str_prefix(arg,"study"))
    {
	if (ch->train < 1)
	{
            act("$N tells you '`2You do not have enough training sessions.``'", ch,NULL,trainer,TO_CHAR);
	    return;
	}
        act("$N helps you apply your training to practices.", ch,NULL,trainer,TO_CHAR);
	ch->practice += 10;
	ch->train -=1 ;
	return;
    }
    act("$N tells you '`2I do not understand...``'",ch,NULL,trainer,TO_CHAR);
}

void do_spells(CHAR_DATA *ch, char *argument)
{
    char arg[MIL], spell_list[LEVEL_IMMORTAL + 2][MSL], spell_columns[LEVEL_IMMORTAL + 2], buf[MSL];
    int sn, level, sk_level, min_lev = 1, max_lev = LEVEL_HERO+1, mana;
    bool fAll = FALSE, found = FALSE;
    CSKILL_DATA* cSkill;

    if (IS_NPC(ch))
        return;
    if (argument[0] != '\0')
    {
	fAll = TRUE;
	if (str_prefix(argument,"all"))
	{
	    argument = one_argument(argument,arg);
	    if (!is_number(arg))
	    {
		send_to_char("Arguments must be numerical or all.\n\r",ch);
		return;
	    }
	    max_lev = atoi(arg);
            if (max_lev < 1 || max_lev > LEVEL_HERO)
	    {
                sendf(ch,"Levels must be between 1 and %d.\n\r",LEVEL_HERO);
		return;
	    }
	    if (argument[0] != '\0')
	    {
		argument = one_argument(argument,arg);
		if (!is_number(arg))
		{
		    send_to_char("Arguments must be numerical or all.\n\r",ch);
		    return;
		}
		min_lev = max_lev;
		max_lev = atoi(arg);
                if (max_lev < 1 || max_lev > LEVEL_HERO)
		{
                    sendf(ch,"Levels must be between 1 and %d.\n\r",LEVEL_HERO);
		    return;
		}
		if (min_lev > max_lev)
		{
		    send_to_char("That would be silly.\n\r",ch);
		    return;
		}
	    }
	}
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
    {
        spell_columns[level] = 0;
        spell_list[level][0] = '\0';
    }
    for (sn = 0; sn < MAX_SKILL; sn++)
    {
        if (skill_table[sn].name == NULL )
	    break;
	cSkill = ch->pCabal ? get_cskill( ch->pCabal, sn ) : NULL;
	if (cSkill){
	  level = cSkill->pSkill->level;
	  sk_level = sklevel(ch,sn);
	}
	else
	  level = sk_level = sklevel(ch,sn);

	if ( (sk_level < LEVEL_IMMORTAL + 2 || sk_level == CABAL_COST_FAILED)
	     && level >= min_lev 
	     && level <= max_lev
	     && skill_table[sn].spell_fun != spell_null 
	     && ch->pcdata->learned[sn] > 0)
	  {
	    mana = _mana_cost(ch, sn);
	    found = TRUE;

	    if (ch->level < sk_level){
	      if (sk_level == CABAL_COST_FAILED)
	        sprintf(buf,"%-16s <`!%3d/%d``> m/cp  ",skill_table[sn].name, mana, get_cskill_cost(ch, ch->in_room, cSkill));
	      else
	    	sprintf(buf,"%-18s  n/a       ", skill_table[sn].name);
	    }
	    else
	    {
	      if (cSkill)
		sprintf(buf,"%-17s %3d/%d m/cp  ",skill_table[sn].name, mana, get_cskill_cost(ch, ch->in_room, cSkill));
	      else
		sprintf(buf,"%-19s %3d mana  ",skill_table[sn].name,mana);
	    }
	    if (spell_list[level][0] == '\0')
	      sprintf(spell_list[level],"\n\rLevel %2d: %s",level,buf);
            else
	      {
          	if ( ++spell_columns[level] % 2 == 0)
		  strcat(spell_list[level],"\n\r          ");
          	strcat(spell_list[level],buf);
	      }
	  }
    }
    if (!IS_NPC(ch) && ch->pcdata->newskills != NULL )
    {
	SKILL_DATA *nsk;
	for (nsk = ch->pcdata->newskills; nsk != NULL; nsk = nsk->next )
	{
	  if ((level=nsk->level) < LEVEL_IMMORTAL + 2 && level >= min_lev && level <= max_lev
	      &&skill_table[nsk->sn].spell_fun != spell_null)
	  {
	    found = TRUE;
	    if (ch->level < nsk->level)
	    	sprintf(buf,"%-18s  n/a       ", skill_table[nsk->sn].name);
	    else
	    {
                mana = UMAX(skill_table[nsk->sn].min_mana, 100/(2 + ch->level - nsk->level));
	        sprintf(buf,"%-19s %3d mana  ",skill_table[nsk->sn].name,mana);
	    }
	    if (spell_list[level][0] == '\0')
          	sprintf(spell_list[level],"\n\rLevel %2d: %s",level,buf);
            else
	    {
          	if ( ++spell_columns[level] % 2 == 0)
		    strcat(spell_list[level],"\n\r          ");
          	strcat(spell_list[level],buf);
	    }
	  }
	}
    }
    if (!found)
    {
      	send_to_char("No spells found.\n\r",ch);
      	return;
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
      	if (spell_list[level][0] != '\0')
            send_to_char(spell_list[level],ch);
    send_to_char("\n\r",ch);
}

void do_songs(CHAR_DATA *ch, char *argument)
{
    char arg[MIL], spell_list[LEVEL_IMMORTAL + 2][MSL], spell_columns[LEVEL_IMMORTAL + 2], buf[MSL];
    int sn, level, min_lev = 1, max_lev = LEVEL_HERO+1, mana;
    bool fAll = FALSE, found = FALSE;
    if (IS_NPC(ch))
        return;
    if (argument[0] != '\0')
    {
	fAll = TRUE;
	if (str_prefix(argument,"all"))
	{
	    argument = one_argument(argument,arg);
	    if (!is_number(arg))
	    {
		send_to_char("Arguments must be numerical or all.\n\r",ch);
		return;
	    }
	    max_lev = atoi(arg);
            if (max_lev < 1 || max_lev > LEVEL_IMMORTAL + (IS_IMMORTAL(ch) ? 1 : (-1)))
	    {
                sendf(ch,"Levels must be between 1 and %d.\n\r",LEVEL_IMMORTAL+(IS_IMMORTAL(ch) ? 1 : (-1)));
		return;
	    }
	    if (argument[0] != '\0')
	    {
		argument = one_argument(argument,arg);
		if (!is_number(arg))
		{
		    send_to_char("Arguments must be numerical or all.\n\r",ch);
		    return;
		}
		min_lev = max_lev;
		max_lev = atoi(arg);
                if (max_lev < 1 || max_lev > LEVEL_IMMORTAL + (IS_IMMORTAL(ch) ? 1 : (-1)))
		{
                    sendf(ch,"Levels must be between 1 and %d.\n\r",LEVEL_IMMORTAL+(IS_IMMORTAL(ch) ? 1 : (-1)));
		    return;
		}
		if (min_lev > max_lev)
		{
		    send_to_char("That would be silly.\n\r",ch);
		    return;
		}
	    }
	}
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
    {
        spell_columns[level] = 0;
        spell_list[level][0] = '\0';
    }
    for (sn = 0; sn < MAX_SONG; sn++)
    {
        if (song_table[sn].name == NULL )
	    break;
	if ((level=sglevel(ch,sn)) < LEVEL_IMMORTAL + 2 && level >= min_lev && level <= max_lev
        && song_table[sn].song_fun != song_null && ch->pcdata->songlearned[sn] > 0)
        {
	    found = TRUE;
	    if (ch->level < sglevel(ch,sn))
	    	sprintf(buf,"%-23s  n/a       ", song_table[sn].name);
	    else
	    {
                mana = UMAX(song_table[sn].min_mana, 100/(2 + ch->level - sglevel(ch,sn)));
	        sprintf(buf,"%-24s %3d mana  ",song_table[sn].name,mana);
	    }
	    if (spell_list[level][0] == '\0')
          	sprintf(spell_list[level],"\n\rLevel %2d: %s",level,buf);
            else
	    {
          	if ( ++spell_columns[level] % 2 == 0)
		    strcat(spell_list[level],"\n\r          ");
          	strcat(spell_list[level],buf);
	    }
	}
    }
    if (!found)
    {
      	send_to_char("No songs found.\n\r",ch);
      	return;
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
      	if (spell_list[level][0] != '\0')
            send_to_char(spell_list[level],ch);
    send_to_char("\n\r",ch);
}

void do_skills(CHAR_DATA *ch, char *argument)
{
    char arg[MIL], skill_list[LEVEL_IMMORTAL + 2][MSL], skill_columns[LEVEL_IMMORTAL + 2], buf[MSL];
    int sn, level, sk_level, min_lev = 1, max_lev = LEVEL_HERO+1;
    bool fAll = FALSE, found = FALSE;
    CSKILL_DATA* cSkill;
    if (IS_NPC(ch))
        return;
    if (argument[0] != '\0')
    {
	fAll = TRUE;
	if (str_prefix(argument,"all"))
	{
	    argument = one_argument(argument,arg);
	    if (!is_number(arg))
	    {
		send_to_char("Arguments must be numerical or all.\n\r",ch);
		return;
	    }
	    max_lev = atoi(arg);
            if (max_lev < 1 || max_lev > LEVEL_HERO)
	    {
                sendf(ch,"Levels must be between 1 and %d.\n\r", LEVEL_HERO);
		return;
	    }
	    if (argument[0] != '\0')
	    {
		argument = one_argument(argument,arg);
		if (!is_number(arg))
		{
		    send_to_char("Arguments must be numerical or all.\n\r",ch);
		    return;
		}
		min_lev = max_lev;
		max_lev = atoi(arg);
                if (max_lev < 1 || max_lev > LEVEL_HERO)
		{
                    sendf(ch,"Levels must be between 1 and %d.\n\r",LEVEL_HERO);
		    return;
		}
		if (min_lev > max_lev)
		{
		    send_to_char("That would be silly.\n\r",ch);
		    return;
		}
	    }
	}
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
    {
        skill_columns[level] = 0;
        skill_list[level][0] = '\0';
    }
    for (sn = 0; sn < MAX_SKILL; sn++)
    {
        if (skill_table[sn].name == NULL )
	    break;
	
	cSkill = ch->pCabal ? get_cskill( ch->pCabal, sn ) : NULL;
	if (cSkill){
	  level = cSkill->pSkill->level;
	  sk_level = sklevel(ch,sn);
	}
	else
	  level = sk_level = sklevel(ch,sn);

	if ( (sk_level < LEVEL_IMMORTAL + 2 || sk_level == CABAL_COST_FAILED)
	     && level >= min_lev 
	     && level <= max_lev
	     && skill_table[sn].spell_fun == spell_null 
	     && ch->pcdata->learned[sn] > 0)
	  {
	    found = TRUE;
	    if (ch->level < sk_level){
	      if (sk_level == CABAL_COST_FAILED){
		sprintf(buf,"%-17s <`!%3d``>      ",skill_table[sn].name, 
			URANGE(0, ch->pcdata->learned[sn] + ch->pcdata->to_learned[sn], 110));
	      }
	      else
		sprintf(buf,"%-18s  n/a      ", skill_table[sn].name);
	    }
	    else if (ch->pcdata->to_learned[sn] != 0)
	      sprintf(buf,"%-18s `%s%3d``      ",
		      skill_table[sn].name, 
		      ch->pcdata->to_learned[sn] > 0 ? "@" : "1",
		      URANGE(0, ch->pcdata->learned[sn] + ch->pcdata->to_learned[sn], 110));
	    else
	      sprintf(buf,"%-18s %3d      ",skill_table[sn].name, 
		      URANGE(0, ch->pcdata->learned[sn] + ch->pcdata->to_learned[sn], 110));
	    if (skill_list[level][0] == '\0')
          	sprintf(skill_list[level],"\n\rLevel %2d: %s",level,buf);
            else
	    {
          	if ( ++skill_columns[level] % 2 == 0)
		    strcat(skill_list[level],"\n\r          ");
          	strcat(skill_list[level],buf);
	    }
	}
    }
    /* add on any skill sets */
    if (HAS_SS(ch->class)){
      int ss = 0;
      /* put in each group of ss's at their level */
      if ( (ss = ss_lookup(class_table[ch->class].ss)) != 0){
	int i = 0;
	int picks = 0;
	/* check if we even have selections at this level */
	for (i = 0; ss_table[ss].level > 0 && i < MAX_SELECT; i++){
	  int level = ss_table[ss].level[i];
	  
	  if (ss_table[ss].picks[i] == 0
	      || IS_NULLSTR(ss_table[ss].group[i]))
	    break;
	  /* check for level range dicatated by the command */
	  if (level < min_lev || level > max_lev)
	    continue;
	  /* check if we have any picks out of this group */
	  if ( (picks = can_group_select(ch, ss_group_lookup(ss_table[ss].group[i]), level)) == 0)
	    continue;
	  found = TRUE;
	  if (ch->level >= level)
	    sprintf(buf,"%-17s [%3d]     ",ss_table[ss].group[i], picks);
	  else
	    sprintf(buf,"%-17s [%3s]     ",ss_table[ss].group[i], " n/a");
	  if (skill_list[level][0] == '\0')
	    sprintf(skill_list[level],"\n\rLevel %2d: %s",level,buf);
	  else
	    {
	      if ( ++skill_columns[level] % 2 == 0)
		strcat(skill_list[level],"\n\r          ");
	      strcat(skill_list[level],buf);
	    }
	}
      }
    }
    if (!IS_NPC(ch) && ch->pcdata->newskills != NULL )
    {
	SKILL_DATA *nsk;
	for (nsk = ch->pcdata->newskills; nsk != NULL; nsk = nsk->next )
	{
	  if ((level=nsk->level) < LEVEL_IMMORTAL + 2 
	      && level >= min_lev && level <= max_lev
	      && skill_table[nsk->sn].spell_fun == spell_null
	      && nsk->learned > 0)
	  {
	    found = TRUE;
	    if (ch->level < nsk->level)
	    	sprintf(buf,"%-18s  n/a      ", skill_table[nsk->sn].name);
	    else
                sprintf(buf,"%-18s %3d      ", skill_table[nsk->sn].name, nsk->learned);
	    if (skill_list[level][0] == '\0')
          	sprintf(skill_list[level],"\n\rLevel %2d: %s",level,buf);
            else
	    {
          	if ( ++skill_columns[level] % 2 == 0)
		    strcat(skill_list[level],"\n\r          ");
          	strcat(skill_list[level],buf);
	    }
	  }
	}
    }
    if (!found)
    {
      	send_to_char("No skills found.\n\r",ch);
      	return;
    }
    for (level = 0; level < LEVEL_IMMORTAL + 2; level++)
      	if (skill_list[level][0] != '\0')
            send_to_char(skill_list[level],ch);
    send_to_char("\n\r",ch);
}

int exp_per_level(CHAR_DATA *ch, int level)
{
    int temp;
    if (IS_NPC(ch))
	return 1000; 
    temp = (pc_race_table[ch->race].class_mult + class_table[ch->class].extra_exp);
    return temp+temp*(level-1)*0.2;
}

long total_exp(CHAR_DATA *ch)
{
    int temp, i, total;
    if (IS_NPC(ch))
        return (ch->level+1)*1000; 
    temp = (pc_race_table[ch->race].class_mult + class_table[ch->class].extra_exp);
    total = temp;
    for (i = 1; i <= ch->level; i++)
        total += exp_per_level(ch,i);
    return total;
}

void check_improve( CHAR_DATA *ch, int sn, bool success, int bonus_gain ){
  SKILL_DATA* nsk = NULL;
  CSKILL_DATA* cSkill = NULL;

  //const
  const int base_gain = int_app[get_curr_stat(ch,STAT_INT)].learn;
  const int smart_mod = 2;//given to races that learn faster
  const int dnd_mul = 300;//%multiplier of gain for dnd system spells

  int limit = 100;	   //how far can the skill be improved.
  int rating = 0;
  sh_int *learned = 0;
  int* progress = 0;
  int gain = base_gain;

  //npcs do not learn
  if (IS_NPC(ch))
    return;
  //spells cast on self do not case learning either
  else if (is_affected(ch, gsn_nolearn))
    return;
  //do not learn skills we cannot use yet
  else if (ch->level < sklevel(ch, sn) )
    return;

  /* get info on the skill we are going to learn */
  /* first check if we should look at dynamic skills */
  if ( ch->pCabal && (cSkill = get_cskill(ch->pCabal, sn)) != NULL){
    rating = cSkill->pSkill->rating;
    learned = &ch->pcdata->learned[sn];
  }
  else if ( (nsk = nskill_find(ch->pcdata->newskills,sn)) == NULL){
    rating = skill_table[sn].rating[ch->class];
    learned = &ch->pcdata->learned[sn];
  }
  else{
    rating = nsk->rating;
    learned = &nsk->learned;
  }

  //get skill limit
  limit = get_skillmax( ch, sn );

  /* easy abort cases */
  if (rating == 0 || *learned < 2 || *learned >= limit)
    return;
  else if (ch->level <= 10 && *learned >= 80)
    return;
  else
    progress = &ch->pcdata->progress[sn];

  /* calculate progress gain */
  //penalty from the skill_table 1 = normal, 9 = very hard
  //ratings of 10 (racial skills are treated as 1)
  if (rating == 10)
    rating = 1;
  rating = URANGE(1, rating, 9);
  gain = 2 * base_gain / (1 + rating);

  //multiply the basic gain by lag for this skill if any
  gain = gain * UMAX(1, skill_table[sn].beats / PULSE_VIOLENCE);

  //Double for skills that cannot be used in combat
  if (skill_table[sn].minimum_position > POS_FIGHTING)
    gain += gain;

  //due to legacy issues, we treat bonus of 1 as 0
  if (bonus_gain == 1)
    bonus_gain -=1;
  gain += bonus_gain;
  gain += UMAX(0, get_curr_stat(ch,STAT_WIS) - 20);
  if (ch->race == grn_half_elf || IS_PERK( ch, PERK_SICKLY))
    gain += smart_mod;
  if (ch->pcdata->condition[COND_HUNGER] <= 5)
    gain /=2;
  //failure gain
  if (!success)
    gain = 15 * gain / 10;
  gain = UMAX(1, gain);

  if (IS_DNDS(ch) 
      && cSkill == NULL
      && skill_table[sn].spell_fun != spell_null
      && !IS_GNBIT(sn, GN_NO_DND)){
    gain = dnd_mul * gain / 100;
  }

  if (skill_table[sn].spell_fun == spell_null)
    gain = gain * (100 + ch->aff_mod[MOD_SKILL_LEARN]) / 100;
  else
    gain = gain * (100 + ch->aff_mod[MOD_SPELL_LEARN]) / 100;
  
  //force increase
  if (bonus_gain == -99)
    *progress = 0;
  //decrease progress
  *progress -= gain;

  /* check for increase of skill */
  if (*progress < 1){
    *learned += 1;
    *progress = get_skill_reps( *learned );
    *progress += (rand() % 11) * *progress / 100;

    sendf(ch,"You have become better at %s!\n\r", skill_table[sn].name);
    gain_exp(ch, number_range( rating, rating * 15));

    if (*learned == limit){
      sendf(ch, "You have now mastered <%s>!\n\r",skill_table[sn].name);
      *progress = 0;
    }
  }
}

void check_improve_old( CHAR_DATA *ch, int sn, bool success, int multiplier )
{
  SKILL_DATA* nsk = NULL;
  CSKILL_DATA* cSkill = NULL;
  //const
  const int base_chance = int_app[get_curr_stat(ch,STAT_INT)].learn;
  const int level_mod = 50; //(percent of lvl bonus)
  const int wis_mod = 50; //(percent of lvl bonus)
  const int smart_mod = 10;//given to smart races.
  const int dnd_mul = 600;//multiplier of chance for dnd spell system spells

  int limit = 100;	   //how far can the skill be improved.
  int mod = 0;

  int rating = 0;
  sh_int *learned = 0;
  int chance;
  bool dcheck = TRUE;

  if (IS_NPC(ch))
    return;
  else if (is_affected(ch, gsn_nolearn))
    return;

  if (sn > 5000){
    dcheck = FALSE;
    sn -= 5000;
  }

  if (ch->level < sklevel(ch,sn) )
    return;

  limit = get_skillmax( ch, sn );
  /* get info on the skill we are going to learn */
  /* first check if we should look at dynamic skills */
  if ( ch->pCabal && (cSkill = get_cskill(ch->pCabal, sn)) != NULL){
    rating = cSkill->pSkill->rating;
    learned = &ch->pcdata->learned[sn];
  }
  else if ( (nsk = nskill_find(ch->pcdata->newskills,sn)) == NULL){
    rating = skill_table[sn].rating[ch->class];
    learned = &ch->pcdata->learned[sn];
  }
  else{
    rating = nsk->rating;
    learned = &nsk->learned;
  }

/* check for skill stats now */

  if (rating == 0
      || *learned < 2 
      || *learned >= limit)
    return;

  if (ch->level <= 10 && *learned >= 80)
    return;

  /* check if this is a dnd spell caster */
  if (multiplier == -99){
    sendf(ch,"You have become better at %s!\n\r", skill_table[sn].name);
    *learned += 1;
    gain_exp(ch, rating);
    return;
  }
  chance = base_chance;
  //benefit from multiplier.
  chance = (9 + UMAX(1, multiplier)) * chance / 10;
  //penalty from the skill_table
  chance = (11  - ( rating >= 10? 6: rating)) * chance / 10;
//level bonus
  chance += level_mod * ch->level / 100;
//smart races bonus
  if (ch->race == race_lookup("half-elf")
      || ch->race == race_lookup("faerie")
      || IS_PERK( ch, PERK_SICKLY)
      )
    chance += smart_mod;
//wisdom bonus
  chance += wis_mod *  get_curr_stat(ch,STAT_WIS) / 100;

  if (ch->pcdata->condition[COND_HUNGER] <= 5)
    chance /=2;

  if (!success)
    chance = 12 * chance / 10;
  chance = UMAX(1, chance);

  if (IS_DNDS(ch) 
      && cSkill == NULL
      && skill_table[sn].spell_fun != spell_null
      && !IS_GNBIT(sn, GN_NO_DND)){
    chance += dnd_mul * chance / 100;
  }
  if (number_range(1,1000) > chance){
    if (number_percent() < 5 && dcheck)
      check_improve(ch,sn+5000,success,multiplier);
    return;
  }
  if (skill_table[sn].spell_fun == spell_null)
    mod = ch->aff_mod[MOD_SKILL_LEARN];
  else
    mod = ch->aff_mod[MOD_SPELL_LEARN];
  if (success){
    chance = URANGE(5,limit - *learned, 95);
    chance = chance * (100 + mod) / 100;
    if (number_percent() < chance){
      sendf(ch,"You have become better at %s!\n\r", skill_table[sn].name);
      *learned += 1;
      gain_exp(ch, number_range( rating, rating * 15));
    }
  }
  else{
    chance = URANGE(5, *learned / 2, 30);
    chance = chance * (100 + mod) / 100;
    if (number_percent() < chance){
      sendf(ch,"You learn from your mistakes, and your %s skill improves.\n\r",skill_table[sn].name);
      *learned += number_range(1,3);
      *learned = UMIN(*learned, limit);
      gain_exp(ch, rating * 20);
    }
  }
  if (*learned == limit)
    sendf(ch, "You have now mastered <%s>!\n\r",skill_table[sn].name);
}

int group_lookup( const char *name )
{
    int gn;
    for ( gn = 0; gn < MAX_GROUP; gn++ )
    {
        if ( group_table[gn].name == NULL )
            break;
        if ( LOWER(name[0]) == LOWER(group_table[gn].name[0]) && !str_prefix( name, group_table[gn].name ) )
            return gn;
    }
    return -1;
}

void gn_add( CHAR_DATA *ch, int gn)
{
    int i;
    ch->pcdata->group_known[gn] = TRUE;
    for ( i = 0; i < MAX_IN_GROUP; i++)
    {
        if (group_table[gn].spells[i] == NULL)
            break;
        group_add(ch,group_table[gn].spells[i],FALSE);
    }
}
	
void group_add( CHAR_DATA *ch, const char *name, bool deduct)
{
    int sn = skill_lookup(name), gn = group_lookup(name);
    if (IS_NPC(ch))
	return;
    if (sn != -1)
    {
        if (ch->pcdata->learned[sn] == 0 || ch->pcdata->learned[sn] == 1 )
	{
	    if (deduct)
	        ch->pcdata->learned[sn] = 100;
	    else
	        ch->pcdata->learned[sn] = 1;
	}
	return;
    }
    if (gn != -1)
    {
	if (ch->pcdata->group_known[gn] == FALSE)  
	    ch->pcdata->group_known[gn] = TRUE;
        gn_add(ch,gn);
    }
}

void do_envenom(CHAR_DATA *ch, char *argument)
{
    OBJ_DATA *obj;
    AFFECT_DATA af;
    bool fAdv = get_skill(ch, skill_lookup("lotus scourge")) > 1;

    int percent, skill, np = number_percent();
    if ((skill = get_skill(ch,gsn_envenom)) == 0)
    {
	send_to_char("Are you crazy? You'd poison yourself!\n\r",ch);
	return;
    }
    if (argument[0] == '\0')
    {
	send_to_char("Envenom what item?\n\r",ch);
	return;
    }
    obj =  get_obj_list(ch,argument,ch->carrying);
    if (obj== NULL)
    {
	send_to_char("You don't have that item.\n\r",ch);
	return;
    }
    if (ch->mana < 50)
    {
	send_to_char("Rest up a bit first.\n\r",ch);
	return;
    }
    ch->mana -= 50;
    if (fAdv){
      send_to_char("Using the lore of the Lotus Scourge you prepare a deadly toxin.\n\r", ch);
    }
    if (obj->item_type == ITEM_FOOD || obj->item_type == ITEM_DRINK_CON)
    {
        if (UMAX(1,np + 2*(get_curr_stat(ch,STAT_LUCK) - 16)) < skill)
	{
	    act("$n treats $p with deadly poison.",ch,obj,NULL,TO_ROOM);
	    act("You treat $p with deadly poison.",ch,obj,NULL,TO_CHAR);
	    if (!obj->value[3])
	    {
		obj->value[3] = 1;
		check_improve(ch,gsn_envenom,TRUE,1);
	    }
	    else
		send_to_char("It's already poisoned.\n\r",ch);
	    WAIT_STATE2(ch,skill_table[gsn_envenom].beats);
	    return;
	}
	act("You fail to poison $p.",ch,obj,NULL,TO_CHAR);
	if (!obj->value[3])
	    check_improve(ch,gsn_envenom,FALSE,1);
	WAIT_STATE2(ch,skill_table[gsn_envenom].beats);
	return;
     }
     if (obj->item_type == ITEM_THROW)
     {
       if (obj->value[3] < 0 || attack_table[obj->value[3]].damage == DAM_BASH)
	 {
	   send_to_char("You can only envenom edged weapons.\n\r",ch);
	   return;
	 }
       if (IS_WEAPON_STAT(obj,WEAPON_POISON))
	 {
	   act("$p is already envenomed.",ch,obj,NULL,TO_CHAR);
	   return;
	 }
       percent = number_percent();
       percent -= 3 * (get_curr_stat(ch,STAT_LUCK) - 10);
       if (percent < 4 * skill / 5)
	 {
	   af.where     = TO_WEAPON;
	   af.type      = gsn_poison;
	   af.level     = fAdv ? ch->level + 5 : ch->level;
	   af.duration  = fAdv ? ch->level : ch->level * percent / 75;
	   af.location  = 0;
	   af.modifier  = 0;
	   af.bitvector = WEAPON_POISON;
	   affect_to_obj(obj,&af);
	   act("$n coats $p with deadly venom.",ch,obj,NULL,TO_ROOM);
	   act("You coat $p with venom.",ch,obj,NULL,TO_CHAR);
	   check_improve(ch,gsn_envenom,TRUE,3);
	   WAIT_STATE2(ch,skill_table[gsn_envenom].beats);
	   return;
	 }
       else
	 {
	   act("You fail to envenom $p.",ch,obj,NULL,TO_CHAR);
	   check_improve(ch,gsn_envenom,FALSE,3);
	   WAIT_STATE2(ch,skill_table[gsn_envenom].beats);
	   return;
	 }
     }
     act("You can't poison $p.",ch,obj,NULL,TO_CHAR);
}

void do_berserk( CHAR_DATA *ch, char *argument)
{
    int chance, hp_percent;
    if ((chance = 3 * get_skill(ch,gsn_berserk) / 4) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if ((IS_NPC(ch) && !IS_SET(ch->off_flags,OFF_BERSERK))
    || (!IS_NPC(ch) && ch->level < skill_table[gsn_berserk].skill_level[ch->class]))
    {
	send_to_char("You turn red in the face, but nothing happens.\n\r",ch);
	return;
    }
    if (IS_AFFECTED(ch,AFF_BERSERK) || is_affected(ch,gsn_berserk) || is_affected(ch,skill_lookup("frenzy")))
    {
	send_to_char("You get a little madder.\n\r",ch);
	return;
    }
    if (IS_AFFECTED(ch,AFF_CALM) || is_affected(ch,gsn_prayer))
    {
	send_to_char("You can't get worked up in your calm state.\n\r",ch);
	return;
    }
    if (!IS_NPC(ch) && ch->mana < 50)
    {
	send_to_char("You can't get up enough energy.\n\r",ch);
	return;
    }
    if (ch->position == POS_FIGHTING && chance > 1)
	chance += 35;
    hp_percent = 100 * ch->hit/ch->max_hit;
    if (number_percent() < chance)
    {
	AFFECT_DATA af;
	WAIT_STATE2(ch,PULSE_VIOLENCE);

	ch->move = UMAX(ch->move - 50, 0);
	if (!IS_NPC(ch))
	  ch->mana -= 50;
	ch->hit += 2 * ch->level;

	act("Your pulse races as you are consumed by rage!",ch,NULL,NULL,TO_CHAR);
	act("$n gets a wild look in $s eyes.",ch,NULL,NULL,TO_ROOM);
	check_improve(ch,gsn_berserk,TRUE,1);
	af.where	= TO_AFFECTS;
	af.type		= gsn_berserk;
	af.level	= ch->level;
        af.duration     = number_fuzzy(ch->level / 8);
	af.modifier	= UMAX(1,ch->level/8);
	af.bitvector 	= AFF_BERSERK;
	af.location	= APPLY_DAMROLL;
	affect_to_char(ch,&af);
	af.location	= APPLY_HITROLL;
	af.modifier	= UMAX(1, ch->level / 16);
	affect_to_char(ch,&af);
	af.modifier	= 40;
	af.location	= APPLY_AC;
	affect_to_char(ch,&af);
	af.modifier	= ch->level;
	af.location	= APPLY_HIT;
	affect_to_char(ch, &af);
    }
    else
    {
	WAIT_STATE2(ch,3 * PULSE_VIOLENCE);
	ch->mana -= 25;
	send_to_char("Your pulse speeds up, but nothing happens.\n\r",ch);
	check_improve(ch,gsn_berserk,FALSE,1);
    }
}

void do_bash( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;

//Data
    int chance = 4 * get_skill(ch,gsn_bash) /5;
    int dam = number_range(10 + ch->level/2, ch->size *  ch->level / 2);
    int vic_lag  = PULSE_VIOLENCE;
    int ch_lag = skill_table[gsn_bash].beats;

//bools
    bool fSuccess = FALSE;
    bool fYell = FALSE;
    one_argument(argument,arg);

    if (chance == 0)
    {
	send_to_char("Bashing? What's that?\n\r",ch);
	return;
    }

    if (arg[0] == '\0')
    {
	victim = ch->fighting;
        if (victim == NULL)
	{
	    send_to_char("But you aren't fighting anyone!\n\r",ch);
	    return;
	}
    }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
	send_to_char("They aren't here.\n\r",ch);
	return;
    }

    if ( victim == ch )
    {
      send_to_char("Self mutilation is not your style.\n\r",ch);
      return;
    }

    if (is_safe(ch,victim))
	return;

    //Get chance to bash.
    chance += ch->carry_weight/200 - victim->carry_weight/200;
    chance += get_curr_stat(ch,STAT_STR) - get_curr_stat(victim,STAT_DEX);
    chance += GET_AC2(victim,AC_BASH) /25;
    chance -= get_skill(victim,gsn_dodge)/20;
    chance += (ch->level - victim->level);
    chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    if ( ch->race == race_lookup("avian") 
	 || victim->race == race_lookup("faerie") )
      chance -=5;
    if ( victim->class == class_lookup("thief") )
      chance -= 5;
    if (is_affected(victim,gsn_horse))
      chance -= 5;
    if (!IS_NPC(victim) && victim->pcdata->pStallion && number_percent() < get_skill(victim, gsn_mounted)){
      chance -= 12;
      check_improve(victim, gsn_mounted, TRUE, 0);
    }
    chance += affect_by_size(ch,victim);

    //check if target should yell.
      fYell = (ch->fighting != victim && victim->fighting != ch);
    //sound attack to justice /imm
      a_yell(ch,victim);
//      sendf( ch, "chance: %d", chance );
    if (number_percent() < chance)
      {
	vic_lag  = URANGE(1, number_range(1, ch->size - victim->size + 3), 4) * PULSE_VIOLENCE;
	fSuccess = TRUE;
      }
    else
      {
	dam = 0;
      }

    //predict interdict
    if (predictCheck(ch, victim, "bash", skill_table[gsn_bash].name))
      return;

//MANTIS CHECK
    if (is_affected(victim,gsn_mantis) && fSuccess)
      {
	act("You use $n's momentum against him, and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	act("$N reverses your attack, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	act("$N reversed $n's attack, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	WAIT_STATE2(ch, URANGE(1, number_range(1, victim->size), 3) * PULSE_VIOLENCE);
	damage(victim,ch,dam,gsn_mantis,DAM_BASH,TRUE);
	affect_strip(victim,gsn_mantis);
	return;
      }//END MANTIS

//check for lag protect
    if (!do_lagprot(ch, victim, chance, &dam, &vic_lag, gsn_bash, fSuccess, fYell))
      {
	if (fYell)
	  {
	    sprintf(buf, "Help! %s is trying to bash me!",PERS(ch,victim));
	    j_yell(victim,buf);
	  }
	if (fSuccess)
	  {

           act("$n sends you sprawling with a powerful bash!",ch,NULL,victim,TO_VICT);
	   act("You slam into $N, and send $M flying!",ch,NULL,victim,TO_CHAR);
	   act("$n sends $N sprawling with a powerful bash.",ch,NULL,victim,TO_NOTVICT);
	 }
      	else
	  {
	    act("You fall flat on your face!", ch,NULL,victim,TO_CHAR);
	    act("$n falls flat on $s face.", ch,NULL,victim,TO_NOTVICT);
	    act("You evade $n's bash, causing $m to fall flat on $s face.",ch,NULL,victim,TO_VICT);
	  }
      }//END IF NO PROTECTION
	
	
    if (!fSuccess || dam == 0 || vic_lag == 0)
    {
      check_improve(ch, gsn_bash, FALSE, 1);	
      ch_lag = 3 * ch_lag / 2;
    }
    else
      check_improve(ch, gsn_bash, TRUE, 1);	
    
    WAIT_STATE2(ch, ch_lag);
    if (vic_lag != 0 && dam != 0)
      WAIT_STATE2(victim, vic_lag);
    if (ch->race == race_lookup("fire") && number_percent() < 3 * ch->level / 2)
      damage(ch,victim,3 * dam / 2,gsn_bash ,DAM_FIRE,TRUE);
    else
      damage(ch,victim,dam,gsn_bash,DAM_BASH,TRUE);

    if (ch && victim && ch->fighting == victim && dam > 0)
      check_ccombat_actions( victim, ch, CCOMBAT_BASHED);
}


/* does the actual dirt kicking: */
/* wait = true    will lag the dirt kicker */
/* wait = false   will not lag the dirt kicker */
void do_dirting ( CHAR_DATA *ch, int wait, char *argument) {
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;
    int chance;
    one_argument(argument,arg);
    if ( (chance = get_skill(ch,gsn_dirt)) == 0)
    {
	send_to_char("You get your feet dirty.\n\r",ch);
	return;
    }
    if (arg[0] == '\0')
    {
	victim = ch->fighting;
	if (victim == NULL)
	{
	    send_to_char("But you aren't in combat!\n\r",ch);
	    return;
	}
    }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
	send_to_char("They aren't here.\n\r",ch);
	return;
    }
    if (is_safe(ch,victim))
	return;
    if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
        sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
        return;
    }
    if (IS_AFFECTED(victim,AFF_BLIND))
    {
	act("$E's already been blinded.",ch,NULL,victim,TO_CHAR);
	return;
    }
    if ( victim == ch )
	return;


    chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
    chance += (ch->level - victim->level);
    chance -= get_skill(victim,gsn_dodge)/10;
    chance += UMAX(0, victim->size - SIZE_MEDIUM) * 5;
    
    chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    switch(ch->in_room->sector_type)
    {
	case(SECT_INSIDE):		chance -= 25;	break;
	case(SECT_CITY):		chance -= 15;	break;
	case(SECT_FIELD):		chance +=  5;	break;
	case(SECT_FOREST):				break;
	case(SECT_HILLS):				break;
	case(SECT_MOUNTAIN):		chance += 10;	break;
	case(SECT_WATER_SWIM):		chance  =  0;	break;
	case(SECT_WATER_NOSWIM):	chance  =  0;	break;
	case(SECT_AIR):			chance  =  0;  	break;
	case(SECT_DESERT):		chance += 25;   break;
    }
    if (chance == 0)
    {
	send_to_char("There isn't any dirt to kick.\n\r",ch);
	return;
    }
    if (wait == TRUE) {
      WAIT_STATE2(ch,skill_table[gsn_dirt].beats);
    }
    a_yell(ch,victim);

    //predict interdict
    if (predictCheck(ch, victim, "dirt", skill_table[gsn_dirt].name))
      return;

    chance = chance - 25 + UMIN(ch->level,25);
    if (is_affected(victim, gsn_mist_form))
      {
	act("You kick a few stones right through the mist.", ch, NULL, victim, TO_CHAR);
	act("$n kicks a bit of dirt right through $N.", ch, NULL, victim, TO_NOTVICT);
	act("$N kick a handfull of dirt through your non-corporeal form.", ch, NULL, victim, TO_CHAR);
	chance = 0;
      }
    if (number_percent() < chance)
    {
      bool fDirtProt =  (IS_EVIL(victim) && victim->race == race_lookup("slith") && number_percent() < 15 + victim->level);
	AFFECT_DATA af;
        if (ch->fighting != victim && victim->fighting != ch)
        {
            sprintf(buf, "Help! %s kicked dirt into my eyes!",PERS(ch,victim));
            j_yell(victim,buf);
        }
	act("$n is blinded by the dirt in $s eyes!",victim,NULL,NULL,TO_ROOM);
	act("$n kicks dirt in your eyes!",ch,NULL,victim,TO_VICT);
        damage(ch,victim,number_range(2,5),gsn_dirt,DAM_NONE,TRUE);
	send_to_char("You can't see a thing!\n\r",victim);
        check_improve(ch,gsn_dirt,TRUE,1);

	if (fDirtProt)
	  {
	    send_to_char("Your lizard ancestry serves you well and you easly recover.\n\r", victim);
	    return;
	  }

	af.where	= TO_AFFECTS;
	af.type 	= gsn_dirt;
	af.level 	= ch->level;
	af.duration	= 0;
	af.location	= APPLY_HITROLL;
        if (!IS_NPC(victim) && number_percent() < get_skill(victim,gsn_blind_fighting)){
	  if (is_affected(victim, gsn_battletrance))
	    af.modifier      = 0;
	  else
            af.modifier      = -3;
	}
        else
            af.modifier      = -6;
	af.bitvector 	= AFF_BLIND;
	
	affect_to_char(victim,&af);

        af.location     = APPLY_AC;
        if (!IS_NPC(victim) && number_percent() < get_skill(victim,gsn_blind_fighting)){
	  if (is_affected(victim, gsn_battletrance))
	    af.modifier      = 0;
	  else
            af.modifier      = +5;
	}
        else
            af.modifier      = +15;
	
	  affect_to_char(victim,&af);
    }
    else
    {
        if (ch->fighting != victim && victim->fighting != ch)
        {
            sprintf(buf, "Help! %s tried to kick dirt into my eyes!",PERS(ch,victim));
            j_yell(victim,buf);
        }
	damage(ch,victim,0,gsn_dirt,DAM_NONE,TRUE);
	check_improve(ch,gsn_dirt,FALSE,1);
        if (ch->fighting == NULL) {
	  if (wait == TRUE) {
	    WAIT_STATE2(ch,skill_table[gsn_dirt].beats);
	  }
	}
    }
}

void do_dirt( CHAR_DATA *ch, char *argument ) {
     do_dirting (ch, TRUE, argument);
}

void trip( CHAR_DATA *ch, CHAR_DATA* victim, int chance)
{
  bool fTrample = !IS_NPC(ch) && get_skill(ch, gsn_trample) > 1;
  int position = victim->position;

  if ((IS_AFFECTED(victim,AFF_FLYING) 
       && !is_affected(victim,gsn_thrash)) 
      || (!IS_NPC(victim) && victim->pcdata->pStallion != NULL && get_skill(victim, gsn_mounted)))
    {
      act("$S feet aren't on the ground.",ch,NULL,victim,TO_CHAR);
      act("Luckily your feet aren't on the ground.",ch,NULL,victim,TO_VICT);
      return;
    }
    if (check_ccombat_actions( victim, ch, CCOMBAT_TRIPPED))
      return;

    if (number_percent() < get_skill(victim, gsn_balance) 
	&& is_empowered_quiet(victim,1) && victim->mana > 0)
      {
	act("$n tries to trip you, but you keep your balance!",ch,NULL,victim,TO_VICT);
	act("You try to trip $N, but $E keeps $S balance!",ch,NULL,victim,TO_CHAR);
	act("$n tries to trip $N, but $E keeps $S balance.",ch,NULL,victim,TO_NOTVICT);
	check_improve(victim,gsn_balance,TRUE,50);
	victim->mana -= URANGE(0,25,victim->mana);

      }
    else
      {
	act("$n trips you and you go down!",ch,NULL,victim,TO_VICT);
	act("You trip $N and $E goes down!",ch,NULL,victim,TO_CHAR);
	act("$n trips $N, sending $M to the ground.",ch,NULL,victim,TO_NOTVICT);
	if (!is_affected(victim, gsn_iron_will) 
	    || victim->mana < 1
	    || number_percent() < (95 + (victim->level - ch->level) * 3)){

	  if (fTrample && ch->size >= victim->size)
	    WAIT_STATE2(victim, ch->size * PULSE_VIOLENCE);
	  else
	    WAIT_STATE2(victim, UMIN(2,number_range(1, victim->size)) * PULSE_VIOLENCE);
	  position = POS_RESTING;
	}
	else{
	  send_to_char("Through your force of will you remain upright.\n\r", ch);
	  act("$n somehow remains upright.", victim, NULL, NULL, TO_ROOM);
	  victim->mana -= URANGE(0,25,victim->mana);
	}
      }
    if (fTrample && ch->size >= victim->size)
      damage(ch,victim, number_range(10,  20) * ch->size, gsn_trample, DAM_BASH, TRUE);
    else
      damage(ch,victim, number_range(2,  2 +  2 * victim->size), gsn_trip,DAM_BASH,TRUE);

    if (ch && ch->fighting && victim && victim->in_room){
      victim->position = position;
      check_ccombat_actions( ch, victim, CCOMBAT_TRIP);
    }

}

void do_trip( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;
    int chance;
    one_argument(argument,arg);
    if ( (chance = get_skill(ch,gsn_trip)) == 0)
    {
	send_to_char("Tripping?  What's that?\n\r",ch);
	return;
    }
    if (!is_empowered(ch,0))
	return;
    if (arg[0] == '\0')
    {
	victim = ch->fighting;
	if (victim == NULL)
	{
	    send_to_char("But you aren't fighting anyone!\n\r",ch);
	    return;
 	}
    }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
	send_to_char("They aren't here.\n\r",ch);
	return;
    }
    if ((IS_AFFECTED(victim,AFF_FLYING) && !is_affected(victim,gsn_thrash)) 
	|| (!IS_NPC(victim) && victim->pcdata->pStallion != NULL && get_skill(victim, gsn_mounted)))
      {
	act("$S feet aren't on the ground.",ch,NULL,victim,TO_CHAR);
	act("Luckily your feet aren't on the ground.",ch,NULL,victim,TO_VICT);
	return;
      }
    if ( victim == ch )
	return;
    if (is_safe(ch,victim))
	return;
    if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
        sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
        return;
    }
    chance += (get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX))*3;
    chance += (ch->level - victim->level);
//bigger guys are easier to trip
    chance += UMAX(0, victim->size - SIZE_MEDIUM) * 5;
    chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));

    if (is_affected(victim,gsn_horse))
	chance -= 20;
    if (IS_AFFECTED2(victim,AFF_BLUR))
        chance /= 2;

    a_yell(ch,victim);
    //predict interdict
    if (predictCheck(ch, victim, "trip", skill_table[gsn_trip].name))
      return;

    if (number_percent() < chance)
    {
	if (is_affected(victim,gsn_mantis) && !(IS_AFFECTED(ch,AFF_FLYING) && !is_affected(ch,gsn_thrash)))
	{
    	    if (ch->fighting != victim && victim->fighting != ch)
    	    {
    	        sprintf(buf, "Help! %s just tried to tripped me!",PERS(ch,victim));
    	        j_yell(victim,buf);
    	    }
            act("You reversed $n's trip, and $e goes down!",ch,NULL,victim,TO_VICT);
	    act("$N reverses your trip, and you go down!",ch,NULL,victim,TO_CHAR);
            act("$N reversed $n's trip, sending $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	    if (!(is_affected(ch, gsn_iron_will)  && ch->mana > 0) || number_percent() < 50 + victim->level - ch->level){
	      ch->position = POS_RESTING;
	        WAIT_STATE2(ch, UMIN(2,number_range(ch->size,1)) * PULSE_VIOLENCE);
	    }
	    else{
	      send_to_char("Through your force of will you remain upright.\n\r", ch);
	      act("$n somehow remains upright.", victim, NULL, NULL, TO_ROOM);
	      victim->mana -= URANGE(0,25,victim->mana);
	      ch->mana -= URANGE(0,25,ch->mana);
	    }
            damage(victim,ch,number_range(2, 2 +  2 * ch->size),gsn_trip,DAM_BASH,TRUE);
	    affect_strip(victim,gsn_mantis);
	    return;
	}
        if (ch->fighting != victim && victim->fighting != ch)
        {
            sprintf(buf, "Help! %s just tripped me!",PERS(ch,victim));
            j_yell(victim,buf);
        }
 	if (ch->class == class_lookup("monk"))
	{
	    act("$n trips you with a leg sweep and you go down!",ch,NULL,victim,TO_VICT);
	    act("You trip $N with a leg sweep and $E goes down!",ch,NULL,victim,TO_CHAR);
	    act("$n trips $N with a leg sweep, sending $M to the ground.",ch,NULL,victim,TO_NOTVICT);
	    if (!(is_affected(victim, gsn_iron_will) && victim->mana > 0) || number_percent() < (25 + victim->level - ch->level)){
	        WAIT_STATE2(victim, UMIN(2,number_range(victim->size,1)) * PULSE_VIOLENCE);
	    victim->position = POS_RESTING;
	    }
	    else{
	      send_to_char("Through your force of will you remain upright.\n\r", ch);
	      act("$n somehow remains upright.", victim, NULL, NULL, TO_ROOM);
	      victim->mana -= URANGE(0,25,victim->mana);
	    }
	    damage(ch,victim,number_range(2, 2 +  2 * victim->size),gsn_trip,DAM_BASH,TRUE);

	}
	else
	  trip(ch, victim, chance);
	WAIT_STATE2(ch,skill_table[gsn_trip].beats);
	check_improve(ch,gsn_trip,TRUE,1);
    }
    else
    {
        if (ch->fighting != victim && victim->fighting != ch)
        {
            sprintf(buf, "Help! %s tried to trip me!",PERS(ch,victim));
            j_yell(victim,buf);
        }
	damage(ch,victim,0,gsn_trip,DAM_BASH,TRUE);
        check_improve(ch,gsn_trip,FALSE,1);
	WAIT_STATE2(ch,2 * skill_table[gsn_trip].beats / 3);
    } 
}

void do_lash( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    CHAR_DATA *victim;
    AFFECT_DATA af;                  // affect data (for air_thrash)

    one_argument(argument,arg);
    if (arg[0] == '\0')
    {
	victim = ch->fighting;
    }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
	return;
    }
    act("$n lashes at you with $s weapon and you go down!",ch,NULL,victim,TO_VICT);
    act("You lash at $N with your weapon and $N goes down!",ch,NULL,victim,TO_CHAR);
    act("$n lashes at $N with $s, sending $M to the ground.",ch,NULL,victim,TO_NOTVICT);

/* air thrash the victim if flying */
    if (IS_AFFECTED(victim, AFF_FLYING) && !is_affected(victim, gsn_thrash)) {
      af.where  = TO_AFFECTS;
      af.type   = gsn_thrash;
      af.level  = ch->level;
      af.duration = 0;
      af.modifier = 0;
      af.location = 0;
      af.bitvector = 0;
      affect_to_char(victim,&af);
      act("You can't seem to get back into the air",victim,NULL,NULL,TO_CHAR);
      act("$n can't seem to get back into the air",victim,NULL,NULL,TO_ROOM);
    }
}

void do_backstab( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;
    OBJ_DATA *obj, *obj2;
    int chance, dual_chance, wpnswitch;
    one_argument( argument, arg );
    if ((chance = get_skill(ch,gsn_backstab)) == 0)
    {
	send_to_char("You don't know how to backstab.\n\r",ch);
	return;
    }
    if (arg[0] == '\0')
    {
        send_to_char("Backstab whom?\n\r",ch);
        return;
    }
    if (ch->fighting != NULL)
    {
	send_to_char("You can't backstab while fighting.\n\r",ch);
	return;
    }
    if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
        send_to_char("They aren't here.\n\r",ch);
        return;
    }
    if (victim->fighting != NULL)
    {
	sendf(ch, "%s won't hold still long enough.\n\r", PERS(victim,ch));
	return;
    }
    if (IS_NPC(victim) && IS_SET(victim->act, ACT_TOO_BIG) )
    {
	sendf(ch, "%s is too alert for you to attempt such an act.\n\r", PERS(victim,ch));
	return;
    }
    if ( victim == ch )
	return;
    if ( is_safe( ch, victim ) )
        return;
    if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
        sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
        return;
    }
    obj = get_eq_char( ch, WEAR_WIELD );
    obj2 = get_eq_char( ch, WEAR_SECONDARY);
    wpnswitch = FALSE;
    if (obj == NULL 
	|| (obj->value[0] != WEAPON_DAGGER
	    && obj->value[0] != WEAPON_EXOTIC
	    && obj->value[0] != WEAPON_SPEAR))
    {
	wpnswitch = TRUE;
	if (obj2 == NULL 
	    || (obj2->value[0] != WEAPON_DAGGER
		&& obj2->value[0] != WEAPON_EXOTIC
		&& obj2->value[0] != WEAPON_SPEAR))
	  {
	    send_to_char( "You need to wield a piercing weapon to backstab.\n\r", ch );
	    return;
	}
    }
    if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
    {
	send_to_char("You can't seem to get up enough speed.\n\r",ch);
	return;
    }
    if ( !IS_NPC(ch) && victim->hit < (victim->max_hit * 0.85) )
    {
        sendf(ch, "%s is hurt and suspicious ... you can't sneak up.\n\r", PERS(victim,ch) );
	return;
    }
    dual_chance = chance;
    chance += get_curr_stat(ch,STAT_DEX)+get_curr_stat(ch,STAT_INT)/2;
    chance -= get_curr_stat(victim,STAT_DEX)+get_curr_stat(ch,STAT_WIS)/2;
    if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
	chance += 10;
    if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
        chance -= 10;
    chance += (ch->level - victim->level);
    chance += 2*(get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    if (!IS_AWAKE(victim) )
        chance += 10;
    WAIT_STATE2( ch, skill_table[gsn_backstab].beats );
    a_yell(ch,victim);

    //predict interdict
    if (predictCheck(ch, victim, "backstab", skill_table[gsn_backstab].name))
      return;

    if ( number_percent( ) < chance || !IS_AWAKE(victim) )
    {
	check_improve(ch,gsn_backstab,TRUE,1);
//MANTIS CHECK
	if ( (is_affected(victim,gsn_mantis) || get_skill(victim, gsn_shadowmaster) > 1) && IS_AWAKE(victim)){
	  act("You sense $n's movement and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	  act("$N senses your attack, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	  act("$N senses $n's attack, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	  WAIT_STATE2(ch, URANGE(2, 1 + number_range(1, victim->size), 4) * PULSE_VIOLENCE);
	  do_visible(ch, "");
      
	  sprintf(buf, "Help!  %s just tried to backstab me!",PERS(ch,victim));
	  j_yell(victim,buf);
	  affect_strip(victim,gsn_mantis);
	  damage(victim,ch,10,gsn_mantis,DAM_BASH,TRUE);
	  return;
	}//END MATIS

        sprintf(buf, "Help! %s backstabbed me!",PERS(ch,victim));
    	j_yell(victim,buf);
	if (!wpnswitch)
	    one_hit( ch, victim, gsn_backstab, FALSE );
	if (wpnswitch)
	{
	    if (number_percent( ) < get_skill(ch, gsn_dual_wield))
		one_hit( ch, victim, gsn_backstab, TRUE );
	    else
		damage( ch, victim, 0, gsn_backstab, DAM_NONE, TRUE);
	}
  	dual_chance -= chance;
	if ((chance = get_skill(ch, gsn_dual_backstab)) != 0 && (!wpnswitch)
	    && (obj != NULL 
		&& (obj->value[0] == WEAPON_DAGGER 
		    || obj->value[0] == WEAPON_EXOTIC
		    || obj->value[0] == WEAPON_SPEAR))
	    && (obj2 != NULL 
		&& (obj2->value[0] == WEAPON_DAGGER 
		    || obj2->value[0] == WEAPON_EXOTIC
		    || obj2->value[0] == WEAPON_SPEAR)) )
	  {
	    if ((number_percent( ) < 3*(chance - dual_chance) /4
	    && number_percent( ) < get_skill(ch, gsn_dual_wield)) )
	    {
	    	check_improve(ch,gsn_dual_backstab,TRUE,1);
		one_hit( ch, victim, gsn_dual_backstab, TRUE );
	    }
	    else
		check_improve(ch,gsn_dual_backstab,FALSE,1); 
	} 
    }
    else
    {
        check_improve(ch,gsn_backstab,FALSE,1);
        if (ch->fighting == NULL)
        {
            sprintf(buf, "Help! %s tried to backstab me!",PERS(ch,victim));
            j_yell(victim,buf);
        }
	damage( ch, victim, 0, gsn_backstab,DAM_NONE,TRUE);
    	dual_chance -= chance;
	if ((chance = get_skill(ch, gsn_dual_backstab)) != 0 && (!wpnswitch)
    	&& (obj != NULL && (obj->value[0] == 2 || obj->value[0] == 3))
	&& (obj2 != NULL && (obj2->value[0] == 2 || obj2->value[0] == 3)))
	{
	    if ((number_percent( ) < (2 * (chance - dual_chance) /3) 
	    && number_percent( ) < get_skill(ch, gsn_dual_wield)))
	    {
	    	check_improve(ch,gsn_dual_backstab,TRUE,1);
		one_hit( ch, victim, gsn_dual_backstab, TRUE );
	    }
	    else
		check_improve(ch,gsn_dual_backstab,FALSE,1);
	} 
    }
}

void do_rescue( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    CHAR_DATA *victim, *v_next, *ech, *fch = NULL;
    int chance = 0;
    int skill = get_skill(ch, gsn_rescue);
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Rescue whom?\n\r", ch );
	return;
    }
    if ( ( victim = get_char_room( ch, NULL, arg ) ) == NULL )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }
    if ( victim == ch )
	return;
/* psalm of one god */
    if (is_affected(ch, gsn_ogtrium))
      skill = 150;

    if (!IS_NPC(ch) && skill < 1)
    {
	send_to_char( "You don't know how to rescue.\n\r", ch );
	return;
    }
    if ( victim->fighting == NULL )
    {
	sendf(ch, "%s is not fighting right now.\n\r", PERS(victim,ch) );
	return;
    }
/* special guards */
    if (IS_NPC(ch) 
	&& (ch->pIndexData->vnum == MOB_VNUM_SPECIAL_GUARD 
	    || ch->pIndexData->vnum == MOB_VNUM_HOUND)
	&& !IS_AREA(ch->in_room->area, AREA_LAWFUL)
	&& !IS_WANTED(victim->fighting))
      return;
    if (is_safe(ch, victim->fighting))
    	return;
    for ( ech = victim->in_room->people; ech != NULL; ech = v_next )
    {
        v_next = ech->next_in_room;
        if ( ech->fighting != NULL && ech->fighting == victim)
        {
    	    if ( IS_NPC(ch) && ch->leader != NULL && !IS_NPC(ch->leader) && is_safe(ch->leader, ech) ) 
    		continue;
	    else if (is_safe(ch,ech))
		continue; 
	    fch = ech;
	    break;
	}
    }
    if ( ch->fighting == victim )
    {
	send_to_char( "Too late.\n\r", ch );
	return;
    }
    WAIT_STATE2( ch, skill_table[gsn_rescue].beats );
    WAIT_STATE2( victim, 2 * PULSE_VIOLENCE);
    if ( fch == NULL )
    {
	send_to_char( "You cannot rescue them.\n\r", ch );
	return;
    }
    chance = skill;
    if (chance > 0);
	chance += 2*(get_curr_stat(ch,STAT_LUCK) - 16);
    if ( number_percent() > chance)
    {
	send_to_char( "You failed the rescue.\n\r", ch );
	check_improve(ch,gsn_rescue,FALSE,1);
	return;
    }
    act( "You rescue $N!",  ch, NULL, victim, TO_CHAR    );
    act( "$n rescues you!", ch, NULL, victim, TO_VICT    );
    act( "$n rescues $N!",  ch, NULL, victim, TO_NOTVICT );
    check_improve(ch,gsn_rescue,TRUE,1);
    stop_fighting( fch, FALSE );
    if (victim->fighting == fch)
    	stop_fighting( victim, FALSE );
    if ( ch->class == class_lookup("paladin") && is_affected(ch,gsn_heroism))
	do_charge(ch,fch->name);
    set_fighting( ch, fch );
    set_fighting( fch, ch );
}

void kick( CHAR_DATA* ch, CHAR_DATA* victim, int chance ){
  int dam = number_range( ch->level/2, 8 * ch->level / 5);
  
  chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
  chance += (ch->level - victim->level);
  chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
  
  if ( number_percent( ) < chance )
    {
      int chance2 = get_skill(ch,gsn_double_kick);
      if (is_affected(victim,gsn_mantis))
	{
	  act("You step out of $n's kick, and deliver one of your own!",ch,NULL,victim,TO_VICT);
	  act("$N steps out of your kick, and delivers one of $S own!",ch,NULL,victim,TO_CHAR);
	  act("$N steps out of $n's kick, and delivers one of $S own.",ch,NULL,victim,TO_NOTVICT);
	  damage(victim,ch,dam/2,gsn_kick,DAM_BASH,TRUE);
	  affect_strip(victim,gsn_mantis);
	  return;
	}
      chance2 += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
      chance2 += (ch->level - victim->level);
      chance2 += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
      damage(ch,victim,dam,gsn_kick,DAM_BASH,TRUE);
      if (ch->fighting == victim && number_percent() < 3*get_skill(ch,gsn_double_kick)/4)
	{
	  if (is_affected(ch,gsn_crane))
	    chance2 += 20;
	  if (number_percent() < chance2)
	    {
              chance = 3*((ch->level /2) + (3*get_skill(ch,gsn_double_kick)/4) )/4;
              if (ch->class == class_lookup("monk") && number_percent() < chance) 
		{
                  if (is_affected(ch,gsn_monkey))
		    {
                      send_to_char( "You unleash the technique of Fu Manchu.\n\r", ch );
                      damage(ch,victim,3*dam/4, gsn_double_kick,DAM_BASH,TRUE);
		      if (victim->position > POS_RESTING && !is_safe(ch, victim))
			damage(ch,victim,2*dam/3, gsn_double_kick,DAM_BASH,TRUE);
		      if (victim->position > POS_RESTING && !is_safe(ch, victim))
			damage(ch,victim,2*dam/3, gsn_double_kick,DAM_BASH,TRUE);
		    }
                  else if (is_affected(ch,gsn_tiger))
		    {
                      send_to_char("You tear with the claws of the tiger.\n\r", ch); 
                      damage(ch,victim,11*dam/10, gsn_double_kick,DAM_PIERCE,TRUE);
		    }
                  else if (is_affected(ch,gsn_buddha))
		    {
                      send_to_char("You invoke the essence of the soul.\n\r", ch);
                      damage(ch,victim,20*dam/10, gsn_double_kick,DAM_MENTAL, TRUE);
		    }
                  else if (is_affected(ch,gsn_horse))
		    {
                      send_to_char("You kick with the strength of the horse.\n\r",ch);
                      damage(ch,victim,12*dam/10, gsn_double_kick,DAM_BASH,TRUE);
		    }
                  else if (is_affected(ch,gsn_dragon))
		    {
                      send_to_char("You summon the spirit of the dragon.\n\r",ch);
                      damage(ch,victim,2*dam/1, gsn_double_kick,DAM_ENERGY,TRUE);
		    }
		  else if (is_affected(ch,gsn_drunken))
		    {
		      damage(ch,victim,number_range( 2*dam/3, dam),gsn_double_kick,DAM_BASH,TRUE);
		      if ( number_percent( ) < 3 * chance / 2 )
			{
			  send_to_char("You stagger into your opponent like a blind drunk.\n\r",ch);
			  act("$n sweeps your legs with a staggering motion!",ch,NULL,victim,TO_VICT);
			  act("$n sweeps $N's legs with a staggering motion!",ch,NULL,victim,TO_NOTVICT);
			  if ((IS_AFFECTED(victim,AFF_FLYING) 
			       && !is_affected(victim,gsn_thrash)) 
			      || (!IS_NPC(victim) && victim->pcdata->pStallion != NULL && get_skill(victim, gsn_mounted)))
			    {
			      act("$S feet aren't on the ground.",ch,NULL,victim,TO_CHAR);
			      act("Luckily your feet aren't on the ground.",ch,NULL,victim,TO_VICT);
			    }
			  else
			    WAIT_STATE2(victim, UMIN(2,number_range(victim->size,1)) * PULSE_VIOLENCE);
			}
		    }
		  else 
                    damage(ch,victim,number_range( 2*dam/3, dam),gsn_double_kick,DAM_BASH,TRUE);
		}
	      else
		damage(ch,victim,number_range( dam/2, dam), gsn_double_kick,DAM_BASH,TRUE);
	      check_improve(ch,gsn_double_kick,TRUE,10);
	    }
	  else
	    {
	      damage( ch, victim, 0, gsn_double_kick,DAM_BASH,TRUE);
	      check_improve(ch,gsn_double_kick,FALSE,10);
	    }
	}
      check_improve(ch,gsn_kick,TRUE,10);
    }
  else
    {
      damage( ch, victim, 0, gsn_kick,DAM_BASH,TRUE);
      check_improve(ch,gsn_kick,FALSE,10);
    }
}
void do_kick( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim = ch->fighting;
    int chance;
    if ( (chance = get_skill(ch,gsn_kick)) == 0)
    {
        send_to_char("You better leave the martial arts to fighters.\n\r", ch );
	return;
    }
    if (victim == NULL ){
        send_to_char( "You aren't fighting anyone.\n\r", ch );
        return;
    }
    WAIT_STATE2( ch, skill_table[gsn_kick].beats );
    kick(ch, victim, chance );
}

bool disarm( CHAR_DATA *ch, CHAR_DATA *victim ){

  OBJ_DATA *obj, *wield = get_eq_char(ch, WEAR_WIELD);
  int skill = get_skill(victim, gsn_double_grip);
  bool fStr = FALSE;
  bool fSeize = FALSE;
  bool fExoSeize = FALSE;
  bool fPGrip = FALSE;

  if ( ( obj = get_eq_char( victim, WEAR_WIELD ) ) == NULL 
       && ( obj = get_eq_char( victim, WEAR_SECONDARY ) ) == NULL )
    return FALSE;
  if ( IS_STONED(victim)
       || IS_OBJ_STAT(obj,ITEM_NOREMOVE) 
       || is_affected(victim, gsn_graft_weapon)){
    act("$S weapon won't budge!",ch,NULL,victim,TO_CHAR);
    act("$n tries to disarm you, but your weapon won't budge!",ch,NULL,victim,TO_VICT);
    act("$n tries to disarm $N, but fails.",ch,NULL,victim,TO_NOTVICT);
    return FALSE;
  }

  if (obj != NULL 
      && (obj->value[0] == WEAPON_POLEARM 
	  || obj->value[0] == WEAPON_STAFF
	  || obj->value[0] == WEAPON_AXE)
      && get_skill(victim, skill_lookup("power grip")) > 1)
    skill += 15;
  else if (is_affected(victim, gsn_ironarm) && get_eq_char(victim, WEAR_SECONDARY) != NULL){
    fStr = TRUE;
    skill += 15;
  }
  if (is_affected(victim, gsn_istrength) && has_twohanded(victim) != NULL){
    fStr = TRUE;
    skill = 200;
  }

  if ( (is_affected(victim,gsn_double_grip)  || fStr)
       && number_percent() < (4 * skill / 3) - 75) {
    act("You fail to disarm $N's weapon from $S powerfull grasp.",ch,NULL,victim,TO_CHAR);
    act("$n tries to disarm you, but your grip is too strong.",ch,NULL,victim,TO_VICT);
    act("$n tries to disarm $N, but $E grips $S weapon tightly.",ch,NULL,victim,TO_NOTVICT);
    check_improve(ch,gsn_disarm, FALSE,1);
    check_improve(victim,gsn_double_grip, FALSE, 33);
    return FALSE;
  }

  act( "$n disarms you and sends your weapon flying!", ch, NULL, victim, TO_VICT    );
  act( "You disarm $N!",  ch, NULL, victim, TO_CHAR    );
  act( "$n disarms $N!",  ch, NULL, victim, TO_NOTVICT );
  
  if (check_ccombat_actions( ch, victim, CCOMBAT_DISARM ))
    return FALSE;

  /* check for power grip (MUST be before obj_from_char) */
  if (obj != NULL 
      && (obj->value[0] == WEAPON_POLEARM 
	  || obj->value[0] == WEAPON_STAFF
	  || obj->value[0] == WEAPON_AXE)
      && is_affected(victim, gsn_double_grip)
      && get_skill(victim, skill_lookup("power grip")) > 1){
    fPGrip = TRUE;
  }

  obj_from_char( obj );

  /* check for advanced disarms */
  if ( wield != NULL
       && (wield->value[0] == WEAPON_EXOTIC || wield->value[0] == WEAPON_WHIP)){
    int sn = skill_lookup("weapon seize");
    if (number_percent() < get_skill(ch, sn)){
      check_improve(ch, sn, TRUE, 0);
      fSeize = TRUE;
      /* check for exotic seize */
      if (wield->value[0] == WEAPON_EXOTIC 
	  && get_skill(ch, gsn_exotic_mastery) > 1)
	fExoSeize = TRUE;
    }
    else
      check_improve(ch, sn, FALSE, -99);
  }
  
  if (!fExoSeize 
      && (IS_OBJ_STAT(obj,ITEM_NODROP) 
	  || IS_OBJ_STAT(obj,ITEM_INVENTORY)
	  || fPGrip) ){
    obj_to_char( obj, victim );
  }
  else if (fSeize){
    act("With a flick of $p $n grabs the weapon.", ch, wield, NULL, TO_ROOM);
    act("With a flick of $p you grab the weapon.", ch, wield, NULL, TO_CHAR);
    obj_to_char( obj, ch );
  }
  else{
    obj_to_room( obj, victim->in_room );
    if (IS_NPC(victim) && victim->wait == 0 && can_see_obj(victim,obj))
      get_obj(victim,obj,NULL);
  }
  return TRUE;
}

void do_disarm( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    OBJ_DATA *obj2;
    int chance, hth = 0, ch_weapon, vict_weapon, ch_vict_weapon;
    bool fIronArm = TRUE;

    if ((chance =  get_skill(ch,gsn_disarm)) == 0){
      send_to_char( "Huh?\n\r", ch );
      return;
    }
    else if ( (obj = getBmWep( ch, TRUE )) == NULL 
	      && (obj = getBmWep( ch, FALSE )) == NULL 
	      && ((hth = get_skill(ch,gsn_hand_to_hand)) == 0 
		  || (IS_NPC(ch) && !IS_SET(ch->off_flags,OFF_DISARM))) )
      {
	send_to_char( "You must wield a weapon to disarm.\n\r", ch );
	return;
      }
    else if ( ( victim = ch->fighting ) == NULL ){
      send_to_char( "You aren't fighting anyone.\n\r", ch );
      return;
    }
    else if ( ( obj2 = get_eq_char( victim, WEAR_WIELD ) ) == NULL 
	      && ( obj2 = get_eq_char( victim, WEAR_SECONDARY ) ) == NULL ){
      sendf(ch, "%s is not wielding a weapon.\n\r", PERS(victim,ch) );
      return;
    }

    ch_weapon = get_weapon_skill_obj(ch, obj);
    vict_weapon = get_weapon_skill_obj(victim, obj2);
    ch_vict_weapon = get_weapon_skill_obj(ch, obj2);

    if (IS_NPC(victim))
	vict_weapon = UMAX(victim->level * 2, 75);
    
    if ( obj == NULL){
      if (ch->class == class_lookup("monk"))
	chance = chance * hth/100;
      else
	chance = chance * hth/150;
    }
    else
      chance = chance * ch_weapon/100;

    chance += get_weapon_obj_rating( obj, WEAPON_WITHDIS ) * 4;
    chance += get_weapon_obj_rating( obj2, WEAPON_TOBEDIS ) * 4;

    if (ch->class != gcn_blademaster || !is_affected(ch, gsn_ironarm) || get_eq_char(ch, WEAR_SECONDARY) == NULL){
      fIronArm = FALSE;
      ch_vict_weapon = 100;
    }
    chance += (ch_vict_weapon - vict_weapon) / 2; 
    chance += 2 * (get_curr_stat(ch,STAT_DEX)-get_curr_stat(victim,STAT_STR));
    chance += 2*(get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    chance += (ch->level - victim->level);
    chance -= get_skill(victim,gsn_parry)/10;
    if (IS_NPC(victim))
      chance -= victim->level/10;

    if (ch->class == class_lookup("monk") 
	&& is_affected(ch,gsn_dragon) 
	&& is_empowered(ch,0))
      chance += 15;
    if (number_percent() < chance 
	&& (victim->level - ch->level) < 10){
      WAIT_STATE2( ch, skill_table[gsn_disarm].beats );
      check_improve(ch,gsn_disarm,TRUE,1);
      if ( fIronArm){
	WAIT_STATE2(victim, PULSE_VIOLENCE );
	damage(ch, victim, UMIN(victim->hit, number_range(3, 10)), gsn_ironarm, DAM_INTERNAL, TRUE);
      }
      disarm( ch, victim );
    }
    else{
      WAIT_STATE2(ch,skill_table[gsn_disarm].beats);
      act("You fail to disarm $N.",ch,NULL,victim,TO_CHAR);
      act("$n tries to disarm you, but fails.",ch,NULL,victim,TO_VICT);
      act("$n tries to disarm $N, but fails.",ch,NULL,victim,TO_NOTVICT);
      check_improve(ch,gsn_disarm,FALSE,1);
    }
}

void shield_disarm( CHAR_DATA *ch, CHAR_DATA *victim )
{
    OBJ_DATA *obj;
    if ( (obj = get_eq_char( victim, WEAR_SHIELD ) )== NULL)
	return;
    if ( IS_STONED(victim) || IS_OBJ_STAT(obj,ITEM_NOREMOVE))
    {
        act("$S shield won't budge!",ch,NULL,victim,TO_CHAR);
        act("$n tries to disarm your shield, but it won't budge!",ch,NULL,victim,TO_VICT);
        act("$n tries to disarm $N's shield, but fails.",ch,NULL,victim,TO_NOTVICT);
	return;
    }
    act( "$n disarms your shield and it falls to the ground!", ch, NULL, victim, TO_VICT    );
    act( "You disarm $N's shield!",  ch, NULL, victim, TO_CHAR    );
    act( "$n disarms $N's shield!",  ch, NULL, victim, TO_NOTVICT );
    obj_from_char( obj );
    if ( IS_OBJ_STAT(obj,ITEM_NODROP) || IS_OBJ_STAT(obj,ITEM_INVENTORY) )
	obj_to_char( obj, victim );
    else
    {
	obj_to_room( obj, victim->in_room );
	if (IS_NPC(victim) && victim->wait == 0 && can_see_obj(victim,obj))
            get_obj(victim,obj,NULL);
    }
}

void do_shield_disarm( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    int chance, ch_weapon, hth;

    if ((chance = 4 * get_skill(ch,gsn_shield_disarm) / 5) == 0)
    {
        send_to_char( "You don't know how to disarm shields.\n\r", ch );
	return;
    }
    if ( ( victim = ch->fighting ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }
    if ( ( obj = get_eq_char( victim, WEAR_SHIELD ) ) == NULL )
    {
        sendf(ch, "%s is not wearing a shield.\n\r", PERS(victim,ch) );
	return;
    }
    //bonus for bless
    if (obj && IS_GOOD(victim) && IS_OBJ_STAT(obj,ITEM_BLESS))
      chance -= 15;
    else if (obj && IS_EVIL(victim) && IS_OBJ_STAT(obj,ITEM_DARK))
      chance -= 15;

    hth = get_skill(ch,gsn_hand_to_hand);
    ch_weapon = get_weapon_skill_obj(ch, obj);

    if (IS_NPC(ch))
      chance /= 2;

    if ( obj == NULL){
      if (ch->class == class_lookup("monk"))
	chance = chance * hth/100;
      else
	chance = chance * hth/150;
    }
    else
      chance = chance * ch_weapon/100;

    chance += get_weapon_obj_rating( obj, WEAPON_WITHSDIS ) * 4;    
    chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_STR);
    chance += (ch->level - victim->level);
    chance -= get_skill(victim,gsn_shield_block)/4;
    chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));

    if (ch->class == class_lookup("monk") && is_affected(ch,gsn_dragon) && is_empowered(ch,0))
      chance += 15;

    if (number_percent() < chance)
    {
        WAIT_STATE2( ch, skill_table[gsn_shield_disarm].beats );
        shield_disarm( ch, victim );
        check_improve(ch,gsn_shield_disarm,TRUE,1);
    }
    else
    {
        WAIT_STATE2(ch,skill_table[gsn_shield_disarm].beats);
        act("You fail to disarm $N's shield.",ch,NULL,victim,TO_CHAR);
        act("$n tries to disarm your shield, but fails.",ch,NULL,victim,TO_VICT);
        act("$n tries to disarm $N's shield, but fails.",ch,NULL,victim,TO_NOTVICT);
        check_improve(ch,gsn_shield_disarm,FALSE,1);
    }
}

void do_lore( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj;
    int chance;
    int sn = skill_lookup("history of armaments");
    int sn2 = skill_lookup("arms maintenance");
    bool fExtract  = FALSE;

    one_argument( argument, arg );
    if (ch->fighting != NULL)
    {
        send_to_char("You're too busy fighting!\n\r",ch);
        return;
    }
    if (arg[0] == '\0')
    {
        send_to_char("Lore what?\n\r",ch);
        return;
    }
    obj = get_obj_list(ch,arg,ch->carrying);
    if (obj== NULL || CAN_WEAR(obj,ITEM_WEAR_TATTOO))
    {
        send_to_char("You don't have that item.\n\r",ch);
        return;
    }
    if ((chance = get_skill(ch,gsn_lore)) <= 1)
    {
        send_to_char("It looks like what it appears to be.\n\r",ch);
        return;
    }
    if (ch->mana < 30)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    WAIT_STATE(ch,skill_table[gsn_lore].beats);

    ch->mana -= 30;
    act("You examine $p closely.",ch,obj,NULL,TO_CHAR);
    act("$n examines $p closely.",ch,obj,NULL,TO_ROOM);

    if (obj->pIndexData->vnum == OBJ_VNUM_CLONE){
      fExtract = TRUE;
      obj = create_object( get_obj_index(obj->cost), obj->level);
    }


    if (obj->item_type == ITEM_ARMOR
	&& number_percent() < get_skill(ch, sn)){
      send_to_char("You dip into your knowledge of weapons and armor.\n\r", ch);
      check_improve(ch, sn, TRUE, 5);
      spell_identify(skill_lookup("identify"), ch->level, ch, obj, TARGET_OBJ);
    sendf(ch, "Rumor has it that you can find it in %s.\n\r", obj->pIndexData->area->name);
      if (fExtract)
	extract_obj ( obj );
      return;
    }
    else if (obj->item_type == ITEM_WEAPON
	     && number_percent() < get_skill(ch, sn2)){
      send_to_char("You dip into your knowledge of weapons.\n\r", ch);
      check_improve(ch, sn2, TRUE, 5);
      spell_identify(skill_lookup("identify"), ch->level, ch, obj, TARGET_OBJ);
      sendf(ch, "Rumor has it that you can find it in %s.\n\r", obj->pIndexData->area->name);
      if (fExtract)
	extract_obj ( obj );
      return;
    }
    else
      check_improve(ch, sn, FALSE, 5);
    chance += 25;
    chance += 5 * (get_curr_stat(ch,STAT_LUCK) - 14);
    if (number_percent() > chance)
    {
        send_to_char("The meaning of this object escapes you at the moment.\n\r",ch);
	if (fExtract)
	  extract_obj ( obj );
        return;
    }
    chance = get_skill(ch,gsn_lore);
    chance += get_curr_stat(ch,STAT_WIS) + get_curr_stat(ch,STAT_INT) - 40;
    chance += UMAX(0, (ch->level - obj->level) / 2);
    chance = UMAX(0, 110 - chance);
    chance = number_range(-chance, chance);
    if (ch->class == class_lookup("bard"))
      chance = 0;

    sendf( ch,"Object is type %s, material %s.\n\rWeight is %d, value is %d, level is %d.\n\r",
	   item_name(obj->item_type), 
	   obj->material, 
	   obj->weight / 10 + (obj->weight * chance / 1000),
	   obj->cost + (obj->cost *  chance / 100), 
	   obj->level + (obj->level * chance / 100));
    switch ( obj->item_type )
    {
    case ITEM_SOCKET:
      if (IS_SOC_STAT(obj, SOCKET_ARMOR)
	  && IS_SOC_STAT(obj, SOCKET_WEAPON))
	act("Armor and Weapon socket.",
	    ch, obj, NULL, TO_CHAR);
      else if (IS_SOC_STAT(obj, SOCKET_ARMOR))
	act("Armor only socket.",
	    ch, obj, NULL, TO_CHAR);
      else if (IS_SOC_STAT(obj, SOCKET_WEAPON))
	act("Weapon only socket.",
	    ch, obj, NULL, TO_CHAR);
      else 
	act("Weapon only socket.",
	    ch, obj, NULL, TO_CHAR);
      break;
    case ITEM_DRINK_CON:
      sendf(ch,"It holds %s-colored %s.\n\r", 
	    liq_table[obj->value[2]].liq_color, 
	    liq_table[obj->value[2]].liq_name);
      break;
    case ITEM_CONTAINER:
	sendf(ch,"Capacity: %d#  Maximum weight: %d#\n\r",
	      obj->value[3] + (obj->value[3] * chance/100), 
	      obj->value[0] + (obj->value[0] * chance/100));
	break;
    case ITEM_WEAPON:
      send_to_char("Weapon type is ",ch);
      if (IS_WEAPON_STAT(obj, WEAPON_TWO_HANDS) 
	  || obj->value[0] == WEAPON_STAFF)
	send_to_char("two-handed ", ch);
      switch (obj->value[0])
	{
        case(WEAPON_EXOTIC) : send_to_char("exotic.\n\r",ch);       break;
        case(WEAPON_SWORD)  : send_to_char("sword.\n\r",ch);        break; 
        case(WEAPON_DAGGER) : send_to_char("dagger.\n\r",ch);       break;
        case(WEAPON_SPEAR)  : send_to_char("spear.\n\r",ch);  break;
        case(WEAPON_STAFF)  : send_to_char("staff.\n\r",ch);  break;
        case(WEAPON_MACE)   : send_to_char("mace/club.\n\r",ch);    break;
        case(WEAPON_AXE)    : send_to_char("axe.\n\r",ch);          break;
        case(WEAPON_FLAIL)  : send_to_char("flail.\n\r",ch);        break;
        case(WEAPON_WHIP)   : send_to_char("whip.\n\r",ch);         break;
        case(WEAPON_POLEARM): send_to_char("polearm.\n\r",ch);      break;
        default             : send_to_char("unknown.\n\r",ch);      break;
 	}
      if (obj->pIndexData->new_format)
	sendf(ch,"Average damage is %d.\n\r",
              (1 + obj->value[2])* obj->value[1]/ 2 +(1 + obj->value[2]) * (obj->value[1]/ 2) * chance / 100);
	else
	  sendf( ch, "Average damage is %d.\n\r",
		 (obj->value[1] + (obj->value[2]) / 2) + 
		 (obj->value[1] + (obj->value[2]) / 2) * chance/100);
      if ( IS_OBJ_STAT(obj, ITEM_SOCKETABLE))
	{
	  if (obj->contains){
	    act( "$p has the following affixed to it:", ch, obj, NULL, TO_CHAR );
	    show_list_to_char( obj->contains, ch, TRUE, TRUE );  
	  }
	  else
	    act( "$p seems to have a space to attach something to it.", ch, obj, NULL, TO_CHAR );
	}
      break;
    case ITEM_ARMOR:
      sendf( ch, "Armor class is %d pierce, %d bash, %d slash, and %d vs. magic.\n\r", 
	     obj->value[0] + obj->value[0] * chance/100, 
	     obj->value[1] + obj->value[1] * chance/100,
	     obj->value[2] + obj->value[2] * chance/100, 
	     obj->value[3] + obj->value[3] * chance/100);
      if ( IS_OBJ_STAT(obj, ITEM_SOCKETABLE))
	{
	  if (obj->contains){
	    act( "$p has the following affixed to it:", ch, obj, NULL, TO_CHAR );
	    show_list_to_char( obj->contains, ch, TRUE, TRUE );  
	  }
	  else
	    act( "$p seems to have a space to attach something to it.", ch, obj, NULL, TO_CHAR );
	}

      break;
    case ITEM_PROJECTILE:
      sendf(ch, "Is a projectile of type %s\n\r", 
	    flag_string(projectile_type, obj->value[0]));
      if (obj->pIndexData->new_format)
	sendf(ch,"Average damage is %d.\n\r",
              (1 + obj->value[2])* obj->value[1]/ 2 +(1 + obj->value[2]) * (obj->value[1]/ 2) * chance / 100);
      else
	sendf( ch, "Average damage is %d.\n\r",
	       (obj->value[1] + (obj->value[2]) / 2) + 
	       (obj->value[1] + (obj->value[2]) / 2) * chance/100);
      break;
    case ITEM_RANGED:
      if (obj->value[3] == 0)
	sendf(ch, "Can be used to fire: %s.\n\r", 
	      flag_string(projectile_type, obj->value[0]));
      else{
	OBJ_INDEX_DATA* ammo = get_obj_index( obj->value[3] );
	sendf(ch, "Can be used to fire: %s.\n\r", 
	      ammo == NULL ? "NOT FOUND" : ammo->short_descr);
      }
      sendf(ch, "Has capacity of: %d, and rate of fire: %d\n\r",
	    chance * obj->value[1] / 100, chance * obj->value[2] / 100);
      break;      
    }
    if (obj->pCabal || obj->race || obj->class >= 0){
      sendf(ch, "You have a feeling only a %s%s%s%s%s%scan use it.\n\r",
	    obj->race ? race_table[obj->race].name : "",
	    obj->race ? " " : "",
	    obj->class >= 0 ? class_table[obj->class].name : "",
	    obj->class >= 0 ? " ": "",
	    obj->pCabal ? obj->pCabal->name : "",
	    obj->pCabal ? " ": "");
    }
    if (CAN_WEAR(obj, ITEM_UNIQUE))
      send_to_char("Unique item.\n\r",ch);
    if (CAN_WEAR(obj, ITEM_RARE))
      send_to_char("Rare item.\n\r",ch);
    if (CAN_WEAR(obj, ITEM_PARRY))
      send_to_char("Can be dual parried.\n\r",ch);
    sendf(ch, "Rumor has it that you can find it in %s.\n\r", obj->pIndexData->area->name);
    check_improve(ch,gsn_lore,TRUE,1);
    if (fExtract)
      extract_obj ( obj );
}

void do_lay_on_hands(CHAR_DATA *ch, char *argument)
{
    CHAR_DATA *victim;
    char arg[MIL];
    sh_int chance;
    AFFECT_DATA af;
    const int cost = ch->class == class_lookup("crusader") ? 100 : 50;
    one_argument (argument, arg);
    if ((chance = get_skill (ch, gsn_lay_on_hands)) == 0)
    {
        send_to_char("You do not know the secrets of this skill.\n\r", ch);
        return;
    }
    if (is_affected(ch,gsn_lay_on_hands))
    {
	send_to_char("You can't sustain another lay on hands at this time.\n\r",ch);
	return;
    }
    victim = get_char_room(ch, NULL, arg);
    if ( victim == NULL )
    {
        send_to_char("They aren't here.\n\r", ch);
        return;
    }
    if ( victim == ch )
    {
        send_to_char("You can't lay on hands yourself.\n\r",ch);
        return;
    }
    if (ch->mana < cost)
    {
	send_to_char("You don't have enough mana to perform a lay on hands.\n\r",ch);
	return;
    }
    if (number_percent() > chance)
    {
        act("Something disturbs your concentration and you fail the lay on hands.", ch,NULL,NULL,TO_CHAR);
	act("$n's hands glow with a soft light, but it fades suddenly.",ch,NULL,NULL,TO_ROOM);
        ch->mana -= 25;
	check_improve(ch,gsn_lay_on_hands,FALSE,1);
    }
    else
    {
      if (ch->class == class_lookup("crusader")){
	act("You chant an ancient psalm as you press your hands against $N's back.",ch,NULL,victim,TO_CHAR);
	act("$n chants an ancient psalm as $e presses $s hands against $N's back.",ch,NULL,victim,TO_NOTVICT);
	act("$n chants an ancient psalm as $e presses $s hands against your back.",ch,NULL,victim,TO_VICT);
      }
      else{
	act("Your hands glow with a soft light as you place them on $N's wounds.",ch,NULL,victim,TO_CHAR);
	act("$n's hands glow with a soft light as $e places them on your wounds.",ch,NULL,victim,TO_VICT);
	act("$n's hands glow with a soft light as $e places them on $N's wounds.",ch,NULL,victim,TO_NOTVICT);
      }
      ch->mana -= cost;
      
//Embrace check.
      if (is_affected(victim, gsn_embrace_poison))
	{
	  if (embrace_heal_check(gsn_lay_on_hands, ch->level, ch, victim,  0))
	    affect_strip(victim, gsn_embrace_poison);
	}
      else
	{
	  int gain = victim->max_hit - victim->hit;
	  gain = ch->level * 2 + number_range(gain / 4, gain / 2);
	  gain = UMIN(gain, ch->level * 10);

	  victim->hit = UMIN(victim->max_hit, victim->hit + gain );

	  check_dispel( -99, victim, gsn_blindness);
	  check_dispel( -99, victim, gsn_death_grasp);
	  check_dispel( -99, victim, gsn_poison);
	  check_dispel( -99, victim, gsn_plague);
	  check_dispel( -99, victim, skill_lookup("dysentery"));
	  check_dispel( -99, victim, gsn_curse);
	  update_pos( victim );
	}//end embrace check
      check_improve(ch,gsn_lay_on_hands,TRUE,1);
    }
    af.type         = gsn_lay_on_hands;
    af.level        = ch->level;
    if (IS_NPC(ch))
      af.duration     = 1;
    else
      af.duration     = ch->class == class_lookup("crusader") ? 12 : 24;
    af.location     = 0;
    af.modifier     = 0;
    af.bitvector    = 0;
    affect_to_char(ch,&af);
    if (!IS_NPC(ch))
      {
	ch->pcdata->condition[COND_HUNGER] = 5;
        ch->pcdata->condition[COND_THIRST] = 5;
      }
    WAIT_STATE2(ch,skill_table[gsn_lay_on_hands].beats);
}

void do_detect_hidden( CHAR_DATA *ch, char *argument )
{
    int chance;
    AFFECT_DATA af;
    if ( (chance = get_skill(ch,gsn_detect_hidden)) == 0 )
    {	
        send_to_char("Huh?\n\r",ch);
	return;
    }
    if (ch->mana < 10)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    if ( IS_AFFECTED(ch, AFF_DETECT_HIDDEN) )
    {
        send_to_char("You are already as alert as you can be. \n\r",ch);
        return;
    }
    WAIT_STATE2(ch,skill_table[gsn_detect_hidden].beats);
    if (number_percent() > chance)
    {
	ch->mana -= 5;
	send_to_char("You peer around intently, but the shadows seem unrevealing.\n\r",ch);
        check_improve(ch,gsn_detect_hidden,FALSE,1);
	return;
    }
    ch->mana -= 10;
    af.where     = TO_AFFECTS;
    af.type      = gsn_detect_hidden;
    af.level     = ch->level;
    af.duration  = ch->level;
    af.location  = 0;
    af.modifier  = 0;
    af.bitvector = AFF_DETECT_HIDDEN;
    affect_to_char( ch, &af );
    send_to_char( "Your awareness improves.\n\r", ch );
    check_improve(ch,gsn_detect_hidden,TRUE,1);
}

void do_cleave( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    int chance, success;
    one_argument( argument, arg );
    if ((chance = get_skill(ch,gsn_cleave)) == 0)
    {
	send_to_char("You don't know how to cleave.\n\r",ch);
	return;
    }
    if (ch->fighting != NULL)
    {
	send_to_char("Not while you're fighting.\n\r",ch);
	return;
    }
    if (arg[0] == '\0')
    {
        send_to_char("Who do you wish to cleave?\n\r",ch);
        return;
    }
    if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
        send_to_char("They aren't here.\n\r",ch);
        return;
    }
    if (victim->fighting != NULL)
    {
	sendf(ch, "%s won't hold still long enough.\n\r", PERS(victim,ch));
	return;
    }
    if (IS_NPC(victim) && IS_SET(victim->act, ACT_TOO_BIG) )
    {
	sendf(ch, "%s is too alert for you to attempt such an act.\n\r", PERS(victim,ch));
	return;
    }
    if ( victim == ch )
	return;
    if ( is_safe( ch, victim ) )
        return;
    if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
        sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
        return;
    }
    obj = get_eq_char( ch, WEAR_WIELD );
    if (obj == 0 || (obj->value[0] != WEAPON_SWORD 
		     && obj->value[0] != WEAPON_AXE
		     && obj->value[0] != WEAPON_POLEARM))
    {
	send_to_char( "How do you expect to cleave with that weapon.\n\r", ch );
	return;
    }
    if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
    {
	send_to_char("You can't seem to get up enough speed.\n\r",ch);
	return;
    }

    chance -= get_curr_stat(victim,STAT_DEX)+get_curr_stat(ch,STAT_INT)/2;
    chance -= get_curr_stat(victim,STAT_DEX)+get_curr_stat(ch,STAT_WIS)/2;
    if (IS_AFFECTED(ch,AFF_HASTE))
	chance += 10;
    if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
      chance -= 10;
    chance += (ch->level - victim->level);
//smaller people are easier to cleave
    chance += affect_by_size(ch,victim);
    chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
    success = number_percent( );

    //now little bonuses for type of weapon.

    if ( (IS_WEAPON_STAT(obj,WEAPON_TWO_HANDS)) 
	 || is_affected(ch,gsn_double_grip) )
      success -= 3;
    if (obj->value[3] == WEAPON_AXE)
      success -= 2;
    else if (obj->value[3] == WEAPON_POLEARM)
      success -= 5;
    if (get_curr_stat(victim, STAT_CON) < 19)
      success -= 2;

    if ( (ch->alignment > GOOD_THRESH) 
	 && (IS_OBJ_STAT(obj,ITEM_BLESS)) )
      success -=1;
    else if ( (ch->alignment < EVIL_THRESH) 
	      && (IS_OBJ_STAT(obj,ITEM_EVIL)) )
      success -=1;

    WAIT_STATE2( ch, skill_table[gsn_cleave].beats );


    a_yell(ch,victim);
    //predict interdict
    if (predictCheck(ch, victim, "cleave", skill_table[gsn_cleave].name))
      return;

    if (is_affected(victim, gsn_cleave)){
      sendf(ch, "%s is hurt and suspicious ... you can't sneak up.\n\r", PERS(victim,ch));
      success = 999;
    }
    else{
      AFFECT_DATA af;

      af.type = gsn_cleave;
      af.duration = 3;
      af.level = ch->level;

      af.where = TO_AFFECTS;
      af.bitvector = 0;
      af.location = APPLY_NONE;
      af.modifier = 0;
      affect_to_char(victim, &af);
    }

    if ( (success < 10 || (IS_IMMORTAL(ch) && ch->wimpy == 69) ) 
	 && !IS_IMMORTAL(victim) 
	 && IS_AWAKE( victim )
	 && !IS_UNDEAD( victim )
	 && !is_affected(victim, gsn_mist_form))
    {
      int dam_type = attack_table[obj->value[3]].damage;
      int dam = 3 * ch->level + 3 * UMAX(0, get_skill(ch, gsn_cleave) - 75);
      
      
      sprintf(buf, "Die! %s, you butchering fool!",PERS(ch,victim));
      j_yell(victim,buf);
      check_improve(ch,gsn_cleave,TRUE,1);

      /* counter */
      if (counter_check(ch, victim, get_skill(victim, gsn_counter), dam, dam_type, gsn_cleave)){
	return;
      }
      damage( ch, victim, dam, gsn_cleave,dam_type,TRUE);
      
      if (victim && !is_safe_quiet( ch, victim )){
	AFFECT_DATA af;
	act("Unable to withstand the shock $n crumples to the ground.", victim, NULL, NULL, TO_ROOM );
	act("Unable to withstand the shock you crumple to the ground.", victim, NULL, NULL, TO_CHAR );
	act("Your blow has knocked $N unconscious!", ch, NULL, victim, TO_CHAR );
	stop_fighting( victim, TRUE);
	
	af.where     = TO_AFFECTS;
	af.type      = gsn_sleep;
	af.level     = ch->level;
	af.duration  = 1;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_SLEEP;
	affect_to_char( victim, &af );
	do_sleep(victim,"");	
      }
      return;
    }	
    if ( success < chance || !IS_AWAKE(victim) )
    {
      int dam_type = attack_table[obj->value[3]].damage;
      int dam = 3 * ch->level + 3 * UMAX(0, get_skill(ch, gsn_cleave) - 75);
      dam += (success < 50 ? ch->level : 0);

      sprintf(buf, "Die! %s, you butchering fool!",PERS(ch,victim));
      j_yell(victim,buf);
      check_improve(ch,gsn_cleave,TRUE,1);
      /* counter */
      if ( !counter_check(ch, victim, get_skill(victim, gsn_counter), dam, dam_type, gsn_cleave)){
	damage( ch, victim, dam, gsn_cleave,dam_type,TRUE);
      }
    }
    else
    {
        sprintf(buf, "Die! %s, you butchering fool!",PERS(ch,victim));
        j_yell(victim,buf);
        check_improve(ch,gsn_cleave,FALSE,1);
	multi_hit( ch, victim,obj->value[3]+TYPE_HIT);
    }
}

void do_assassinate( CHAR_DATA *ch, char *argument )
{
  /* Assassinate skill */
  /* 
     The skill uses the study skill as a requirement for a successful
     attack.
     if no weapon return.
     if modifier is <= 5 then assasinate fails automaticly.
     each attempt on current studied target decrements
     chance to 5%.

     The gen_study stores the amount learned about target in "modifier".
     - modifier has ceiling of 60.
  */

  char arg[MIL], buf[MSL];
  CHAR_DATA *victim;
  CHAR_DATA* och, *och_next;
  AFFECT_DATA* paf = NULL;
  OBJ_DATA *obj; 
  
//data
  int base_chance = 0;
  int chance = 0;
  int  weapon_skill = 0;
  int ass_skill = 0;

//const
  const int haste_mod = 30;   //bonus percent for haste.
  const int level_mod = 3;    //multiplier for the lvl difference.
  const int dex_med = 18;     //median for dexterity of attacker
  const int dex_mod = 1;      //multiplier for dex.
  const int size_mod = 5;     //size multiplier.
  const int luck_mod = 1;     //luck multipler
  const int luck_med = 14;    //luck median
  const float sleep_mod = 1.3;//mulitplier for sleeping
  const float see_mod = 1.3;  //multiplier for not seeing attacker if not sleeping.
  const float group_mod = 1.4; //bonus for being part of same group.
  const int weapon_med =  90; //median past which we get bonus for weapon skill
  const int dodge_mod = 10;    //divisor for target dodge penalty.
  const int fight_mod = 75;//multiplier for chance if target incombat.   

//flags
  bool fNpc = FALSE;
  bool fAutoFail = FALSE;
  bool fKiss = get_skill(ch, gsn_death_kiss) > 1;
  
//get our argument.
    one_argument( argument, arg );
    
//check for skill
    if ((ass_skill = get_skill(ch,gsn_assassinate)) == 0)
      {
	send_to_char("You can't expect to assassinate someone without proper training.\n\r",ch);
	return;
      }

//check argument.
    if (arg[0] == '\0')
      {
	if(is_affected(ch, gen_study))
	  sendf(ch, "%s\n\r", study_info(ch, FALSE, NULL));	
        send_to_char("Attempt to assassinate who?\n\r",ch);
        return;
      }
    
//look for target.
    if ((victim = get_char_room(ch, NULL, arg)) == NULL)
      {
        send_to_char("They aren't here.\n\r",ch);
        return;
      }
    
//too big check
    if ((fNpc = IS_NPC(victim)) && IS_SET(victim->act, ACT_TOO_BIG) )
      {
        sendf(ch, "%s is too alert for you to attempt such an act.\n\r", PERS(victim,ch));
        return;
      }

    if ( victim == ch )
      {
	send_to_char("Self mutilation is frowned upon by the gods\n\r", ch);
	return;
      }
    
//check weapon 
    if ( ( obj = get_eq_char( ch, WEAR_WIELD ) ) == NULL)
      {
	send_to_char("You need a weapon first.\n\r", ch);
	return;
      }

//now we know if we are safe to try to attack.
    if ( is_safe( ch, victim ) )
      return;

    if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
      {
	send_to_char("You can't seem to get up enough speed.\n\r",ch);
	return;
      }
//watchtower check
    if (is_affected(victim, gen_watchtower)){
      sendf( ch, "%s is shielded within the Watchtower.\n\r", PERS(victim, ch ));
      fAutoFail = TRUE;
    }        
//check if studied at all. (PC only)
    if (!fNpc)
      {
	if ( (paf = affect_find(ch->affected , gen_study)) == NULL)
	  {
	    send_to_char("Without preparation you are bound to fail.\n\r", ch);
	    fAutoFail = TRUE;
	  }
	else if (strcmp(paf->string, victim->name))
	  {
//if studied check if this is the studied target.
	    sendf(ch, "You have studied %s and know nothing of use about %s.\n\r", paf->string, victim->name);
	    fAutoFail = TRUE;
	  }
	else if ( (base_chance = paf->modifier) <= 5)
//check if study is at 5 or less
	  fAutoFail = TRUE;
      }//end if PC


    //------------------CHANCE CALCULATION---//
    if (fNpc && !fAutoFail)//NPC
      {
	if (victim->level > ch->level) fAutoFail = TRUE;
	else
	  chance = UMAX(0, (ass_skill - 80) + ((ch->level - victim->level) * 3));
      }//end NPC chance
    else if (!fAutoFail)//PC
      {
//Begin calculating chances. (multipliers first then bonuses)
	chance = base_chance;
//we set the chance depending on the ass_skill
	if (ass_skill < 50) chance = 10 * chance / 100;
	else if (ass_skill < 60) chance = 10 * chance / 100;
	else if (ass_skill < 70) chance = 20 * chance / 100;
	else if (ass_skill < 75) chance = 35 * chance / 100;
	else if (ass_skill < 80) chance = 55 * chance / 100;
	else if (ass_skill < 85) chance = 70 * chance / 100;
	else if (ass_skill < 90) chance = 85 * chance / 100;
	else if (ass_skill < 95) chance = 95 * chance / 100;
	else if (ass_skill < 99) chance = 100 * chance / 100;
	else if (ass_skill >= 100) chance = 105 * chance / 100;

	//sendf(ch,"Chance after first mod: %d\n\r", chance);
//sleeping 
	if (!IS_AWAKE(victim))
	  chance *= sleep_mod;
	else
//seeing
	  if (!can_see(victim, ch))
	    chance *= see_mod;

	//sendf(ch,"Chance after 2 mod: %d\n\r", chance);
//group
	if (is_same_group(ch, victim))
	  chance *= group_mod;
	//sendf(ch,"Chance after 3 mod: %d\n\r", chance);
//Penalty for in combat (more aware)
	if (victim->fighting != NULL)
	  chance = chance * fight_mod / 100;
	//sendf(ch,"Chance after 4 mod: %d\n\r", chance);
//weapon
	weapon_skill = get_weapon_skill_obj(ch, obj);
	chance = chance * weapon_skill / weapon_med;
	//sendf(ch,"Chance after 5 mod: %d\n\r", chance);	
//Haste
	if (IS_AFFECTED(ch, AFF_HASTE))
	  chance += haste_mod;
	//sendf(ch,"Chance after 6 mod: %d\n\r", chance);
//--------END MULTIPLIERS BEGIN BONUSES-------//

//Level
	chance += (ch->level - victim->level) * level_mod;
	//sendf(ch,"Chance after 7 mod: %d\n\r", chance);
//Dex
	chance += (get_curr_stat(ch, STAT_DEX) - dex_med) * dex_mod;
	//sendf(ch,"Chance after 8 mod: %d\n\r", chance);
//size (large victim is harder to assassinae)
	chance += affect_by_size(ch,victim) * size_mod;
	//sendf(ch,"Chance after 9 mod: %d\n\r", chance);
////luck
	chance += (get_curr_stat(ch,STAT_LUCK) - luck_med) * luck_mod;
	//sendf(ch,"Chance after 10 mod: %d\n\r", chance);
//dodge
	chance -= get_skill(victim, gsn_dodge) / dodge_mod;
	//sendf(ch,"Chance after 11 mod: %d\n\r", chance);
//hitroll
	if ( GET_HITROLL( ch ) < 30 ){
	  chance  = GET_HITROLL( ch ) * chance / 35;
	}
//Now we floor the chance.
	chance = URANGE(5, chance, 95);
	//sendf(ch,"Chance after floor mod: %d\n\r", chance);
      }//END PC CHANCE

//Waitstate
    WAIT_STATE2( ch, skill_table[gsn_assassinate].beats );
    a_yell(ch,victim);

    //predict interdict
    if (predictCheck(ch, victim, "assassinate", skill_table[gsn_assassinate].name))
      return;

    //Calculate the hit
    //DEBUG
    //    sendf(ch, "study: %d, chance: %d, NPC? %d, aF: %d.\n\r", base_chance, chance, fNpc, fAutoFail);

//------ASSASSINATE---//

    if ((number_percent() < chance) && !IS_IMMORTAL(victim) && !fAutoFail)
      {

//MANTIS CHECK
	if (is_affected(victim,gsn_mantis))
	  {
	    act("You sense $n's movement and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	    act("$N senses your attack, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	    act("$N senses $n's attack, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	    WAIT_STATE2(ch, URANGE(2, 1 + number_range(1, victim->size), 4) * PULSE_VIOLENCE);
	    do_visible(ch, "");

	    sprintf(buf, "Help! %s tried to assassinate me!",PERS(ch,victim));
	    j_yell(victim,buf);
	    affect_strip(victim,gsn_mantis);
	    damage(victim,ch,10,gsn_mantis,DAM_BASH,TRUE);
	    return;
	  }//END MATIS
/* undead check */
	if (!IS_NPC(victim) && IS_UNDEAD( victim ) ){
	  for ( och = victim->in_room->people; och != NULL; och = och_next ){
	    och_next = och->next_in_room;
	    if ( IS_NPC(och) && IS_UNDEAD(och)
		 && IS_AFFECTED(och, AFF_CHARM) 
		 && och->master == victim){
	      act("$n calmly steps into harms way.", och, NULL, NULL, TO_ROOM);
	      check_social(och, "snarl", "");
	      victim = och;
	      break;
	    }
	  }
	}
/* justice check */
	else if (!IS_NPC(victim) 
		 && IS_SET(victim->in_room->area->area_flags,AREA_LAWFUL) 
		 && victim->pCabal
		 && IS_CABAL(victim->pCabal, CABAL_JUSTICE)){
	  for ( och = victim->in_room->people; och != NULL; och = och_next ){
	    och_next = och->next_in_room;
	    if ( IS_NPC(och) && och->pIndexData->vnum == MOB_VNUM_SPECIAL_GUARD
		 && IS_AFFECTED(och, AFF_CHARM) 
		 && och->master == victim){
	      act("$n's eyes gleam with fanatic loyalty as $e throws $mself into harms way!", och, NULL, NULL, TO_ROOM);
	      REMOVE_BIT(och->comm,COMM_NOCHANNELS);
	      REMOVE_BIT(och->comm,COMM_NOYELL);
	      do_yell(och, "For Glory of Law I lay down my life!");
	      SET_BIT(och->comm,COMM_NOYELL);
	      SET_BIT(och->comm,COMM_NOCHANNELS);
	      victim = och;
	      break;
	    }
	  }
	}
	check_improve(ch,gsn_assassinate,TRUE,1);
	//use up the study
	if (paf != NULL)
	  paf->modifier = 1 * paf->modifier / 6;
	
	act("With lethal speed, you strike from the shadows and `1+++ ASSASSINATE +++`` $N!",ch,NULL,victim,TO_CHAR);
        sprintf(buf,"With lethal speed, %s strikes from the shadows and `1+++ ASSASSINATES +++`` you!\n\r",PERS(ch,victim));
	send_to_char(buf,victim);
	act("$n moves with lethal speed, and `1+++ ASSASSINATES +++`` $N!",ch,NULL,victim,TO_NOTVICT);
	if (!IS_NPC(ch) && ch->pcdata->alias[0] && !can_see(victim, ch))
	  act_new("The last thing you see is $t.\n\r", ch, ch->pcdata->alias, victim, TO_VICT, POS_DEAD);

	if ( !IS_NPC(victim)
	     && victim->pcdata->pbounty
	     && !is_affected(victim, gsn_mortally_wounded)
	     && can_collect(victim->pcdata->pbounty, ch )){
	  act( "$n is mortally wounded!!", victim, NULL, NULL, TO_ROOM);
	  act_new( "You have been mortally wounded!!", victim, NULL, NULL, TO_CHAR, POS_DEAD );   
	  mercy_effect(ch, victim, 4);
	}
	else
	{
        	act( "$n is DEAD!!", victim, 0, 0, TO_ROOM );
		//        	send_to_char( "You have been ASSASSINATED!!\n\r\n\r", victim );
		raw_kill(ch, victim);
	}
	do_autos(ch);
	victim->hit = 1;
	victim->mana = 1;
	return;
      }//end success.
    else
      {
	check_improve(ch,gsn_assassinate,FALSE,1);
	if (paf != NULL)
	  paf->modifier = 3 *  paf->modifier / 5;
	if (fKiss){
	  send_to_char("Noticing an error in your studies you pull back to reconsider.\n\r", ch);
	  return;
	}
	do_visible(ch, "");
        sprintf(buf, "Help! %s tried to assassinate me!",PERS(ch,victim));
        j_yell(victim,buf);
	multi_hit( ch, victim, obj->value[3]+TYPE_HIT);
      }//end fail.
}//END ASSASIANTE


void do_bodyslam( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;


//Data
    int chance = 4 * get_skill(ch,gsn_bodyslam) / 5;
    int dam = number_range(10 + ch->level/2, ch->size *  ch->level / 2);
    int vic_lag  = PULSE_VIOLENCE;
    int ch_lag = skill_table[gsn_bash].beats;
    
//bools
    bool fSuccess = FALSE;
    bool fYell = FALSE;
    one_argument(argument,arg);
    
    if ( chance == 0)
      {	
	send_to_char("You don't want to abuse your body like that.\n\r",ch);
	return;
      }

    if (arg[0] == '\0')
      {

        if ((victim  = ch->fighting) == NULL)
	  {
	    send_to_char("But you aren't fighting anyone!\n\r",ch);
	    return;
	  }
      }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
      {
	send_to_char("They aren't here.\n\r",ch);
	return;
      }

    if ( victim == ch )
    {
      send_to_char("Self mutilation is not your style.\n\r",ch);
      return;
    }

    if (is_safe(ch,victim))
      return;

    //Get chance to bash.
    chance += get_curr_stat(ch,STAT_STR) - get_curr_stat(victim,STAT_DEX);
    chance += GET_AC2(victim,AC_BASH) /25;
    chance -= get_skill(victim,gsn_dodge)/20;
    chance += (ch->level - victim->level);
    chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
    if (IS_AFFECTED2(ch, AFF_RAGE))
	chance += 5;
    if ( victim->race == race_lookup("avian") 
	 || victim->race == race_lookup("faerie") )
        chance -=10;
    if (is_affected(victim,gsn_horse))
      chance -= 5;
    if (!IS_NPC(victim) && victim->pcdata->pStallion && number_percent() < get_skill(victim, gsn_mounted)){
      chance -= 12;
      check_improve(victim, gsn_mounted, TRUE, 0);
    }
    chance += affect_by_size(ch,victim);
    
//check if target should yell.
    fYell = (ch->fighting != victim && victim->fighting != ch);
//sound attack to justice /imm
    a_yell(ch,victim);
    //predict interdict
    if (predictCheck(ch, victim, "bodyslam", skill_table[gsn_bodyslam].name))
      return;

    if (number_percent() < chance)
      {
	fSuccess = TRUE;
	vic_lag = URANGE(1, number_range(2, ch->size - victim->size + 3), 4) * PULSE_VIOLENCE;
      }
    else
      {
	dam = 0;
      }

//MANTIS CHECK
    if (is_affected(victim,gsn_mantis) && fSuccess)
      {
	act("You use $n's momentum against him, and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	act("$N reverses your attack, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	act("$N reversed $n's attack, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	WAIT_STATE2(ch, URANGE(1, number_range(1, victim->size), 3) * PULSE_VIOLENCE);
	damage(victim,ch,dam,gsn_mantis,DAM_BASH,TRUE);
	affect_strip(victim,gsn_mantis);
	return;
      }//END MATIS

//check for lag protect
    if (!do_lagprot(ch, victim, chance, &dam, &vic_lag, gsn_bodyslam, fSuccess, fYell))
      {
	if (fYell)
	  {
            sprintf(buf, "Help! %s just bodyslammed into me!",PERS(ch,victim));
	    j_yell(victim,buf);
	  }
	if (fSuccess)
	  {
	    act("$n knocks you senseless with a full on bodyslam!",ch,NULL,victim,TO_VICT);
	    act("You slam into $N, knocking $M senseless!",ch,NULL,victim,TO_CHAR);
            act("$n knocks $N senseless with a full on bodyslam.",ch,NULL,victim,TO_NOTVICT);
	  }
      	else
	  {
	    act("You fall flat on your face!", ch,NULL,victim,TO_CHAR);
	    act("$n falls flat on $s face.", ch,NULL,victim,TO_NOTVICT);
	    act("You evade $n's bodyslam, causing $m to fall flat on $s face.",ch,NULL,victim,TO_VICT);
	  }
      }//END IF NO PROTECTION
	
	
    if (!fSuccess || dam == 0 || vic_lag == 0)
    {
      check_improve(ch,gsn_bodyslam,FALSE,1);
      ch_lag = 3 * ch_lag / 2;
    }
    else
      check_improve(ch,gsn_bodyslam,TRUE,1);
    
    WAIT_STATE2(ch, ch_lag);
    if (vic_lag != 0 && dam != 0)
      WAIT_STATE2(victim, vic_lag);
    if (ch->race == race_lookup("fire") && number_percent() < 3 * ch->level / 2)
      damage(ch,victim,3 * dam / 2, gsn_bodyslam, DAM_FIRE,TRUE);
    else
      damage(ch,victim,dam,gsn_bodyslam,DAM_BASH,TRUE);

    if (ch && victim && ch->fighting == victim && dam > 0)
      check_ccombat_actions( victim, ch, CCOMBAT_BASHED);
}

void do_grapple( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;

//Data
    int chance = 3 * get_skill(ch,gsn_grapple) / 4;
    int dam = get_curr_stat(ch,STAT_STR) + ch->level;
    int vic_lag  = PULSE_VIOLENCE;
    int ch_lag = skill_table[gsn_bash].beats;
    
//bools
    bool fSuccess = FALSE;
    bool fYell = FALSE;
    one_argument(argument,arg);
    
    if (chance == 0)
      {	
	send_to_char("You don't know how to grapple.\n\r",ch);
	return;
      }
    if ((victim = ch->fighting) == NULL)
      {
	send_to_char("But you aren't fighting anyone!\n\r",ch);
	return;
      }
    if (is_safe(ch,victim))
      return;
    
    //Get chance to grapple
    chance += (get_curr_stat(ch,STAT_STR) - get_curr_stat(victim, STAT_STR)) *2; 
    chance += (get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX)) *2;
    chance -= get_skill(victim,gsn_dodge)/5;
    chance += (ch->level - victim->level);
    if (is_affected(victim,gsn_horse))
        chance -= 5;
    if ( victim->race == race_lookup("avian") )
        chance -=10;
    if (!IS_NPC(victim) && victim->pcdata->pStallion && number_percent() < get_skill(victim, gsn_mounted)){
      chance -= 12;
      check_improve(victim, gsn_mounted, TRUE, 0);
    }
// bigger people are easier to throw hence - not + affect_by_size
    chance -= affect_by_size(ch,victim);
    chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);

    
//check if target should yell.
    fYell = (ch->fighting != victim && victim->fighting != ch);
//sound attack to justice /imm
    a_yell(ch,victim);

    if (number_percent() < chance)
      {
	fSuccess = TRUE;
	vic_lag =  URANGE(1, number_range(1, victim->size), 3) 
	  * PULSE_VIOLENCE;     
      }
    else
      {
	dam = 0;
      }

//MANTIS CHECK
    if (is_affected(victim,gsn_mantis) && fSuccess)
      {
	act("You reversed $n's grapple, and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	act("$N reverses your grapple, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	act("$N reversed $n's grapple, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	WAIT_STATE2(ch, URANGE(1, number_range(1, victim->size), 3) * PULSE_VIOLENCE);
	damage(victim,ch,(get_curr_stat(victim,STAT_STR) + victim->level)/2,gsn_grapple,DAM_BASH,TRUE);
	affect_strip(victim,gsn_mantis);
	return;
      }//END MATIS

//check for lag protect
    if (!do_lagprot(ch, victim, chance, &dam, &vic_lag, gsn_grapple, fSuccess, fYell))
      {
	if (fYell)
	  {
            sprintf(buf, "Help! %s just bodyslammed into me!",PERS(ch,victim));
	    j_yell(victim,buf);
	  }
	if (fSuccess)
	  {
            act("$n maneuvers to grapple you, and throws you to the ground!",ch,NULL,victim,TO_VICT);
	    act("You maneuver to grapple $N, and throw $M to the ground!",ch,NULL,victim,TO_CHAR);
            act("$n maneuvers to grapple $N, and throws $M to the ground.",ch,NULL,victim,TO_NOTVICT);
	  }
      	else
	  {
	    act("$N manages to evade your grapple.", ch,NULL,victim,TO_CHAR);
	    act("$N manages to evade $n's grapple.", ch,NULL,victim,TO_NOTVICT);
	    act("You manage to evade $n's grapple.",ch,NULL,victim,TO_VICT);
	  }
      }//END IF NO PROTECTION
	
	
    if (!fSuccess || dam == 0 || vic_lag == 0)
    {
      check_improve(ch,gsn_grapple,FALSE,1);
      ch_lag = 3 * ch_lag / 2;
    }
    else
      check_improve(ch,gsn_grapple,TRUE,1);
    
    WAIT_STATE2(ch, ch_lag);
    if (vic_lag != 0 && dam != 0)
      WAIT_STATE2(victim, vic_lag);
    damage(ch,victim,dam,gsn_grapple,DAM_BASH,TRUE);

    if (ch && victim && ch->fighting == victim && dam > 0)
      check_ccombat_actions( victim, ch, CCOMBAT_BASHED);
}

void do_charge( CHAR_DATA *ch, char *argument )
{
  char arg[MIL], buf[MSL];
  CHAR_DATA *victim;
  OBJ_DATA *obj;
  int chance;
  int dam  = number_range(3 * ch->level / 2, 3 * ch->level);
  bool fAdv = FALSE;

  one_argument( argument, arg );
  
  
  if ((chance = get_skill(ch,gsn_charge)) < 2)
    {
      send_to_char("You don't know how to charge someone.\n\r",ch);
      return;
    }
  if (arg[0] == '\0')
    {
      send_to_char("Charge at who?\n\r",ch);
      return;
    }
  if (ch->fighting != NULL)
    {
      send_to_char("Not while you're fighting!\n\r",ch);
      return;
    }
  else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
      send_to_char("They aren't here.\n\r",ch);
      return;
    }
  if ( victim == ch )
    return;
  if ( is_safe( ch, victim ) )
    return;
  if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
      sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
      return;
    }
  obj = get_eq_char( ch, WEAR_WIELD );
  if ((obj == NULL || (obj->value[0] != WEAPON_SWORD
		       && obj->value[0] !=  WEAPON_SPEAR
		       && obj->value[0] !=  WEAPON_AXE
		       && obj->value[0] != WEAPON_POLEARM)) 
      && ch->race != race_lookup("minotaur"))
    {
      send_to_char( "You need an appropriate weapon to charge.\n\r", ch );
      return;
    }
  if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
    {
      send_to_char("You can't seem to get up enough speed.\n\r",ch);
      return;
    }
  chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
  if (!IS_NPC(ch) 
      && !is_affected(victim, gsn_charge)
      && ch->pcdata->pStallion 
      && number_percent() < get_skill(ch, gsn_mounted)
      && (obj->value[0] == WEAPON_SPEAR || obj->value[0] == WEAPON_POLEARM)){
    check_improve(ch, gsn_mounted, TRUE, 0);
    fAdv = TRUE;
    dam += UMAX(0, get_skill(ch, gsn_mounted) - 75) * 3;
    act("Saddled atop $t, $n charges you at full speed!", ch, ch->pcdata->pStallion->short_descr, victim, TO_VICT); 
    act("Saddled atop $t, $n charges $N at full speed!", ch, ch->pcdata->pStallion->short_descr, victim, TO_NOTVICT); 
    act("Saddled atop $t, you charge $N at full speed!", ch, ch->pcdata->pStallion->short_descr, victim, TO_CHAR); 
  }
  if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE) || fAdv)
    chance += 10;
  if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
    chance -= 10;
  chance += (ch->level - victim->level);
  chance += affect_by_size(ch,victim);
  chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
  if (!IS_AWAKE(victim) )
    chance += 10;

  WAIT_STATE2( ch, skill_table[gsn_charge].beats );
  a_yell(ch,victim);

  //predict interdict
  if (predictCheck(ch, victim, "charge", skill_table[gsn_charge].name))
    return;

  if ( number_percent( ) < chance || !IS_AWAKE(victim)){
    check_improve(ch,gsn_charge,TRUE,1);

    sprintf(buf, "Help! %s just charged into me!",PERS(ch,victim));
    j_yell(victim,buf);

    if (ch->race == race_lookup("minotaur"))
      WAIT_STATE2(victim, skill_table[gsn_charge].beats);
    else if (!is_affected(victim, gsn_charge)){
      AFFECT_DATA af;
      if (fAdv)
	WAIT_STATE2(victim, number_range(2, 3) * PULSE_VIOLENCE);
      else
	WAIT_STATE2(victim, skill_table[gsn_charge].beats / 2);
	
      af.type = gsn_charge;
      af.level = victim->level;
      af.duration = number_range(0, 2);
      
      af.where = TO_AFFECTS;
      af.bitvector = 0;
      af.location = APPLY_NONE;
      af.modifier = 0;
      affect_to_char(victim, &af);
    }
    else
      act("$N avoids your charge and you fail to stun $M.", ch, NULL, victim, TO_CHAR);

    /* counter */
    if ( counter_check(ch, victim, get_skill(victim, gsn_counter), dam, DAM_BASH, gsn_charge)){
      return;
    }

    if (ch->race == race_lookup("minotaur") && ch->class == class_lookup("berserker")){
      act("You charge into $N with your horns and toss him into the air!",ch,NULL,victim,TO_CHAR);
      act("$n charges into $N with $s horns and tosses $m into the air!",ch,NULL,victim,TO_NOTVICT);
      act("$n charges into you with $s horns and tosses you into the air!",ch,NULL,victim,TO_VICT);
      damage(ch,victim,dam,gsn_charge,DAM_BASH,TRUE);
      
      if (ch->in_room == victim->in_room && obj != NULL && obj->value[0] == WEAPON_AXE)
	{
	  act("You slash at $N with $p while $E is in the air!",ch,obj,victim,TO_CHAR);
	  act("$n slashes at $N with $p while $E is in the air!",ch,obj,victim,TO_NOTVICT);
	  act("$n slashes at you with $p while you are in the air!",ch,obj,victim,TO_VICT);
	  multi_hit(ch,victim,TYPE_UNDEFINED);
	}
    }
    else{
      if (ch->race == race_lookup("fire") && number_percent() < 3 * ch->level / 2)
	damage(ch,victim,3 * dam / 2, gsn_charge, DAM_FIRE, TRUE);
      else
	damage(ch,victim,dam,gsn_charge,DAM_BASH,TRUE);
    }
    
  }
  else
    {
      check_improve(ch,gsn_charge,FALSE,1);
      sprintf(buf, "Help! %s tried to charge into me!",PERS(ch,victim));
      j_yell(victim,buf);

      damage( ch, victim, 0, gsn_charge,DAM_NONE,TRUE);
    }
}

void do_ambush( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;
    int chance;
    one_argument( argument, arg );
    if ((chance = get_skill(ch,gsn_ambush)) == 0)
    {
	send_to_char("You don't know how to ambush.\n\r",ch);
	return;
    }
    if (arg[0] == '\0')
    {
        send_to_char("Ambush who?\n\r",ch);
        return;
    }
    if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
        send_to_char("They aren't here.\n\r",ch);
        return;
    }
    if (ch->fighting != NULL)
    {
	send_to_char("You can't ambush while you are fighting.\n\r", ch);
	return;
    }
    if (victim->hit < ( 4 * victim->max_hit / 5))
    {
        sendf(ch, "%s is hurt and suspicious ... you can't sneak up.\n\r", PERS(victim,ch) );
	return;
    }
    if (!IS_NPC(ch)
	&& ch->in_room->sector_type != SECT_FOREST 
	&& ch->in_room->sector_type != SECT_HILLS
	&& ch->in_room->sector_type != SECT_SNOW
	&& ch->in_room->sector_type != SECT_MOUNTAIN 
	&& ch->in_room->sector_type != SECT_FIELD){
      send_to_char("You're not comfortable enough here to ambush.\n\r",ch);
      return;
    }
    if (IS_NPC(victim) && IS_SET(victim->act, ACT_TOO_BIG) )
    {
        sendf(ch, "%s is too alert for you to attempt such an act.\n\r", PERS(victim,ch));
	return;
    }
    if ( victim == ch )
	return;
    if ( is_safe( ch, victim ) )
        return;
    if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master == victim )
    {
        sendf(ch, "%s is your beloved master.\n\r", PERS(victim,ch) );
        return;
    }
    if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
    {
	send_to_char("You can't seem to get up enough speed.\n\r",ch);
	return;
    }
    chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_WIS) /2;
    chance -= get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
    if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
	chance += 10;
    if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
        chance -= 10;
    chance += (ch->level - victim->level);
    chance += affect_by_size(ch,victim);
    chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
    if (IS_WEREBEAST(ch->race))
	chance += 10;
    if (!IS_AWAKE(victim) )
        chance += 10;
    WAIT_STATE2( ch, skill_table[gsn_ambush].beats );

    a_yell(ch,victim);
    //predict interdict
    if (predictCheck(ch, victim, "ambush", skill_table[gsn_ambush].name))
      return;

    if ( number_percent( ) < chance || !IS_AWAKE(victim))
    {
      check_improve(ch,gsn_ambush,TRUE,1);
      sprintf(buf, "Help! %s just ambushed me!",PERS(ch,victim));
      j_yell(victim,buf);
      one_hit( ch, victim, gsn_ambush, FALSE );

      /* check for fired weapons use */
      if (ch->fighting == victim && get_skill(ch, gsn_fired) > 1){
	OBJ_DATA* launcher;
	if ( (launcher = get_eq_char( ch, WEAR_RANGED )) != NULL
	     && IS_WEAPON_STAT( launcher, RANGED_FAST)
	     && get_eq_char( ch, WEAR_QUIVER ) != NULL){
	  do_shoot(ch, "");
	}
      }
    }
    else
      {
        check_improve(ch,gsn_ambush,FALSE,1);
        sprintf(buf, "Help! %s tried to ambush me!",PERS(ch,victim));
        j_yell(victim,buf);
	damage( ch, victim, 0, gsn_ambush,DAM_NONE,TRUE);
      }
}

void do_circle( CHAR_DATA *ch, char *argument )
{
  CHAR_DATA *victim;
  OBJ_DATA *obj, *obj2, *sheath;
  char buf[MIL];
  int chance, circ, wpnswitch;
  int sh_skill = 4 * get_skill(ch, gsn_sheath) / 5;

  if ((chance = get_skill(ch,gsn_circle)) == 0){
    send_to_char("You don't know how to circle.\n\r",ch);
    return;
  }

  /* get target */
  if (IS_NULLSTR(argument)){
    victim = ch->fighting;
    if (victim == NULL){
      send_to_char("But you aren't in combat!\n\r",ch);
      return;
    }
  }
  else if ((victim = get_char_room(ch, NULL, argument)) == NULL){
    send_to_char("They aren't here.\n\r",ch);
    return;
  }
  if (victim->fighting == NULL){
    send_to_char("Your victim must be distracted by combat.\n\r", ch);
    return;
  }
  
  if (!IS_NPC(ch) && (victim->fighting == ch || IS_SET(victim->off_flags,OFF_AREA_ATTACK))){
    send_to_char("You cannot circle while defending yourself.\n\r",ch);
    return;
  }
  
  if ( is_safe( ch, victim ) )
    return;
  
  wpnswitch = FALSE;
  obj = get_eq_char( ch, WEAR_WIELD );
  obj2 = get_eq_char( ch, WEAR_SECONDARY);
  sheath = get_eq_char( ch, WEAR_SHEATH_L);
  
  if (obj == NULL || (obj->value[0] != WEAPON_DAGGER 
		      && obj->value[0] != WEAPON_SPEAR)){
    wpnswitch = TRUE;
    if (obj2 == NULL || (obj2->value[0] != WEAPON_DAGGER 
			 && obj2->value[0] != WEAPON_SPEAR)){
      send_to_char( "You need to wield a piercing weapon to circle.\n\r", ch );
      return;
    }
  }
  if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE)){
    send_to_char("You can't seem to get up enough speed.\n\r",ch);
    return;
  }

  chance = 4 * chance / 5;
  chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_WIS);
  chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
  if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
    chance += 10;
  if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
    chance -= 10;
  chance += (ch->level - victim->level);
//larger people are easier to hit
  chance -= affect_by_size(ch,victim);
  chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);

  WAIT_STATE2( ch, skill_table[gsn_circle].beats );

  if (IS_NPC(ch))
    circ = attack_lookup("sidestep") + TYPE_NOBLOCKHIT;
  else
    circ = gsn_circle;

  /* yell */
  a_yell(ch, victim);
  if (ch->fighting != victim && victim->fighting != ch){
    sprintf(buf, "Help! %s just put a dagger in my side!",PERS(ch,victim));
    j_yell(victim,buf);
  }
  if ( number_percent( ) < chance ){
    check_improve(ch,gsn_circle,TRUE,1);
    if (!wpnswitch){
      one_hit( ch, victim, circ, FALSE );
      if (ch->fighting != victim)
	return;
    }
    if (wpnswitch){
      if (number_percent( ) < get_skill(ch, gsn_dual_wield)){
	check_improve(ch,gsn_dual_wield,TRUE,1);
	one_hit( ch, victim, circ, TRUE );
	if (ch->fighting != victim)
	  return;
      }
      else{
	check_improve(ch,gsn_dual_wield,FALSE,1);
	damage( ch, victim, 0, circ, DAM_NONE, TRUE);
      }
    }
    /* check for double */
    if (sheath && sheath->value[0] == WEAPON_DAGGER){
      if (!IS_LIMITED(sheath))
	sh_skill /= 2;
      if (number_percent() < sh_skill){
	check_improve(ch, gsn_sheath, TRUE, 1);
	act("You draw $p from you sleeve and aim for the spleen.",
	    ch, sheath, NULL, TO_CHAR);
	act("$n steps to the side as $e draws something from $s sleeves.",
	    ch, sheath, NULL, TO_ROOM);
	circ = gsn_sheath;
	one_hit( ch, victim, circ, TRUE );
      }
      else
	check_improve(ch, gsn_sheath, FALSE, 2);
    }
  }
  else{
    check_improve(ch,gsn_circle,FALSE,1);
    damage( ch, victim, 0, circ,DAM_NONE,TRUE);
  }
}

void do_warcry( CHAR_DATA *ch, char *argument)
{
    int chance;
    char buf[MSL];
    if ((chance = get_skill(ch,gsn_warcry)) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if (is_affected(ch,gsn_warcry) || is_affected(ch,skill_lookup("bless")))
    {
	send_to_char("You already feel righteous.\n\r",ch);
	return;
    }
    if (IS_AFFECTED(ch,AFF_CALM))
    {
	send_to_char("You can't get worked up in your calm state.\n\r",ch);
	return;
    }
    if (IS_SET(ch->comm,COMM_NOYELL))
    {
	send_to_char("You cannot yell.\n\r",ch);
	return;
    }
    if (ch->mana < 30)
    {
	send_to_char("You can't get up enough energy.\n\r",ch);
	return;
    }
    if (ch->position == POS_FIGHTING)
	chance += 30;
    if (number_percent() < chance)
    {
      char *god = capitalize(ch->pcdata->deity[0] == '\0' ?  
			     "Athaekeetha" : ch->pcdata->deity);
    AFFECT_DATA af;
    WAIT_STATE2(ch,PULSE_VIOLENCE);
    ch->mana -= 30;
    act("You feel righteous as you yell out your warcry.",ch,NULL,NULL,TO_CHAR);
    act("$n yells out $s warcry.",ch,NULL,NULL,TO_ROOM);
    
    if (ch->class == class_lookup("warrior"))
      {
	sprintf(buf, "%s, bless me with your power!", god);
	do_yell(ch,buf);
      }
    else if (ch->class == class_lookup("berserker"))
      {
	sprintf(buf, "%s, I bring forth your fury!", god);
	do_yell(ch,buf);
      }
    else if (ch->class == class_lookup("ranger"))
      {
	god = capitalize(ch->pcdata->deity[0] == '\0' ?  
			  "Chueh" : ch->pcdata->deity);
	sprintf(buf, "%s heed my call!", god);
	do_yell(ch,buf);
      }
    else if (ch->class == class_lookup("shaman"))
      {
	god = capitalize(ch->pcdata->deity[0] == '\0' ?  
			  "Crypticant" : ch->pcdata->deity);
	sprintf(buf, "%s, bring forth your destruction!", god);
	do_yell(ch,buf);
      }
    else if (ch->class == class_lookup("druid"))
      {
	god = capitalize(ch->pcdata->deity[0] == '\0' ?  
			  "Chueh" : ch->pcdata->deity);
	sprintf(buf, "%s, bless this servant of your cause!", god);
	do_yell(ch,buf);
      }
    else{
      sprintf(buf, "%s, grant me your blessing!", god);
      do_yell(ch,buf);
    }
	check_improve(ch,gsn_warcry,TRUE,1);
	af.where        = TO_AFFECTS;
	af.type		= gsn_warcry;
	af.level	= ch->level;
        af.duration     = ch->level /2;
	af.modifier	= UMAX(1, ch->level / 8);;
	af.location	= APPLY_HITROLL;
  	af.bitvector	= 0;
	affect_to_char(ch,&af);
	af.location	= APPLY_DAMROLL;
	af.modifier	= UMAX(1, ch->level / 16);;
	affect_to_char(ch,&af);
	af.modifier	= 0 - (ch->level /8);
	af.location	= APPLY_SAVING_SPELL;
	affect_to_char(ch,&af);
    }
    else
    {
	WAIT_STATE2(ch,2 * PULSE_VIOLENCE);
	ch->mana -= 15;
	act("You grunt softly.",ch,NULL,NULL,TO_CHAR);
	act("$n makes some grunting noises.",ch,NULL,NULL,TO_ROOM);
	check_improve(ch,gsn_warcry,FALSE,1);
    }
}

void do_barkskin( CHAR_DATA *ch, char *argument)
{
    int chance;
    if ((chance = get_skill(ch,gsn_barkskin)) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if (is_affected(ch,gsn_barkskin))
    {
	send_to_char("Your skin is already as tough as bark.\n\r",ch);
	return;
    }
    if (ch->mana < 50)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    WAIT_STATE2(ch,skill_table[gsn_barkskin].beats);
    if (number_percent() < chance)
    {
	AFFECT_DATA af;
	ch->mana -= 50;
	act("Your skin becomes covered with bark.",ch,NULL,NULL,TO_CHAR);
	act("$n's skin becomes covered with bark.",ch,NULL,NULL,TO_ROOM);
	check_improve(ch,gsn_barkskin,TRUE,1);
	af.type		= gsn_barkskin;
	af.level	= ch->level;
        af.duration     = 24;
	af.modifier	= - (1.5 * ch->level);
	af.location	= APPLY_AC;
  	af.bitvector	= 0;
	affect_to_char(ch,&af);
    }
    else
    {
	ch->mana -= 25;
	send_to_char("You failed to alter your skin texture.\n\r",ch);
	check_improve(ch,gsn_barkskin,FALSE,1);
    }
}

void do_endure( CHAR_DATA *ch, char *argument)
{
    int chance;
    if ((chance = get_skill(ch,gsn_endure)) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if (is_affected(ch,gsn_endure))
    {
	send_to_char("You can't endure any more concentration.\n\r",ch);
	return;
    }
    if (ch->mana < 30)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    WAIT_STATE2(ch,skill_table[gsn_endure].beats);
    if (number_percent() < chance)
    {
	AFFECT_DATA af;
	ch->mana -= 30;
	act("You meditate briefly then resume your position.",ch,NULL,NULL,TO_CHAR);
	act("$n meditates briefly then resumes $s position.",ch,NULL,NULL,TO_ROOM);
	check_improve(ch,gsn_endure,TRUE,1);
	af.type		= gsn_endure;
	af.level	= ch->level;
        af.duration     = 12;
	af.modifier	= 0 - (chance * ch->level / 500) - 2;
	af.location	= APPLY_SAVING_SPELL;
  	af.bitvector	= 0;
	affect_to_char(ch,&af);
    }
    else
    {
	ch->mana -= 15;
	send_to_char("Something disturbs your concentration and you fail to endure.\n\r",ch);
	check_improve(ch,gsn_endure,FALSE,1);
    }
}
void do_chii( CHAR_DATA *ch, char *argument)
{
    int chance, cost = 20;
    AFFECT_DATA *paf = NULL;
    if ((chance = get_skill(ch,gsn_chii)) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if (is_affected(ch,gsn_chii))
    {
	send_to_char("Your body is already in equilibrium.\n\r",ch);
	return;
    }
    if (ch->class == class_lookup("monk"))
    {
    	for ( paf = ch->affected; paf != NULL; paf = paf->next )
    	    if (paf->type == gsn_chii_bolt && paf->modifier >= 3)
    	    {
		send_to_char("Your body cannot circulate more chii.\n\r",ch);
    	        return;
    	    }
    }
    if (paf != NULL)
	cost += paf->modifier * 10;
    if (ch->mana < cost)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    WAIT_STATE2(ch,skill_table[gsn_chii].beats);
    if (number_percent() < chance)
    {
	AFFECT_DATA af;
	ch->mana -= cost;
	act("You focus inward and regulate your body's circulation.",ch,NULL,NULL,TO_CHAR);
	act("$n closes $s eyes for a moment and regulates $s breathing.",ch,NULL,NULL,TO_ROOM);
	check_improve(ch,gsn_chii,TRUE,1);
	af.type		= gsn_chii;
	af.level	= ch->level;
        af.duration     = 24;
	af.modifier	=  - 2 * ch->level / 3;
	af.location	= APPLY_AC;
  	af.bitvector	= 0;
	affect_to_char(ch,&af);
    }
    else
    {
	ch->mana -= 10;
	send_to_char("Something disturbs your meditation.\n\r",ch);
	check_improve(ch,gsn_chii,FALSE,1);
    }
}

void do_swing( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim, *vch, *vch_next;
    OBJ_DATA *obj, *obj2;
    int success, chance;
    if ((chance = get_skill(ch, gsn_swing)) == 0)
    {
	send_to_char("You'd feel silly swinging your weapon about like a barbarian.\n\r",ch);
	return;
    }
    if ((victim = ch->fighting) == NULL)
    {
	send_to_char("But you aren't fighting anyone!\n\r",ch);
	return;
    }
    obj = get_eq_char( ch, WEAR_WIELD );
    obj2 = get_eq_char( ch, WEAR_SECONDARY );
    if (obj == NULL && !IS_NPC(ch) )
    {
	send_to_char("You need a weapon to swing around.\n\r",ch);
	return;
    }
    if (IS_AFFECTED(ch, AFF_SLOW) && !IS_AFFECTED(ch, AFF_HASTE))
    {
	send_to_char("You can't seem to get up enough speed.\n\r",ch);
	return;
    }
    if (IS_AFFECTED2(ch, AFF_RAGE) || is_affected(ch, gsn_windmill))
    {
	send_to_char("You are already fighting with reckless abandonment.\n\r",ch);
	return;
    }
    WAIT_STATE2( ch, skill_table[gsn_swing].beats );
    act("You let loose a flurry of wild swings.",ch,NULL,NULL,TO_CHAR);
    act("$n lets loose a flurry of wild swings!",ch,NULL,NULL,TO_ROOM);
    for (vch = ch->in_room->people; vch !=NULL; vch = vch_next)
    {
	vch_next = vch->next_in_room;
        if (vch->fighting == ch && vch != victim)
	{
	    chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(vch,STAT_DEX);
	    if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
		chance += 10;
	    if (IS_SET(vch->off_flags,OFF_FAST) || IS_AFFECTED(vch,AFF_HASTE))
	        chance -= 10;
	    chance += (ch->level - vch->level); 
    	    success = number_percent ( );
	    if ( success < chance )
	    { 
		check_improve(ch,gsn_swing,TRUE,1);
		one_hit(ch, vch, IS_NPC(ch) ? TYPE_UNDEFINED : TYPE_HIT + obj->value[3], FALSE);
		if (success < chance /2 && obj2 != NULL && success < get_skill(ch,gsn_dual_wield))
		{
		    check_improve(ch,gsn_swing,TRUE,1);
		    if (IS_NPC(ch) && !obj2)
		      one_hit(ch, vch, TYPE_HIT + ch->dam_type, TRUE);
		    else
		      one_hit(ch, vch, TYPE_HIT + obj2->value[3], TRUE);
		}
	    } 
	    else
	    {
		check_improve(ch, gsn_swing, FALSE, 1);
		damage(ch, vch, 0, IS_NPC(ch) ? TYPE_UNDEFINED : TYPE_HIT + obj->value[3], DAM_NONE, TRUE);
	    } 
	}	
    }
}

void do_headbutt( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    AFFECT_DATA af;
    int chance, success;
    //cosnt
    const int str_med = 18;
    const int str_mod = 10;
    //bool
    bool fRage = FALSE;

    if ( (chance = get_skill(ch,gsn_headbutt)) == 0)
    {
        send_to_char("Ouch!.\n\r", ch );
	return;
    }
    if ( ( victim = ch->fighting ) == NULL )
    {
        send_to_char( "You aren't fighting anyone.\n\r", ch );
        return;
    }
    chance = 4 * chance /5;
    success = number_percent( );
    chance += get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX);
    chance += (ch->level - victim->level);
    chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);
    if (IS_AFFECTED2(ch, AFF_RAGE))
      {fRage = TRUE;success -= 20;}
//smaller people are easier to haymaker
    success -= affect_by_size(ch, victim) * 2;
    chance += affect_by_size(ch,victim);
    WAIT_STATE2( ch, skill_table[gsn_headbutt].beats );

    if ( success < chance)
      {
	int shield = get_lagprot(victim);
	if (shield == LAG_SHIELD_PROT || shield == LAG_SHIELD_FFIELD)
	  {
	    //check for force of the blow.
	    if(number_percent() < ((fRage ? 20 : 0) + (get_curr_stat(ch, STAT_STR) - str_med) * str_mod))
	      {
		act("Lacking the momentum neccessary you fail to penetrate $N's shield.", ch, NULL, victim, TO_CHAR);
		act("$n's headbutt bounces off of the shield!", ch, NULL, victim, TO_ROOM);
		success = 100;
	      }
	    else
	      {
		act("Striking with great force your $N's shield.", ch, NULL, victim, TO_CHAR);
		act("$n's headbutt goes right through the shield!", ch, NULL, victim, TO_ROOM);
	      }
	  }
      
	damage(ch,victim,number_range( ch->level / 2, UMAX(0, 70 - success)), gsn_headbutt,DAM_BASH,TRUE);
	check_improve(ch,gsn_headbutt,TRUE,8);

	if (IS_SET(victim->act, ACT_UNDEAD) 
	    || victim->class == class_lookup("vampire") 
	    || victim->class == class_lookup("lich")
	    || check_immune(victim, DAM_BASH, FALSE) == IS_IMMUNE)
	  {
	    act("$N seems to shake off the blow!", ch, NULL, victim, TO_NOTVICT);
	    act("You easly shake off the blow.", ch, NULL, victim, TO_VICT);
	    act("$N seems to not even notice the blow.", ch, NULL, victim, TO_ROOM);

	    chance = 0;
	  }
	if (success < chance)
	  {
	    act("You feel dizzy from the massive blow to the head.",victim, NULL, NULL, TO_CHAR);
	    act("$n looks dizzy from the blow to the head.", victim, NULL, NULL, TO_ROOM);
	    if (!is_affected(victim, gsn_headbutt))
	      {
		af.type		= gsn_headbutt;
		af.level		= ch->level;
		af.duration     	= 0;
		af.modifier		= 0;
		af.location		= APPLY_NONE;
		af.bitvector	= 0;
		affect_to_char(victim,&af);
	      }
	  }
      }//end if success
    else
      {
	damage( ch, victim, 0, gsn_headbutt,DAM_BASH,TRUE);
	check_improve(ch,gsn_headbutt,FALSE,8);
      }
}//end do_headbutt

void do_keen_sight( CHAR_DATA *ch, char *argument )
{
    int chance;
    AFFECT_DATA af;
    if ( (chance = get_skill(ch,gsn_keen_sight)) == 0 )
    {	
        send_to_char("Huh?\n\r",ch);
	return;
    }
    if (ch->mana < 10)
    {
	send_to_char("You don't have enough mana.\n\r",ch);
	return;
    }
    if ( is_affected(ch, gsn_keen_sight) )
    {
        send_to_char("You vision is already as sharp as it can get.\n\r",ch);
        return;
    }
    WAIT_STATE2(ch,skill_table[gsn_keen_sight].beats);
    if (number_percent() > chance)
    {
	ch->mana -= 5;
	send_to_char("You squint your eyes, but fail to adjust your vision.\n\r",ch);
        check_improve(ch,gsn_keen_sight,FALSE,1);
	return;
    }
    ch->mana -= 10;
    af.where	 = TO_AFFECTS2;
    af.type      = gsn_keen_sight;
    af.level     = ch->level;
    af.duration  = ch->level;
    af.location  = 0;
    af.modifier  = 0;
    af.bitvector = AFF_KEEN_SIGHT;
    affect_to_char( ch, &af );
    send_to_char( "Your vision sharpens.\n\r", ch );
    check_improve(ch,gsn_keen_sight,TRUE,1);
}

void do_pilfer( CHAR_DATA *ch, char *argument ){
  
  CHAR_DATA *victim;
  OBJ_DATA *obj;
  char arg[MIL];
  int chance, roll = number_percent();
  if ( (chance = get_skill(ch,gsn_pilfer)) == 0)
    {
      send_to_char("You are not skilled enough to pilfer.\n\r", ch );
      return;
    }
  if ( ( victim = ch->fighting ) == NULL )
    {
      send_to_char( "You aren't fighting anyone.\n\r", ch );
      return;
    }
  one_argument( argument, arg );
  if ( arg[0] == '\0' )
    {
      send_to_char( "Pilfer what?\n\r", ch );
      return;
    }
  if ( IS_NPC(victim) && IS_SET(victim->act,ACT_TOO_BIG) )
    {
      sendf(ch, "%s is too alert for you to pilfer from them.\n\r", PERS2(victim));
      return;
    }
  if (!can_see(victim,ch))
    chance += 25;
  chance += (get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_DEX));
  chance += (ch->level - victim->level);
  chance += (get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));

  if (!can_see(ch,victim))
    chance /= 3;
  chance = URANGE(0,chance,75);
  WAIT_STATE2( ch, skill_table[gsn_pilfer].beats );
  
  if ( roll < chance && !(ch->level + 8 < victim->level))
    {
      damage(ch,victim,number_range( 2*ch->level/3,3*ch->level/2), gsn_pilfer,DAM_NONE,TRUE);
      if ( ( obj = get_obj_carry( victim, arg, ch ) ) == NULL ){
	send_to_char( "You can't find it.\n\r", ch );
	return;
      }
      if ( !can_drop_obj( ch, obj ) || IS_SET(obj->extra_flags, ITEM_INVENTORY) )
    	{
	  send_to_char( "You can't knock it loose.\n\r", ch );
	  return;
    	}
      act("You knock $p loose from $N's inventory.",ch,obj,victim,TO_CHAR);
      act("$n knocks $p loose from $N's inventory.",ch,obj,victim,TO_NOTVICT);
      act("$n knock $p loose from your inventory.",ch,obj,victim,TO_VICT);
      obj_from_char( obj );
      obj_to_room( obj, victim->in_room );
      if (IS_NPC(victim) && victim->wait == 0 && can_see_obj(victim,obj))
	get_obj(victim,obj,NULL);
      check_improve(ch,gsn_pilfer,TRUE,1);
    }
  else if ( roll < chance*2 )
    {
      damage(ch,victim,number_range( ch->level/2, 6*ch->level/5), gsn_pilfer,DAM_NONE,TRUE);
      check_improve(ch,gsn_pilfer,TRUE,1);    
    }
  else
    {
      damage( ch, victim, 0, gsn_pilfer,DAM_NONE,TRUE);
      check_improve(ch,gsn_pilfer,FALSE,1);
    }
}


void do_thrust( CHAR_DATA *ch, char *argument )
{
 
    char arg[MIL], buf[MSL];
    CHAR_DATA *victim;

//Data
    int chance = 4 * get_skill(ch,gsn_thrust) /5;
    int dam = number_range(10 + ch->level/2,(2 * ch->level));
    int vic_lag  = PULSE_VIOLENCE;
    int ch_lag = skill_table[gsn_thrust].beats;

//bools
    bool fSuccess = FALSE;
    bool fYell = FALSE;
    bool fElder = get_skill(ch, gsn_unholy_gift) > 1;

//modifiers.
    int size = 0;

    if (is_affected(ch, gsn_wolf_form)){
      do_tackle( ch, argument );
      return;
    }
    one_argument(argument,arg);
    if (chance == 0)
    {
	send_to_char("Thrust? What's that?\n\r",ch);
	return;
    }

    if (arg[0] == '\0')
    {
	victim = ch->fighting;
        if (victim == NULL)
	{
	    send_to_char("But you aren't fighting anyone!\n\r",ch);
	    return;
	}
    }
    else if ((victim = get_char_room(ch, NULL, arg)) == NULL)
    {
	send_to_char("They aren't here.\n\r",ch);
	return;
    }

    if ( victim == ch )
    {
      send_to_char("Self mutilation is not your style.\n\r",ch);
      return;
    }

    if (is_safe(ch,victim))
	return;

    chance += get_curr_stat(ch,STAT_STR) - get_curr_stat(victim,STAT_DEX);
    chance += GET_AC2(victim,AC_BASH) /25;
    chance -= get_skill(victim,gsn_dodge)/20;
    chance += ch->level - victim->level;
    size = affect_by_size(ch,victim);

    if (fElder && size < 0)
      size = 0;
    chance +=  size;

    if (is_affected(victim,gsn_horse))
      chance -= 10;
    if ( victim->race == race_lookup("avian") 
	 || victim->race == race_lookup("faerie") )
      chance -= 10;
    if ( victim->class == class_lookup("thief") )
      chance -= 5;
    if (!IS_NPC(victim) && victim->pcdata->pStallion){
      if(number_percent() < get_skill(victim, gsn_mounted)){
	chance -= 12;
	check_improve(victim, gsn_mounted, TRUE, 0);
      }
    }
    //check if target should yell.
      fYell = (ch->fighting != victim && victim->fighting != ch);

      a_yell(ch,victim);
      //predict interdict
      if (predictCheck(ch, victim, "thrust", skill_table[gsn_thrust].name))
	return;

      act("You extend an open palm toward $N. and a powerful force hurls at $M!",ch,NULL,victim,TO_CHAR);
      act("$n extends an open palm toward $N.",ch,NULL,victim,TO_NOTVICT);
      act("$n extends an open palm toward you, and a powerful force hurls at you!",ch,NULL,victim,TO_VICT);

    if (number_percent() < chance)
      {
	vic_lag  = number_range(2,4) * PULSE_VIOLENCE;
	fSuccess = TRUE;
      }
    else
      {
	dam = 0;
      }

//MANTIS CHECK
    if (is_affected(victim,gsn_mantis) && fSuccess)
      {
	act("You use $n's momentum against him, and throw $m to the ground!",ch,NULL,victim,TO_VICT);
	act("$N reverses your attack, and throws you to the ground!",ch,NULL,victim,TO_CHAR);
	act("$N reversed $n's attack, and throws $m to the ground.",ch,NULL,victim,TO_NOTVICT);
	WAIT_STATE2(ch, URANGE(1, number_range(1, victim->size), 3) * PULSE_VIOLENCE);
	damage(victim,ch,dam,gsn_mantis,DAM_BASH,TRUE);
	affect_strip(victim,gsn_mantis);
	return;
      }//END MANTIS

//check for lag protect
    if (!do_lagprot(ch, victim, chance, &dam, &vic_lag, gsn_thrust, fSuccess, fYell))
      {
	if (fYell)
	  {
            sprintf(buf, "Help! %s just knocked me flying!",PERS(ch,victim));
            j_yell(victim,buf);
	  }
	if (fSuccess)
	  {

        act("$n knocks you flying with a powerful thrust!",ch,NULL,victim,TO_VICT);
     	  act("Your thrust knocks $N flying!",ch,NULL,victim,TO_CHAR);
        act("$n knocks $N flying with a powerful thrust.",ch,NULL,victim,TO_NOTVICT);
	 }
      	else
	  {
        act("$N evades your thrust!", ch,NULL,victim,TO_CHAR);
        act("$N evades $n's thrust.", ch,NULL,victim,TO_NOTVICT);
        act("You evade $n's thrust.",ch,NULL,victim,TO_VICT);
	  }
      }//END IF NO PROTECTION

	
    if (!fSuccess || dam == 0 || vic_lag == 0)
    {
      check_improve(ch, gsn_thrust, FALSE, 1);	
      ch_lag = 3 * ch_lag / 2;
    }
    else{
      check_improve(ch, gsn_thrust, TRUE, 1);	
      if (!IS_NPC(victim))
	victim->pcdata->pStallion = NULL;      
    }
    
    WAIT_STATE2(ch, ch_lag);
    if (vic_lag != 0 && dam != 0)
      WAIT_STATE2(victim, vic_lag);
    damage(ch,victim,dam,gsn_thrust,DAM_BASH,TRUE);

    if (ch && victim && ch->fighting == victim && dam > 0)
      check_ccombat_actions( victim, ch, CCOMBAT_BASHED);
}

void disarm_offhand( CHAR_DATA *ch, CHAR_DATA *victim ){

  OBJ_DATA *obj, *wield;
  bool fSeize = FALSE;
  bool fExoSeize = FALSE;
  
  if ( ( obj = get_eq_char( victim, WEAR_SECONDARY ) ) == NULL )
    return;
  if ( IS_STONED(victim) || IS_OBJ_STAT(obj,ITEM_NOREMOVE) || is_affected(victim, gsn_graft_weapon))
    {
      act("$S's secondary weapon won't budge!",ch,NULL,victim,TO_CHAR);
      act("$n tries to disarm you, but your secondary weapon won't budge!",ch,NULL,victim,TO_VICT);
      act("$n tries to disarm $N, but fails.",ch,NULL,victim,TO_NOTVICT);
      return;
    }
  act( "$n disarms you and sends your secondary weapon flying!", ch, NULL, victim, TO_VICT    );
  act( "You disarm $N!",  ch, NULL, victim, TO_CHAR    );
  act( "$n disarms $N!",  ch, NULL, victim, TO_NOTVICT );
  obj_from_char( obj );

  /* check for advanced disarms */
  if ( (wield = get_eq_char(ch, WEAR_WIELD)) != NULL
     && (wield->value[0] == WEAPON_EXOTIC || wield->value[0] == WEAPON_WHIP)){
    int sn = skill_lookup("weapon seize");
    if (number_percent() < get_skill(ch, sn)){
      check_improve(ch, sn, TRUE, 0);
      fSeize = TRUE;
      /* check for exotic seize */
      if (wield->value[0] == WEAPON_EXOTIC 
	  && get_skill(ch, gsn_exotic_mastery) > 1)
	fExoSeize = TRUE;
    }
    else
      check_improve(ch, sn, FALSE, -99);
  }
  if (!fExoSeize 
      && (IS_OBJ_STAT(obj,ITEM_NODROP) || IS_OBJ_STAT(obj,ITEM_INVENTORY)) )
    obj_to_char( obj, victim );
  else if (fSeize){
    act("With a flick of $p $n grabs the weapon.", ch, wield, NULL, TO_ROOM);
    act("With a flick of $p you grab the weapon.", ch, wield, NULL, TO_CHAR);
    obj_to_char( obj, ch );
  }
  else{
    obj_to_room( obj, victim->in_room );
    if (IS_NPC(victim) && victim->wait == 0 && can_see_obj(victim,obj))
      get_obj(victim,obj,NULL);
  }
}

void do_offhand_disarm( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    OBJ_DATA *obj2;
    
    int chance, hth = 0, ch_weapon, vict_weapon, ch_vict_weapon;

    if ((chance = get_skill(ch,gsn_offhand_disarm)) == 0)
    {
        send_to_char( "Huh?\n\r", ch );
	return;
    }
    if ( (obj = get_eq_char( ch, WEAR_WIELD )) == NULL
	 && ( obj = get_eq_char( ch, WEAR_SECONDARY )) == NULL 
	 && ((hth = get_skill(ch,gsn_hand_to_hand)) == 0 
	     || (IS_NPC(ch) && !IS_SET(ch->off_flags,OFF_DISARM))))
    {
	send_to_char( "You must wield a weapon to disarm.\n\r", ch );
	return;
    }

    if ( ( victim = ch->fighting ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }
    if ( ( obj2 = get_eq_char( victim, WEAR_SECONDARY ) ) == NULL )
    {
	sendf(ch, "%s is not wielding a secondary weapon.\n\r", PERS(victim,ch) );
	return;
    }

    ch_weapon = get_weapon_skill_obj(ch, obj);
    vict_weapon = get_weapon_skill_obj(victim, obj2);
    ch_vict_weapon = get_weapon_skill_obj(ch, obj2);

    if (IS_NPC(victim))
	vict_weapon = UMAX(victim->level * 2, 75);
    if ( get_eq_char(ch,WEAR_WIELD) == NULL)
	chance = chance * hth/150;
    else
	chance = chance * ch_weapon/100;

    chance += get_weapon_obj_rating( obj, WEAPON_WITHDIS ) * 4;
    chance += get_weapon_obj_rating( obj2, WEAPON_TOBEDIS ) * 4;
    chance += (ch_vict_weapon - vict_weapon) / 2; 

    chance += 2*(get_curr_stat(ch,STAT_DEX) - get_curr_stat(victim,STAT_STR));
    chance += (ch->level - victim->level);
    chance -= get_skill(victim,gsn_dual_parry)/10;
    if (IS_NPC(victim))
	chance -= victim->level/10;
    chance += 2*(get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK));
    if (ch->class == class_lookup("monk") && is_affected(ch,gsn_dragon) && is_empowered(ch,0))
	chance += 25;
    if (number_percent() < chance && (victim->level - ch->level) < 10)
    {
      int skill = get_skill(victim, gsn_double_grip);
      bool fStr = FALSE;
      if (is_affected(victim, gsn_istrength) && has_twohanded(victim) != NULL){
	fStr = TRUE;
	skill = 110;
      }
      WAIT_STATE2( ch, skill_table[gsn_offhand_disarm].beats );
      if ( (is_affected(victim,gsn_double_grip) || fStr)
	   && number_percent() < ((4 * skill / 3) - 75) ){
	act("You fail to disarm $N's weapon from $S powerfull grasp.",ch,NULL,victim,TO_CHAR);
	act("$n tries to disarm you, but your grip is too strong.",ch,NULL,victim,TO_VICT);
	act("$n tries to disarm $N, but $E grips $S weapon tightly.",ch,NULL,victim,TO_NOTVICT);
	check_improve(ch,gsn_offhand_disarm,FALSE,1);
	check_improve(victim,gsn_double_grip, FALSE, -99);
	return;
      }
      disarm_offhand( ch, victim );
      check_improve(ch,gsn_offhand_disarm,TRUE,1);
    }
    else
    {
	WAIT_STATE2(ch,skill_table[gsn_offhand_disarm].beats);
	act("You fail to disarm $N.",ch,NULL,victim,TO_CHAR);
	act("$n tries to disarm you, but fails.",ch,NULL,victim,TO_VICT);
	act("$n tries to disarm $N, but fails.",ch,NULL,victim,TO_NOTVICT);
	check_improve(ch,gsn_offhand_disarm,FALSE,1);
    }
}



//03-25 xxxxx Viri: Modifed do_spells(..) to peoperly calculate manna costs
//using _mana_cost(..) from magic.c.
//05-02-00 Viri: rewrote do_assasinate
//05-30-00 Viri: Added get_lagshield