daleken/
daleken/data/notes/
daleken/data/player/
daleken/data/system/poses/
daleken/doc/Homepage/images/
daleken/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	 ||
    || Chastain, Michael Quan, and Mitchell Tse.			 ||
    || Original Diku Mud copyright (C) 1990, 1991			 ||
    || by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt,	 ||
    || Tom Madsen, and Katja Nyboe.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  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.					 ||
    || ----------------------------------------------------------------- ||
    ||                             fight.c                               ||
    || Combat, combat skills and death code.                             ||
 *_/<>\_________________________________________________________________/<>\_*/


#include <math.h>
#include "mud.h"
#include "event.h"

#if !defined( PI )
#define PI 3.14159265358979323846
#endif

/* fight.c functions */
void set_fighting	args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
bool disarm		args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
void one_hit		args( ( CHAR_DATA *ch, CHAR_DATA *victim,
				int dt, int wpn ) );
bool check_atemi	args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );


CHAR_DATA *find_target( CHAR_DATA *ch, const char *argument,
			const char *cmd )
{
    CHAR_DATA *victim;

    if( ch->fighting )
	return ch->fighting;

    if( argument == NULL || argument[0] == '\0' )
    {
	charprintf( ch, "%s whom?\n\r", cmd );
	return NULL;
    }

    if( !check_blind( ch ) )
	return NULL;

    if( !( victim = get_char_room( ch, argument ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return NULL;
    }

    if( !IS_NPC( victim ) )
    {
	if( ch != victim && !xIS_SET( victim->act, PLR_OUTLAW )
	    && !xIS_SET( victim->act, PLR_BATTLE )
	    && !IS_SET( ch->in_room->room_flags, ROOM_ARENA )
	    && !is_clan_enemy( victim, ch ) )
	{
	    send_to_char( "You must MURDER a player.\n\r", ch );
	    return NULL;
	}
    }
    else
    {
	if( IS_AFFECTED( victim, AFF_CHARM ) && victim->master )
	{
	    send_to_char( "You must MURDER a charmed creature.\n\r", ch );
	    return NULL;
	}
    }

    if( is_safe( ch, victim ) )
	return NULL;

    if( IS_AFFECTED( ch, AFF_CHARM )
	&& ( !IS_NPC( victim ) || ch->master == victim ) )
    {
	send_to_char( "You lack the self control to attack someone!\n\r", ch );
	return NULL;
    }

    if( ch->fighting && ch->fighting != victim )
    {
	send_to_char( "You are too busily occupied fighting someone else.\n\r",
		      ch );
	return NULL;
    }

    check_killer( ch, victim );
    return victim;
}


void do_kill( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    if( !( victim = find_target( ch, argument, "Kill" ) ) )
	return;

    if( ch->fighting )
    {
	send_to_char( "You do the best you can!\n\r", ch );
	return;
    }

    if( victim == ch )
    {
	send_to_char( "You hit yourself.  Ouch!\n\r", ch );
	multi_hit( ch, ch, TYPE_UNDEFINED );
	return;
    }

    WAIT_STATE( ch, PULSE_PER_SECOND );
    multi_hit( ch, victim, TYPE_UNDEFINED );
    return;
}


/*
 * I'm only allowing backstabbing with the primary weapon...immortals
 * who wield two weapons, with the first not being a dagger, will be
 * unable to backstab or circle.  Tough cookie.	 --- Thelonius
 */
void do_backstab( CHAR_DATA *ch, const char *argument )
{
    OBJ_DATA *obj;
    CHAR_DATA *victim;

    if( !IS_NPC( ch ) && !can_use( ch, gsn_backstab ) )
    {
	send_to_char(
	    "You better leave the assassin trade to thieves.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Backstab" ) ) )
	return;

    if( victim == ch )
    {
	send_to_char( "How can you sneak up on yourself?\n\r", ch );
	return;
    }

    if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) ) &&
	  !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
	|| obj->value[3] != 11 )
    {
	send_to_char( "You need to wield a piercing weapon.\n\r", ch );
	return;
    }

    if( victim->fighting )
    {
	send_to_char( "You can't backstab a fighting person.\n\r", ch );
	return;
    }

    if( IS_AWAKE( victim ) && victim->hit < victim->max_hit )
    {
	act( "$N is hurt and suspicious ... you can't sneak up.",
	     ch, NULL, victim, TO_CHAR );
	return;
    }

    WAIT_STATE( ch, skill_table[gsn_backstab].beats );
    if( !IS_AWAKE( victim ) || IS_NPC_CLASS( ch )
	|| get_success( ch, gsn_backstab, 100 ) )
    {
	if( !IS_AWAKE( victim ) )
	    victim->position = POS_STANDING;
	if( check_atemi( ch, victim ) )
	    multi_hit( ch, victim, gsn_atemi );
	else
	    multi_hit( ch, victim, gsn_backstab );
    }
    else
	damage( ch, victim, 0, gsn_backstab, obj->wear_loc );

    return;
}


bool check_atemi( CHAR_DATA *ch, CHAR_DATA *victim )
{
    OBJ_DATA *obj;

    if( !get_success( ch, gsn_atemi, 100 ) || number_bits( 3 ) != 0 )
	return FALSE;

    switch( number_bits( 4 ) )
    {
    default:
	break;

    case 0:
	/* Knock them unconcious for a moment (extra damage later) */
	act( "$n crumple$% to the ground.",
	     victim, NULL, ch, TO_ALL );
	victim->position = POS_SLEEPING;
	WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, 2 * PULSE_VIOLENCE );
	return TRUE;

    case 1: case 2: case 3:
	/* effectively a ram */
	send_to_char( "You are stuck from behind and find yourself reeling.\n\r", victim );
	act( "$n reels backwards from $O savage blow.",
	     victim, NULL, ch, TO_ROOM );
	victim->position = POS_SMASHED;
	WAIT_STATE( victim, 3 * PULSE_VIOLENCE );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, 3 * PULSE_VIOLENCE );
	return TRUE;

    case 4: case 5: case 6: case 7:
	/* lag the opponent a little, make them get up */
	act( "$n is forced to $s knees by $O strike!",
	     victim, NULL, ch, TO_ALL );
	victim->position = POS_GETTING_UP;
	WAIT_STATE( victim, PULSE_VIOLENCE );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, PULSE_VIOLENCE );
	return TRUE;

    case 8:
	/* double backstab with each weapon */
	if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) ) )
	    return FALSE;
	if( !( obj = get_eq_char( ch, WEAR_WIELD_L ) )
	    || obj->value[3] != 11 )
	    return FALSE;
	act( "$n strike$% $N with each hand, ONE-TWO!",
	     ch, NULL, victim, TO_ALL );
	one_hit( ch, victim, gsn_atemi, WEAR_WIELD_L );
	return TRUE;

    case 9:
	/* drop weapon/shield */
	if( !( obj = get_eq_char( victim, WEAR_WIELD_R ) )
	    && !( obj = get_eq_char( victim, WEAR_WIELD_L ) )
	    && !( obj = get_eq_char( victim, WEAR_WIELD_DOUBLE ) )
	    && !( obj = get_eq_char( victim, WEAR_SHIELD ) ) )
	    return FALSE;
	act( "$O strike paralyses $n and forces $m to drop $p.",
	     victim, obj, ch, TO_ROOM );
	act( "Your arm goes numb and you drop $p.",
	     victim, obj, victim, TO_CHAR );
	obj_from_char( obj );
	obj_to_room( obj, victim->in_room );
	return TRUE;

    case 10: case 11:
	/* Remove all dodges and parries etc. for the next round */
	act( "$O strike momentarily stuns $n.", victim, NULL, ch, TO_ALL );
	act( "You're stunned by $n's blow.", victim, NULL, ch, TO_CHAR );
	victim->extra_bits |= CH_EX_RESET;
	return TRUE;
    }
    return FALSE;
}


void do_circle( CHAR_DATA *ch, const char *argument )
{
    OBJ_DATA *obj;
    CHAR_DATA *rch;
    CHAR_DATA *victim;

    if( ( !IS_NPC( ch ) && !can_use( ch, gsn_circle ) )
	|| ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) )
    {
	send_to_char(
	    "You'd better leave the assassin trade to thieves.\n\r", ch );
	return;
    }

    if( !ch->fighting )
    {
	send_to_char( "You must be fighting in order to do that.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Circle around" ) ) )
	return;

    if( victim == ch )
    {
	send_to_char( "You spin around in a circle.  Whee!\n\r", ch );
	return;
    }

    if( victim != ch->fighting )
    {
	send_to_char( "One fight at a time.\n\r", ch );
	return;
    }

    if( !victim->fighting )
    {
	act( "Why?  $E isn't bothering anyone.", ch, NULL, victim, TO_CHAR );
	return;
    }

    if( !is_same_group( ch, victim->fighting ) )
    {
	send_to_char( "Why call attention to yourself?\n\r", ch );
	return;
    }

    for( rch = ch->in_room->people; rch; rch = rch->next_in_room )
	if( rch->fighting == ch )
	    break;

    if( rch )
    {
	send_to_char( "You're too busy being hit right now.\n\r", ch );
	return;
    }

    if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
	  && !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
	|| obj->value[3] != 11 )
    {
	send_to_char( "You need to wield a piercing weapon.\n\r", ch );
	return;
    }

    act( "$n circle$% around behind $N...", ch, NULL, victim, TO_ALL );

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

    if( IS_NPC_CLASS( ch ) || get_success( ch, gsn_circle, 50 ) )
    {
	stop_fighting( victim, FALSE );
	multi_hit( ch, victim, gsn_circle );
    }
    else
	act( "You failed to get around $M", ch, NULL, victim, TO_CHAR );

    return;
}


void do_flee( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    ROOM_INDEX_DATA *was_in;
    ROOM_INDEX_DATA *now_in;
    int attempt;

    if( !( victim = ch->fighting ) )
    {
	if( ch->position == POS_FIGHTING )
	    ch->position = POS_STANDING;
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

    if( ch->position < POS_FIGHTING )
    {
	send_to_char( "Get up first.\n\r", ch );
	return;
    }

    if( !IS_NPC( ch->fighting )
	&& ch->fighting->pcdata->pc_bits >= PC_BIT_STRANGLE )
    {
	act( "$N has $S hands around your throat, free yourself first!",
	     ch, NULL, ch->fighting, TO_CHAR );
	return;
    }

    if( IS_AFFECTED( ch, AFF_BERSERK ) )
    {
	send_to_char( "You can't flee, you're BERSERK!\n\r", ch );
	return;
    }

    if( IS_AFFECTED( ch, AFF_HOLD ) )
    {
	send_to_char( "You are stuck in a snare!  You can't move!\n\r", ch );
	act( "$n wants to flee, but is caught in a snare!",
	     ch, NULL, NULL, TO_ROOM );
	return;
    }

    was_in = ch->in_room;
    for( attempt = 0; attempt < 6; attempt++ )
    {
	EXIT_DATA *pexit;
	int door;

	door = number_door( );
	if( ( pexit = was_in->exit[door] ) == 0
	    || !pexit->to_room
	    || IS_SET( pexit->exit_info, EX_CLOSED )
	    || ( IS_NPC( ch )
		 && ( IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB )
		      || ( xIS_SET( ch->act, ACT_STAY_AREA )
			   && pexit->to_room->area != ch->in_room->area ) ) ) )
	    continue;

	stop_fighting( ch, TRUE );
	move_char( ch, door );
	if( ( now_in = ch->in_room ) == was_in )
	    continue;

	ch->in_room = was_in;
	act( "$n has fled!", ch, NULL, NULL, TO_ROOM );
	ch->in_room = now_in;

	if( !IS_NPC( ch ) )
	{
	    send_to_char( "&rYou flee from combat!  You lose 25 exps.&n\n\r", ch );
	    gain_exp( ch, -2500 );
	    if( IS_NPC( victim ) && xIS_SET( victim->act, ACT_HUNTER ) )
	    {
		victim->tracking = ch;
		create_char_event( victim, evn_hunt_fleer,
				   number_range( PULSE_MOBILE / 2,
						 3 * PULSE_MOBILE / 2 ) );
	    }
	}
	else
	{
	    ch->tracking = NULL;
	    strip_events( &ch->events, evn_hunt_fleer );
	    ch->fearing = victim;
	}

	return;
    }

    send_to_char( "You failed!	You lose 10 exps.\n\r", ch );
    gain_exp( ch, -10 );
    return;
}



void do_berserk( CHAR_DATA *ch, const char *argument )
{
    AFFECT_DATA af;

    /* Don't allow charmed mobs to do this, check player's level */
    if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
	|| ( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_berserk ) ) )
    {
	send_to_char( "You're not enough of a warrior to go Berserk.\n\r",
		      ch );
	return;
    }

    if( IS_AFFECTED( ch, AFF_CALM ) )
    {
	send_to_char( "You are feeling too mellow to berserk.\n\r", ch );
	return;
    }

    if( !ch->fighting )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

    if( IS_AFFECTED( ch, AFF_BERSERK ) )
	return;

    send_to_char(
	"Your weapon hits your foe and blood splatters all over!\n\r",
	ch );
    send_to_char( "The taste of blood begins to drive you crazy!\n\r",
		  ch );

    if( get_success( ch, gsn_berserk, 100 ) )
    {
	af.type = gsn_berserk;
	af.level = LEVEL_HERO;
	af.duration = -1;
	af.location = APPLY_HITROLL;
	af.modifier = ch->level / 6;
	vset( af.bitvector, AFF_BERSERK );
	affect_to_char( ch, &af, NULL );

	af.location = APPLY_DAMROLL;
	affect_to_char( ch, &af, NULL );

	af.location = APPLY_AC;
	af.modifier *= 7;
	affect_to_char( ch, &af, NULL );

	send_to_char( "You have gone BERSERK!\n\r", ch );
	act( "$n has gone BERSERK!", ch, NULL, NULL, TO_ROOM );

	return;
    }
    send_to_char( "You shake off the madness.\n\r", ch );

    return;
}



void do_rescue( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    CHAR_DATA *fch;
    int count;

    /* Don't allow charmed mobs to do this, check player's level */
    if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
	|| ( !IS_NPC( ch ) && !can_use( ch, gsn_rescue ) ) )
    {
	send_to_char(
	    "You'd better leave the heroic acts to warriors.\n\r", ch );
	return;
    }

    if( IS_AFFECTED( ch, AFF_BERSERK ) )
    {
	send_to_char( "You can't rescue anyone, you're BERSERK!\n\r", ch );
	return;
    }

    if( argument[0] == '\0' )
    {
	send_to_char( "Rescue whom?\n\r", ch );
	return;
    }

    if( !check_blind( ch ) )
	return;

    if( !( victim = get_char_room( ch, argument ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if( victim == ch )
    {
	send_to_char( "What about fleeing instead?\n\r", ch );
	return;
    }

    if( !IS_NPC( ch ) && IS_NPC( victim ) )
    {
	send_to_char( "They don't need your help!\n\r", ch );
	return;
    }

    if( ch->fighting == victim )
    {
	send_to_char( "Too late.\n\r", ch );
	return;
    }

    if( !victim->fighting )
    {
	send_to_char( "That person is not fighting right now.\n\r", ch );
	return;
    }

    if( !is_same_group( ch, victim ) )
    {
	send_to_char( "Why would you want to?\n\r", ch );
	return;
    }

    WAIT_STATE( ch, skill_table[gsn_rescue].beats );

    count = 0;
    for( fch = victim->in_room->people; fch; fch = fch->next_in_room )
    {

	if( !IS_NPC( fch )
	    || fch->deleted )
	    continue;

	if( fch->fighting == victim )
	{
	    if( number_range( 0, count ) == 0 )
		break;
	    count++;
	}
    }

    if( !fch
	|| ( !IS_NPC( ch ) && !get_success( ch, gsn_rescue, 100 ) ) )
    {
	send_to_char( "You fail the rescue.\n\r", ch );
	return;
    }

    act( "&c$n rescue$% $N!", ch, NULL, victim, TO_ALL );

    for( fch = victim->in_room->people; fch; fch = fch->next_in_room )
    {
	if( fch->fighting != victim )
	    continue;
	if( IS_AFFECTED( fch, AFF_BERSERK ) )
	{
	    act( "$N's blind rage prevents you from distracting him.",
		 ch, NULL, fch, TO_CHAR );
	    continue;
	}

	stop_fighting( fch, FALSE );

	set_fighting( fch, ch );
    }

    return;
}



void do_taunt( CHAR_DATA *ch, const char *argument )
{
    AFFECT_DATA af;

    if( IS_NPC( ch ) || !can_use( ch, gsn_taunt ) )
    {
	send_to_char( "You can laugh, but you still don't get the joke.\n\r",
		      ch );
	return;
    }

    if( argument[0] == '\0' )
    {
	WAIT_STATE( ch, skill_table[gsn_taunt].beats );

	affect_strip( ch, gsn_taunt );
	if( get_success( ch, gsn_taunt, 100 ) )
	{
	    if( IS_AFFECTED( ch, AFF_TAUNT ) )
		send_to_char( "You try to behave with more decorum.\n\r", ch );
	    else
	    {
		act( "$n begins to laugh at everyone viciously.",
		     ch, NULL, NULL, TO_ROOM );
		send_to_char( "You now invite trouble.\n\r", ch );
		af.type = gsn_taunt;
		af.level = 0;
		af.duration = -1;
		af.location = APPLY_SPEED;
		af.modifier = 2 + ch->level / 50;
		vset( af.bitvector, AFF_TAUNT );
		affect_to_char( ch, &af, NULL );
	    }
	}
    }
    else
    {
	CHAR_DATA *vch;

	if( !( vch = get_char_room( ch, argument ) ) )
	{
	    send_to_char( "You can't taunt someone who isn't here.\n\r", ch );
	    return;
	}

	WAIT_STATE( ch, skill_table[gsn_taunt].beats );

	if( IS_AFFECTED( vch, AFF_BERSERK ) )
	{
	    act( "You taunt $N but $E is raging too much to notice.",
		 ch, NULL, vch, TO_CHAR );
	    act( "$n is trying to attract your attention, unsuccessfully.",
		 ch, NULL, vch, TO_VICT );
	    act( "$n taunts $N but $E is raging too much to notice.",
		 ch, NULL, vch, TO_NOTVICT );
	    return;
	}

	act( "You taunt $N mercilessly and $E turns on you in a rage!",
	     ch, NULL, vch, TO_CHAR );
	act( "$n says something derogatory about your mother, ARRGGGHHHH!",
	     ch, NULL, vch, TO_VICT );
	act( "$n taunts $N and $E turns to attack!",
	     ch, NULL, vch, TO_NOTVICT );

	af.type = gsn_berserk;
	af.level = LEVEL_HERO;
	af.duration = -1;
	af.location = APPLY_HITROLL;
	af.modifier = vch->level / 6;
	vset( af.bitvector, AFF_BERSERK );
	affect_to_char( vch, &af, NULL );

	stop_fighting( vch, FALSE );
	set_fighting( vch, ch );
    }

    return;
}


void do_kick( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    /* Don't allow charmed mobs to do this, check player's level */
    if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
	|| ( !IS_NPC( ch ) && !can_use( ch, gsn_kick ) ) )
    {
	send_to_char(
	    "You'd better leave the martial arts to fighters.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Kick" ) ) )
	return;

    WAIT_STATE( ch, skill_table[gsn_kick].beats );
    if( get_success( ch, gsn_kick, 100 ) )
	damage( ch, victim, number_range( 1, ch->level ), gsn_kick,
		WEAR_NONE );
    else
	damage( ch, victim, 0, gsn_kick, WEAR_NONE );

    return;
}


void do_snapkick( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    int dam, success;

    /* Don't allow charmed mobs to do this, check player's level */
    if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
	|| ( !IS_NPC( ch ) && !can_use( ch, gsn_snapkick ) ) )
    {
	send_to_char(
	    "You'd better leave the martial arts to martial artists.\n\r",
	    ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Kick" ) ) )
	return;

    success = victim->level - ch->level;
    success *= 3;
    success += ( get_size( victim ) - get_size( ch ) ) / 3;
    success = URANGE( 5, success + number_percent( ), 100 );
    dam = get_success( ch, gsn_snapkick, 100 ) / 2;
    success -= dam;
    if( success < 0 && number_bits( 3 ) == 0
	&& victim->position >= POS_FIGHTING )
    {
	act( "$o snapkick slams $N into the ground!",
	     ch, NULL, victim, TO_ALL );
	victim->position = POS_SMASHED;
	WAIT_STATE( victim,
		    UMIN( success, skill_table[gsn_snapkick].beats * 2 ) );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up,
			       UMIN( success, skill_table[gsn_snapkick].beats * 2 ) );
    }
    if( dam )
    {
	dam = number_range( ch->level / 2, ch->level * 3 / 2 );
	dam *= get_curr_str( ch ) + get_curr_dex( ch );
	dam /= 30;
    }
    else
	dam = 0;

    WAIT_STATE( ch, skill_table[gsn_snapkick].beats );
    damage( ch, victim, dam, gsn_snapkick, WEAR_NONE );

    return;
}


void do_disarm( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    int percent;

    /* Don't allow charmed mobiles to do this, check player's level */
    if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
	|| ( !IS_NPC( ch ) && !can_use( ch, gsn_disarm ) ) )
    {
	send_to_char( "You don't know how to disarm opponents.\n\r", ch );
	return;
    }

    if( !get_eq_char( ch, WEAR_WIELD_R )
	&& !get_eq_char( ch, WEAR_WIELD_L )
	&& ( IS_NPC( ch ) || ch->pcdata->learned[gsn_barehand] <= 0 ) )
    {
	send_to_char( "You must wield a weapon to disarm.\n\r", ch );
	return;
    }

    if( !ch->fighting )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Disarm" ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if( victim->fighting != ch && ch->fighting != victim )
    {
	act( "$E is not fighting you!", ch, NULL, victim, TO_CHAR );
	return;
    }

    if( !get_eq_char( victim, WEAR_WIELD_R )
	&& !get_eq_char( victim, WEAR_WIELD_L )
	&& !get_eq_char( victim, WEAR_WIELD_DOUBLE ) )
    {
	send_to_char( "Your opponent is not wielding a weapon.\n\r", ch );
	return;
    }

    WAIT_STATE( ch, skill_table[gsn_disarm].beats );
    percent = 100 + victim->level - ch->level;
    percent = percent * 2 / 3;
    if( !get_success( ch, gsn_disarm, percent ) || !disarm( ch, victim ) )
	send_to_char( "You failed to disarm.\n\r", ch );
    return;
}


void do_sla( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *rch;

    rch = get_char( ch );

    if( !authorized( rch, "slay" ) )
	return;

    send_to_char( "If you want to SLAY, spell it out.\n\r", ch );
    return;
}


void do_slay( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    CHAR_DATA *rch;
    char arg[MAX_INPUT_LENGTH];

    rch = get_char( ch );

    if( !authorized( rch, "slay" ) )
	return;

    argument = one_argument( argument, arg );
    if( arg[0] == '\0' )
    {
	send_to_char( "Usage: slay <character> [type]\n\r"
		      "[type] is one of the following:\n\r"
		      "9mm, deheart, demon, immolate, laughing, pounce,\n\r"
		      " shatter, skin, slit.\n\r", ch );
	return;
    }

    if( !( victim = get_char_room( ch, arg ) ) )
    {
	send_to_char( "They aren't here.\n\r", ch );
	return;
    }

    if( ch == victim )
    {
	send_to_char( "Suicide is a mortal sin.\n\r", ch );
	return;
    }

    if( !IS_NPC( victim ) && victim->level >= ch->level )
    {
	send_to_char( "You failed.\n\r", ch );
	return;
    }

    if( argument[0] == '\0' )
	act( "$n slay$% $N in cold blood!", ch, NULL, victim, TO_ALL );
    else if( !str_prefix( argument, "9mm" ) )
    {
	act( "$n pull$% out $s 9mm and bust$% a cap in $O ass.",
	     ch, NULL, victim, TO_ALL );
    }
    else if( !str_prefix( argument, "deheart" ) )
    {
	act( "You rip through $N's chest and pull out $M beating "
	     "heart in your hand.", ch, NULL, victim, TO_CHAR );
	act( "You feel a sharp pain as $n rips into your chest and tears "
	     "out your still beating heart.", ch, NULL, victim, TO_VICT );
	act( "Specks of blood hit your face as $n rips through $N's chest "
	     "pulling out $S beating heart.", ch, NULL, victim, TO_NOTVICT );
    }
    else if ( !str_cmp( argument, "demon" ) )
    {
	act( "$N gesture$%, and a slavering demon appears.", ch, NULL, victim, TO_ALL );
	act( "With a horrible grin, the foul creature turns on $N...\n\r"
	     "...who screams in panic before being eaten alive.",
	     victim, NULL, NULL, TO_ROOM );
	act( "With a horrible grin, the foul creature turns on you...\n\r"
	     "...you scream in panic before being eaten alive.",
	     victim, NULL, NULL, TO_CHAR );
    }
    else if( !str_prefix( argument, "immolate" ) )
    {
	act( "Your fireball turns $N into a blazing inferno.",
	     ch, NULL, victim, TO_CHAR );
	act( "$n releases a searing fireball in your direction.",
	     ch, NULL, victim, TO_VICT );
	act( "$n points at $N, who bursts into a flaming inferno.",
	     ch, NULL, victim, TO_NOTVICT );
    }
    else if( !str_prefix( argument, "laughing" ) )
    {
	act( "$N point$% at $n and fall$% down laughing.  $E dies laughing.",
	     victim, NULL, ch, TO_ROOM );
	act( "$N points at you and falls down laughing.\n\r"
	     "You die from the humility!", victim, NULL, ch, TO_CHAR );
    }
    else if( !str_prefix( argument, "pounce" ) )
    {
	act( "Leaping upon $N with bared fangs, you tear open $S throat and "
	     "toss the corpse to the ground...",  ch, NULL, victim, TO_CHAR );
	act( "In a heartbeat, $n rips $s fangs through your throat!\n\r"
	     "Your blood sprays and pours to the ground as your life ends...",
	     ch, NULL, victim, TO_VICT );
	act( "Leaping suddenly, $n sinks $s fangs into $N's throat.\n\r"
	     "As blood sprays and gushes to the ground, $n tosses $N's "
	     "dying body away.",  ch, NULL, victim, TO_NOTVICT );
    }
    else if( !str_prefix( argument, "shatter" ) )
    {
	act( "$n freeze$% $N with a glance and shatter$% your frozen body "
	     "into tiny shards.", ch, NULL, victim, TO_ALL );
    }
    else if( !str_prefix( argument, "skin" ) )
    {
	act( "You rip the flesh from $N and send his soul to "
	     "the fiery depths of hell.", ch, NULL, victim, TO_CHAR );
	act( "Your flesh is torn from your bones and you are sent to "
	     "the flames of hell.", ch, NULL, victim,TO_VICT );
	act( "$n rips the flesh off of $N, releasing his soul into "
	     "the fiery depths of hell.", ch, NULL, victim, TO_NOTVICT );
    }
    else if( !str_prefix( argument, "slit" ) )
    {
	act( "You calmly slit $N's throat.", ch, NULL, victim, TO_CHAR );
	act( "$n reaches out with a clawed finger and calmly slits $O throat.",
	     ch, NULL, victim, TO_ROOM );
    }
    raw_kill( ch, victim );
    return;
}


void do_fee( CHAR_DATA *ch, const char *argument )
{
    send_to_char(
	"IF you wish to feed on someone or something, type FEED!\n\r",
	ch );
    return;
}


/* Vampiric bite.  Feeding */
void do_feed( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    AFFECT_DATA af;
    int dam;
    int heal;

    if( !( victim = find_target( ch, argument, "Feed on" ) ) )
	return;

    if( victim == ch )
    {
	send_to_char( "You cannot lunge for your own throat.\n\r", ch );
	return;
    }

    send_to_char( "You must have blooood!\n\r", ch );
    act( "$n lunges for $O throat!", ch, NULL, victim, TO_ROOM );

    WAIT_STATE( ch, PULSE_VIOLENCE );

    if( !victim->fighting )
	set_fighting( victim, ch );

    if( str_cmp( race_table[ch->race].name, "Vampire" ) )
    {
	send_to_char( "You missed!\n\r", ch );
	if( !ch->fighting )
	    set_fighting( ch, victim );
	return;
    }

    if( ch->fighting )
    {
	if( number_percent( ) > ch->level + dice( 3, 5 ) )
	{
	    send_to_char( "You missed!\n\r", ch );
	    return;
	}
    }

    /* If the victim is asleep, he deserves to be bitten.  : ) */
    if( !ch->fighting )
    {
	if( number_percent( ) > ( ch->level * 1.75 ) && IS_AWAKE( victim ) )
	{
	    send_to_char( "You missed!\n\r", ch );
	    set_fighting( ch, victim );
	    return;
	}
    }

    dam = dice( 3, ch->level );
    damage( ch, victim, dam, gsn_vampiric_bite, WEAR_NONE );

    /* Lets see if we can get some food from this attack */
    if( !IS_NPC( ch )
	&& number_percent( ) < ( 34 - victim->level + ch->level ) )
    {
	/* If not hungry, thirsty or damaged, then continue */
	if( ch->pcdata->condition[COND_FULL] >
	    race_table[ch->race].hunger_mod * 40 / 5
	    && ch->pcdata->condition[COND_THIRST]
	    > race_table[ch->race].thirst_mod * 40 / 5
	    && ( ch->hit * 100 / ch->max_hit > 75 ) )
	{
	    return;
	}
	else
	{
	    send_to_char( "Ahh!	 Blood!	 Food!	Drink!\n\r", ch );
	    heal = number_range( 1, dam ) / 2;
	    ch->hit = UMIN( ch->max_hit, ch->hit + heal );
	    /* Get full as per drinking blood */
	    gain_condition( ch, COND_FULL, heal * 25 );
	    /* Quench thirst as per drinking blood absolute value */
	    gain_condition( ch, COND_THIRST, heal * 12 );
	}
    }

    /* Ok now we see if we can infect the victim */

/*    if( IS_NPC( victim ) )  --This might turn out to be fun :)
      return; */

    if( victim->level < 11 || get_age( victim ) < 21 )
	return;

    if( saves_spell( ch->level, victim, ch, gsn_vampiric_bite )
	|| number_bits( 1 ) == 0 )
	return;

    if( ( obj = get_eq_char( victim, ITEM_HOLD ) ) )
    {
	if( IS_OBJ_STAT( obj, ITEM_VAMPIRE_BANE ) && ch->level < 21 )
	    return;
	else if( IS_OBJ_STAT( obj, ITEM_HOLY ) )
	{
	    if( ch->level < 32 )
		return;
	    else if( victim->level > ch->level )
		return;
	}
    }

    af.type = gsn_vampiric_bite;
    af.duration = UMAX( 5, 30 - ch->level );
    af.location = APPLY_NONE;
    af.modifier = 0;
    vset( af.bitvector, AFF_VAMP_BITE );
    affect_join( victim, &af );

    send_to_char( "Ahh!	 Taste the power!\n\r", ch );
    send_to_char( "Your blood begins to burn!\n\r", victim );
    return;
}


void do_stake( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    bool found = FALSE;
    int chance;

    if( !( victim = find_target( ch, argument, "Stake" ) ) )
	return;

    if( IS_NPC( victim ) )
    {
	send_to_char( "You may not stake NPC's.\n\r", ch );
	return;
    }

    /* Check here to see if they have a stake in hand.
     * Changed slightly to allow any wooden weapon that is wielded
     * and can stab or pierce.		--Symposium
     */
    for( obj = ch->carrying; obj; obj = obj->next_content )
    {
	if( obj->item_type == ITEM_WEAPON
	    && ( obj->value[3] == 2 || obj->value[3] == 11 )
	    && ( obj->wear_loc == WEAR_WIELD_R
		 || obj->wear_loc == WEAR_WIELD_L
		 || obj->wear_loc == WEAR_WIELD_DOUBLE )
	    && !str_cmp( flag_string( material_flags,
				      &obj->pIndexData->material ), "wood" ) )
	{
	    found = TRUE;
	    break;
	}
    }

    if( !found )
    {
	send_to_char( "You lack a wielded stake to stake.\n\r", ch );
	act( "$n screams and lunges at $N then realizes $e doesnt have a stake",
	     ch, NULL, victim, TO_ROOM );
	multi_hit( ch, victim, TYPE_UNDEFINED );
	return;
    }

    act( "$n screams and lunges at $N with $p.", ch, obj, victim, TO_ALL );

    /* Calculate chances -> autokill the vampire. */
    chance = IS_NPC( ch ) ? UMIN( 60, ch->level )
	: ch->pcdata->learned[gsn_stake];
    chance = chance - victim->level + ch->level;

    if( number_percent( ) < chance
	|| !IS_AWAKE( victim )
	|| str_cmp( race_table[ch->race].name, "Vampire" ) )
    {
	if( !str_cmp( race_table[victim->race].name, "Vampire" ) )
	{
	    /* remove the curse, this isn't done when they are killed */
	    affect_strip( victim, gsn_vampiric_bite );

	    victim->hit = 1;
	    damage( ch, victim, 4, gsn_stake, WEAR_NONE );
	}
	else
	    multi_hit( ch, victim, TYPE_UNDEFINED );
    }
    else  /* vampire staking another vampire, strange?, feed instead. */
	do_feed( victim, ch->name );

    return;
}


void do_impale( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *obj;

    if( !can_use( ch, gsn_impale ) )
    {
	send_to_char( "Learn how to do this first please.\n\r", ch );
	return;
    }
    if( !( victim = find_target( ch, argument, "Impale" ) ) )
	return;

    if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
	  && !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
	|| obj->value[3] != 11 )
    {
	send_to_char( "You need to wield a piercing weapon.\n\r", ch );
	return;
    }

    if( ch->level + get_success( ch, gsn_impale, 500 ) + get_curr_str( ch )
	> number_percent( ) + victim->level + get_curr_str( victim ) )
    {
	act( "You pull back then shove your weapon into $N's chest!", ch, NULL, victim, TO_CHAR );
	act( "$n drives $s weapon straight into you!.", ch, NULL, victim, TO_VICT );
	act( "$n impales $N on $s weapon!", ch, NULL, victim, TO_NOTVICT );
	one_hit( ch, victim, gsn_impale, obj->wear_loc );
	WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, 2 * PULSE_VIOLENCE );
    }
    else
    {
	act( "You try to impale $N but $E manages to avoid you.", ch, NULL, victim, TO_CHAR );
	act( "$n tries to impale you but you manage to avoid $m.", ch, NULL, victim, TO_VICT );
	act( "$n barely misses impaling $N.", ch, NULL, victim, TO_NOTVICT );
	damage( ch, victim, 0, gsn_impale, obj->wear_loc );
    }
    WAIT_STATE( ch, skill_table[gsn_impale].beats );
    return;
}



void do_headbutt( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *helmet;
    AFFECT_DATA af;
    int hps, num, move = 25;

    /* Don't allow charmed mobs to do this, check player's level */
    if( !can_use( ch, gsn_headbutt ) )
    {
	send_to_char(
	    "You'd better leave the power fighting to fighters.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Headbutt" ) ) )
	return;

    if( ch->move < move )
    {
	if( !get_success( ch, gsn_stamina, 100 ) )
	{
	    send_to_char( "You are too exhausted.\n\r", ch );
	    return;
	}
	if( ch->hit < ch->max_hit / 3 )
	{
	    send_to_char(
		"Your body is too exhausted, "
		"your tired muscles will move no more.\n\r", ch );
	    return;
	}
	send_to_char( "You push your tired body past it's limits.\n\r", ch );
	move -= ch->move;
	ch->move = 0;
	ch->hit -= move;
	WAIT_STATE( ch, skill_table[gsn_stamina].beats );
    }
    else
	ch->move -= move;

    helmet = get_eq_char( ch, WEAR_HEAD );

    hps = victim->hit;
    WAIT_STATE( ch, skill_table[gsn_headbutt].beats );
    if( ( num = get_success( ch, gsn_headbutt, 100 ) ) )
    {
	one_hit( ch, victim, gsn_headbutt, WEAR_WIELD_R );
    }
    else
    {
	damage( ch, victim, 0, gsn_headbutt, WEAR_NONE );
	one_hit( ch, ch, gsn_headbutt, WEAR_NONE );
	if( !helmet || number_percent( ) > ch->pcdata->learned[gsn_headbutt] / 3 )
	    victim = ch;
    }
    if( victim == ch->fighting && hps > victim->hit &&
	( ( ch != victim && number_percent( ) < num / 7 )
	  || ( ch == victim && number_percent( ) > num / 2 ) ) )
    {
	af.type = skill_lookup( "sleep" );
	af.duration = number_range( 0, 2 );
	af.location = APPLY_NONE;
	af.modifier = 0;
	vset( af.bitvector, AFF_SLEEP );
	act( "$o eyes glaze over and $e crumple$% to the ground.",
	     victim, NULL, NULL, TO_ALL );
	stop_fighting( victim, TRUE );
	do_sleep( victim, "" );
    }

    return;
}


void do_smash( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    if( !can_use( ch, gsn_smash ) )
    {
	send_to_char( "You should learn how to use the skill first.\n\r",
		      ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Smash" ) ) )
	return;

    WAIT_STATE( ch, skill_table[gsn_smash].beats );
    if( get_success( ch, gsn_smash, 90 ) )
	one_hit( ch, victim, gsn_smash, WEAR_NONE );
    else
	damage( ch, victim, 0, gsn_smash, WEAR_NONE );
}


void do_ram( CHAR_DATA *ch, const char *argument )
{
    int success, wait;
    CHAR_DATA *victim;

    if( !can_use( ch, gsn_ram ) )
    {
	send_to_char( "You should learn how to use the skill first.\n\r",
		      ch );
	return;
    }
    if( !get_eq_char( ch, WEAR_SHIELD ) )
    {
	send_to_char( "I would advise wearing a shield first.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Ram" ) ) )
	return;

    success = ch->level - victim->level;
    success *= 3;
    success += ( get_size( ch ) - get_size( victim ) ) / 3;
    if( !IS_NPC_CLASS( ch ) )
	success += get_success( ch, gsn_ram, 500 );
    else
	success += UMIN( ch->level, 90 );
    success += get_curr_str( ch ) - 30;
    if( victim->position <= POS_SMASHED )
	success /= 2;
    success -= number_percent( );
    if( success > 0 )
    {
	if( victim->position <= POS_SMASHED )
	{
	    send_to_char( "Let them get up first.\n\r", ch );
	    return;
	}
	act( "$n ram$% into $N sending $M sprawling.",
	     ch, NULL, victim, TO_ALL );
	stop_juggling( victim );
	victim->position = POS_SMASHED;
	damage( ch, victim, number_range( ch->level / 2, ch->level * 3 / 2 ),
		gsn_ram, WEAR_NONE );
	wait = skill_table[gsn_ram].beats
	    + UMIN( success, 4 * skill_table[gsn_ram].beats );
	WAIT_STATE( victim, wait );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, wait );
	WAIT_STATE( ch, skill_table[gsn_ram].beats );
    }
    else
    {
	act( "You try to ram into $N but you fall over.",
	     ch, NULL, victim, TO_CHAR );
	act( "$n trie$% to ram into $N but $e fall$% over.",
	     ch, NULL, victim, TO_ROOM );
	ch->position = POS_SMASHED;
	if( !victim->fighting )
	    multi_hit( victim, ch, TYPE_UNDEFINED );
	WAIT_STATE( ch, 2 * skill_table[gsn_ram].beats );
    }

    return;
}


/*
 * Slit throat, specialised backstab.
 * More damage, better maximum damage etc...
 */
void do_slit_throat( CHAR_DATA *ch, const char *argument )
{
    OBJ_DATA *obj;
    CHAR_DATA *victim;

    if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_slit_throat ) )
    {
	send_to_char(
	    "You better leave the assassin trade to thieves.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Slit the throat of" ) ) )
	return;

    if( victim == ch )
    {
	send_to_char( "How can you sneak up on yourself?\n\r", ch );
	return;
    }

    if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
	|| ( obj->value[3] != 1 && obj->value[3] != 3 ) )
    {
	send_to_char( "You need to wield a slicing or slashing weapon.\n\r",
		      ch );
	return;
    }

    WAIT_STATE( ch, skill_table[gsn_slit_throat].beats );
    act( "You slit $N a nice new smile.", ch, NULL, victim, TO_CHAR );
    act( "$n sneaks up on $N and slashes $S throat!",
	 ch, NULL, victim, TO_NOTVICT );
    if( !IS_AWAKE( victim )
	|| get_success( ch, gsn_slit_throat, 100 ) )
    {
	multi_hit( ch, victim, gsn_slit_throat );
	xSET_BIT( victim->affected_by, AFF_BLEEDING );
    }
    else
	damage( ch, victim, 0, gsn_slit_throat, WEAR_WIELD_R );

    return;
}


void do_tend( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    OBJ_DATA *band;

    if( !( *argument ) )
	victim = ch;
    else
	victim = get_char_room( ch, argument );

    if( !( victim ) )
    {
	send_to_char( "Tend whom?\n\r", ch );
	return;
    }
    if( !IS_AFFECTED( victim, AFF_BLEEDING )
	&& !victim->damaged_parts )
    {
	send_to_char( "They have no need of your assistance.\n\r", ch );
	return;
    }

    if( ( !IS_NPC( victim ) || ch != victim )
	&& ( victim->damaged_parts & victim->body_parts ) )
    {
	if( can_use( ch, gsn_field_dressing ) )
	{
	    WAIT_STATE( ch, skill_table[gsn_field_dressing].beats );
	    if( !get_success( ch, gsn_field_dressing, 100 ) )
	    {
		act( "$n tries to use $s field dressing techniques on $N, but fails.",
		     ch, NULL, victim, TO_ROOM );
		act( "You fail to properly use your field dressing techniques.",
		     ch, NULL, victim, TO_CHAR );
		return;

	    }

	    act( "$n use$% field dressing techniques to repair $O wounds.",
		 ch, NULL, victim, TO_ALL );
	}
	else	/* can't use field dressing */
	{
	    for( band = ch->carrying; band; band = band->next_content )
		if( band->pIndexData->vnum == OBJ_VNUM_BANDAGES )
		    break;
	    if( !band )
	    {
		send_to_char(
		    "You can't repair their wounds without bandages.\n\r",
		    ch );
		return;
	    }
	    if( ch == victim )
	    {
		act( "$n wrap$% $s wounds with $p.", ch, band, NULL, TO_ALL );
	    }
	    else
	    {
		act( "$n wraps $O wounds with $p.", ch, band, victim, TO_ALL );
	    }
	    extract_obj( band );
	    WAIT_STATE( ch, PULSE_VIOLENCE * 2 );
	}

	victim->damaged_parts = 0;
    }

    xREMOVE_BIT( victim->affected_by, AFF_BLEEDING );
    if( ch != victim )
    {
	act( "$n tend$% $O wounds.", ch, NULL, victim, TO_ALL );
    }
    else
    {
	act( "$n tend$% $s own wounds.", ch, NULL, NULL, TO_ALL );
    }
    WAIT_STATE( ch, PULSE_VIOLENCE );
    return;
}



void do_stomp( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    if( !can_use( ch, gsn_stomp ) )
    {
	bad_command( ch );
	return;
    }
    if( !( victim = find_target( ch, argument, "Stomp on" ) ) )
	return;

    if( victim->position >= POS_FIGHTING )
    {
	send_to_char( "They must be on the ground before you can stomp on them.\n\r", ch );
	return;
    }

    if( ch->level + get_success( ch, gsn_stomp, 500 ) + get_curr_str( ch )
	> number_percent( ) + victim->level + get_curr_str( victim ) )
    {
	act( "$n stomp$% down on $N's head with a sickening crunching sound!",
	     ch, NULL, victim, TO_ALL );
	one_hit( ch, victim, gsn_stomp, WEAR_WIELD_L );
	WAIT_STATE( victim, PULSE_VIOLENCE );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, PULSE_VIOLENCE );
    }
    else
    {
	act( "You try to stomp on $N but $E rolls out of the way.", ch, NULL, victim, TO_CHAR );
	act( "$n tries to stomp on you but you manage to avoid $m.", ch, NULL, victim, TO_VICT );
	act( "$n barely misses stomping on $N.", ch, NULL, victim, TO_NOTVICT );
	damage( ch, victim, 0, gsn_stomp, WEAR_NONE );
    }
    WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
    return;
}



void do_strangle( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    AFFECT_DATA af;

    if( IS_NPC( ch ) || !can_use( ch, gsn_strangle ) )
    {
	send_to_char( "You don't know how to strangle yet.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Strangle" ) ) )
	return;

    if( victim->fighting != ch )
    {
	victim->fighting = ch;
	if( victim->position != POS_SMASHED )
	    victim->position = POS_FIGHTING;
    }
    ch->fighting = victim;

    WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
    if( !get_success( ch, gsn_strangle, 100 ) )
    {
	send_to_char( "You fail to get a good grip.\n\r", ch );
	return;
    }
    af.type = gsn_strangle;
    af.level = LEVEL_HERO;
    af.location = APPLY_NONE;
    af.modifier = 0;
    af.duration = ch->level;
    vset( af.bitvector, AFF_HOLD );
    affect_to_char( victim, &af, NULL );
    act( "$n grab$% hold of $N and start$% throttling $M!", ch, NULL, victim, TO_ALL );
    SET_BIT( ch->pcdata->pc_bits, PC_BIT_STRANGLE );
    if( get_time_left( ch->in_room->events, evn_room_violence ) < 0 )
	create_room_event( ch->in_room, evn_room_violence,
			   PULSE_VIOLENCE );
    return;
}


/*
 * for those strangling
 */
void strangle_hit( CHAR_DATA *ch )
{
    int pwr;
    int dam;

    if( IS_NPC( ch ) || !ch->fighting )
	return;

    pwr = ch->pcdata->pc_bits / PC_BIT_STRANGLE;
    dam = number_range( ch->level / 2, ch->level );
    dam += get_damroll( ch );
    if( IS_SET( ch->pcdata->pc_bits, PC_BIT_HANDOFKAZ ) )
    {
	dam += get_curr_int( ch ) * 2;
	dam = power( dam, get_success( ch, gsn_hand_of_kaz, 250 ), pwr );
	ch->pcdata->pc_bits += PC_BIT_STRANGLE;
	damage( ch, ch->fighting, dam, gsn_hand_of_kaz, WEAR_NONE );
    }
    else
    {
	dam += get_curr_dex( ch ) * 2;
	dam = power( dam, get_success( ch, gsn_strangle, 250 ), pwr );
	ch->pcdata->pc_bits += PC_BIT_STRANGLE;
	damage( ch, ch->fighting, dam, gsn_strangle, WEAR_NONE );
    }
    return;
}


/*
 * for those being strangled
 */
void strangle_struggle( CHAR_DATA *ch )
{
    int chance;

    if( !ch->fighting || IS_NPC( ch->fighting ) )
	return;

    if( IS_SET( ch->fighting->pcdata->pc_bits, PC_BIT_HANDOFKAZ ) )
    {
	chance = get_curr_int( ch ) - get_curr_int( ch->fighting );
	chance -= ch->fighting->pcdata->learned[gsn_hand_of_kaz] / 2;
	chance += ch->level - ch->fighting->level;
	if( chance + 75 > number_percent( ) )
	{
	    act( "$n wrenches free of $O death grip.",
		 ch, NULL, ch->fighting, TO_ALL );
	    ch->fighting->pcdata->pc_bits %= PC_BIT_STRANGLE;
	    REMOVE_BIT( ch->fighting->pcdata->pc_bits, PC_BIT_HANDOFKAZ );
	    /*
	     * Optional -- Symposium
	     *	    multi_hit( ch, ch->fighting, TYPE_UNDEFINED );
	     */
	}
	else
	{
	    act( "You strain to free yourself of $N's death grip",
		 ch, NULL, ch->fighting, TO_CHAR );
	    act( "$n is straining to free $mself from $N's death grip.",
		 ch, NULL, ch->fighting, TO_NOTVICT );
	    act( "You feel $n's heart beat weakly in your fist.",
		 ch, NULL, ch->fighting, TO_VICT );
	}
    }
    else
    {
	chance = get_curr_dex( ch ) - get_curr_dex( ch->fighting );
	chance -= ch->fighting->pcdata->learned[gsn_strangle] / 2;
	chance += ch->level - ch->fighting->level;
	if( chance + 75 > number_percent( ) )
	{
	    act( "You struggle free of $N's stranglehold.",
		 ch, NULL, ch->fighting, TO_CHAR );
	    act( "$n frees $mself from $N's stranglehold.",
		 ch, NULL, ch->fighting, TO_NOTVICT );
	    act( "$n slips from your grasp.",
		 ch, NULL, ch->fighting, TO_VICT );
	    ch->fighting->pcdata->pc_bits %= PC_BIT_STRANGLE;
	    /*
	     * Optional -- Symposium
	     *	    multi_hit( ch, ch->fighting, TYPE_UNDEFINED );
	     */
	}
	else
	{
	    act( "You struggle to free yourself of $N's stranglehold.",
		 ch, NULL, ch->fighting, TO_CHAR );
	    act( "$n is struggling to free $mself from $N's stranglehold.",
		 ch, NULL, ch->fighting, TO_NOTVICT );
	    act( "$n is struggling but you hold firm.",
		 ch, NULL, ch->fighting, TO_VICT );
	}
    }
    return;
}


void do_trip( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_trip ) )
    {
	send_to_char( "You can't use that yet.\n\r", ch );
	return;
    }

    if( !( victim = find_target( ch, argument, "Trip" ) ) )
	return;

    if( !ch->fighting )
	set_fighting( ch, victim );

    if( IS_SET( victim->body_parts, BODY_PART_WINGS )
	|| xIS_SET( victim->affected_by, AFF_FLYING ) )
    {
	act( "You watch as your leg sweeps underneath $N.",
	     ch, NULL, victim, TO_CHAR );
	act( "$n try to trip you but $s leg passes under you.",
	     ch, NULL, victim, TO_VICT );
	act( "$n tries to trip $N but $s leg passes under $E.",
	     ch, NULL, victim, TO_NOTVICT );
	WAIT_STATE( ch, PULSE_VIOLENCE * 2 );
	if( !victim->fighting )
	    set_fighting( victim, ch );
	return;
    }

    if( !IS_NPC( ch )
	&& get_success( ch, gsn_trip, 200 )
	+ 2 * ( get_curr_dex( ch ) + ch->level - victim->level )
	- 45 < number_percent( ) )
    {
	act( "You try to trip $N and you stumble.",
	     ch, NULL, victim, TO_CHAR );
	act( "$n trie$% to trip $N and $e stumble$%.",
	     ch, NULL, victim, TO_ROOM );
	WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
	if( !victim->fighting )
	    set_fighting( victim, ch );
	return;
    }
    WAIT_STATE( ch, PULSE_VIOLENCE );
    if( victim->position < POS_FIGHTING )
    {
	send_to_char( "Let them get up first, eh?\n\r", ch );
	return;
    }
    if( !IS_NPC( ch ) || victim->wait == 0 )
    {
	int wait;

	victim->fighting = NULL;
	act( "You trip $N and $N goes down!", ch, NULL, victim, TO_CHAR );
	act( "$n trips you and you go down!", ch, NULL, victim, TO_VICT );
	act( "$n trips $N and $N goes down!", ch, NULL, victim, TO_NOTVICT );

	wait = number_range( 3 * PULSE_VIOLENCE, 5 * PULSE_VIOLENCE );
	WAIT_STATE( victim, wait );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, wait );
	stop_juggling( victim );
	victim->position = POS_SLEEPING;
    }

    return;
}


bool throw( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;

    if( !( victim = find_target( ch, argument, "Throw" ) ) )
	return FALSE;

    if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_throw ) )
    {
	send_to_char( "Maybe you should learn the proper technique "
		      "before trying to throw people.\n\r", ch );
	return TRUE;
    }

    if( !ch->fighting )
	set_fighting( ch, victim );

    if( !IS_NPC_CLASS( ch )
	&& get_success( ch, gsn_throw, 200 ) + get_curr_str( ch )
	+ get_curr_dex( ch ) + 2 * ( ch->level - victim->level )
	- 45 < number_percent( ) )
    {
	act( "You try to throw $N but $E slips from your grasp.",
	     ch, NULL, victim, TO_CHAR );
	act( "$n tries to throw you but you manage to slip $s grasp.",
	     ch, NULL, victim, TO_VICT );
	act( "$n tries to throw $N but $E slips out of $s grasp.",
	     ch, NULL, victim, TO_NOTVICT );
	WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
    }
    else if( !IS_NPC_CLASS( ch ) || victim->wait == 0 )
    {
	int wait;

	victim->fighting = NULL;
	act( "$n grab$% $N throw$% $M to the ground!",
	     ch, NULL, victim, TO_ALL );

	WAIT_STATE( ch, PULSE_VIOLENCE );
	wait = number_range( 3 * PULSE_VIOLENCE, 5 * PULSE_VIOLENCE );
	WAIT_STATE( victim, wait );
	if( IS_NPC( victim ) )
	    create_char_event( victim, evn_stand_up, wait );
	stop_juggling( victim );
	victim->position = POS_SLEEPING;
    }

    return TRUE;
}



void do_whirlwind( CHAR_DATA *ch, const char *argument )
{
    CHAR_DATA *victim;
    CHAR_DATA *next;
    OBJ_DATA *obj;
    int move = 100;

    if( !can_use( ch, gsn_whirlwind ) )
    {
	send_to_char( "Maybe you should learn how first.\n\r", ch );
	return;
    }
    if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
	&& !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) )
	&& !( obj = get_eq_char( ch, WEAR_WIELD_L ) ) )
    {
	send_to_char( "You should be wearing a weapon.\n\r", ch );
	return;
    }
    if( ch->move < move )
    {
	if( !get_success( ch, gsn_stamina, 100 ) )
	{
	    send_to_char( "You are too exhausted.\n\r", ch );
	    return;
	}
	if( ch->hit < ch->max_hit / 3 )
	{
	    send_to_char(
		"Your body is too exhausted, "
		"your tired muscles will move no more.\n\r", ch );
	    return;
	}
	send_to_char( "You push your tired body past it's limits.\n\r", ch );
	move -= ch->move;
	ch->move = 0;
	ch->hit -= move;
	WAIT_STATE( ch, skill_table[gsn_stamina].beats );
    }
    else
	ch->move -= move;

    send_to_char( "You sweep your weapon around viciously.\n\r", ch );
    act( "$n sweeps $s weapon around the room!", ch, NULL, NULL, TO_ROOM );
    if( !get_success( ch, gsn_whirlwind, 100 ) )
	return;
    WAIT_STATE( ch, skill_table[gsn_whirlwind].beats );
    for( victim = ch->in_room->people; victim; victim = next )
    {
	next = victim->next_in_room;
	if( !IS_NPC( ch ) && !IS_NPC( victim ) &&
	    !xIS_SET( ch->act, PLR_BATTLE ) &&
	    !xIS_SET( victim->act, PLR_BATTLE ) &&
	    !IS_SET( ch->in_room->room_flags, ROOM_ARENA ) )
	    continue;
	if( IS_NPC( ch ) && IS_NPC( victim ) )
	    continue;
	if( !IS_NPC( ch ) && is_affected( victim, AFF_CHARM ) )
	    continue;
	one_hit( ch, victim, gsn_whirlwind, obj->wear_loc );
    }
    return;
}


#define MAX_COMBO 5
void do_combo( CHAR_DATA *ch, const char *argument )
{
    static const int type_hit = TYPE_HIT;
    const struct combo_type
    {
	const char *name;
	const int * hit_gsn[MAX_COMBO];
    }
    combo_table[] =
    {
	{ "eagle combo",
	  { &gsn_jab, &type_hit, &gsn_jab, &gsn_backhand }
	},
	{ "pummel combo",
	  { &gsn_jab, &gsn_jab, &gsn_backhand, &gsn_uppercut }
	},
	{ "bull combo",
	  { &gsn_backhand, &gsn_knee, &gsn_uppercut }
	},
	{ "viper combo",
	  { &gsn_backhand, &gsn_knee, &gsn_elbow,
	    &gsn_uppercut, &gsn_roundhouse }
	},
	{ "dragon combo",
	  { &gsn_elbow, &gsn_knee, &gsn_uppercut,
	    &gsn_roundhouse, &gsn_uppercut }
	},
	{  NULL, { 0 } }
    };
    CHAR_DATA *victim;
    int typ, sn, i, savehit;

    if( IS_NPC( ch ) )
	return;
    if( !( victim = ch->fighting ) )
    {
	send_to_char( "You should be fighting first.\n\r", ch );
	return;
    }
    if( argument[0] == '\0' )
    {
	send_to_char( "Which combo?\n\r", ch );
	return;
    }
    if( get_eq_char( ch, WEAR_WIELD_DOUBLE ) || get_eq_char( ch, WEAR_WIELD_R )
	|| get_eq_char( ch, WEAR_WIELD_L ) || get_eq_char( ch, WEAR_SHIELD )
	|| get_eq_char( ch, WEAR_HOLD_L ) || get_eq_char( ch, WEAR_HOLD_R ) )
    {
	send_to_char( "Are you joking? Your gear gets in the way!\n\r", ch );
	return;
    }

    for( typ = 0; combo_table[typ].name; typ++ )
    {
	if( !str_prefix( argument, combo_table[typ].name ) )
	    break;
    }
    if( !combo_table[typ].name )
    {
	send_to_char( "That combination is not possible.\n\r", ch );
	return;
    }

    sn = skill_lookup( combo_table[typ].name );
    if( sn <= 0 || !can_use( ch, sn ) )
    {
	send_to_char( "You wave your hands about and"
		      " succeed in making an idiot of yourself.\n\r", ch );
	return;
    }

    WAIT_STATE( ch, skill_table[sn].beats );
    if( !get_success( ch, sn, 100 ) )
    {
	send_to_char( "You wave your hands about and"
		      " succeed in making an idiot of yourself.\n\r", ch );
	return;
    }

    i = 0;
    savehit = victim->hit;
    one_hit( ch, victim, TYPE_HIT, WEAR_WIELD_R );
    while( i < MAX_COMBO && *combo_table[typ].hit_gsn[i] > 0 )
    {
	if( victim->deleted || victim != ch->fighting
	    || victim->hit >= savehit )
	    return;
	if( *combo_table[typ].hit_gsn[i] == TYPE_HIT
	    || get_success( ch, *combo_table[typ].hit_gsn[i], 100 ) )
	{
	    savehit = victim->hit;
	    one_hit( ch, victim, *combo_table[typ].hit_gsn[i], WEAR_WIELD_R );
	    ++i;
	    continue;
	}
	damage( ch, victim, 0, *combo_table[typ].hit_gsn[i], WEAR_WIELD_R );
	return;
    }
    return;
}


void do_blink( CHAR_DATA *ch, const char *argument )
{
    if( IS_NPC( ch ) || !can_prac( ch, gsn_blink ) )
    {
	send_to_char( "You can't use this skill.\n\r", ch );
	return;
    }
    if( argument[0] == '\0' )
    {
	if( ch->pcdata->blink > 0 )
	    charprintf( ch, "You are blinking at %d%%.\n\r",
			ch->pcdata->blink );
	else if( ch->pcdata->blink == 0 )
	    send_to_char( "You aren't blinking incoming attacks.\n\r", ch );
	else
	    charprintf( ch, "If you were blinking you would be at %d%%.\n\r",
			ch->pcdata->blink * -1 );
	return;
    }

    if( !str_cmp( argument, "on" ) )
    {
	if( ch->pcdata->blink >= 0 )
	{
	    send_to_char( "Please specify the rate of blinking.\n\r", ch );
	    return;
	}
	ch->pcdata->blink = URANGE( 0, ch->pcdata->blink * -1, 50 );
	charprintf( ch, "You will attempt to blink at a rate of %d.\n\r",
		    ch->pcdata->blink );
	return;
    }
    if( !str_cmp( argument, "off" ) )
    {
	if( ch->pcdata->blink <= 0 )
	{
	    send_to_char( "You weren't blinking attacks.\n\r", ch );
	    return;
	}
	ch->pcdata->blink *= -1;
	send_to_char( "You wont attempt to blink incoming attacks.\n\r", ch );
	return;
    }
    if( !is_number( argument ) )
    {
	send_to_char( "Please specify a rate of blinking, 'on' or 'off'.\n\r",
		      ch );
	return;
    }
    ch->pcdata->blink = URANGE( 0, atoi( argument ), 50 );
    charprintf(
	ch, "You will attempt to blink incoming attacks %d%% of the time.\n\r",
	ch->pcdata->blink );
    return;
}