dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// skill_ke.cpp - skills written by Kerenos
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/

#include "include.h"
#include "o_lookup.h"
#include "db.h"
#include "ictime.h"

// Prototype declarations
HERB_DATA *find_herb( char_data * ch, char *herb );
void	entangle( char_data *ch, char_data *victim );
void    dismount( char_data *);
void	flourish_totemstaff_guardian( char_data *ch, OBJ_DATA *obj );
void	flourish_totemstaff_spirit(   char_data *ch, OBJ_DATA *obj );
void	forage_food( char_data *ch );
void	forage_herbs( char_data *ch );
int		get_birthmonth( char_data *ch );
int		calculate_season( void );
char *format_obj_to_char_new( OBJ_DATA *obj, char_data *ch, bool fShort );
DECLARE_DO_FUN( do_cast );
char *	const	month_name	[] =
{
    "Winter", "the Winter Storm", "the Frost Blight", 
	"the Return","Blight","the Dragon",
	"Light",  "the Sun", "the Heat", 
	"the Great War", "the Shadows", "the Long Shadows", 
};

/**************************************************************************/
// Kerenos - Sept 98
void do_forage( char_data *ch, char *argument )
{
	if ( IS_NULLSTR( argument ))
	{
		ch->println( "Syntax:  forage [food/herbs]" );
		return;
	}
	if ( !str_prefix( argument, "food" ))
	{
		forage_food( ch );
		return;
	}
	if ( !str_prefix( argument, "herbs" ))
	{
		forage_herbs( ch );
		return;
	}

	ch->println( "Syntax:  forage [food/herbs]" );
	return;	
}

/**************************************************************************/
void forage_food( char_data *ch )
{
	OBJ_INDEX_DATA		*pObjIndex;
	OBJ_DATA			*pObj;
	int					chance;
	
	chance = get_skill( ch, gsn_forage )+10;
	if ( chance < 11){
		ch->println("You don't know how to forage for food.");
		return;
	}

	// make it easier for newbies
	if (ch->level<30)
		chance+=ch->level;
	
	if ( ch->in_room->sector_type == SECT_INSIDE
		|| ch->in_room->sector_type == SECT_CITY
		|| ch->in_room->sector_type == SECT_WATER_NOSWIM
		|| ch->in_room->sector_type == SECT_UNDERWATER
		|| ch->in_room->sector_type == SECT_CAVE
		|| ch->in_room->sector_type == SECT_SWAMP
		|| ch->in_room->sector_type == SECT_AIR ) {
		ch->println("You cannot find any foodstuffs around here.");
		return;
	}

	if (chance<number_range(0,105)){
		ch->wrapln("You forage around for something to eat but didnt manage to find "
			"any suitable foodstuffs here.");
#ifdef unix	
        WAIT_STATE( ch, PULSE_PER_SECOND *number_range(3,5));
#endif
		return;
	}

	
	if (( pObjIndex = get_obj_index( OBJ_VNUM_MUSHROOM )) == NULL ) {
		ch->println("Food item non-existant, please report this with a note to admin.");
		return;
	}
	
	pObj = create_object( pObjIndex);
	
	//  Free up old object names and descriptions
	
	free_string( pObj->description );
	free_string( pObj->name );
	free_string( pObj->short_descr );
	
	//  Make food timer 24 hours for perishable foods, no stockpiling allowed :)
	
	pObj->timer = 24;
	
	//  Change food desc according to terrain type
	
	switch ( ch->in_room->sector_type ) {
		
	case SECT_FIELD:
		pObj->description = str_dup( "You see a bunch of eldeberries here." );
		pObj->short_descr = str_dup( "a bunch of eldeberries" );
		pObj->name		  = str_dup( "eldeberries bunch" );
		break;
	case SECT_FOREST:
		pObj->description = str_dup( "You see a handful of hazelnuts." );
		pObj->short_descr = str_dup( "a handful of hazelnuts" );
		pObj->name		  = str_dup( "hazelnuts" );
		break;
	case SECT_HILLS:
		pObj->description = str_dup( "Some wild berries are here." );
		pObj->short_descr = str_dup( "some wild berries" );
		pObj->name		  = str_dup( "berries wild" );
		break;
	case SECT_MOUNTAIN:
		pObj->description = str_dup( "You see a tangy wild root." );
		pObj->short_descr = str_dup( "a tangy wild root" );
		pObj->name		  = str_dup( "root wild tangy" );
		break;
	case SECT_WATER_SWIM:
		pObj->description = str_dup( "You look upon a fresh, dead trout." );
		pObj->short_descr = str_dup( "a fresh, dead trout" );
		pObj->name		  = str_dup( "trout" );
		break;
	case SECT_DESERT:
		pObj->description = str_dup( "You see a pulpy cactus heart here, looks good enough to eat." );
		pObj->short_descr = str_dup( "the heart of a cactus" );
		pObj->name		  = str_dup( "cactus heart pulp" );
		break;
	}
	
	//  Send the message to the world!
#ifdef unix	
	WAIT_STATE( ch, PULSE_PER_SECOND * number_range(6, 10));
#endif
	obj_to_room( pObj, ch->in_room );
	
	ch->println("You found something to eat.");
	act( "$n seems to be searching for something.", ch, NULL, NULL, TO_ROOM );
	
	check_improve( ch, gsn_forage, true, 2 );
	return;
}

/**************************************************************************/
void forage_herbs( char_data *ch )
{
	OBJ_INDEX_DATA		*pHerb;
	OBJ_DATA			*herb_obj;
	HERB_DATA			*herb;
	int					vnum, chance, num = 0;
	static vn_int		vnum_field[500]; // show me a mud ever with more than 500 herbs
	bool				found = false;
	
	chance = get_skill( ch, gsn_forage );

	if ( chance < 1 ){
		ch->println( "You don't know how to forage." );
		return;
	}

	if ( IS_AFFECTED(ch, AFF_BLIND) ) {
		ch->println( "You can't see a thing." );
		return;
	}

	for( herb = herb_list; herb; herb = herb->next )
	{
		if ( ch->in_room->sector_type != herb->sector )
			continue;

		if ( herb->continent )
		{
			if ( ch->in_room->area->continent != herb->continent ){
				continue;
			}
		}

		if ( herb->area >= 0 )
		{
			if ( ch->in_room->area->vnum != herb->area )
				continue;
		}

		if ( herb->season >=0 )
		{
			if ( calculate_season() != herb->season )
				continue;
		}

		if ( timefield_table[herb->timefield].lowhour != -1 )
		{
			if (   time_info.hour < timefield_table[herb->timefield].lowhour
				|| time_info.hour > timefield_table[herb->timefield].highhour )
				continue;
		}
		
		if (( chance + modifier_table[herb->difficulty].modifier ) < number_percent())
			continue;

		found = true;
		vnum_field[num] = herb->vnum_result;
		num++;
	}

	int seconds_lag = number_range(6, 10);
#ifdef WIN32
	seconds_lag =1;
#endif
	ch->println( "You look around for herbs..." );
	WAIT_STATE( ch, PULSE_PER_SECOND *seconds_lag);	

	if ( !found )
	{
		ch->println(seconds_lag, "You didn't find anything that resembled a useful herb." );
		return;
	}
				
	vnum = vnum_field[number_range( 0, num-1 )];
	
	if (( pHerb = get_obj_index( vnum )) == NULL ) {
		ch->println(seconds_lag, "You didn't find anything that resembled a useful herb." );
		return;
	}
	
	herb_obj = create_object( pHerb);
//??herb_obj->timer = 96;
	obj_to_char( herb_obj, ch );

	ch->printlnf( seconds_lag, "You found %s!", format_obj_to_char_new( herb_obj, ch, true));

	// act is seen before the player finds out they found something - but will do for now :)
	act( "$n has found an herb.", ch, NULL, NULL, TO_ROOM ); 
	check_improve( ch, gsn_forage, true, 2 );
	return;
}

/**************************************************************************/
void do_cook( char_data *ch, char *argument )
{
	OBJ_DATA		*obj;
	OBJ_DATA		*fire;
	OBJ_DATA		*cookware;
	ROOM_INDEX_DATA	*pIndexRoom = ch->in_room;
	char			arg[MIL];
	int				chance;
	bool			foundfire = false;
	bool			foundpan  = false;


	chance = get_skill( ch, gsn_cook ) + 30;
	if ( chance < 31){
		ch->println("You don't know the first thing about cooking.");
		return;
	}

	one_argument( argument, arg );

	if IS_NULLSTR( arg ) {
		ch->println("What do you wish to cook?");
		return;
	}

	if (( obj = get_obj_carry( ch, arg )) == NULL ) {
		ch->println("You are not carrying that.");
		return;
	}

	if ( obj->item_type != ITEM_FOOD ) {
		ch->println("You can only cook foodstuffs.");
		return;
	}

	if ( obj->timer == 0 ) {
		act( "$p appears to be cooked already.", ch, obj, NULL, TO_CHAR );
		return;
	}

	for ( fire = pIndexRoom->contents; fire; fire = fire->next_content ) {
		if ( fire->pIndexData->vnum == OBJ_VNUM_FIRE ) {
			foundfire = true;
			break;
		}
    }

	if ( !foundfire ) {
		ch->println("There needs to be a fire for you to cook properly.");
		return;
	}

    for ( cookware = ch->carrying; cookware; cookware = cookware->next_content )
    {
        if ( !str_cmp( cookware->pIndexData->material, "cookware" )
			 && cookware->wear_loc == WEAR_HOLD ) {
			foundpan = true;
            break;
		}
    }

	if ( !foundpan ) {
		ch->println("You need to hold a cooking pot of some kind to cook the food.");
		return;
	}

	if ( chance < number_percent() ) {
		act( "You fail miserably attempting to cook $p, ruining it completely.", ch, obj, NULL, TO_CHAR );
		extract_obj( obj );		
		check_improve( ch, gsn_cook, false, 3 );
		WAIT_STATE( ch, skill_table[gsn_cook].beats/2 );
		return;
	}

	act( "You busy yourself cooking $p, and do it to perfection!", ch, obj, NULL, TO_CHAR );
	act( "$n busies $mself cooking $p.", ch, obj, NULL, TO_ROOM );
	obj->timer = 0;

	if ( obj->pIndexData->vnum == OBJ_VNUM_SLICE ) {
		replace_string( obj->description, "A slice of cooked meat lies here." );
		replace_string( obj->short_descr, "a slice of cooked meat" );
		replace_string( obj->name, "slice meat cooked" );
	}	
	check_improve( ch, gsn_cook, true, 4 );
	WAIT_STATE( ch, skill_table[gsn_cook].beats );
	return;
}
/**************************************************************************/
void do_flip( char_data *ch, char *argument )
{
	int				face = number_range( 0, 1);
	bool			spam = false;
	OBJ_INDEX_DATA	*coinIndex;
	OBJ_DATA		*coin;

	if ( IS_NULLSTR( argument )) {
		ch->println("What do you want to flip, a silver or a gold coin?");
		return;
	}

	if ( ch->desc && ch->desc->repeat>5 )
		spam = true;

	if ( is_name( argument, "silver" ))
	{
		if ( ch->silver < 1 ) {
			ch->println("You have no silver coins to flip.");
			return;
		}

		coinIndex	= get_obj_index( OBJ_VNUM_SILVER_ONE );
		coin		= create_object( coinIndex);
		ch->silver -= 1;
		free_string( coin->description );

		if ( face ) {
			act( "$n flips a coin high into the air and lands showing heads.", ch, NULL, NULL, TO_ROOM );
			ch->println("You flip a coin high into the air.  It lands showing heads.");
			coin->description = str_dup( "You see a silver coin showing heads." );
		} else {
			act( "$n flips a coin high into the air and lands showing tails.", ch, NULL, NULL, TO_ROOM );
			ch->println("You flip a coin high into the air.  It lands showing tails.");
			coin->description = str_dup( "You see a silver coin showing tails." );
		}
		if ( !IS_OOC(ch) ) { obj_to_room( coin, ch->in_room ); }
	}
	else if ( is_name( argument, "gold" ))
	{
		if ( ch->gold < 1 ) {
			ch->println("You have no gold coins to flip.");
			return;
		}

		coinIndex	= get_obj_index( OBJ_VNUM_GOLD_ONE );
		coin		= create_object( coinIndex);
		ch->gold   -= 1;
		free_string( coin->description );

		if ( face ) {
			act( "$n flips a coin high into the air and lands showing heads.", ch, NULL, NULL, TO_ROOM );
			ch->println("You flip a coin high into the air.  It lands showing heads.");
			coin->description = str_dup( "You see a gold coin showing heads." );
		} else {
			act( "$n flips a coin high into the air and lands showing tails.", ch, NULL, NULL, TO_ROOM );
			ch->println("You flip a coin high into the air.  It lands showing tails.");
			coin->description = str_dup( "You see a gold coin showing tails." );
		}
		if ( !IS_OOC(ch)) { obj_to_room( coin, ch->in_room ); }
	}
	else
	{
		ch->println("What do you want to flip, a silver or a gold coin?");
	}
	if ( spam )
		WAIT_STATE( ch, PULSE_PER_SECOND * 10 );	
}
/**************************************************************************/
void do_hobble( char_data *ch, char *argument )
{
    char_data * victim;
    OBJ_DATA  * obj;
    char        arg[MIL];
    int         chance;

	if ((chance = get_skill(ch,gsn_hobble)) == 0)
	{
		do_huh(ch,"");
		return;
	}

    one_argument( argument, arg );

    obj = ( get_eq_char( ch, WEAR_WIELD ));

    if ( !obj ) {
        ch->println("You need to wield a mace to hobble someone.");
        return;
    }
    
	if ( obj ) {
        if ( obj->value[0] != WEAPON_MACE ) {
            ch->println("You are not wielding a mace.");
            return;
        }
    }

	if( IS_RIDING( ch )) {
		ch->println("You cannot reach your opponents legs while mounted.");
		return;
	}
    if ( IS_NULLSTR( arg )) {
        if (( victim = ch->fighting ) == NULL ) {
            ch->println("But you aren't fighting anyone!");
            return;
        }
    }
    else if (( victim = get_char_room( ch, arg )) == NULL ) {
        ch->printlnf("You can't seem to find '%s' here.", arg);
        return;
    }

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

	if ( is_safe( ch, victim ))
		return;

	if ( !can_initiate_combat( ch, victim, CIT_GENERAL )) return;	
	
    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }


// INSERT WEAPON SPECIALIZATION CHECK HERE

    if ( get_skill( ch,gsn_hobble ) > number_percent() ) {
        act( "You `Bsmash`x $p against $N's legs!", ch, obj, victim, TO_CHAR );
		act( "$n `Bsmashes`x $p against $N's legs!", ch, obj, victim, TO_NOTVICT );
		act( "$n `Bsmashes`x $p on your legs!", ch, obj, victim, TO_VICT );
        if ( damage( ch, victim, number_range( 1, ch->level / 2 ), gsn_hobble, DAM_BASH, true)) {
	        victim->position = POS_RESTING;
		    DAZE_STATE( victim, skill_table[gsn_hobble].beats*2/3 );
			victim->move -= number_range(( ch->level/5 ), ch->level);
		}
        check_improve( ch, gsn_hobble, true, 1 );
        WAIT_STATE( ch, skill_table[gsn_hobble].beats );
	}
    else {
        damage( ch, victim, 0, gsn_hobble, DAM_BASH, false );
        check_improve( ch, gsn_hobble, false, 1 );

		ch->println("You swing wildly and don't manage to connect the blow.");

        act("$n tries to hobble $N but misses completely.", ch, NULL, victim, TO_NOTVICT);
        act("You deftly evade $n's attempt to hobble you.", ch, NULL, victim, TO_VICT );
        WAIT_STATE( ch, skill_table[gsn_hobble].beats );
    }
    return;
}

/**************************************************************************/
void do_shieldcleave( char_data *ch, char *argument )
{
    char_data * victim;
    OBJ_DATA  * obj;
	OBJ_DATA  * shield;
    char        arg[MIL];
    int         chance;


	if ((chance = get_skill(ch,gsn_shieldcleave)) == 0)
	{
		do_huh(ch,"");
		return;
	}

    one_argument( argument, arg );

    obj = ( get_eq_char( ch, WEAR_WIELD ));

    if ( !obj ) {
        ch->println("You need to wield an axe to cleave a shield.");
        return;
    }
    
	if ( obj ) {
        if ( obj->value[0] != WEAPON_AXE ) {
            ch->println("You are not wielding an axe.");
            return;
        }
    }

    if (( victim = ch->fighting ) == NULL ) {
		ch->println("You aren't fighting anyone.");
		return;
    }

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

	shield = ( get_eq_char( victim, WEAR_SHIELD ));

	if ( !shield ) {
		ch->println("Your opponent is not wearing a shield.");
		return;
	}

    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }

	if ( is_safe( ch, victim ))
		return;

// INSERT WEAPON SPECIALIZATION CHECK HERE

    if ( get_skill( ch,gsn_shieldcleave ) > number_percent() ) {

		chance = 40;
		if IS_WEAPON_STAT( obj, WEAPON_SHARP )		chance += 10;
		if IS_WEAPON_STAT( obj, WEAPON_VORPAL )		chance += 20;
		if IS_WEAPON_STAT( obj, WEAPON_FROST )		chance += 10;
		if IS_WEAPON_STAT( obj, WEAPON_FLAMING )	chance += 5;
		if IS_WEAPON_STAT( obj, WEAPON_SHOCKING )	chance += 5;
		if IS_OBJ_STAT( shield,	OBJEXTRA_BLESS )		chance -= 25;
		if IS_OBJ_STAT( shield,	OBJEXTRA_MAGIC )		chance -= 20;
		if IS_OBJ_STAT( shield,	OBJEXTRA_GLOW )			chance -=  5;
		if IS_OBJ_STAT( shield,	OBJEXTRA_CHAOS )		chance -= number_range(1,25);
		if IS_OBJ_STAT( shield,	OBJEXTRA_HUM )			chance -=  5;
		if IS_OBJ_STAT( shield,	OBJEXTRA_NONMETAL )		chance += 10;
		if IS_OBJ_STAT( shield,	OBJEXTRA_BURN_PROOF )	chance -= 35;

		if ( number_range( 1, 100 ) < chance ) {
			ch->println("Your axe `Bslices`x through the shield like butter.");
	        act("$n `Bslices`x right through $N's shield.", ch, NULL, victim, TO_NOTVICT);
	        act("$n has `Bdestroyed`x your shield.", ch, NULL, victim, TO_VICT);
			extract_obj( shield );	
		} else {
	        act( "$N's shield withstands your blow!", ch, obj, victim, TO_CHAR );
			act( "$n smashes against $N's shield without effect!", ch, obj, victim, TO_NOTVICT );
			act( "Your shield resonates agains $N's swing, but holds firm.", ch, obj, victim, TO_VICT );
		}
		check_improve( ch, gsn_shieldcleave, true, 1 );
        WAIT_STATE( ch, skill_table[gsn_shieldcleave].beats );
	}
    else {
        check_improve( ch, gsn_shieldcleave, false, 1 );

		ch->println("You swing wildly and don't manage to connect the blow.");
        act("$n tries to cleave $N's shield and misses completely.", ch, NULL, victim, TO_NOTVICT);
        victim->println("You manage to avoid your shield being cleaved in two.");
        WAIT_STATE( ch, skill_table[gsn_shieldcleave].beats );
    }
    return;
}
/**************************************************************************/
void do_hurl( char_data *ch, char *argument )
{
	char		arg[MIL];
	char_data	*victim = NULL;
	OBJ_DATA	*dagger = NULL;
	int			dam;
	int			chance;


	chance = get_skill( ch, gsn_hurl );
	if ( chance < 1)
	{
		do_huh(ch,"");
		return;
	}


	dagger = get_eq_char( ch, WEAR_WIELD );


	if ( !dagger )
	{
		ch->println("You have to have your dagger readied in your hand.");
		return;
	}

	if ( dagger->value[0] != WEAPON_DAGGER )
	{
		ch->println("You may only hurl daggers.");
		return;
	}

    if ( !can_drop_obj( ch, dagger ))
    {
		ch->println("You can't let go of that.");
		return;
    }

	one_argument( argument, arg );

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

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

	if ( is_safe( ch, victim ))
		return;

    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }


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

	act( "$n hurls $p at $N.",  ch, dagger, victim, TO_NOTVICT );
	act( "You hurl $p at $N.",  ch, dagger, victim, TO_CHAR );
	act( "$n hurls $p at you.", ch, dagger, victim, TO_VICT );

	if (( ch->level + 5 ) < dagger->level
	||  number_percent() >= 10 + get_skill( ch, gsn_hurl ) * 4/5 )
	{
		act( "$p misses $N and lands on the ground.", ch, dagger, victim, TO_CHAR );
		act( "$n hurls $p but it misses and lands on the ground.", ch, dagger, NULL, TO_ROOM );
		obj_from_char( dagger );
		obj_to_room( dagger, ch->in_room );
		check_improve( ch, gsn_hurl, false, 1 );
	    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
	    {
			act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
			extract_obj( dagger );
		}
	}
	else
	{
		chance = number_range(1,10);
		switch (chance)
		{
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
				obj_from_char( dagger );
				dam = dice( dagger->value[1], dagger->value[2] );
				if (damage( ch, victim, dam, gsn_hurl, DAM_PIERCE, true ))
				{
					if ( get_eq_char( victim, WEAR_LODGED_ARM ) != NULL ) {
						obj_to_room( dagger, ch->in_room );
						act( "$p doesn't lodge into your arm.", ch, dagger, victim, TO_VICT );
						act( "$p hurts $N but doesn't succesfully lodge.", ch, dagger, victim, TO_CHAR );
					    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
						{
							act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
							extract_obj( dagger );
						}
					}
					else
					{
						obj_to_char( dagger, victim );
						SET_BIT( dagger->extra_flags, OBJEXTRA_LODGED );
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_LODGED_ARM;
						wear_obj( victim, dagger, true, false);
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_WIELD;
					}
				}
				else
				{
					obj_to_room( dagger, ch->in_room );
				    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
					{
						act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
						extract_obj( dagger );
					}
				}
				check_improve( ch, gsn_hurl, true, 1 );
				break;
			case 6:
			case 7:
			case 8:
				obj_from_char( dagger );
				dam = 3 * ( dice( dagger->value[1], dagger->value[2] )/2);
				if ( damage( ch, victim, dam, gsn_hurl, DAM_PIERCE, true ))
				{
					if ( get_eq_char( victim, WEAR_LODGED_LEG ) != NULL ) {
						obj_to_room( dagger, ch->in_room );
						act( "$p doesn't lodge into your leg.", ch, dagger, victim, TO_VICT );
						act( "$p hurts $N but doesn't succesfully lodge.", ch, dagger, victim, TO_CHAR );
					    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
						{
							act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
							extract_obj( dagger );
						}
					}
					else
					{
						obj_to_char( dagger, victim );
						SET_BIT( dagger->extra_flags, OBJEXTRA_LODGED );
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_LODGED_LEG;
						wear_obj( victim, dagger, true, false);
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_WIELD;
					}
				}
				else
				{
					obj_to_room( dagger, ch->in_room );
				    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
					{
						act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
						extract_obj( dagger );
					}
				}
				check_improve( ch, gsn_hurl, true, 1 );
				break;
			case 9:
			case 10:
				obj_from_char( dagger );
				dam = 2 * ( dice( dagger->value[1], dagger->value[2] ));
				if ( damage( ch, victim, dam, gsn_hurl, DAM_PIERCE, true ))
				{
					if ( get_eq_char( victim, WEAR_LODGED_RIB ) != NULL ) {
						obj_to_room( dagger, ch->in_room );
						act( "$p doesn't lodge into your rib.", ch, dagger, victim, TO_VICT );
						act( "$p hurts $N but doesn't succesfully lodge.", ch, dagger, victim, TO_CHAR );
					    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
						{
							act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
							extract_obj( dagger );
						}
					}
					else
					{
						obj_to_char( dagger, victim );
						SET_BIT( dagger->extra_flags, OBJEXTRA_LODGED );
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_LODGED_RIB;
						wear_obj( victim, dagger, true, false);
						dagger->wear_flags = OBJWEAR_TAKE | OBJWEAR_WIELD;
					}
				}
				else
				{
					obj_to_room( dagger, ch->in_room );
				    if ( IS_OBJ_STAT( dagger, OBJEXTRA_MELT_DROP ))
					{
						act( "$p dissolves into smoke.", ch, dagger, NULL, TO_ROOM );
						extract_obj( dagger );
					}
				}
				check_improve( ch, gsn_hurl, true, 1 );
				break;
		}
	}
	return;
}
/**************************************************************************/	
void do_entangle( char_data *ch, char *)
{
    char_data *victim;
    OBJ_DATA *whip, *vObj;
    int chance,hth,ch_weapon,vict_weapon,ch_vict_weapon;

    hth = 0;

    if ((chance = get_skill(ch,gsn_entangle)) == 0)
    {
		do_huh(ch,"");
		return;
    }

	whip = get_eq_char( ch, WEAR_WIELD );

	if ( !whip )
	{
		ch->println("You must be wielding a whip to entangle.");
		return;
	}
	if ( whip->value[0] != WEAPON_WHIP )
	{
		ch->println("You must be wielding a whip to entangle.");
		return;
	}

    if (( victim = ch->fighting ) == NULL )
    {
		ch->println("You aren't fighting anyone.");
		return;
    }

    if (( vObj = get_eq_char( victim, WEAR_WIELD ) ) == NULL ) 
	if (( vObj = get_eq_char( victim, WEAR_SECONDARY) ) == NULL )
    {
		ch->println("Your opponent is not wielding a weapon.");
		return;
    }

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

    // find weapon skills
    ch_weapon = get_weapon_skill(ch,get_weapon_sn(ch));
    vict_weapon = get_weapon_skill(victim,get_weapon_sn(victim));
    ch_vict_weapon = get_weapon_skill(ch,get_weapon_sn(victim));

    // skill 
	chance = chance * ch_weapon/100;

    chance += (ch_vict_weapon/2 - vict_weapon) / 2; 

    // quickness/agility  vs. strength 
    chance += (ch->modifiers[STAT_QU] + ch->modifiers[STAT_AG])/2;
    chance -= 2 * victim->modifiers[STAT_ST];

    // level 
    chance += (ch->level - victim->level) * 2;
 
    // and now the attack 
    if (number_percent() < chance)
    {
		WAIT_STATE( ch, skill_table[gsn_entangle].beats );
		entangle( ch, victim );
		check_improve(ch,gsn_entangle,true,1);
    }
    else
    {
		WAIT_STATE(ch,skill_table[gsn_entangle].beats);
		act("You fail to grab their weapon.",ch,NULL,NULL,TO_CHAR);
		act("$n tries to entangle your weapon, but fails.",ch,NULL,victim,TO_VICT);
		act("$n tries to entangle $N's weapon, but fails.",ch,NULL,victim,TO_NOTVICT);
		check_improve(ch,gsn_entangle,false,1);
    }
    return;
}
/**************************************************************************/
void do_dervish( char_data *ch, char * )
{
	char_data	*pChar;
	char_data	*pChar_next = NULL;
	OBJ_DATA	*spear;
	bool		found = false;
	int			chance;
	
    if ( get_skill(ch,gsn_dervish) == 0 )
    {
		do_huh(ch,"");
		return;
    }
 
	spear = get_eq_char( ch, WEAR_WIELD );

	if ( !spear )
	{
		ch->println("You must be wielding a spear to perform this dance.");
		return;
	}
	if ( spear->value[0] != WEAPON_SPEAR )
	{
		ch->println("You must be wielding a spear to perform this dance.");
		return;
	}

	act( "$n holds $p firmly and begins to whirl about like a dervish...", ch, spear, NULL, TO_ROOM );
	act( "You hold $p firmly and begin to whirl like a maddened dervish...",  ch, spear, NULL, TO_CHAR );
   
	for ( pChar = ch->in_room->people; pChar; pChar = pChar_next )
	{
		chance = get_skill( ch, gsn_dervish );

		pChar_next = pChar->next_in_room;


		if ( is_safe( ch, pChar ))
			continue;

		if ( IS_AFFECTED( ch, AFF_CHARM )
		&& ch->master == pChar )
			continue;

		if ( IS_IMMORTAL( pChar )
		&& INVIS_LEVEL(pChar)>= LEVEL_IMMORTAL )
			continue;

		if ( is_same_group( ch, pChar ))
		{
			if ( number_percent() < 75 )
				continue;
		}
	
		if (number_percent() < chance)
		{
			act( "With a crazed look, $n turns towards YOU!", ch, NULL, pChar, TO_VICT );
			one_hit( ch, pChar, gsn_dervish, false );
			if ( pChar != ch )
				found = true;
		}
	}
   
	if ( !found )
	{
		ch->println("You feel dizzy, and a tiny bit embarassed.");
		if (( number_percent() < 10 ) && !IS_IMMORTAL( ch ))
		{
			act( "$n drops $p.", ch, spear, NULL, TO_ROOM );
			act( "You drop $p.", ch, spear, NULL, TO_CHAR );
			obj_from_char( spear );
			obj_to_room( spear, ch->in_room );
			check_improve( ch, gsn_dervish, false, 1 );
		}
	}
	else
		check_improve( ch, gsn_dervish, true, 1 );

	WAIT_STATE( ch, skill_table[gsn_dervish].beats );
	ch->move = int( ch->move * 0.9 );

	if ( number_percent() < 25 )
	{
		act( "$n loses $s balance and falls into a heap.", ch, NULL, NULL, TO_ROOM );
		ch->println("You lose your balance and fall into a heap.");
		ch->position = POS_RESTING;
	}
	return;
}
/**************************************************************************/
void do_cutoff( char_data *ch, char * )
{
	if ( get_skill( ch, gsn_cutoff) == 0 ) {
		do_huh(ch,"");
		return;
	}

	if ( ch->position != POS_FIGHTING ) {
		ch->println("You can only use this during combat.");
		return;
	}

	if ( !IS_SET( ch->dyn, DYN_IS_CUTTING_OFF )) {
		ch->println("You will now cut off fleeing or retreating enemies.");
		SET_BIT( ch->dyn, DYN_IS_CUTTING_OFF );
	} else {
		ch->println("You will no longer cut off fleeing or retreating enemies.");
		REMOVE_BIT( ch->dyn, DYN_IS_CUTTING_OFF );
	}

	return;
}
/**************************************************************************/
void do_sheathe( char_data *ch, char * )
{
	OBJ_DATA	*weapon = get_eq_char( ch, WEAR_WIELD );

	if ( get_eq_char( ch, WEAR_SHEATHED ) != NULL )
	{
		ch->println("You already have a weapon sheathed, use draw to remove it.");
		return;
	}

	if ( !weapon )
	{
		ch->println("You must be wielding a weapon in order to sheathe it.");
		return;
	}

	if ( weapon->value[0] == WEAPON_EXOTIC
	||   weapon->value[0] == WEAPON_STAFF
        ||      weapon->value[0] == WEAPON_SPEAR
	||	 weapon->value[0] == WEAPON_POLEARM )
	{
		ch->println("You cannot sheathe that weapon.");
		return;
	}

	if ( IS_WEAPON_STAT(weapon,WEAPON_TWO_HANDS)) {
		act ( "$p is too large to be sheathed properly.", ch, weapon, NULL, TO_CHAR );
		return;
	}

	if ( !IS_IMMORTAL( ch) && IS_SET( weapon->extra_flags, OBJEXTRA_NOREMOVE) )
    {
		act( "You can't remove $p.", ch, weapon, NULL, TO_CHAR );
		return;
    }

	unequip_char( ch, weapon );
	weapon->wear_loc = WEAR_SHEATHED;
	act( "With a flourish, you sheathe $p.", ch, weapon, NULL, TO_CHAR );
	act( "With a flourish, $n sheathes $p.", ch, weapon, NULL, TO_ROOM );

	return;
}
/**************************************************************************/
DECLARE_DO_FUN( do_stand );
/**************************************************************************/
void do_draw( char_data *ch, char * )
{
	OBJ_DATA	*weapon = get_eq_char( ch, WEAR_SHEATHED );

	if ( !weapon )
	{
		ch->println("You don't have a weapon sheathed.");
		return;
	}

	if ( get_eq_char( ch, WEAR_WIELD ) != NULL )
	{
		ch->println("You must have a free hand to draw a weapon.");
		return;
	}

	if ( !IS_IMMORTAL(ch) && IS_SET( weapon->extra_flags, OBJEXTRA_NOREMOVE ))
    {
		act( "You can't remove $p.", ch, weapon, NULL, TO_CHAR );
		return;
    }

	if ( ch->position < POS_STANDING )
	{
		do_stand(ch, "");
		if(ch->position < POS_STANDING){
			return;
		}
	}

	equip_char( ch, weapon, WEAR_WIELD );
	act( "You draw $p with unequaled grace.", ch, weapon, NULL, TO_CHAR );
	act( "$n draws $p.", ch, weapon, NULL, TO_ROOM );

	return;
}
/**************************************************************************/
void do_conceal( char_data *ch, char * )
{
	OBJ_DATA	*weapon = get_eq_char( ch, WEAR_WIELD );

	if ( !IS_IMMORTAL( ch ))
	{
		if ( ch->specialization != SPECIALIZE_DAGGER )
		{
			do_huh(ch,"");
			return;
		}
	}

	if ( get_eq_char( ch, WEAR_CONCEALED ) != NULL )
	{
		ch->println("You may only have one weapon concealed.");
		return;
	}

	if ( !weapon )
	{
		ch->println("You must be wielding your dagger in order to conceal it.");
		return;
	}

	if ( weapon->value[0] != WEAPON_DAGGER )
	{
		ch->println("You can only conceal daggers.");
		return;
	}

	if ( !IS_IMMORTAL(ch) && IS_SET( weapon->extra_flags, OBJEXTRA_NOREMOVE) )
    {
		act( "You can't remove $p.", ch, weapon, NULL, TO_CHAR );
		return;
    }

	unequip_char( ch, weapon );
	weapon->wear_loc = WEAR_CONCEALED;
	act( "When no one is looking, you secretly conceal $p.", ch, weapon, NULL, TO_CHAR );

	return;
}
/**************************************************************************/
// CELRION
void do_charge( char_data *ch, char *argument )
{
	char			arg[MIL], dir[MIL];
	char_data		*victim		= NULL;
	char_data		*mount;
	OBJ_DATA		*polearm	= NULL;
	ROOM_INDEX_DATA *in_room;
	ROOM_INDEX_DATA *to_room	= NULL;
	EXIT_DATA *pexit;
	int				door;
	int				chance;
	int				dam;

	chance = get_skill( ch, gsn_charge );
	if ( chance < 1)
	{
		do_huh(ch,"");
		return;
	}

	if ( !IS_RIDING( ch ))
	{
		ch->println("You need to be mounted to charge.");
		return;
	}

	mount = ch->mounted_on;

	polearm = get_eq_char( ch, WEAR_WIELD );

	if ( !polearm )
	{
		ch->println("You need to wield a polearm first.");
		return;
	}

	if ( polearm->value[0] != WEAPON_POLEARM )
	{
		ch->println("You can only charge with polearms.");
		return;
	}

	//Insert Specialization check (somewhere near here at least)

	argument = one_argument ( argument, dir );
	one_argument ( argument, arg );

	if (arg[0] == '\0')
	{
		ch->println("Charge who or what?");
		return;
	}

	door = dir_lookup( dir );
	
    if ( door == -1 )
	{
		ch->printlnf("'%s' is an invalid direction.", dir); 
		ch->println("Syntax: charge <direction> <name>");
		return;
    }

	in_room = ch->in_room;

	if ( ( pexit   = in_room->exit[door] ) == NULL
		||   ( to_room = pexit->u1.to_room   ) == NULL 
		||   !can_see_room(ch,pexit->u1.to_room))
    {
		ch->println("Alas, you cannot go that way.");
		return;
    }

	if (IS_SET(pexit->exit_info, EX_CLOSED)
		&&  (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_NOPASS))
		&&   !IS_SET(TRUE_CH(ch)->act, PLR_HOLYWALK))
    {
		
		act( "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
		return;
    }

	switch (door)
	{
		case 4:
			act( "$n charges upward!", ch, NULL, NULL, TO_ROOM);
			break;
		case 5:
			act( "$n charges down!", ch, NULL, NULL, TO_ROOM);
			break;
		default:
			act( "$n charges to the $T!", ch, NULL, dir_name[door], TO_ROOM);
			break;
	}

	act( "You charge $T!", ch, NULL, dir_name[door], TO_CHAR );
	
	char_from_room(ch);
	char_to_room(ch, to_room);
	char_from_room(mount);
	char_to_room(mount, to_room);

	if ((victim = get_char_room(ch,arg)) == NULL)
	{
		ch->println("They aren't here.");
		act( "$n charges into the room and looks around quizzically.", ch, NULL, NULL, TO_ROOM);
		return;
	}

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

	if( is_safe (ch, victim) )
		return;

	if ( !can_initiate_combat( ch, victim, CIT_GENERAL )) return;

    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }

	//Stole chance mods from bash, I liked 'em.

    chance += ch->modifiers[STAT_ST];
    chance -= victim->modifiers[STAT_QU];
    chance -= GET_AC(victim,AC_PIERCE) /25;

    if (IS_SET(mount->off_flags,OFF_FAST) || IS_AFFECTED(mount,AFF_HASTE))
		chance += 10;
    if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
		chance -= 30;

    chance += (((ch->level + mount->level)/2) - victim->level);

    if (!IS_NPC(victim) && chance < get_skill(victim,gsn_dodge) )
		chance -= 3 * (get_skill(victim,gsn_dodge) - chance);

	//Move suckdown, also if tired then chance is slashed greatly.

	if( mount->move < mount->max_move/2 ) chance /= 2;
	if( !IS_NPC (ch) && ch->pcdata->tired > 16 ) chance /= 2;
	
	//Actually hitting at this point.

    if (number_percent() < chance )
    {
		act("$n charges into the room and hits you with $p!", ch,polearm, victim,TO_VICT);
		act("You charge into the room and slam $N!",ch,NULL,victim,TO_CHAR);
		act("$n charges into the room and slams right into $N!", ch,NULL,victim,TO_NOTVICT);
		check_improve(ch,gsn_charge,true,1);
		
		DAZE_STATE(victim, 3 * PULSE_VIOLENCE);
		WAIT_STATE(ch,skill_table[gsn_charge].beats);
		if( IS_RIDING (victim))
		{
			if ( number_range(1,3) > 1)
			{
				dismount(victim);
				victim->position = POS_RESTING;
				act("You have been dismounted!", ch, NULL, victim, TO_VICT );
				act("$N has been dismounted!", ch, NULL, victim, TO_NOTVICT );
				act("You have dismounted $N!", ch, NULL, victim, TO_CHAR );
			}
		}

		dam = 3 * ( dice( polearm->value[1], polearm->value[2] ));
		dam	+= 2 * ch->size + chance/10;

		damage( ch, victim, dam, gsn_charge, DAM_PIERCE, true );

		//Stole damage from bash but moreso.
	}
	else
	{
		damage(ch,victim,0,gsn_charge,DAM_BASH,false);
		act("You charge into the room and miss $N completely!",
			ch,NULL,victim,TO_CHAR);
		act("$n charges at $N and completely misses!",
			ch,NULL,victim,TO_NOTVICT);
		act("$n charges right past you, in a vain attempt to hit you!",
			ch,NULL,victim,TO_VICT);
		check_improve(ch,gsn_charge,false,1);
		WAIT_STATE(ch,skill_table[gsn_charge].beats * 3/2); 
    }
	mount->move -= mount->move / 3;
}
/**************************************************************************/
void do_overhead( char_data *ch, char *argument )
{
    char_data * victim;
    OBJ_DATA  * axe;
	OBJ_DATA  * helm;
    char        arg[MIL];
    int         chance, dam;

	if ((chance = get_skill(ch,gsn_shieldcleave)) == 0)
	{
		do_huh(ch,"");
		return;
	}

    one_argument( argument, arg );

    axe = ( get_eq_char( ch, WEAR_WIELD ));

    if ( !axe ) {
        ch->println("You need to wield an axe to do an overhead swing.");
        return;
    }
    
	if ( axe ) {
        if ( axe->value[0] != WEAPON_AXE )
		{
			ch->println("You are not wielding an axe.");
            return;
        }
    }

    if (( victim = ch->fighting ) == NULL ) {
		ch->println("You aren't fighting anyone.");
		return;
    }

 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}

	helm = ( get_eq_char( victim, WEAR_HEAD ));
	
    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }

	if ( is_safe( ch, victim ))
		return;

// INSERT WEAPON SPECIALIZATION CHECK HERE

	dam = dice( axe->value[1], axe->value[2] );

	if ( helm )
	{
	    if ( get_skill( ch, gsn_overhead ) > number_percent() )
		{
			chance = 50;
			if IS_WEAPON_STAT( axe, WEAPON_SHARP )		chance += 10;
			if IS_WEAPON_STAT( axe, WEAPON_VORPAL )		chance += 20;
			if IS_WEAPON_STAT( axe, WEAPON_FROST )		chance += 10;
			if IS_WEAPON_STAT( axe, WEAPON_FLAMING )	chance += 5;
			if IS_WEAPON_STAT( axe, WEAPON_SHOCKING )	chance += 5;
			if IS_OBJ_STAT( helm,	OBJEXTRA_BLESS )		chance -= 25;
			if IS_OBJ_STAT( helm,	OBJEXTRA_MAGIC )		chance -= 20;
			if IS_OBJ_STAT( helm,	OBJEXTRA_GLOW )			chance -=  5;
			if IS_OBJ_STAT( helm,	OBJEXTRA_CHAOS )		chance -= number_range(1,25);
			if IS_OBJ_STAT( helm,	OBJEXTRA_HUM )			chance -=  5;
			if IS_OBJ_STAT( helm,	OBJEXTRA_NONMETAL )		chance += 10;
			if IS_OBJ_STAT( helm,	OBJEXTRA_BURN_PROOF )	chance -= 35;

			if ( number_range( 1, 100 ) < chance )
			{
				helm->condition -= axe->level;

				if ( helm->condition <= 0 )
				{
					act( "Your axe `Bslices`x through $p, destroying it.", ch, helm, NULL, TO_CHAR );
					act( "$n `Bslices`x $p.", ch, helm, NULL, TO_NOTVICT );
					act( "$n has `Bdestroyed`x $p.", ch, helm, victim, TO_VICT );
					extract_obj( helm );
					dam *= 3/2;
				}
				else
				{
					act( "Your axe dents $p worn by your opponent.", ch, helm, NULL, TO_CHAR );
					act( "$n dents your $p.", ch, helm, victim, TO_VICT );
					dam *= 3/4;
				}
			}
			else
			{
				act( "$N's helm remains unscathed!", ch, NULL, victim, TO_CHAR );
				act( "$p resonates agains $N's swing, but holds firm.", ch, axe, victim, TO_VICT );
				dam /= 2;
			}
			check_improve( ch, gsn_overhead, true, 1 );
			WAIT_STATE( ch, skill_table[gsn_overhead].beats );
		}
		else
		{
			check_improve( ch, gsn_overhead, false, 1 );
			act( "$N deftly evades your blow.", ch, NULL, victim, TO_CHAR );
			act( "$n tries to split $N in two but misses.", ch, NULL, victim, TO_NOTVICT);
			act( "$n tries to split you in two but misses.", ch, NULL, victim, TO_VICT );
	        WAIT_STATE( ch, skill_table[gsn_overhead].beats );
	    }
	}
	else
	{
	    if ( get_skill( ch, gsn_overhead ) > number_percent())
		{
			dam *= 3/2;
			check_improve( ch, gsn_overhead, true, 1 );
	        WAIT_STATE( ch, skill_table[gsn_overhead].beats );
		}
		else
		{
			dam *= 0;
			check_improve( ch, gsn_overhead, false, 1 );
	        WAIT_STATE( ch, skill_table[gsn_overhead].beats * 3/2 );
			act( "$N deftly evades your blow.", ch, NULL, victim, TO_CHAR );
			act( "$n tries to split $N in two but misses.", ch, NULL, victim, TO_NOTVICT);
			act( "$n tries to split you in two but misses.", ch, NULL, victim, TO_VICT );
		}
	}
	
	if ( dam )
		damage( ch, victim, dam, gsn_overhead, DAM_BASH, true );
	else
		damage( ch, victim, dam, gsn_overhead, DAM_BASH, false );

	return;
}
/**************************************************************************/
void do_boneshatter( char_data *ch, char *argument )
{
    char_data * victim;
    OBJ_DATA  * mace;
    char        arg[MIL];
    int         chance;
	
	if ((chance = get_skill(ch,gsn_boneshatter)) == 0)
	{
		do_huh(ch,"");
		return;
	}
	
	one_argument( argument, arg );

	mace = ( get_eq_char( ch, WEAR_WIELD ));

    if ( !mace ) {
        ch->println("You need to wield a mace to shatter bones.");
        return;
    }
    
	if ( mace ) {
        if ( mace->value[0] != WEAPON_MACE ) {
            ch->println("You are not wielding a mace.");
            return;
        }
    }
	
    if ( IS_NULLSTR( arg )) {
        if (( victim = ch->fighting ) == NULL ) {
            ch->println("But you aren't fighting anyone!");
            return;
        }
    }
    else if (( victim = get_char_room( ch, arg )) == NULL ) {
        ch->printlnf("You can't seem to find '%s' here.", arg);
        return;
    }
	
 	if(ch == victim)
 	{
     	    ch->println("Yeah, right.");
      	   return;
    	}
	
	if ( is_safe( ch, victim ))
		return;
		
    if ( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim ) {
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);
		return;
    }
	
		// INSERT WEAPON SPECIALIZATION CHECK HERE
	
    if ( get_skill( ch,gsn_boneshatter ) > ( number_percent() + 20 ))
	{
        act( "You smash $p against $N.", ch, mace, victim, TO_CHAR );
		act( "$n smashes $p against $N!", ch, mace, victim, TO_NOTVICT );
		act( "$n smashes $p against you!", ch, mace, victim, TO_VICT );
        if ( damage( ch, victim, dice( mace->value[1], mace->value[2] ),
			 gsn_boneshatter, DAM_BASH, true ))
		{
			AFFECT_DATA		af;

			if ( !is_affected( victim, gsn_boneshatter )) {

				af.where		= WHERE_AFFECTS;
				af.type			= gsn_boneshatter;
				af.level		= ch->level;
				af.duration		= ch->level/10;
				af.modifier		= -10;
				af.bitvector	= 0;
			    af.location		= APPLY_ST;
			    affect_to_char( victim, &af );
				af.where		= WHERE_AFFECTS;
				af.modifier		= -10;
				af.bitvector	= 0;
				af.location		= APPLY_AG;
				affect_to_char( victim, &af );
				act( "You hear the sickening sound of bones crunching.", ch, NULL, NULL, TO_CHAR );
				act( "PAIN! The sickening sound of your bones crunching overwhelms you.", ch, NULL, victim, TO_VICT );
				act( "$N looks like $e is in a world of pain.", ch, NULL, victim, TO_NOTVICT );
			}
			victim->position = POS_RESTING;
			DAZE_STATE( victim, skill_table[gsn_boneshatter].beats*2/3 );
		}
		check_improve( ch, gsn_boneshatter, true, 1 );
		WAIT_STATE( ch, skill_table[gsn_boneshatter].beats );
	}
    else
	{
        damage( ch, victim, 0, gsn_boneshatter, DAM_BASH, false );
        check_improve( ch, gsn_boneshatter, false, 1 );
		
		ch->println("You swing wildly and don't manage to connect the blow.");
		
        WAIT_STATE( ch, skill_table[gsn_boneshatter].beats );
    }
    return;
}

/**************************************************************************/
void do_bury( char_data *ch, char *argument )
{
	OBJ_DATA	*obj;
	OBJ_DATA	*contents;
	OBJ_DATA	*shovel;
	bool		fshovel = false;
	char		arg[MIL];

	one_argument( argument, arg );

	if ( arg[0] == '\0' )
	{
		ch->println("Bury what?");
		return;
	}

    for ( shovel = ch->carrying; shovel; shovel = shovel->next_content )
    {
        if ( !str_cmp( shovel->pIndexData->material, "shovel" )
			 && ( shovel->wear_loc == WEAR_HOLD
			 ||   shovel->wear_loc == WEAR_WIELD )) {
			fshovel = true;
            break;
		}
    }

	if ( !fshovel ) {
        ch->println("You must be holding a shovel to dig with.");
        return;
	}	

	obj = get_obj_list( ch, arg, ch->in_room->contents );
	
	if ( obj ==  NULL )
	{
		act( "I see not $T here.", ch, NULL, arg, TO_CHAR );
		return;
	}

	if ( !IS_OUTSIDE( ch )
		|| ch->in_room->sector_type == SECT_CITY
		|| ch->in_room->sector_type == SECT_UNDERWATER
		|| ch->in_room->sector_type == SECT_WATER_SWIM
		|| ch->in_room->sector_type == SECT_WATER_NOSWIM
		|| ch->in_room->sector_type == SECT_AIR ) {

		ch->println("You can't bury anything here.");
		return;
	}

	if (   obj->item_type == ITEM_FURNITURE			// prevent stupid item burials
		|| obj->item_type == ITEM_PORTAL
		|| obj->item_type == ITEM_TOKEN
		|| obj->item_type == ITEM_FOUNTAIN
		|| obj->item_type == ITEM_BOAT )
	{
		ch->println("You can't bury that.");
		return;
	}

	if ( !IS_NPC( ch ))
	{
		if ( !IS_IMMORTAL( ch ))
		{
			++ch->pcdata->tired;
			WAIT_STATE( ch, 36 );
		}

		if (   obj->item_type == ITEM_CORPSE_PC
			|| obj->item_type == ITEM_CORPSE_NPC )
		{
			act( "You dig a grave and place $p within.",  ch, obj, NULL, TO_CHAR );
			act( "$n digs a grave and places $p within.", ch, obj, NULL, TO_ROOM );
			++ch->pcdata->tired;					// graves are tiresome :)
		}
		else
		{
			act( "You dig a hole and place $p within.",  ch, obj, NULL, TO_CHAR );
			act( "$n digs a hole and places $p within.", ch, obj, NULL, TO_ROOM );
		}
	}

	// Set corpse and all it's potential items as buried

	SET_BIT( obj->extra2_flags, OBJEXTRA2_BURIED );

	// Only set PC_CORPSE items as buried since NPC_CORPSE items poof when the corpse does
	// Container contents dont need to be flagged as buried

	if ( obj->item_type == ITEM_CORPSE_PC )
	{
		for ( contents = obj->contains; contents; contents = contents->next_content )
		{
			SET_BIT( contents->extra2_flags, OBJEXTRA2_BURIED );
		}
	}
	return;
}

/**************************************************************************/
void do_dig( char_data *ch,	char * )
{
	OBJ_DATA	*obj;
	OBJ_DATA	*pcCorpse;
	OBJ_DATA	*shovel;
	bool		found = false;
	bool		fshovel = false;

    for ( shovel = ch->carrying; shovel; shovel = shovel->next_content )
    {
        if ( !str_cmp( shovel->pIndexData->material, "shovel" )
			 && ( shovel->wear_loc == WEAR_HOLD
			 ||   shovel->wear_loc == WEAR_WIELD )) {
			fshovel = true;
            break;
		}
    }

	if ( !fshovel )
	{
        ch->println("You must be holding a shovel to dig with.");
        return;
	}	

	if ( !IS_OUTSIDE( ch )
		|| ch->in_room->sector_type == SECT_CITY
		|| ch->in_room->sector_type == SECT_UNDERWATER
		|| ch->in_room->sector_type == SECT_WATER_SWIM
		|| ch->in_room->sector_type == SECT_WATER_NOSWIM
		|| ch->in_room->sector_type == SECT_AIR )
	{

		ch->println("You can't dig here.");
		return;
	}


	for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
	{
		if ( IS_SET( obj->extra2_flags, OBJEXTRA2_BURIED ))
		{
			REMOVE_BIT( obj->extra2_flags, OBJEXTRA2_BURIED );
			found = true;
			if ( obj->item_type == ITEM_CORPSE_PC )
			{
				for ( pcCorpse = obj->contains; pcCorpse; pcCorpse = pcCorpse->next_content )
				{
					REMOVE_BIT( pcCorpse->extra2_flags, OBJEXTRA2_BURIED );
				}
			}
		}
	}

	if ( !IS_NPC( ch ))	{
		if ( !IS_IMMORTAL( ch )) {
			++ch->pcdata->tired;
			WAIT_STATE( ch, 36 );
		}
		act( "You begin to dig.", ch, NULL, NULL, TO_CHAR );
		act( "$n begins to dig.", ch, NULL, NULL, TO_ROOM );
	}

	if ( found ) {
		act( "You have unearthed something.", ch, NULL, NULL, TO_CHAR );
		act( "$n has unearthed something.", ch, NULL, NULL, TO_ROOM );
	}
}

/**************************************************************************/
void do_shadow( char_data *ch, char *argument )
{
    char		arg[MIL];
    char_data	*victim;
	int			chance = get_skill( ch, gsn_shadow );

	one_argument( argument, arg );

	if ( chance < 1 )
	{
		ch->println("Your attempts at shadowing someone would be useless.");
		return;
	}

	if ( arg[0] == '\0' )
	{
		ch->println("Who do you want to shadow?");
		return;
	}

	if (( victim = get_char_room( ch, arg )) == NULL )
    {
		ch->println("They aren't here.");
		return;
    }

	if ( IS_AFFECTED(ch, AFF_CHARM) && ch->master != NULL )
    {
		ch->println("You're too busy following someone else.");
		return;
	}

	if ( victim == ch )
	{
		if ( ch->master == NULL )
		{
			ch->println("You stalk yourself like a fool.");
			return;
		}
		SET_BIT( ch->dyn, DYN_SILENTLY );
		stop_follower(ch);
		REMOVE_BIT( ch->dyn, DYN_SILENTLY );
		return;
	}

	if (IS_IMMORTAL(victim))
	{
		ch->println("Ok.");
		return;
    }

	if ( ch->master != NULL )
	{
		SET_BIT( ch->dyn, DYN_SILENTLY );
		stop_follower( ch );
		REMOVE_BIT( ch->dyn, DYN_SILENTLY );
	}

	SET_BIT( ch->dyn, DYN_SILENTLY );
	add_follower( ch, victim );
	REMOVE_BIT( ch->dyn, DYN_SILENTLY );

	ch->println("Ok.");

    if ( chance > number_percent() )
	{
		check_improve( ch, gsn_shadow, true, 2 );
	}
	else
	{
		check_improve( ch, gsn_shadow, false, 4 );
		victim->println("You have a feeling someone is following you.");
	}

	return;
}

/**************************************************************************/
void do_cannibalize( char_data *ch, char * )
{
	int		chance	= get_skill( ch, gsn_cannibalize );
	int		gain	= UMIN( 50, ch->level * 5 );

	if ( chance < 1 )
	{
		do_huh( ch, "" );
		return;
	}

	if (ch->fighting != NULL)
	{
		ch->println("You cannot do this while fighting.");
        return;
    }

	gain += UMAX( -25, chance - 75 );

	if ( (ch->hit) <= gain )
	{
		ch->println("You would surely die if you tried this now.");
		return;
	}

	ch->println("You draw magical power from your life force.");
	act( "$n is enveloped in a cold blue aura.", ch, NULL, NULL, TO_ROOM );
	ch->hit  -= gain;
	ch->mana += gain;

	WAIT_STATE( ch, 18 );
	check_improve(	ch, gsn_cannibalize, true, 1 );
	return;	
}

/**************************************************************************/
void do_fork( char_data *ch, char *argument )
{
	int	mana, roll;

	REMOVE_BIT( ch->dyn, DYN_SUCCESS_CAST );

	do_cast(ch,argument);
	roll = number_percent();

	if ( IS_SET( ch->dyn, DYN_SUCCESS_CAST ) && roll < get_skill(ch,gsn_fork) / 4 )
	{
		ch->println("You successfully forked the spell!");
		mana = ch->mana;
		do_cast( ch, argument );
		ch->mana = mana - (roll / 6);
		check_improve(ch,gsn_fork,true,1);
	}

	return;
}

/**************************************************************************/
void do_flourish( char_data *ch, char *argument )
{
	OBJ_DATA * obj = get_eq_char( ch, WEAR_WIELD );

	if ( !obj ){
		ch->println( "You are not wielding a druidic staff." );
		return;
	}
	
	if(obj->pIndexData->vnum==OBJ_VNUM_DRUIDSTAFF){
		ch->println( "Your druidstaff has no additional powers." );
	}else if (obj->pIndexData->vnum==OBJ_VNUM_TOTEMSTAFF){
		if ( !str_cmp( argument, "totemguardian" )){
			flourish_totemstaff_guardian( ch, obj );
		}
		if ( !str_cmp( argument, "totemspirit" )){
			flourish_totemstaff_spirit( ch, obj );
		}
	}
	return;
}

/**************************************************************************/
void flourish_totemstaff_guardian( char_data *ch, OBJ_DATA *obj )
{
	MOB_INDEX_DATA *pMob;
	char_data *totem;
	int vnum;
	int month = get_birthmonth( ch );
	int foo, i;		// reusable piece of junk generic var

	if ( month < 0 )
	{
		ch->println( "You have not chosen your age yet.  Type help setage to see how this is done." );
		return;
	}

	vnum = MOB_VNUM_TOTEM_BEAR + month;	// Bear = 60 and is used as an offset

	if (( pMob = get_mob_index( vnum )) == NULL )
	{
		ch->printf( "Vnum %d not found for your totem mob, please report to the admin.", vnum );
		return;
	}
	
	// Make the mob
	totem = create_mobile( pMob, UMIN( ch->level, 99));
	totem->level		= UMIN( ch->level, 99);

	// determine it's hitpoints
	foo  = dice( mob_balance_lookup( totem->level, 0 ),
				 mob_balance_lookup( totem->level, 1 ));

	totem->max_hit		= foo + mob_balance_lookup( totem->level, 2 );
	totem->hit			= totem->max_hit;

	// determine it's AC
	foo = mob_balance_lookup( totem->level, MOB_BALANCE_AC );

	for ( i = 0; i < 4; i++ )
		totem->armor[i] = foo;

	// determine it's damage
	totem->damage[DICE_NUMBER]	= mob_balance_lookup( totem->level, MOB_BALANCE_NUM_DAM_DIE );
	totem->damage[DICE_TYPE]	= mob_balance_lookup( totem->level, MOB_BALANCE_DAM_DIE_TYPE );
	totem->damage[DICE_BONUS]	= mob_balance_lookup( totem->level, MOB_BALANCE_DAM_BONUS );

	// set it to follow the druid
	add_follower( totem, ch );
	totem->leader = ch;

	ch->println( "You flourish your druidstaff which pulsates with a greenish glow and vanishes from your hands." );
	act( "$n flourishes $s druidstaff which pulsates in a greenish glow.", ch, obj, NULL, TO_ROOM );
    char_to_room( totem, ch->in_room);  // send mob to summoner
	act( "$n has suddenly arrived.", totem, NULL, NULL, TO_ROOM );
	act("$N looks at you with adoring eyes.", ch, NULL, totem, TO_CHAR );
	SET_BIT( totem->affected_by, AFF_CHARM );
	extract_obj( obj );					// nuke the staff

	return;
}
/**************************************************************************/
void flourish_totemstaff_spirit( char_data *ch, OBJ_DATA *)
{ 
	ch->println("flourish_totemstaff_spirit(): not yet implemented.");
}
/**************************************************************************/
void do_herblore( char_data *ch, char *argument )
{
	char arg[MIL];
	OBJ_DATA *herb;
	HERB_DATA *h;
	int chance = get_skill( ch, gsn_herblore);
	int skillroll;

	if ( IS_OOC( ch ))
	{
		ch->println( "Not in an OOC room." );
		return;
	}

	if ( chance == 0 )
	{
		ch->println( "You know nothing about herbs." );
		return;
	}

	one_argument( argument, arg );
	
	if ( arg[0] == '\0' )
	{
		ch->println( "Learn about which herb?" );
		return;
	}

	herb = get_obj_list( ch, argument, ch->carrying );

	if ( herb == NULL )
	{
		ch->println( "You don't have that herb." );
		return;
	}

	if ( herb->item_type != ITEM_HERB )
	{
		ch->println( "That is not an herb." );
		return;
	}

	h = find_herb( ch, arg );

	if ( !h )
	{
		ch->println( "You couldn't learn anything from that particular herb." );
		return;
	}

	skillroll = number_range( 1, 100 );

	if ( skillroll > ( chance - h->difficulty ))
	{
		ch->println( "You couldn't learn anything useful." );
		check_improve( ch, gsn_herblore, false, 2 );
		return;
	}

	switch (number_range( 1, 5 ))
	{
	case (1):
		ch->printlnf( "%s only grows %s.",
			h->name,
			sector_desc[h->sector].name );
		break;
	case (2):
		if ( !h->continent)	{
			ch->printlnf( "%s is prolific, and can be found in any continent of %s.",
				h->name, capitalize(game_settings->realm_name));
		}else{
			ch->printlnf( "%s is indigenous to %s.",
				h->name,
				h->continent->name );
		}
		break;
	case (3):
		if ( h->month == -1 )
		{
			ch->printlnf( "%s is a perennial plant.",
				h->name );
		}
		else
		{
			ch->printlnf( "%s only grows in the month of %s.",
				h->name,
				month_name[h->month] );
		}
		break;
	case (4):
		if ( h->season == -1 )
		{
			ch->printlnf( "%s is a perennial plant.",
				h->name );
		}
		else
		{
			ch->printlnf( "%s only grows during the season of %s.",
				h->name,
				season_table[h->season].name );
		}
		break;
	case (5):
		if ( timefield_table[h->timefield].lowhour == -1 )
		{
			ch->printlnf( "%s may be harvested successfully at any time of the day or night.",
				h->name );
		}
		else
		{
			ch->printlnf( "%s can only be successfully harvested %s.",
				h->name,
				timefield_table[h->timefield].name );
		}
		break;
	}

	act( "$n studies $p.", ch, herb, NULL, TO_ROOM );

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

	check_improve( ch, gsn_herblore, true, 5 );

    return;
}



/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/