zim/area/
zim/bin/
zim/clans/plists/
zim/corefiles/
zim/doc/muddy/
zim/gods/
zim/log/
zim/player/
zim/skill_tree/
zim/tmp/
/*
 * $Id: skills.c 978 2006-12-08 07:38:16Z zsuzsu $
 */

/***************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR  *
 *     ANATOLIA has been brought to you by ANATOLIA consortium		   *
 *	 Serdar BULUT {Chronos} 	bulut@rorqual.cc.metu.edu.tr	   *
 *	 Ibrahim Canpunar  {Asena}	canpunar@rorqual.cc.metu.edu.tr    *
 *	 Murat BICER  {KIO}		mbicer@rorqual.cc.metu.edu.tr	   *
 *	 D.Baris ACAR {Powerman}	dbacar@rorqual.cc.metu.edu.tr	   *
 *     By using this code, you have agreed to follow the terms of the	   *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence		   *
 ***************************************************************************/

/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,	   *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *									   *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	   *
 *  Chastain, Michael Quan, and Mitchell Tse.				   *
 *									   *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc	   *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.						   *
 *									   *
 *  Much time and thought has gone into this software and you are	   *
 *  benefitting.  We hope that you share your changes too.  What goes	   *
 *  around, comes around.						   *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1995 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@pacinfo.com)				   *
*	    Gabrielle Taylor (gtaylor@pacinfo.com)			   *
*	    Brian Moore (rom@rom.efn.org)				   *
*	By using this code, you have agreed to follow the terms of the	   *
*	ROM license, in the file Rom24/doc/rom.license			   *
***************************************************************************/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>

#if !defined(WIN32)
#	include <unistd.h>
#endif
#include <ctype.h>

#include "merc.h"
#include "debug.h"
#include "update.h"
#include "quest.h"
#include "obj_prog.h"
#include "fight.h"
#include "healer.h"
#include "stats.h"

/* command procedures needed */
DECLARE_DO_FUN(do_exits		);
DECLARE_DO_FUN(do_look		);
DECLARE_DO_FUN(do_help		);
DECLARE_DO_FUN(do_affects	);
DECLARE_DO_FUN(do_murder	);
DECLARE_DO_FUN(do_say		);
DECLARE_DO_FUN(do_alist		);
DECLARE_DO_FUN(do_yell		);


/*
 * deprecated
 */
void do_pick(CHAR_DATA *ch, const char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *gch;
	OBJ_DATA *obj;
	int door;
	int chance;

	if ((chance = get_skill(ch, gsn_pick)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	one_argument(argument, arg, sizeof(arg));

	if (arg[0] == '\0') {
		char_puts("Pick what?\n", ch);
		return;
	}

	if (MOUNTED(ch)) {
		  char_puts("You can't pick while mounted.\n", ch);
		  return;
	}

	WAIT_STATE(ch, SKILL(gsn_pick)->beats);

	/* look for guards */
	for (gch = ch->in_room->people; gch; gch = gch->next_in_room) {
		if (IS_NPC(gch)
		&&  IS_AWAKE(gch)
		&&  ch->level + 5 < gch->level) {
			act("$N is standing too close to lock.",
			    ch, NULL, gch, TO_CHAR);
			return;
		}
	}

	if (!IS_NPC(ch) && number_percent() > chance) {
		char_puts("You failed.\n", ch);
		check_improve(ch, gsn_pick, FALSE, 2);
		return;
	}

	if ((obj = get_obj_here(ch, arg)) != NULL) {
		/* portal stuff */
		if (obj->pIndexData->item_type == ITEM_PORTAL) {
		    if (!IS_SET(obj->value[ITEM_PORTAL_EXIT_FLAGS],EX_ISDOOR)) {	
			char_puts("You can't do that.\n", ch);
			return;
		    }

		    if (!IS_SET(obj->value[ITEM_PORTAL_EXIT_FLAGS],EX_CLOSED)) {
			char_puts("It's not closed.\n", ch);
			return;
		    }

		    if (obj->value[ITEM_PORTAL_KEY] < 0) {
			char_puts("It can't be unlocked.\n", ch);
			return;
		    }

		    if (IS_SET(obj->value[ITEM_PORTAL_EXIT_FLAGS],EX_PICKPROOF)) {
			char_puts("You failed.\n", ch);
			return;
		    }

		    REMOVE_BIT(obj->value[ITEM_PORTAL_EXIT_FLAGS],EX_LOCKED);
		    act_puts("You pick the lock on $p.", ch, obj, NULL, TO_CHAR, POS_DEAD);
		    act("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM);
		    check_improve(ch, gsn_pick, TRUE, 2);
		    return;
		}

		
		/* 'pick object' */
		if (obj->pIndexData->item_type != ITEM_CONTAINER)
		    { char_puts("That's not a container.\n", ch); return; }
		if (!IS_SET(obj->value[ITEM_CONTAINER_FLAGS], CONT_CLOSED))
		    { char_puts("It's not closed.\n", ch); return; }
		if (obj->value[ITEM_CONTAINER_KEY] < 0)
		    { char_puts("It can't be unlocked.\n", ch); return; }
		if (!IS_SET(obj->value[ITEM_CONTAINER_FLAGS], CONT_LOCKED))
		    { char_puts("It's already unlocked.\n", ch); return; }
		if (IS_SET(obj->value[ITEM_CONTAINER_FLAGS], CONT_PICKPROOF))
		    { char_puts("You failed.\n", ch); return; }

		REMOVE_BIT(obj->value[ITEM_CONTAINER_FLAGS], CONT_LOCKED);
		act_puts("You pick the lock on $p.", ch, obj, NULL, TO_CHAR, POS_DEAD);
		act("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM);
		check_improve(ch, gsn_pick, TRUE, 2);
		return;
	}

	if ((door = find_door(ch, arg)) >= 0) {
		/* 'pick door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;

		pexit = ch->in_room->exit[door];
		if (!IS_SET(pexit->exit_info, EX_CLOSED) && !IS_IMMORTAL(ch))
		    { char_puts("It's not closed.\n", ch); return; }
		if (pexit->key < 0 && !IS_IMMORTAL(ch))
		    { char_puts("It can't be picked.\n", ch); return; }
		if (!IS_SET(pexit->exit_info, EX_LOCKED))
		    { char_puts("It's already unlocked.\n", ch); return; }
		if (IS_SET(pexit->exit_info, EX_PICKPROOF) && !IS_IMMORTAL(ch))
		    { char_puts("You failed.\n", ch); return; }

		REMOVE_BIT(pexit->exit_info, EX_LOCKED);
		char_puts("*Click*\n", ch);
		act("$n picks the $d.", ch, NULL, pexit->keyword, TO_ROOM);
		check_improve(ch, gsn_pick, TRUE, 2);

		/* pick the other side */
		if ((to_room   = pexit->to_room.r           ) != NULL
		&&   (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
		&&   pexit_rev->to_room.r == ch->in_room)
			REMOVE_BIT(pexit_rev->exit_info, EX_LOCKED);
	}
}

void do_sneak(CHAR_DATA *ch, const char *argument)
{
	AFFECT_DATA	af;
	int		chance;

	if ((chance = get_skill(ch, gsn_sneak)) == 0)
		return;

	if (MOUNTED(ch)) {
		  char_puts("You can't sneak while mounted.\n", ch);
		  return;
	}

	char_puts("You attempt to move silently.\n", ch);
	affect_strip(ch, gsn_sneak);

	if (IS_AFFECTED(ch, AFF_SNEAK))
		return;

	if (number_percent() < chance) {
		check_improve(ch, gsn_sneak, TRUE, 3);
		af.where     = TO_AFFECTS;
		af.type      = gsn_sneak;
		af.level     = ch->level; 
		af.duration  = ch->level;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_SNEAK;
		affect_to_char(ch, &af);
	}
	else
		check_improve(ch, gsn_sneak, FALSE, 3);
}

void do_hide(CHAR_DATA *ch, const char *argument)
{
	int		 chance;
	flag32_t		 sector;
	int cost = 0;
	AFFECT_DATA af;

	cost = move_cost(ch, gsn_hide, STAT_DEX, 1);

	if (MOUNTED(ch)) {
		  char_puts("You can't hide while mounted.\n", ch);
		  return;
	}

	if(is_affected(ch, gsn_rnet_trap)) {
		char_puts("You cannot hide while constricted in a net.\n",ch);
		return;
	}
	if (RIDDEN(ch)) {
		  char_puts("You can't hide while being ridden.\n", ch);
		  return;
	}

	/*if (IS_PUMPED(ch)) {
		  char_puts("You can't hide while your adrenaline is flowing!\n", ch);
		  return;
	}*/

	if (IS_AFFECTED(ch, AFF_FAERIE_FIRE) )  {
		char_puts("You cannot hide while glowing.\n", ch);
		return;
	}

	if (ch->in_room != NULL
	    && ch->in_room->sector_type == SECT_FOREST
	    && is_affected(ch, gsn_pollen) )  {
		char_puts("You cannot hide itching so badly.\n", ch);
		return;
	}

	if (ch->move < cost) {
		char_puts("You don't have enough stamina to hide.\n", ch);
		return;
	}

	char_puts("You attempt to hide.\n", ch);
	if ((chance = get_skill(ch, gsn_hide)) == 0) {
	   char_puts("Huh?\n", ch);
		return;
	}

	sector = ch->in_room->sector_type;
	if (sector == SECT_FOREST
	||  sector == SECT_HILLS
	||  sector == SECT_MOUNTAIN)
		chance -= 20;
	else if (sector == SECT_CITY)
		chance += 20;
	
	if (!is_affected(ch, gsn_hide)) {
		af.where     = TO_AFFECTS;
		af.type      = gsn_hide;
		af.level     = LEVEL(ch);
		af.duration  = -1;
		af.modifier  = 0;
		af.location  = APPLY_NONE;
		af.bitvector = AFF_NO_DISPLAY;
		affect_to_char(ch, &af);
	}

	if (number_percent() < chance) {
		SET_BIT(ch->affected_by, AFF_HIDE);

		check_improve(ch, gsn_hide, TRUE, 7);
	}
	else  {
		REMOVE_BIT(ch->affected_by, AFF_HIDE);
		check_improve(ch, gsn_hide, FALSE, 6);
	}

	ch->move -= cost;

}

void do_camouflage(CHAR_DATA *ch, const char *argument)
{
	int		sn;
	int		chance;
	flag32_t		sector;
	int cost = 0;
	AFFECT_DATA af;

	cost = move_cost(ch, gsn_camouflage, STAT_DEX, 1);

	if (MOUNTED(ch)) {
		char_puts("You can't camouflage while mounted.\n", ch);
		return;
	}

	if (RIDDEN(ch)) {
		char_puts("You can't camouflage while being ridden.\n", ch);
		return;
	}

	if (IS_AFFECTED(ch, AFF_FAERIE_FIRE))  {
		char_puts("You can't camouflage yourself while glowing.\n", ch);
		return;
	}

	if (ch->in_room != NULL
	    && (ch->in_room->sector_type == SECT_FOREST
	    ||  ch->in_room->sector_type == SECT_FIELD
	    ||  ch->in_room->sector_type == SECT_HILLS
	    ||  ch->in_room->sector_type == SECT_MOUNTAIN 
	    ||  ch->in_room->sector_type == SECT_DESERT)
	    && is_affected(ch, gsn_pollen) )  {
		char_puts("You can't camouflage yourself while itching so badly.\n", ch);
		return;
	}

	if ((sn = sn_lookup("camouflage")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("You don't know how to camouflage yourself.\n", ch);
		return;
	}

	if (ch->move < cost) {
		char_puts("You don't have enough stamina to camouflage yourself.\n", ch);
		return;
	}

	sector = ch->in_room->sector_type;
	if (sector != SECT_FOREST
	&&  sector != SECT_HILLS
	&&  sector != SECT_MOUNTAIN) {
		char_puts("There's no cover here.\n", ch);
		act("$n tries to camouflage $mself against the lone leaf on the ground.",
		    ch, NULL, NULL, TO_ROOM);
		return;
	}

	char_puts("You attempt to camouflage yourself.\n", ch);
/*
   Taken out to be equvilant to hide
	WAIT_STATE(ch, SKILL(sn)->beats);
*/
	if (!is_affected(ch, gsn_camouflage)) {
		af.where     = TO_AFFECTS;
		af.type      = gsn_camouflage;
		af.level     = LEVEL(ch);
		af.duration  = -1;
		af.modifier  = 0;
		af.location  = APPLY_NONE;
		af.bitvector = AFF_NO_DISPLAY;
		affect_to_char(ch, &af);
	}

	if (IS_AFFECTED(ch, AFF_CAMOUFLAGE))
		REMOVE_BIT(ch->affected_by, AFF_CAMOUFLAGE);

	if (IS_NPC(ch) || number_percent() < chance) {
		SET_BIT(ch->affected_by, AFF_CAMOUFLAGE);
		check_improve(ch, sn, TRUE, 2);
	}
	else
		check_improve(ch, sn, FALSE, 2);

	ch->move -= cost;
}

void do_track(CHAR_DATA *ch, const char *argument)
{
	ROOM_HISTORY_DATA *rh;
	EXIT_DATA *pexit;
	static char *door[] = { "north","east","south","west","up","down",
		                      "that way" };
	int d;
	int chance;

	if ((chance = get_skill(ch, gsn_track)) == 0) {
		char_puts("There are no train tracks here.\n", ch);
		return;
	}

	WAIT_STATE(ch, SKILL(gsn_track)->beats);
	act("$n checks the ground for tracks.", ch, NULL, NULL, TO_ROOM);

	if (number_percent() < chance) {
		if (IS_NPC(ch)) {
			if (ch->last_fought != NULL
			&&  !IS_SET(ch->pIndexData->act, ACT_NOTRACK))
				add_mind(ch, ch->last_fought->name);
		}

		for (rh = ch->in_room->history; rh != NULL; rh = rh->next)
			if (is_name(argument, rh->name)) {
				check_improve(ch, gsn_track, TRUE, 1);
			if ((d = rh->went) == -1)
				continue;
			char_printf(ch, "%s's tracks lead %s.\n",
				     rh->name, door[d]);
			if ((pexit = ch->in_room->exit[d]) != NULL
			&&  IS_SET(pexit->exit_info, EX_ISDOOR)
			&&  pexit->keyword != NULL)
				doprintf(do_open, ch, "%s", door[d]);
			move_char(ch, rh->went, FALSE);
			return;
		}
	}

	char_puts("You don't see any tracks.\n", ch);
	check_improve(ch, gsn_track, FALSE, 1);
}

void do_vampire(CHAR_DATA *ch, const char *argument)
{
	AFFECT_DATA af;
	int level, duration;
	int chance;
 
	if (is_affected(ch, gsn_vampire)) {
		char_puts("But you are already a vampire. Kill them! Kill them!\n", ch);
		return;
	}

	if ((chance = get_skill(ch, gsn_vampire)) == 0) {
		char_puts("You try to show yourself even more ugly.\n", ch);
		return;
	}

	if (chance < 100) {
		char_puts("Go and ask the questor. He'll help you.\n", ch);
		return;
	}
/*################ # Erebus asked to remove this check so you can change at any time
#	if (weather_info.sunlight == SUN_LIGHT 
#	||  weather_info.sunlight == SUN_RISE) {
#		char_puts("You should wait for the evening or night to transform to a vampire.\n", ch);
#		return;
#	}  
#################
*/

	level = ch->level;
	duration = level / 10 + 5;

	af.type      = gsn_vampire;
	af.level     = level;
	af.duration  = duration;

/* negative immunity */
	af.where = TO_IMMUNE;
	af.location = APPLY_NONE;
	af.modifier = 0;
	af.bitvector = IMM_NEGATIVE;
	affect_to_char(ch, &af);

/* haste */
	af.where     = TO_AFFECTS;
	af.location  = APPLY_DEX;
	af.modifier  = 1 + (level /20);
	af.bitvector = AFF_HASTE;
	affect_to_char(ch, &af);

/* giant strength + infrared */
	af.location  = APPLY_STR;
	af.modifier  = 1 + (level / 20);
	af.bitvector = 0;
	affect_to_char(ch, &af);

/* damroll */
	af.where     = TO_AFFECTS;
	af.location  = APPLY_DAMROLL;
	af.modifier  = ch->level;
	af.bitvector = AFF_BERSERK;
	affect_to_char(ch, &af);

/* flying, infrared */
	af.where     = TO_AFFECTS;
	af.location  = 0;
	af.modifier  = 0;
	af.bitvector = AFF_SNEAK | AFF_FLYING | AFF_INFRARED;
	affect_to_char(ch, &af);

	char_puts("You feel yourself getting greater and greater.\n", ch);
	act("You cannot recognize $n anymore.", ch, NULL, NULL, TO_ROOM);
}

void do_vbite(CHAR_DATA *ch, const char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int chance;

	one_argument(argument, arg, sizeof(arg));

	if ((chance = get_skill(ch, gsn_vampiric_bite)) == 0) {
		char_puts("You don't know how to bite creatures.\n", ch);
		return;
	}

	if (!is_affected(ch, gsn_vampire)) {
		char_puts("You must transform vampire before biting.\n", ch);
		return;
	}

	if (arg[0] == '\0') {
		char_puts("Bite whom?\n", ch);
		return;
	}

	if ((victim = get_char_room(ch, arg)) == NULL) {
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (victim->position != POS_SLEEPING) {
		char_puts("They must be sleeping.\n", ch);
		return;
	}

	if (IS_NPC(ch) && !IS_NPC(victim))
		return;

	if (victim == ch) {
		char_puts("How can you sneak upon yourself?\n", ch);
		return;
	}

	if (victim->fighting != NULL) {
		char_puts("You can't bite a fighting person.\n", ch);
		return;
	}

	if (is_safe(ch, victim))
		return;

	if (victim->hit < (8 * victim->max_hit / 10) ) {
		act_puts("$N is hurt and suspicious ... doesn't worth up.",
			 ch, NULL, victim, TO_CHAR, POS_DEAD);
		return;
	}


	WAIT_STATE(ch, SKILL(gsn_vampiric_bite)->beats);

	if (!IS_AWAKE(victim)
	&&  (IS_NPC(ch) ||
	     number_percent() < ((chance * 7 / 10) +
		(2 * (ch->level - victim->level)) ))) {
		check_improve(ch,gsn_vampiric_bite,TRUE,1);
		one_hit(ch, victim, gsn_vampiric_bite, WEAR_WIELD);
	}
	else {
		check_improve(ch, gsn_vampiric_bite, FALSE, 1);
		damage(ch, victim, 0, gsn_vampiric_bite, DAM_NONE, DAMF_SHOW);
	}
	if (!IS_NPC(victim) && victim->position==POS_FIGHTING) 
		doprintf(do_yell, victim, 
			"Help! %s tried to bite me!", PERS(ch, victim));
}

void do_bash_door(CHAR_DATA *ch, const char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *gch;
	int chance;
	int damage_bash,door;
	int beats;

	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit;
	EXIT_DATA *pexit_rev;

	one_argument(argument, arg, sizeof(arg));
 
	if ((chance = get_skill(ch, gsn_bash_door)) == 0) {
		char_puts("Bashing? What's that?\n", ch);
		return;
	}
 
	if (MOUNTED(ch)) {
        	char_puts("You can't bash doors while mounted.\n", ch);
		return;
	}

	if (RIDDEN(ch)) {
		char_puts("You can't bash doors while being ridden.\n", ch);
		return;
	}

	if (arg[0] == '\0') {
		char_puts("Bash wich door or direction?\n", ch);
		return;
	}

	if (ch->fighting) {	
		char_puts("Wait until the fight finishes.\n", ch);
		return;
	}

	/* look for guards */
	for (gch = ch->in_room->people; gch; gch = gch->next_in_room)
		if (IS_NPC(gch)
		&&  IS_AWAKE(gch) && ch->level + 5 < gch->level) {
			act_puts("$N is standing too close to door.",
				 ch, NULL, gch, TO_CHAR, POS_DEAD);
			return;
		}

	if ((door = find_door(ch, arg)) < 0)
		return;

	pexit = ch->in_room->exit[door];

	if (!IS_SET(pexit->exit_info, EX_CLOSED)) {
		char_puts("It's already open.\n", ch);
		return;
	}

	if (!IS_SET(pexit->exit_info, EX_LOCKED)) {
		char_puts("Just try to open it.\n", ch);
		return;
	}

	if (IS_SET(pexit->exit_info, EX_NOPASS)) {
		char_puts("A mystical shield protects exit.\n", ch); 
		return;
	}

	if (IS_AFFECTED(ch,AFF_FLYING)) {
		char_puts("You bounce against the door"
			" and glide backward across the room.\n", ch);
		return;
	}

	chance -= 90;

	/* modifiers */

	/* size and weight */
	chance += ch_weight_carried(ch) / 100;
	chance += (ch->size - 2) * 20;

	/* stats */
	chance += get_curr_stat(ch, STAT_STR)/4;

	act_puts("You slam into $d, and try to break $d!",
		 ch, NULL, pexit->keyword, TO_CHAR, POS_DEAD);
	act("$n slams into $d, and tries to break it!",
	    ch, NULL, pexit->keyword, TO_ROOM);

	if (room_dark(ch->in_room))
		chance /= 2;

	beats = SKILL(gsn_bash_door)->beats;

	/* now the attack */
	if (number_percent() < chance) {

		WAIT_STATE(ch, beats);

		if (IS_SET(pexit->exit_info, EX_NOBASH)) {
			char_puts("The door is reinforced against"
				" brute strength.\n", ch);
			return;
		}

		if (pexit->lock_level > LEVEL(ch)) {
			char_puts("This lock looks rather strong,"
			" you might consider a more delicate approach.\n", ch);
			return;
		}

		check_improve(ch, gsn_bash_door, TRUE, 1);

		REMOVE_BIT(pexit->exit_info, EX_LOCKED);
		REMOVE_BIT(pexit->exit_info, EX_CLOSED);
		act("$n bashes the $d and breaks the lock.",
		    ch, NULL, pexit->keyword, TO_ROOM);
		act_puts("You succeeded in opening the door.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);

/* open the other side */
		if ((to_room = pexit->to_room.r) != NULL
		&&  (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
		&&  pexit_rev->to_room.r == ch->in_room) {
			ROOM_INDEX_DATA *in_room;

			REMOVE_BIT(pexit_rev->exit_info, EX_CLOSED);
			REMOVE_BIT(pexit_rev->exit_info, EX_LOCKED);

			in_room = ch->in_room;
			ch->in_room = to_room;
			act("$n bashes the $d and breaks the lock.",
			    ch, NULL, pexit->keyword, TO_ROOM);
			ch->in_room = in_room;
		}

		check_improve(ch, gsn_bash_door, TRUE, 1);
	}
	else {
		act_puts("You fall flat on your face!",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		act_puts("$n falls flat on $s face.",
			 ch, NULL, NULL, TO_ROOM, POS_RESTING);
		check_improve(ch, gsn_bash_door, FALSE, 1);
		ch->position = POS_RESTING;
		WAIT_STATE(ch, beats * 3 / 2); 
		damage_bash = ch->damroll +
			      number_range(4,4 + 4* ch->size + chance/5);
		damage(ch, ch, damage_bash, gsn_bash_door, DAM_BASH, DAMF_SHOW);

	}
}

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

	if (get_skill(ch, gsn_blink) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

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

	if (arg[0] == '\0') {
		char_printf(ch, "Your current blink status: %s.\n",
			    IS_SET(ch->conf_flags, PLR_CONF_BLINK) ? "ON" : "OFF");
		return;
	}

	if (!str_cmp(arg, "ON")) {
		SET_BIT(ch->conf_flags, PLR_CONF_BLINK);
		char_puts("Now, your current blink status is ON.\n", ch);
		ch->mana -= 10;
		return;
	}

	if (!str_cmp(arg, "OFF")) {
		REMOVE_BIT(ch->conf_flags, PLR_CONF_BLINK);
		char_puts("Now, your current blink status is OFF.\n", ch);
		return;
	}

	char_printf(ch, "What's that? Is %s a status?\n", arg);

}

void do_vanish(CHAR_DATA *ch, const char *argument)
{
	int chance;
	int sn;
	int min_mana;
	ROOM_INDEX_DATA *dest = NULL;

	if ((sn = sn_lookup("vanish")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (ch->mana < (min_mana = SKILL(sn)->min_mana)) {
		char_puts("You don't have enough power.\n", ch);
		return;
	}
	ch->mana -= min_mana;
	WAIT_STATE(ch, SKILL(sn)->beats);

	if (number_percent() > chance) {
		char_puts("You failed.\n", ch);
		check_improve(ch, sn, FALSE, 1);
		return;
	}

	if (IS_SET(ch->in_room->room_flags, 
		   ROOM_NORECALL | ROOM_PEACE | ROOM_SAFE | ROOM_NOSUMMON)) {
		char_puts("You failed.\n", ch);
		return;
	}

	if (IS_SET(ch->in_room->area->flags, AREA_NOSUMMON)) {
		char_puts("You failed.\n", ch);
		return;
	}

	act("You throw down a small {Dg{wl{Wo{Wb{De{x.", ch, NULL, NULL, TO_CHAR);
	act("$n throws down a small {Dg{wl{Wo{Wb{De{x.", ch, NULL, NULL, TO_ROOM);
	check_improve(ch, sn, TRUE, 1);

  	if (!IS_NPC(ch) && ch->fighting && number_bits(1) == 1) {
		char_puts("You failed.\n", ch);
		return;
	}

	dest = get_random_room(ch, ch->in_room->area);
	if (dest == NULL) {
		char_puts("Nowhere to go!\n", ch);
		return;
	}
	if (IS_SET(dest->room_flags, 
	ROOM_NORECALL | ROOM_SAFE | ROOM_NOSUMMON)) {
		char_puts("Nowhere to go!\n", ch);
		return;
	}

	stop_fighting(ch, TRUE);
	transfer_char(ch, NULL, dest,
		      "$N is gone!", NULL, "$N appears from nowhere.");
}

/*void do_shadow_meld(CHAR_DATA *ch, const char *argument)
{
	int chance;
	if ((chance=get_skill(ch, gsn_shadow_meld)) == 0)
		return;

	if (MOUNTED(ch)) {
		  char_puts("You can't meld into shadows while mounted.\n", ch);
		  return;
	}

	if (IS_PUMPED(ch)) {
		  char_puts("You can't meld into shadows while your adrenaline is gushing!\n", ch);
		  return;
	}

	if (RIDDEN(ch)) {
		  char_puts("You can't meld into shadows while being ridden.\n", ch);
		  return;
	}

	char_puts("You attempt to meld into shadows.\n", ch);
	if (number_percent()<=chance) {
		SET_BIT(ch->affected_by, AFF_SHADOW_MELD);
		check_improve(ch, gsn_shadow_meld, TRUE, 3);
	}
	else check_improve(ch, gsn_shadow_meld, FALSE, 3);
}*/

void do_fade(CHAR_DATA *ch, const char *argument)
{
	int chance;
	int cost = 0;
	AFFECT_DATA af;

	cost = move_cost(ch, gsn_fade, 0, 0);

	if ((chance=get_skill(ch, gsn_fade)) == 0)
		return;

	if (MOUNTED(ch)) {
		  char_puts("You can't fade while mounted.\n", ch);
		  return;
	}

	if (RIDDEN(ch)) {
		  char_puts("You can't fade while being ridden.\n", ch);
		  return;
	}

	if(is_affected(ch, gsn_rnet_trap)) {
		char_puts("You cannot fade while constricted by the net.\n",ch);
		return;
	}

	if (IS_AFFECTED(ch,AFF_FAERIE_FIRE)) {
		char_puts("You can not fade while glowing.\n",ch);
		return;
	}

	if (ch->in_room != NULL
	    && ch->in_room->sector_type == SECT_FOREST
	    && is_affected(ch, gsn_pollen) )  {
		char_puts("You can not fade while itching so badly.\n",ch);
		return;
	}

	if (ch->move < cost) {
		char_puts("You don't have enough stamina to fade.\n", ch);
		return;
	}

	if (!is_affected(ch, gsn_fade)) {
		af.where     = TO_AFFECTS;
		af.type      = gsn_fade;
		af.level     = LEVEL(ch);
		af.duration  = -1;
		af.modifier  = 0;
		af.location  = APPLY_NONE;
		af.bitvector = AFF_NO_DISPLAY;
		affect_to_char(ch, &af);
	}

	if (IS_PUMPED(ch)) {
		char_puts("You attempt to fade.\n", ch);
			if (number_percent() < (chance/2)) {
				SET_BIT(ch->affected_by, AFF_FADE);
				check_improve(ch, gsn_fade, TRUE, 3);
			}
			else
				check_improve(ch, gsn_fade, FALSE, 3);
	}
        else  if (number_percent() < chance) {
		char_puts("You attempt to fade.\n", ch);
	        SET_BIT(ch->affected_by, AFF_FADE);
                check_improve(ch, gsn_fade, TRUE, 3);
	}
	else
                check_improve(ch, gsn_fade, FALSE, 3);

	ch->move -= cost;
}

void do_vtouch(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *victim;
	AFFECT_DATA af;
	int chance;
	int sn;

	if ((sn = sn_lookup("vampiric touch")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("You lack the skill to draining touch.\n", ch);
		return;
	}

	if (!is_affected(ch, gsn_vampire)) {
		char_puts("Let it be.\n", ch);
		return;
	}

	if (IS_AFFECTED(ch, AFF_CHARM))  {
		char_puts("You don't want to drain your master.\n", ch);
		return;
	} 

	if ((victim = get_char_room(ch,argument)) == NULL) {
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (ch == victim) {
		char_puts("Even you are not so stupid.\n", ch);
		return;
	}

	if (is_affected(victim, sn))
		return;

	if (is_safe(ch,victim))
		return;

	WAIT_STATE(ch, SKILL(sn)->beats);

        if (is_affected(victim, gsn_paranoia))  {
                act("$E is way too paranoid for that.", 
			ch, NULL, victim , TO_CHAR);
		return;                                               
        }

	SET_FIGHT_TIME(victim);
	SET_FIGHT_TIME(ch);

	chance = chance * 5/6;
	chance += (LEVEL(ch) - LEVEL(victim)) *3;

	DEBUG(DEBUG_SKILL_VTOUCH,
		"%s[%d] vtouch %d%% %s[%d]",
		ch->name,
		LEVEL(ch),
		chance,
		victim->name,
		LEVEL(victim));

	if (number_percent() < chance
	&&  !IS_CLAN_GUARD(victim)
	&&  !IS_IMMORTAL(victim)) {
		act_puts("You deadly touch $n's neck and put $m to nightmares.",
			 victim, NULL, ch, TO_VICT, POS_DEAD); 
		act_puts("$N deadly touches your neck and puts you "
			 "to nightmares.", victim, NULL, ch, TO_CHAR, POS_DEAD);
		act("$N deadly touches $n's neck and puts $m to nightmares.",
		    victim, NULL, ch, TO_NOTVICT);

		check_improve(ch, sn, TRUE, 1);
		
		af.type = sn;
		af.where = TO_AFFECTS;
		af.level = ch->level;
		af.duration = ch->level / 20 + 1;
		af.location = APPLY_NONE;
		af.modifier = 0;
		af.bitvector = AFF_SLEEP;
		affect_join(victim,&af);

                af.type = gsn_paranoia;
                af.where        = TO_AFFECTS;
                af.level        = ch->level;
                af.duration     = number_fuzzy(af.duration);
                af.location     = APPLY_NONE;
                af.modifier     = 0;
                af.bitvector    = 0;
                affect_join (victim,&af);
		
		if (IS_AWAKE(victim))
			victim->position = POS_SLEEPING;
	} else {
		damage(ch, victim, 0, sn, DAM_NONE, DAMF_SHOW);
		check_improve(ch, sn, FALSE, 1);
	}
}

void do_push(CHAR_DATA *ch, const char *argument)
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	EXIT_DATA *pexit;
	int percent;
	int door;
	int sn;

	argument = one_argument(argument, arg1, sizeof(arg1));
	argument = one_argument(argument, arg2, sizeof(arg2));

	if (arg1[0] == '\0' || arg2[0] == '\0') {
		char_puts("Push whom to what direction?\n", ch);
		return;
	}

	if (MOUNTED(ch)) {
		char_puts("You can't push while mounted.\n", ch);
		return;
	}

	if (RIDDEN(ch)) {
		char_puts("You can't push while being ridden.\n", ch);
		return;
	}

	if (IS_NPC(ch) && IS_SET(ch->affected_by, AFF_CHARM) 
		&& (ch->master != NULL)) {
		char_puts("You are too dazed to push anyone.\n", ch);
		return;
	}

	if ((sn = sn_lookup("push")) < 0)
		return;

	if ((victim = get_char_room(ch, arg1)) == NULL) {
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (!IS_NPC(victim) && victim->desc == NULL) {
		char_puts("You can't do that.\n", ch);
		return;
	}

	if (victim == ch) {
		char_puts("That's pointless.\n", ch);
		return;
	}

	if (victim->position == POS_FIGHTING) {
		char_puts("Wait until the fight finishes.\n", ch);
		return;
	}

	if ((door = find_exit(ch, arg2)) < 0)
		return;

	WAIT_STATE(ch, SKILL(sn)->beats);

	if ((pexit = ch->in_room->exit[door])
	&&  IS_SET(pexit->exit_info, EX_ISDOOR)) {
		if (IS_SET(pexit->exit_info, EX_CLOSED)) {
			char_puts("The door is closed.\n", ch); 
			return;
		}
		if (IS_SET(pexit->exit_info, EX_LOCKED)) {
			char_puts("The door is locked.\n", ch); 
			return;
		}
	}


	if (IS_AFFECTED(ch, AFF_DETECT_WEB)) {
		char_puts("You're webbed, and want to do WHAT?!?\n", ch);
		act("$n stupidly tries to push $N while webbed.",
		    ch, NULL, victim, TO_ROOM);
		return; 
	}

	if (IS_AFFECTED(victim, AFF_DETECT_WEB)) {
		act_puts("You attempt to push $N, but the webs hold $m "
			 "in place.", victim, NULL, ch, TO_VICT, POS_DEAD);
		act("$n attempts to push $n, but fails as the webs hold "
		    "$n in place.", victim, NULL, ch, TO_NOTVICT);
		return; 
	}

	if (is_safe(ch,victim))
		return;

	percent  = number_percent() + (IS_AWAKE(victim) ? 10 : -50);
	percent += can_see(victim, ch) ? -10 : 0;

	if (victim->position == POS_FIGHTING
	||  (IS_NPC(victim) && IS_SET(victim->pIndexData->act, ACT_NOTRACK))
	||  (!IS_NPC(ch) && percent > get_skill(ch, sn))
	||  pexit->to_room.r->area != ch->in_room->area) {
		/*
		 * Failure.
		 */

		char_puts("Oops.\n", ch);
		if (!IS_AFFECTED(victim, AFF_SLEEP)) {
			victim->position = victim->position == POS_SLEEPING ? 
					   POS_STANDING : victim->position;
			act("$n tried to push you.",
			    ch, NULL, victim, TO_VICT);
		}
		act("$n tried to push $N.", ch, NULL, victim, TO_NOTVICT);

		if (IS_AWAKE(victim))
			doprintf(do_yell, victim,
				 "Keep your hands out of me, %s!",
				 ch->name);
		if (!IS_NPC(ch) && IS_NPC(victim)) {
			check_improve(ch, sn, FALSE, 2);
			multi_hit(victim, ch, TYPE_UNDEFINED);
		}
		return;
	}

	act_puts("You push $N to $t.",
		 ch, dir_name[door], victim, TO_CHAR | ACT_TRANS, POS_SLEEPING);
	act_puts("$n pushes you to $t.",
		 ch, dir_name[door], victim, TO_VICT | ACT_TRANS, POS_SLEEPING);
	act("$n pushes $N to $t.",
	    ch, dir_name[door], victim, TO_NOTVICT | ACT_TRANS);
	move_char(victim, door, FALSE);

	check_improve(ch, sn, TRUE, 1);
}

void do_crecall(CHAR_DATA *ch, const char *argument)
{
	ROOM_INDEX_DATA *location;
	clan_t *clan;
	CHAR_DATA *gch;
	AFFECT_DATA af;
	int sn;

	if ((sn = sn_lookup("clan recall")) < 0
	||  get_skill(ch, sn) == 0
	||  (clan = clan_lookup(ch->clan)) == NULL) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (is_affected(ch, sn)) {
		act_puts("You can't pray now.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	if (ch->desc && IS_PUMPED(ch)) {
		act_puts("You are too pumped to pray now.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	act("$n prays to their clan gods for transportation.",
	    ch, NULL, NULL, TO_ROOM);
	
	if ((location = get_room_index(clan->recall_vnum)) == NULL) {
		char_puts("You are completely lost.\n", ch);
		return;
	}

	if (ch->in_room == location)
		return;

	if (IS_SET(ch->in_room->room_flags, ROOM_NORECALL)
	||  IS_AFFECTED(ch, AFF_CURSE) 
	||  IS_RAFFECTED(ch->in_room, RAFF_CURSE)) {
		char_puts("The gods have forsaken you.\n", ch);
		return;
	}

	ch->move /= 2;
	af.type      = sn;
	af.level     = ch->level;
	af.duration  = SKILL(sn)->beats;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = 0;
	affect_to_char(ch, &af);

	ch->move /= 2;
        for (gch = npc_list; gch; gch = gch->next) {
                if (gch->in_room == ch->in_room
		&&  IS_AFFECTED(gch, AFF_CHARM)
                &&  gch->master == ch
		&& !IS_AFFECTED(gch, AFF_SLEEP)
		&& gch->position >= POS_STANDING) {
			recall(gch, location);
                }
        }
	recall(ch, location);
	if(is_affected(ch, gsn_rnet_trap))
		affect_strip(ch, gsn_rnet_trap);
}

void do_escape(CHAR_DATA *ch, const char *argument)
{
	ROOM_INDEX_DATA *was_in;
	ROOM_INDEX_DATA *now_in;
	EXIT_DATA *pexit;
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];
	int door;
	int chance;
	int sn;

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

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

	if (arg[0] == '\0') {
		char_puts("Escape to what direction?\n", ch);
		return;
	}

	if (MOUNTED(ch)) {
		  char_puts("You can't escape while mounted.\n", ch);
		  return;
	}

	if (RIDDEN(ch)) {
		  char_puts("You can't escape while being ridden.\n", ch);
		  return;
	}

	if ((sn = sn_lookup("escape")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Try flee. It may fit you better.\n", ch);
		return;
	}

	was_in = ch->in_room;

	if ((door = find_exit(ch, arg)) < 0) {
		char_puts("PANIC! You couldn't escape!\n", ch);
		return;
	}

	if ((pexit = was_in->exit[door]) == 0
	||  pexit->to_room.r == NULL
	||  (IS_SET(pexit->exit_info, EX_CLOSED) &&
	     (!IS_AFFECTED(ch, AFF_PASS_DOOR) ||
	      IS_SET(pexit->exit_info, EX_NOPASS)) &&
	     !IS_TRUSTED(ch, ANGEL))
	||  IS_SET(pexit->exit_info, EX_NOFLEE)
	||  (IS_NPC(ch) &&
	     IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB))) {
		char_puts("Something prevents you to escape that direction.\n", ch); 
		return;
	}

	WAIT_STATE(ch, SKILL(sn)->beats);

	chance = chance / (IS_AFFECTED(ch, AFF_BLIND) ? 2 : 1);

	if (number_percent() > chance) {
		act_puts("You failed to escape.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		check_improve(ch, sn, FALSE, 1);	
		return;
	}

	check_improve(ch, sn, TRUE, 1);	
	move_char(ch, door, FALSE);
	if ((now_in = ch->in_room) == was_in) {
		char_puts("It's pointless to escape there.\n", ch);
		return;
	}

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

	if (!IS_NPC(ch)) {
		act_puts("You escaped from combat!",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		if (ch->level < LEVEL_HERO) {
			char_printf(ch, "You lose %d exps.\n", 10);
			gain_exp(ch, -10);
		}
	}
	else
		/* Once fled, the mob will not go after */
		ch->last_fought = NULL;

	stop_fighting(ch, TRUE);
}

void do_layhands(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *victim;
	AFFECT_DATA af;
	int sn;
	int hp = 0;

	if ((sn = sn_lookup("lay hands")) < 0
	||  get_skill(ch, sn) == 0) {
		char_puts("You cannot channel healing powers through a laying of hands.\n", ch);
		return;
	}

	WAIT_STATE(ch, SKILL(sn)->beats);

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

	if (is_affected(ch, sn)) {
		 char_puts("You haven't recovered from your last laying of hands.\n", ch);
		 return;
	}

	ch->mana = ch->mana / 2;

        af.type = sn;
        af.where = TO_AFFECTS;
        af.level = ch->level;
        af.duration = 23;
        af.location = APPLY_NONE;
        af.modifier = 0;
        af.bitvector = 0;
        affect_to_char (ch, &af);

	hp = (victim->max_hit - victim->hit) * 2/3;

	if (LEVEL(victim) > LEVEL(ch))
		hp = hp * (LEVEL(victim) - LEVEL(ch) / 100); 

	heal(ch, NULL, victim, sn, LEVEL(ch), hp);

        if (LEVEL(ch) > 80
	&& IS_AFFECTED(victim, gsn_deafen))
                affect_strip(victim, gsn_deafen);

        if (LEVEL(ch) > 77
	&& IS_AFFECTED(victim, AFF_PLAGUE))
                spell_cure_disease (sn_lookup("cure disease"), ch->level,
                        ch, (void*)victim, TARGET_CHAR);

        if (IS_AFFECTED(victim, AFF_BLIND))
                spell_cure_blindness(sn_lookup("cure blindness"), LEVEL(ch),
                        ch, (void*)victim, TARGET_CHAR);
     
        if (IS_AFFECTED(victim, AFF_POISON))
                spell_cure_poison(sn_lookup("cure poison"), LEVEL(ch),
                        ch, (void*)victim, TARGET_CHAR);

        check_improve(ch, sn, TRUE, 1);
}

int send_arrow(CHAR_DATA *ch, CHAR_DATA *victim,OBJ_DATA *arrow, 
	       int door, int chance ,int bonus) 
{
	EXIT_DATA *pExit;
	ROOM_INDEX_DATA *dest_room;
	AFFECT_DATA *paf;
	int damroll = 0, hitroll = 0, sn;
	AFFECT_DATA af;
	OBJ_DATA *bow = NULL;

	if (arrow->value[ITEM_WEAPON_TYPE] == WEAPON_SPEAR)  
		sn = gsn_spear;
	else 
		sn = gsn_arrow;

	for (paf = arrow->affected; paf != NULL; paf = paf->next) {
		if (paf->location == APPLY_DAMROLL)
			damroll += paf->modifier;
		if (paf->location == APPLY_HITROLL)
			hitroll += paf->modifier;
	}

	if (sn == gsn_arrow) {
		bow = get_eq_char(ch, WEAR_WIELD);
		for (paf = bow->affected; paf; paf = paf->next) {
			if (paf->location == APPLY_DAMROLL)
				damroll += paf->modifier;
			if (paf->location == APPLY_HITROLL)
				hitroll += paf->modifier;
		}
	}

	dest_room = ch->in_room;
	chance += GET_NIMROLL(ch);

	damroll *= 10;

	while (1) {
		chance -= 10;

		if (victim->in_room == dest_room) {
			if (number_percent() < chance) { 
				if (check_obj_dodge(ch, victim, arrow, chance))
					return 0;
				act("$p strikes you!",
				    victim, arrow, NULL, TO_CHAR);
				act_puts("Your $p strikes $N!",
					 ch, arrow, victim, TO_CHAR, POS_DEAD);
				if (ch->in_room == victim->in_room)
					act("$n's $p strikes $N!",
					    ch, arrow, victim, TO_NOTVICT);
				else {
					act("$n's $p strikes $N!",
					    ch, arrow, victim, TO_ROOM);
					act("$p strikes $n!",
					    victim, arrow, NULL, TO_ROOM);
				}
				if (is_safe(ch, victim)
				||  (IS_NPC(victim) &&
				     IS_SET(victim->pIndexData->act, ACT_NOTRACK))) {
					act("$p falls from $n doing no visible damage...",
					    victim, arrow, NULL, TO_ALL);
					act("$p falls from $n doing no visible damage...",
					    ch, arrow, NULL, TO_CHAR);
					obj_to_room(arrow, victim->in_room);
				}
				else {
					int dam;

					dam = dice(arrow->value[ITEM_WEAPON_DICE_NUM],
						   arrow->value[ITEM_WEAPON_DICE_SIZE]);
					if (bow) 
						dam += dice(bow->value[ITEM_WEAPON_DICE_NUM],
							   bow->value[ITEM_WEAPON_DICE_SIZE]);
					dam = number_range(dam, 2 * dam);
					dam += damroll + bonus 
						+ get_curr_stat(ch, STAT_STR)/4;
					if (IS_WEAPON_STAT(arrow,
							   WEAPON_POISON)) {
						int level;
						AFFECT_DATA *poison, af;

		      	 if ((poison = affect_find(arrow->affected,gsn_poison)) == NULL)
		          	level = arrow->level;
		      	 else
		          	level = poison->level;
		      	 if (!saves_spell(level,victim,DAM_POISON))
		      	 {
		            char_puts("You feel poison coursing through your veins.",
		              victim);
		            act("$n is poisoned by the venom on $p.",
				victim,arrow,NULL,TO_ROOM);

		            af.where     = TO_AFFECTS;
		            af.type      = gsn_poison;
		            af.level     = level * 3/4;
		            af.duration  = level / 2;
		            af.location  = APPLY_STR;
		            af.modifier  = -1;
		            af.bitvector = AFF_POISON;
		            affect_join(victim, &af);
		      	 }

		  	}
		  	if (IS_WEAPON_STAT(arrow,WEAPON_FLAMING))
		  	{
		      	 act("$n is burned by $p.",victim,arrow,NULL,TO_ROOM);
		      	 act("$p sears your flesh.",victim,arrow,NULL,TO_CHAR);
		      	 fire_effect((void *) victim,arrow->level,dam,TARGET_CHAR);
		        }
		  	if (IS_WEAPON_STAT(arrow,WEAPON_FROST))
		        {
		            act("$p freezes $n.",victim,arrow,NULL,TO_ROOM);
		            act("The cold touch of $p surrounds you with ice.",
		                victim,arrow,NULL,TO_CHAR);
		            cold_effect(victim,arrow->level,dam,TARGET_CHAR);
		        }
		        if (IS_WEAPON_STAT(arrow,WEAPON_SHOCKING))
		        {
		            act("$n is struck by lightning from $p.",victim,arrow,NULL,TO_ROOM);
		            act("You are shocked by $p.",victim,arrow,NULL,TO_CHAR);
		            shock_effect(victim,arrow->level,dam,TARGET_CHAR);
		        }

			if (dam > victim->max_hit / 10 
				&& number_percent() < 50)
			{
			  af.where     = TO_AFFECTS;
			  af.type      = sn;
			  af.level     = ch->level; 
			  af.duration  = -1;
			  af.location  = APPLY_HITROLL;
			  af.modifier  = - (dam / 20);
			  if (IS_NPC(victim)) af.bitvector = 0;
				else af.bitvector = AFF_CORRUPTION;

			  affect_join(victim, &af);

			  obj_to_char(arrow,victim);
			  equip_char(victim,arrow,WEAR_STUCK_IN);
			}
		        else obj_to_room(arrow,victim->in_room); 

		DEBUG(DEBUG_SKILL_SHOOT,
			"shoot: %s[%d] vs %s[%d] hit: %d%% dam: %d",
			ch->name,
			LEVEL(ch),
			(victim) ? victim->name : "no-one",
			(victim) ? LEVEL(victim) : 0,
			chance,
			dam);
		
			damage(ch, victim, dam, sn, DAM_PIERCE, DAMF_SHOW);
			path_to_track(ch,victim,door);

		    }
		    return TRUE;
		  }
		  else {
		 	  obj_to_room(arrow,victim->in_room);
		          act("$p sticks in the ground at your feet!",victim,arrow,NULL, TO_ALL);
		          return FALSE;
		        }
		 }
		pExit = dest_room->exit[ door ];
		 if (!pExit) break;
		else {
			dest_room = pExit->to_room.r;
			if (dest_room->people) {
			 	act("$p sails into the room from the $T!",
				    dest_room->people, arrow,
				    dir_name[rev_dir[door]],
				    TO_ALL | ACT_TRANS);
			}

		}
	}
	return FALSE;
}

static OBJ_DATA *find_arrow(CHAR_DATA *ch)
{
	OBJ_DATA *arrow;
	OBJ_DATA *obj;

	if ((arrow = get_eq_char(ch, WEAR_HOLD)))
		return arrow;

	for (obj = ch->carrying; obj; obj = obj->next_content) {
		if (obj->wear_loc == WEAR_NONE
		||  obj->pIndexData->item_type != ITEM_CONTAINER
		||  !IS_SET(obj->value[ITEM_CONTAINER_FLAGS], CONT_QUIVER)
		||  !obj->contains
		||  (obj->contains->level > ch->level +15))
			continue;
		return obj->contains;
	}

	return NULL;
}

DO_FUN(do_charge) 
{
 	CHAR_DATA* victim;
	OBJ_DATA* wield;
	int chance, direction;
	EXIT_DATA *pexit;
	ROOM_INDEX_DATA *to_room;

	char arg1[512], arg2[512];


	if (IS_NPC(ch) || !(chance = get_skill(ch, gsn_charge))) {
		char_puts("Huh?\n", ch);
		return;
	}

	argument = one_argument(argument, arg1, sizeof(arg1));
	one_argument(argument, arg2, sizeof(arg2));

	if (arg1 == '\0' || arg2 == '\0') {
		char_puts("Charge whom?\n", ch);
		return;
	}

	if ((wield = get_eq_char(ch, WEAR_WIELD)) == NULL) {
		char_puts("You need a weapon to charge.\n", ch);
		return;
	}

	if (wield->value[ITEM_WEAPON_TYPE] != WEAPON_LANCE 
	&& wield->value[ITEM_WEAPON_TYPE] != WEAPON_SPEAR) {
		char_puts("You need lance or spear to charge.\n", ch);
		return;
	}

	if ((direction = find_exit(ch, arg1)) <0 || direction >= MAX_DIR) {
		char_puts("Charge whom?\n", ch);
		return;
	}

	if ((victim = find_char(ch, arg2, direction, 1)) == NULL) { 
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		return;
	}

	if (ch->in_room == victim->in_room) {
		act("$N is here. Just MURDER $M.", ch, NULL, victim, TO_CHAR);
		return;
	}

	if (ch->mount == NULL) {
		char_puts("You have to be riding.\n", ch);
		return;
	}

	if (is_safe(ch, victim))
		return;

	if (victim->hit < victim->max_hit*9/10) {
		act("$N is already bleeding, your honour do not allow you attack $M.", ch, NULL, victim, TO_CHAR);
		return;
	}

	chance = chance * get_skill(ch, gsn_riding)/100;

	if (!move_char_org(ch, direction, FALSE, TRUE))
		return;
	act("$n gallops from $t, charging you!",
	    ch, dir_name[rev_dir[direction]], victim, TO_VICT);
	act("$n gallops from $t, charging $N!",
	    ch, dir_name[rev_dir[direction]], victim, TO_NOTVICT);


	if (number_percent() < chance) {
		one_hit(ch, victim, gsn_charge, WEAR_WIELD);
		WAIT_STATE(victim, SKILL(gsn_charge)->beats * 2);
		WAIT_STATE(ch, SKILL(gsn_charge)->beats);
		check_improve(ch, gsn_charge, TRUE, 1);
	}
	else {
		damage(ch, victim, 0, gsn_charge, DAM_NONE, TRUE);
		check_improve(ch, gsn_charge, FALSE, 1);
		if (number_percent() > get_skill(ch, gsn_riding)) {
			if ((pexit=ch->in_room->exit[direction]) == NULL
			|| (to_room = pexit->to_room.r) == NULL
			|| !can_see_room(ch, to_room)
			|| IS_ROOM_AFFECTED(ch->in_room, RAFF_RANDOMIZER)
			|| IS_SET(pexit->exit_info, EX_CLOSED)) {
				WAIT_STATE(ch, SKILL(gsn_charge)->beats*2);
				return;
			}
			else {
				act("$n cannot hold $s $N.\n",
				    ch, dir_name[direction], ch->mount, TO_NOTVICT);
				act("You cannot hold your $N.",
				    ch, NULL, ch->mount, TO_CHAR);
				move_char(ch, direction, FALSE);
				WAIT_STATE(ch, SKILL(gsn_charge)->beats*5);
				return;
			}
		}
		WAIT_STATE(ch, SKILL(gsn_charge)->beats*2);
	}
}

DO_FUN(do_shoot)
{
	CHAR_DATA *victim;
	OBJ_DATA *wield;
	OBJ_DATA *arrow; 
	char arg1[512],arg2[512];
	bool success;
	int chance, direction;
	int range = (ch->level / 10) + 1;
	
	if (IS_NPC(ch))
		return; /* Mobs can't use bows */

	if (IS_NPC(ch) || (chance = get_skill(ch, gsn_bow)) == 0) {
		char_puts("You don't know how to shoot.\n",ch);
		return;
	}

	argument = one_argument(argument, arg1, sizeof(arg1));
	one_argument(argument, arg2, sizeof(arg2));

	if (arg1[0] == '\0' || arg2[0] == '\0') {
		char_puts("Shoot what direction and whom?\n", ch);
		return;
	}

	if (ch->fighting) {
		CHAR_DATA *vch;

		for (vch = ch->in_room->people; vch; vch = vch->next_in_room)
			if (vch->fighting == ch)
				break;
		if (vch) {
			char_puts("You cannot concentrate "
				  "on shooting arrows.\n", ch);
			return;
		}
	}

	direction = find_exit(ch, arg1);

	if (direction < 0 || direction >= MAX_DIR) {
		char_puts("Shoot which direction and whom?\n",ch);
		return;
	}
		
	if ((victim = find_char(ch, arg2, direction, range)) == NULL) {
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		char_puts("They aren't there.\n", ch);
		return;
	}

	if (!IS_NPC(victim) && victim->desc == NULL) {
		char_puts("You can't do that.\n", ch);
		return;
	}

	if (victim == ch) {
		char_puts("That's pointless.\n", ch);
		return;
	}

	wield = get_eq_char(ch, WEAR_WIELD);

	if (!wield || wield->pIndexData->item_type != ITEM_WEAPON
	||  wield->value[ITEM_WEAPON_TYPE] != WEAPON_BOW) {
		char_puts("You need a bow to shoot!\n", ch);
		return;    	
	}

	if (get_eq_char(ch, WEAR_SECOND_WIELD)
	||  get_eq_char(ch, WEAR_SHIELD)) {
		char_puts("Your second hand should be free!\n",ch);
		return;    	
	}

	if ((arrow = find_arrow(ch)) == NULL) {
		 char_puts("You need an arrow to shoot!\n", ch);
		 return;    	
	}
		
	if (arrow->pIndexData->item_type != ITEM_WEAPON
	||  arrow->value[ITEM_WEAPON_TYPE] != WEAPON_ARROW) {
		char_puts("That's not the right kind of arrow!\n", ch);
		return;
	}
		
	if (is_safe(ch, victim))
		return;

	WAIT_STATE(ch, SKILL(gsn_bow)->beats);

	chance = (chance - 50) * 2;
	if (victim->position == POS_SLEEPING)
		chance += 40;
	if (victim->position == POS_RESTING)
		chance += 10;
	if (victim->position == POS_FIGHTING)
		chance -= 40;

	act_puts("You shoot $p to $T.",
		 ch, arrow, dir_name[direction], TO_CHAR | ACT_TRANS, POS_DEAD);
	act("$n shoots $p to $T.",
	    ch, arrow, dir_name[direction], TO_ROOM | ACT_TRANS);

	if (arrow->carried_by)
		obj_from_char(arrow);
	else if (arrow->in_obj)
		obj_from_obj(arrow);

	success = send_arrow(ch, victim, arrow, direction, chance,
			     dice(arrow->value[ITEM_WEAPON_DICE_NUM],
			     	arrow->value[ITEM_WEAPON_DICE_SIZE]));
	check_improve(ch, gsn_bow, TRUE, 1);
}

void do_human(CHAR_DATA *ch, const char *argument)
{
	if (!is_affected(ch, gsn_vampire)) {
		char_puts("You are already a human.\n", ch);
		return;
	}

	affect_strip(ch, gsn_vampire);
	char_puts("You return to your original size.\n", ch);
}

void do_throw_spear(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *victim;
	OBJ_DATA *spear;
	char arg1[512],arg2[512];
	bool success;
	int chance,direction;
	int range = (ch->level / 10) + 1;

	if (IS_NPC(ch) || (chance = get_skill(ch, gsn_spear)) == 0) {
		char_puts("You don't know how to throw a spear.\n",ch);
		return;
	}

	argument = one_argument(argument, arg1, sizeof(arg1));
	one_argument(argument, arg2, sizeof(arg2));

  	if (arg1[0] == '\0' || arg2[0] == '\0') {
		char_puts("Throw spear what direction and whom?\n", ch);
		return;
	}

	if (ch->fighting) {
		CHAR_DATA *vch;

		for (vch = ch->in_room->people; vch; vch = vch->next_in_room)
			if (vch->fighting == ch)
				break;
		if (vch) {
			char_puts("You cannot concentrate on throwing "
				  "spears.\n", ch);
			return;
		}
	}

	direction = find_exit(ch, arg1);
	if (direction < 0 || direction >= MAX_DIR) {
		char_puts("Throw which direction and whom?\n",ch);
		return;
	}
		
	if ((victim = find_char(ch, arg2, direction, range)) == NULL) {
		WAIT_STATE(ch, MISSING_TARGET_DELAY);
		char_puts("They aren't there.\n", ch);
		return;
	}

	if (!IS_NPC(victim) && victim->desc == NULL) {
		char_puts("You can't do that.\n", ch);
		return;
	}

	if (victim == ch) {
		char_puts("That's pointless.\n", ch);
		return;
	}

	spear = get_eq_char(ch, WEAR_WIELD);
	if (!spear || spear->pIndexData->item_type != ITEM_WEAPON
	||  spear->value[ITEM_WEAPON_TYPE] != WEAPON_SPEAR) {
		char_puts("You need a spear to throw!\n",ch);
		return;    	
	}

	if (get_eq_char(ch,WEAR_SECOND_WIELD) || get_eq_char(ch,WEAR_SHIELD)) {
		char_puts("Your second hand should be free!\n",ch);
		return;    	
	}

	if (is_safe(ch,victim))
		return;

	WAIT_STATE(ch, SKILL(gsn_spear)->beats);

	chance = (chance - 50) * 2;
	if (victim->position == POS_SLEEPING)
		chance += 40;
	if (victim->position == POS_RESTING)
		chance += 10;
	if (victim->position == POS_FIGHTING)
		chance -= 40;

	act_puts("You throw $p to $T.", 
		 ch, spear, dir_name[direction], TO_CHAR, POS_DEAD);
	act("$n throws $p to $T.",
	    ch, spear, dir_name[direction], TO_ROOM | ACT_TRANS);

	obj_from_char(spear);
	success = send_arrow(ch,victim,spear,direction,chance,
			dice(spear->value[ITEM_WEAPON_DICE_NUM],
				spear->value[ITEM_WEAPON_DICE_SIZE]));
	check_improve(ch, gsn_spear, TRUE, 1);
}

void do_settraps(CHAR_DATA *ch, const char *argument)
{
	int chance;

	if ((chance = get_skill(ch, gsn_settraps)) == 0) {
		char_puts("You don't know how to set traps.\n",ch);
		return;
	}

	if (!ch->in_room)
		return;

	if (IS_SET(ch->in_room->room_flags, ROOM_LAW)) {
		char_puts("A mystical power protects the room.\n",ch);
		return;
	}

	WAIT_STATE(ch, SKILL(gsn_settraps)->beats);

	if (IS_NPC(ch) || number_percent() <  chance * 7 / 10) {
	  AFFECT_DATA af,af2;

	  check_improve(ch,gsn_settraps,TRUE,1);

	  if (is_affected_room(ch->in_room, gsn_settraps))
	  {
	char_puts("This room has already trapped.\n",ch);
	return;
	   }

	  if (is_affected(ch,gsn_settraps))
	  {
	char_puts("This skill is used too recently.\n",ch);
	return;
	  }
   
	  af.where     = TO_ROOM_AFFECTS;
	  af.type      = gsn_settraps;
	  af.level     = ch->level;
	  af.duration  = ch->level / 40;
	  af.location  = APPLY_NONE;
	  af.modifier  = 0;
	  af.bitvector = RAFF_THIEF_TRAP;
	  affect_to_room(ch->in_room, &af);

	  af2.where     = TO_AFFECTS;
	  af2.type      = gsn_settraps;
	  af2.level	    = ch->level;
	
	  if (!IS_IMMORTAL(ch) && IS_PUMPED(ch))
	     af2.duration  = 1;
	  else af2.duration = ch->level / 10;

	  af2.modifier  = 0;
	  af2.location  = APPLY_NONE;
	  af2.bitvector = 0;
	  affect_to_char(ch, &af2);
	  char_puts("You set the room with your trap.\n", ch);
	  act("$n set the room with $s trap.",ch,NULL,NULL,TO_ROOM);
	  return;
	}
	else check_improve(ch,gsn_settraps,FALSE,1);

   return;
}

void do_forest(CHAR_DATA* ch, const char* argument)
{
	char arg[MAX_STRING_LENGTH];
	AFFECT_DATA af;
	bool attack;

	if (IS_NPC(ch) || !get_skill(ch, gsn_forest_fighting)) {
		char_puts("Huh?\n", ch);
		return;
	}
	
	one_argument(argument, arg, sizeof(arg));
	if (arg == '\0') {
		char_puts("Usage: forest {{ attack|defense|normal}", ch);
		return;
	}

	if (!str_prefix(arg, "normal")) {
		if (!is_affected(ch, gsn_forest_fighting)) {
			char_puts("You do not use your knowledge of forest "
				  "in fight.\n", ch);
			return;
		}
		else {
			char_puts("You stop using your knowledge of forest in "
				  "fight.\n", ch);
			affect_strip(ch, gsn_forest_fighting);
			return;
		}
	}

	if (!str_prefix(arg, "defense") || !str_prefix(arg, "defence"))
		attack = FALSE;
	else if (!str_prefix(arg, "attack"))
		attack = TRUE;
	else {
		char_puts("Usage: forest {{ attack|defense|normal}", ch);
		return;
	}

	if (is_affected(ch, gsn_forest_fighting))
		affect_strip(ch, gsn_forest_fighting);
	
	af.where 	= TO_AFFECTS;
	af.type  	= gsn_forest_fighting;
	af.level 	= ch->level;
	af.duration	= -1;
	af.bitvector	= 0;

	if (attack) {
		af.modifier	= ch->level/8;
		af.location	= APPLY_HITROLL;
		affect_to_char(ch, &af);
		af.location	= APPLY_DAMROLL;
		act_puts("You feel yourself wild.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		act("$n looks wild.", ch, NULL, NULL, TO_ROOM);
	}
	else {
		af.modifier	= -ch->level;
		af.location	= APPLY_AC;
		act_puts("You feel yourself protected.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		act("$n looks protected.", ch, NULL, NULL, TO_ROOM);
	}

	affect_to_char(ch, &af);
}

static OBJ_DATA *find_shuriken(CHAR_DATA *ch)
{
        OBJ_DATA *shuriken;

        if ((shuriken = get_eq_char(ch, WEAR_HOLD)))
                return shuriken;
        return NULL;
}

int send_shuriken(CHAR_DATA *ch, CHAR_DATA *victim,OBJ_DATA *shuriken,
               int door, int chance)
{
        EXIT_DATA *pExit;
        ROOM_INDEX_DATA *dest_room;
        AFFECT_DATA *paf;
        int hitroll = 0, sn;

        for (paf = shuriken->affected; paf != NULL; paf = paf->next) {
                if (paf->location == APPLY_HITROLL)
                        hitroll += paf->modifier;
        }
	sn = gsn_shuriken;
        dest_room = ch->in_room;
        chance += GET_NIMROLL(ch);
        while (1) {
                chance -= 10;
                if (victim->in_room == dest_room) {
                        if (number_percent() < chance) {
                                if (check_obj_dodge(ch, victim, shuriken, chance))
                                        return 0;
                                act("$p lands painfully in your body!",
                                    victim, shuriken, NULL, TO_CHAR);
                                act_puts("$p lands in $N!",
                                         ch, shuriken, victim, TO_CHAR, POS_DEAD);
                                if (ch->in_room == victim->in_room)
                                        act("$p lands painfully in $N!",
                                            ch, shuriken, victim, TO_NOTVICT);
                                else {
                                        act("$n's $p lands painfully in $N!",
                                            ch, shuriken, victim, TO_ROOM);
                                        act("$p lands painfully in $n!",
                                            victim, shuriken, NULL, TO_ROOM);
                                }
                                if (is_safe(ch, victim)
                                ||  (IS_NPC(victim) &&
                                     IS_SET(victim->pIndexData->act, ACT_NOTRACK))) {
                                        act("$p falls from $n doing no visible damage...",
                                            victim, shuriken, NULL, TO_ALL);
                                        act("$p falls from $n doing no visible damage...",
                                            ch, shuriken, NULL, TO_CHAR);
                                        obj_to_room(shuriken, victim->in_room);
                                }
                                else {
                                        int dam;

					dam = dice(shuriken->value[ITEM_WEAPON_DICE_NUM],
						   shuriken->value[ITEM_WEAPON_DICE_SIZE]);
                                        if (IS_WEAPON_STAT(shuriken,
                                                           WEAPON_POISON)) {
                                                int level;
                                                AFFECT_DATA *poison, af;

                         if ((poison = affect_find(shuriken->affected,gsn_poison)) == NULL)
                                level = shuriken->level;
                         else
                                level = poison->level;
                         if (!saves_spell(level,victim,DAM_POISON))
                         {
                            char_puts("You feel poison coursing through your veins.",
                              victim);
                            act("$n is poisoned by the venom on $p.",
                                victim,shuriken,NULL,TO_ROOM);

                            af.where     = TO_AFFECTS;
                            af.type      = gsn_poison;
                            af.level     = level * 3/4;
                            af.duration  = level / 2;
                            af.location  = APPLY_STR;
                            af.modifier  = -1;
                            af.bitvector = AFF_POISON;
                            affect_join(victim, &af);
                         }
                        }
		  	if (IS_WEAPON_STAT(shuriken,WEAPON_FLAMING))
		  	{
		      	 act("$n is burned by $p.",victim,shuriken,NULL,TO_ROOM);
		      	 act("$p sears your flesh.",victim,shuriken,NULL,TO_CHAR);
		      	 fire_effect((void *) victim,shuriken->level - 5,dam,TARGET_CHAR);
		        }
		  	if (IS_WEAPON_STAT(shuriken,WEAPON_FROST))
		        {
		            act("$p freezes $n.",victim,shuriken,NULL,TO_ROOM);
		            act("The cold touch of $p surrounds you with ice.",
		                victim,shuriken,NULL,TO_CHAR);
		            cold_effect(victim,shuriken->level - 5,dam,TARGET_CHAR);
		        }
		        if (IS_WEAPON_STAT(shuriken,WEAPON_SHOCKING))
		        {
		            act("$n is struck by lightning from $p.",victim,shuriken,NULL,TO_ROOM);
		            act("You are shocked by $p.",victim,shuriken,NULL,TO_CHAR);
		            shock_effect(victim,shuriken->level - 5,dam,TARGET_CHAR);
		        }

                        obj_to_room(shuriken,victim->in_room);

                        damage(ch, victim, dam, sn, DAM_PIERCE, DAMF_SHOW);
                        path_to_track(ch,victim,door);

                    }
                    return TRUE;
                  }
                  else {
                          obj_to_room(shuriken,victim->in_room);
                          act("$p lands in the ground at your feet!",victim,shuriken,NULL, TO_ALL);
                          return FALSE;
                        }
                 }
                pExit = dest_room->exit[ door ];
                 if (!pExit) break;
                else {
                        dest_room = pExit->to_room.r;
                        if (dest_room->people) {
                                act("$p whirs through the room from the $T!",
                                    dest_room->people, shuriken,
                                    dir_name[rev_dir[door]],
                                    TO_ALL | ACT_TRANS);
                        }

                }
        }
        return FALSE;

}

void do_shuriken(CHAR_DATA *ch, const char *argument)
{
        CHAR_DATA *victim;
        OBJ_DATA *shuriken;
        char arg1[512],arg2[512];
        bool success;
        int chance, direction;
        int range = 1;

        if (IS_NPC(ch))
                return; /* Mobs can't use shuriken */

        if (IS_NPC(ch) || (chance = get_skill(ch, gsn_shuriken)) == 0) {
                char_puts("You don't know how to throw shuriken.\n",ch);
                return;
        }

        argument = one_argument(argument, arg1, sizeof(arg1));
        one_argument(argument, arg2, sizeof(arg2));

        if (arg1[0] == '\0' || arg2[0] == '\0') {
                char_puts("Throw what direction and whom?\n", ch);
                return;
        }

        if (ch->fighting) {
                CHAR_DATA *vch;

                for (vch = ch->in_room->people; vch; vch = vch->next_in_room)
                        if (vch->fighting == ch)
                                break;
                if (vch) {
                        char_puts("Your opponent is too close to throw at.\n", ch);
                        return;
                }
                
        }

        direction = find_exit(ch, arg1);

        if (direction < 0 || direction >= MAX_DIR) {
                char_puts("Throw which direction and whom?\n",ch);
                return;
        }

        if ((victim = find_char(ch, arg2, direction, range)) == NULL) {
                WAIT_STATE(ch, MISSING_TARGET_DELAY);
                char_puts("They aren't there.\n", ch);
                return;
        }

        if (!IS_NPC(victim) && victim->desc == NULL) {
                char_puts("You can't do that.\n", ch);
                return;
        }

        if (victim == ch) {
                char_puts("Shurikens, unlike boomerangs, do not come back to the thrower.\n", ch);
                return;
        }

        if (get_eq_char(ch, WEAR_WIELD)) {
                char_puts("You can't throw while wielding a weapon.\n", ch);
                return;
        }

        

        if ((shuriken = find_shuriken(ch)) == NULL) {
                 char_puts("You need a shuriken to throw!\n", ch);
                 return;
        }

        if (shuriken->pIndexData->item_type != ITEM_WEAPON
        ||  shuriken->value[ITEM_WEAPON_TYPE] != WEAPON_SHURIKEN) {
                char_puts("That's not the right kind of shuriken!\n", ch);
                return;
        }

        if (is_safe(ch, victim))
                return;

        WAIT_STATE(ch, SKILL(gsn_shuriken)->beats);

        chance = (chance - 50) * 2;
        if (victim->position == POS_SLEEPING)
                chance += 40;
        if (victim->position == POS_RESTING)
                chance += 10;
        if (victim->position == POS_FIGHTING)
                chance -= 40;

        chance += GET_HITROLL(ch);
	chance += get_curr_stat(ch, STAT_DEX) - get_curr_stat(victim, STAT_DEX);

        act_puts("You throw $p to $T.",
                 ch, shuriken, dir_name[direction], TO_CHAR | ACT_TRANS, POS_DEAD);
        act("$n throws $p to $T.",
            ch, shuriken, dir_name[direction], TO_ROOM | ACT_TRANS);

        if (shuriken->carried_by)
                obj_from_char(shuriken);
        else if (shuriken->in_obj)
                obj_from_obj(shuriken);

        success = send_shuriken(ch, victim, shuriken, direction, chance);
        check_improve(ch, gsn_shuriken, TRUE, 1);
}

static OBJ_DATA *find_dagger(CHAR_DATA *ch)
{
	OBJ_DATA *obj;
		for (obj = ch->carrying; obj; obj = obj->next_content)
		{
			if ((obj->wear_loc == WEAR_NONE) 
			&& (obj->pIndexData->item_type == ITEM_WEAPON)
			&& obj->value[ITEM_WEAPON_TYPE] == WEAPON_DAGGER)
				return obj;
		}
		return NULL;
}

int send_dagger(CHAR_DATA *ch, CHAR_DATA *victim,OBJ_DATA *dagger, int door,
		int chance ,int bonus)
{
        EXIT_DATA *pExit;
        ROOM_INDEX_DATA *dest_room;
        AFFECT_DATA *paf;
        int damroll = 0, hitroll = 0, sn;
        AFFECT_DATA af;
        
        sn = gsn_sling;

        for (paf = dagger->affected; paf != NULL; paf = paf->next) {
                if (paf->location == APPLY_DAMROLL)
                        damroll += paf->modifier;
                if (paf->location == APPLY_HITROLL)
                        hitroll += paf->modifier;
        }

        chance += GET_NIMROLL(ch);
        /*damroll *= 10;*/
        while (1) 
	{
                chance -= 10;                
                if (number_percent() < chance) 
		{
			if (check_obj_dodge(ch, victim, dagger, chance))
                                        return 0;
                        if (is_safe(ch, victim)) 
			{
                                act("$p rebounds harmlessly off of $n...",
                                    victim, dagger, NULL, TO_ALL);
                                act("$p rebounds harmlessly off of $n...",
                                    ch, dagger, NULL, TO_CHAR);
                                obj_to_room(dagger, victim->in_room);
                        }
                        else 
			{
                                int dam;

                                dam = dice(dagger->value[ITEM_WEAPON_DICE_NUM],
                                           dagger->value[ITEM_WEAPON_DICE_SIZE]) / 2;
                                dam += bonus 
					+ get_curr_stat(ch, STAT_STR)/4 
					* LEVEL(ch) / LEVEL_HERO;
                                if (IS_WEAPON_STAT(dagger,
                                                   WEAPON_POISON)) 
				{
                                        int level;
                                        AFFECT_DATA *poison, af;

                         		if ((poison = affect_find(dagger->affected,gsn_poison)) == NULL)
                                		level = dagger->level;
                         		else
                                		level = poison->level;
                         		if (!saves_spell(level,victim,DAM_POISON))
                         		{
                            			char_puts("You feel poison coursing through your veins.",
                              				victim);
                            			act("$n is poisoned by the venom on $p.",
                                			victim,dagger,NULL,TO_ROOM);

                            			af.where     = TO_AFFECTS;
                            			af.type      = gsn_poison;
                           			af.level     = level * 3/4;
                            			af.duration  = level / 2;
                            			af.location  = APPLY_STR;
                            			af.modifier  = -1;
                            			af.bitvector = AFF_POISON;
                            			affect_join(victim, &af);
                         		}

                        	}
                        	if (IS_WEAPON_STAT(dagger,WEAPON_FLAMING))
                        	{
                         		act("$n is burned by $p.",victim,dagger,NULL,TO_ROOM);
                         		act("$p sears your flesh.",victim,dagger,NULL,TO_CHAR);
                         		fire_effect((void *) victim,dagger->level,dam,TARGET_CHAR);
                        	}
                        	if (IS_WEAPON_STAT(dagger,WEAPON_FROST))
                        	{
                            		act("$p freezes $n.",victim,dagger,NULL,TO_ROOM);
                            		act("The cold touch of $p surrounds you with ice.",
                                		victim,dagger,NULL,TO_CHAR);
                            		cold_effect(victim,dagger->level,dam,TARGET_CHAR);
                        	}
                        	if (IS_WEAPON_STAT(dagger,WEAPON_SHOCKING))
                        	{
                            		act("$n is struck by lightning from $p.",victim,dagger,NULL,TO_ROOM);
                            		act("You are shocked by $p.",victim,dagger,NULL,TO_CHAR);
                            		shock_effect(victim,dagger->level,dam,TARGET_CHAR);
                        	}

                        	if (number_percent() < get_skill(ch, gsn_sling) - 50)
                        	{
                          		af.where     = TO_AFFECTS;
                          		af.type      = sn;
                          		af.level     = ch->level;
                          		af.duration  = -1;
                          		af.location  = APPLY_DEX;
                          		af.modifier  = - 1;
                          		af.bitvector = 0;                                

                          		affect_join(victim, &af);

                          		obj_to_char(dagger,victim);
                          		equip_char(victim,dagger,WEAR_STUCK_IN);
					act("You feel a surge of pain as $p buries itself in your leg.",
						victim, dagger, NULL,TO_CHAR);
					act("$n curses in pain as $p buries itself in $s leg.",
						victim, dagger, NULL,TO_ROOM);
                        	}
                        	else {
					obj_to_room(dagger,victim->in_room);
					act("$p strikes a glancing blow to $n, but doesn't lodge.",victim,dagger,NULL,TO_ROOM);
					act("$p strikes you a glancing blow, but doesn't lodge.",victim,dagger,NULL,TO_CHAR);
					dam /= 4;
				}			

                        damage(ch, victim, dam, sn, DAM_PIERCE, DAMF_SHOW);
                        path_to_track(ch,victim,door);

                    	}
                    	return TRUE;
                  }
                  else {
                          obj_to_room(dagger,victim->in_room);
                          act("$p sticks in the ground at your feet!",victim,dagger,NULL, TO_ALL);
                          return FALSE;
                  }
                pExit = dest_room->exit[ door ];
                 if (!pExit) break;
                else {
                        dest_room = pExit->to_room.r;
                        if (dest_room->people) {
                                act("$p darts through the room from the $T!",
                                    dest_room->people, dagger,
                                    dir_name[rev_dir[door]],
                                    TO_ALL | ACT_TRANS);
                        }

                }
        }
                

        return FALSE;
}



void do_sling(CHAR_DATA *ch, const char *argument)
{
        CHAR_DATA *victim;
        OBJ_DATA *dagger;
        char arg1[512],arg2[512];
        bool success;
        int chance, direction;
        int range = 1;

        if (IS_NPC(ch))
                return; /* Mobs can't sling */

        if (IS_NPC(ch) || (chance = get_skill(ch, gsn_sling)) == 0) {
                char_puts("You don't know how to sling daggers.\n",ch);
                return;
        }

        argument = one_argument(argument, arg1, sizeof(arg1));
        one_argument(argument, arg2, sizeof(arg2));

        if (arg1[0] == '\0' || arg2[0] == '\0') {
                char_puts("Throw what direction and whom?\n", ch);
                return;
        }

        if (ch->fighting) {
                CHAR_DATA *vch;

                for (vch = ch->in_room->people; vch; vch = vch->next_in_room)
                        if (vch->fighting == ch)
                                break;
                if (vch) {
                        char_puts("Your opponent is too close.\n", ch);
                        return;
                }
                
        }

        direction = find_exit(ch, arg1);

        if (direction < 0 || direction >= MAX_DIR) {
                char_puts("Throw which direction and whom?\n",ch);
                return;
        }

        if ((victim = find_char(ch, arg2, direction, range)) == NULL) {
                WAIT_STATE(ch, MISSING_TARGET_DELAY);
                char_puts("They aren't there.\n", ch);
                return;
        }

        if (!IS_NPC(victim) && victim->desc == NULL) {
                char_puts("You can't do that.\n", ch);
                return;
        }

        if (victim == ch) {
	        char_puts("Trying to juggle knives?\n", ch);
	        return;
	}        

        if (get_eq_char(ch, WEAR_HOLD) != NULL
	&& get_eq_char(ch, WEAR_SHIELD) != NULL
	&& get_eq_char(ch, WEAR_SECOND_WIELD) != NULL) {
		char_puts("You must have a free hand to sling a dagger.\n", ch);
		return;
	}

	if ((dagger = find_dagger(ch)) == NULL) {
	        char_puts("You need a dagger to sling, quick search your pockets!\n", ch);
	        return;
	}

        if (is_safe(ch, victim))
                return;

        WAIT_STATE(ch, SKILL(gsn_sling)->beats);

        chance = (chance - 50) * 2;
        if (victim->position == POS_SLEEPING)
                chance += 40;
        if (victim->position == POS_RESTING)
                chance += 10;
        if (victim->position == POS_FIGHTING)
                chance -= 40;

	chance += get_curr_stat(ch, STAT_DEX) - get_curr_stat(victim, STAT_DEX);

        act_puts("You sling $p to $T.",
                 ch, dagger, dir_name[direction], TO_CHAR | ACT_TRANS, POS_DEAD);
        act("$n slings $p to $T.",
            ch, dagger, dir_name[direction], TO_ROOM | ACT_TRANS);

        if (dagger->carried_by)
                obj_from_char(dagger);
        else if (dagger->in_obj)
                obj_from_obj(dagger);

        success = send_dagger(ch, victim, dagger, direction, chance, 0);
        check_improve(ch, gsn_sling, TRUE, 1);
}

void do_hometown(CHAR_DATA *ch, const char *argument)
{
	int amount;
	int htn;
	race_t *r;
	class_t *cl;

	if (IS_NPC(ch)) {
		act_puts("You can't change your hometown!",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	if ((r = race_lookup(ORG_RACE(ch))) == NULL
	||  !r->pcdata
	||  (cl = class_lookup(ch->class)) == NULL)
		return;

	if (!IS_SET(ch->in_room->room_flags, ROOM_REGISTRY)) {
		act_puts("You have to be in the Registry "
			 "to change your hometown.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	if ((htn = hometown_permanent(ch)) >= 0) {
		act_puts("Your hometown is $t, permanently. "
			 "You can't change your hometown.",
			 ch, hometown_name(htn), NULL,
			 TO_CHAR | ACT_TRANS, POS_DEAD);
		return;
	}

	amount = (ch->level * 250) + 1000;

	if (argument[0] == '\0') {
		act_puts("The change of hometown will cost you $j gold.",
			 ch, (const void*) amount, NULL, TO_CHAR, POS_DEAD);
		char_puts("Choose from: ", ch);
		hometown_print_avail(ch);
		char_puts(".\n", ch);
		return;
	}

	if ((htn = htn_lookup(argument)) < 0) {
		act_puts("That's not a valid hometown.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	if (htn == ch->hometown) {
		act_puts("But you already live in $t!",
			 ch, hometown_name(htn), NULL,
			 TO_CHAR | ACT_TRANS, POS_DEAD);
		return;
	}

	if (hometown_restrict(HOMETOWN(htn), ch)) {
		act_puts("You are not allowed there.",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	if (ch->pcdata->bank_g < amount) {
		act_puts("You don't have enough money in bank "
			 "to change hometowns!",
			 ch, NULL, NULL, TO_CHAR, POS_DEAD);
		return;
	}

	ch->hometown = htn;
	act_puts("Now your hometown is $t.",
		 ch, hometown_name(ch->hometown),
		 NULL, TO_CHAR | ACT_TRANS, POS_DEAD);
}

void do_bear_call(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *	gch;
	CHAR_DATA *	bear;
	CHAR_DATA *	bear2;
	AFFECT_DATA	af;
	int		i;
	int		chance;
	int		sn;
	int		mana;

	if ((sn = sn_lookup("bear call")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	char_puts("You call for bears help you.\n",ch);
	act("$n shouts a bear call.",ch,NULL,NULL,TO_ROOM);

	if (is_affected(ch, sn)) {
		char_puts("You cannot summon the strength to handle "
			     "more bears right now.\n", ch);
		return;
	}

	for (gch = npc_list; gch; gch = gch->next) {
		if (IS_AFFECTED(gch, AFF_CHARM)
		&&  gch->master == ch
		&&  gch->pIndexData->vnum == MOB_VNUM_BEAR) {
			char_puts("What's wrong with the bear you've got?",
				     ch);
			return;
		}
	}

	if (ch->in_room != NULL
	&&  IS_SET(ch->in_room->room_flags, ROOM_NOMOB)) {
		char_puts("No bears listen you.\n", ch);
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_PEACE |
					    ROOM_PRIVATE | ROOM_SOLITARY)
	||  (ch->in_room->exit[0] == NULL && ch->in_room->exit[1] == NULL
	&&   ch->in_room->exit[2] == NULL && ch->in_room->exit[3] == NULL
	&&   ch->in_room->exit[4] == NULL && ch->in_room->exit[5] == NULL)
	||  (ch->in_room->sector_type != SECT_FIELD
	&&   ch->in_room->sector_type != SECT_FOREST
	&&   ch->in_room->sector_type != SECT_MOUNTAIN
	&&   ch->in_room->sector_type != SECT_HILLS)) {
		char_puts("No bears come to your rescue.\n", ch);
		return;
	}

	mana = SKILL(sn)->min_mana;
	if (ch->mana < mana) {
		char_puts("You don't have enough mana "
			     "to shout a bear call.\n", ch);
		return;
	}
	ch->mana -= mana;

	if (number_percent() > chance) {
		char_puts("No bears listen you.\n", ch);
		check_improve(ch, sn, FALSE, 1);
		return;
	}

	check_improve(ch, sn, TRUE, 1);
	bear = create_mob(get_mob_index(MOB_VNUM_BEAR));

	for (i=0;i < MAX_STATS; i++)
		bear->perm_stat[i] = UMIN(25,2 * ch->perm_stat[i]);

	bear->max_hit = IS_NPC(ch) ? ch->max_hit : ch->pcdata->perm_hit;
	bear->hit = bear->max_hit;
	bear->max_mana = IS_NPC(ch) ? ch->max_mana : ch->pcdata->perm_mana;
	bear->mana = bear->max_mana;
	bear->alignment = ch->alignment;
	bear->level = UMIN(100, 1 * ch->level-2);
	for (i=0; i < 3; i++)
		bear->armor[i] = interpolate(bear->level, 100, -100);
	bear->armor[3] = interpolate(bear->level, 100, 0);
	bear->sex = ch->sex;
	bear->gold = 0;

	bear2 = create_mob(bear->pIndexData);
	clone_mob(bear, bear2);

	SET_BIT(bear->affected_by, AFF_CHARM);
	SET_BIT(bear2->affected_by, AFF_CHARM);
	bear->master = bear2->master = ch;
	bear->leader = bear2->leader = ch;

	char_puts("Two bears come to your rescue!\n",ch);
	act("Two bears come to $n's rescue!", ch, NULL, NULL, TO_ROOM);

	af.where	= TO_AFFECTS;
	af.type 	= sn;
	af.level	= ch->level;
	af.duration	= SKILL(sn)->beats;
	af.bitvector	= 0;
	af.modifier	= 0;
	af.location	= APPLY_NONE;
	affect_to_char(ch, &af);

	char_to_room(bear, ch->in_room);
	char_to_room(bear2, ch->in_room);
}

void do_lion_call(CHAR_DATA *ch, const char *argument)
{
	CHAR_DATA *	gch;
	CHAR_DATA *	lion;
	CHAR_DATA *	lion2;
	AFFECT_DATA	af;
	int		i;
	int		chance;
	int		sn;
	int		mana;

	if ((sn = sn_lookup("lion call")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	char_puts("You call for lions help you.\n",ch);
	act("$n shouts a lion call.",ch,NULL,NULL,TO_ROOM);

	if (is_affected(ch, sn)) {
		char_puts("You cannot summon the strength to handle "
			     "more lions right now.\n", ch);
		return;
	}

	for (gch = npc_list; gch; gch = gch->next) {
		if (IS_AFFECTED(gch,AFF_CHARM)
		&&  gch->master == ch
		&&  gch->pIndexData->vnum == MOB_VNUM_LION) {
			char_puts("What's wrong with the lion you've got?", ch);
			return;
		}
	}

	if (ch->in_room != NULL
	&& IS_SET(ch->in_room->room_flags, ROOM_NOMOB)) {
		char_puts("No lions can listen you.\n", ch);
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_PEACE |
					    ROOM_PRIVATE | ROOM_SOLITARY)
	||  (ch->in_room->exit[0] == NULL && ch->in_room->exit[1] == NULL
	&&   ch->in_room->exit[2] == NULL && ch->in_room->exit[3] == NULL
	&&   ch->in_room->exit[4] == NULL && ch->in_room->exit[5] == NULL)
	||  (ch->in_room->sector_type != SECT_FIELD
	&&   ch->in_room->sector_type != SECT_FOREST
	&&   ch->in_room->sector_type != SECT_MOUNTAIN
	&&   ch->in_room->sector_type != SECT_HILLS)) {
		char_puts("No lions come to your rescue.\n", ch);
		return;
	}

	mana = SKILL(sn)->min_mana;
	if (ch->mana < mana) {
		char_puts("You don't have enough mana "
			     "to shout a lion call.\n", ch);
		return;
	}
	ch->mana -= mana;

	if (number_percent() > chance) {
		check_improve(ch, sn, FALSE, 1);
		char_puts("No lions listen you.\n", ch);
		return;
	}

	check_improve(ch, sn, TRUE, 1);
	lion = create_mob(get_mob_index(MOB_VNUM_LION));

	for (i=0;i < MAX_STATS; i++)
		lion->perm_stat[i] = UMIN(25,2 * ch->perm_stat[i]);

	lion->max_hit = IS_NPC(ch) ? ch->max_hit : ch->pcdata->perm_hit;
	lion->hit = lion->max_hit;
	lion->max_mana = IS_NPC(ch) ? ch->max_mana : ch->pcdata->perm_mana;
	lion->mana = lion->max_mana;
	lion->alignment = ch->alignment;
	lion->level = UMIN(100,1 * ch->level-2);
	for (i=0; i < 3; i++)
		lion->armor[i] = interpolate(lion->level,100,-100);
	lion->armor[3] = interpolate(lion->level,100,0);
	lion->sex = ch->sex;
	lion->gold = 0;

	lion2 = create_mob(lion->pIndexData);
	clone_mob(lion,lion2);

	SET_BIT(lion->affected_by, AFF_CHARM);
	SET_BIT(lion2->affected_by, AFF_CHARM);
	lion->master = lion2->master = ch;
	lion->leader = lion2->leader = ch;

	char_puts("Two lions come to your rescue!\n",ch);
	act("Two lions come to $n's rescue!",ch,NULL,NULL,TO_ROOM);

	af.where	= TO_AFFECTS;
	af.type 	= sn;
	af.level	= ch->level;
	af.duration	= SKILL(sn)->beats;
	af.bitvector	= 0;
	af.modifier	= 0;
	af.location	= APPLY_NONE;
	affect_to_char(ch, &af);

	char_to_room(lion, ch->in_room);
	char_to_room(lion2, ch->in_room);
}

void do_camp(CHAR_DATA *ch, const char *argument)
{
	AFFECT_DATA af;
	int sn;
	int chance;
	int mana;

	if ((sn = sn_lookup("camp")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (is_affected(ch, sn)) {
		char_puts("You don't have enough power to handle more "
			     "camp areas.\n", ch);
		return;
	}

	if (IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_PEACE |
					    ROOM_PRIVATE | ROOM_SOLITARY)
	||  (ch->in_room->sector_type != SECT_FIELD
	&&   ch->in_room->sector_type != SECT_FOREST
	&&   ch->in_room->sector_type != SECT_MOUNTAIN
	&&   ch->in_room->sector_type != SECT_HILLS)) {
		char_puts("There are not enough leaves to camp here.\n",
			     ch);
		return;
	}

	mana = SKILL(sn)->min_mana;
	if (ch->mana < mana) {
		char_puts("You don't have enough mana to make a camp.\n",
			     ch);
		return;
	}
	ch->mana -= mana;

	if (number_percent() > chance) {
		char_puts("You failed to make your camp.\n", ch);
		check_improve(ch, sn, FALSE, 4);
		return;
	}

	check_improve(ch, sn, TRUE, 4);
	WAIT_STATE(ch, SKILL(sn)->beats);

	char_puts("You succeeded to make your camp.\n", ch);
	act("$n succeeded to make $s camp.", ch, NULL, NULL, TO_ROOM);

	af.where	= TO_AFFECTS;
	af.type 	= sn;
	af.level	= ch->level;
	af.duration	= 12;
	af.bitvector	= 0;
	af.modifier	= 0;
	af.location	= APPLY_NONE;
	affect_to_char(ch, &af);

	af.where	= TO_ROOM_CONST;
	af.type		= sn;
	af.level	= ch->level;
	af.duration	= ch->level / 20;
	af.bitvector	= 0;
	af.modifier	= 2 * ch->level;
	af.location	= APPLY_ROOM_HEAL;
	affect_to_room(ch->in_room, &af);

	af.modifier	= ch->level;
	af.location	= APPLY_ROOM_MANA;
	affect_to_room(ch->in_room, &af);
}

void do_request(CHAR_DATA *ch, const char *argument)
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA  *obj;
	AFFECT_DATA af;

	if (is_affected(ch, gsn_reserved)) {
		char_puts("Wait for a while to request again.\n", ch);
		return;
	}

	argument = one_argument(argument, arg1, sizeof(arg1));
	argument = one_argument(argument, arg2, sizeof(arg2));

	if (IS_NPC(ch))
		return;

	if (arg1[0] == '\0' || arg2[0] == '\0') {
		char_puts("Request what from whom?\n", ch);
		return;
	}

	if ((victim = get_char_room(ch, arg2)) == NULL) {
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (!IS_NPC(victim)) {
		char_puts("Why don't you just ask the player?\n", ch);
		return;
	}

	if (!IS_GOOD(ch)) {
		do_say(victim,
		       "I will not give anything to someone so impure.");
		return;
	}

	WAIT_STATE(ch, PULSE_VIOLENCE);

	if (IS_AFFECTED(victim, AFF_CHARM) && victim->master != ch) {
		do_say(victim,
		       "Ask my master, if you want something.");
		return;
	}

	if (((obj = get_obj_carry(victim , arg1)) == NULL
	&&  (obj = get_obj_wear(victim, arg1)) == NULL)
	||  IS_SET(obj->extra_flags, ITEM_INVENTORY)) {
		do_say(victim, "Sorry, I don't have that.");
		return;
	}
	
	if (IS_NEWBIE(ch) && obj->pIndexData->limit >= 0) {
		do_say(victim, "I'm sorry, newbie, I cannot offer you this artifact.");
		return;
	}

	if(obj->level <= victim->level)
	{
		if (obj->level >= ch->level + 16 || obj->level >= ch->level * 2) {
                do_say(victim, "In good time, my child");
                return;
		}
        }
	else
	{
		if(victim->level >= ch->level + 16 || victim->level >= ch->level * 2){
		do_say(victim, "In good time, my child");
		return;
		}
	}

	if (!IS_GOOD(victim)) {
		do_say(victim, "I'm not about to give you anything!");
		do_murder(victim, ch->name);
		return;
	}

	if (obj->wear_loc != WEAR_NONE)
		unequip_char(victim, obj);

	if (!can_drop_obj(ch, obj)) {
		do_say(victim, "Sorry, I can't let go of it.  It's cursed.");
		return;
	}

	if (ch->carry_number + get_obj_number(obj) > can_carry_n(ch)) {
		char_puts("Your hands are full.\n", ch);
		return;
	}

	if (ch->carry_weight + get_obj_weight(obj) > ch_max_carry_weight(ch)) {
		char_puts("You can't carry that much weight.\n", ch);
		return;
	}

	if (!can_see_obj(ch, obj)) {
		act("You don't see that.", ch, NULL, victim, TO_CHAR);
		return;
	}

	if (IS_SET(obj->extra_flags, ITEM_QUIT_DROP)) {
		do_say(victim, "Sorry, I must keep it myself.");
		return;
	}

	obj_from_char(obj);
	obj_to_char(obj, ch);
	act("$n requests $p from $N.", ch, obj, victim, TO_NOTVICT);
	act("You request $p from $N.",	 ch, obj, victim, TO_CHAR);
	act("$n requests $p from you.", ch, obj, victim, TO_VICT);

	oprog_call(OPROG_GIVE, obj, ch, victim);

	act("You feel grateful for the trust of $N.", ch, NULL, victim,
	    TO_CHAR);
	char_puts("and for the goodness you have seen in the world.\n",ch);

	af.type = gsn_reserved;
	af.where = TO_AFFECTS;
	af.level = ch->level;
	af.duration = 2;
	af.location = APPLY_NONE;
	af.modifier = 0;
	af.bitvector = 0;
	affect_to_char(ch, &af);
}

void do_demand(CHAR_DATA *ch, const char *argument)
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA  *obj;
	int chance;

	argument = one_argument(argument, arg1, sizeof(arg1));
	argument = one_argument(argument, arg2, sizeof(arg2));

	if (IS_NPC(ch))
		return;

	if (arg1[0] == '\0' || arg2[0] == '\0') {
		char_puts("Demand what from whom?\n", ch);
		return;
	}

	if ((victim = get_char_room(ch, arg2)) == NULL) {
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (IS_SET(ch->state_flags, STATE_GHOST)) {
		char_puts("You're still a ghost.\n", ch);
		return;
	}

	if (!IS_NPC(victim)) {
		char_puts("Why don't you just want that directly "
			     "from the player?\n", ch);
		return;
	}

	WAIT_STATE(ch, PULSE_VIOLENCE);

	chance = IS_EVIL(victim) ? 10 : IS_GOOD(victim) ? -5 : 0;
	chance += get_curr_stat(ch,STAT_CHA);
	chance += ch->level - victim->level;

	chance = (get_skill(ch, gsn_demand))*chance/100;

	if (number_percent() > chance) {
		do_say(victim, "I'm not about to give you anything!");
		check_improve(ch, gsn_demand, FALSE, 1);
		do_murder(victim, ch->name);
		return;
	}

	check_improve(ch, gsn_demand, TRUE, 1);

	if (((obj = get_obj_carry(victim , arg1)) == NULL
	&&   (obj = get_obj_wear(victim, arg1)) == NULL)
	||  IS_SET(obj->extra_flags, ITEM_INVENTORY)) {
		do_say(victim, "Sorry, I don't have that.");
		return;
	}

	if (IS_SET(obj->extra_flags, ITEM_QUIT_DROP)) {
		do_say(victim, "Forgive me, my master, I can't give it to anyone.");
		return;
	}


	if (obj->wear_loc != WEAR_NONE)
		unequip_char(victim, obj);

	if (!can_drop_obj(ch, obj)) {
		do_say(victim, "It's cursed so, I can't let go of it. "
			       "Forgive me, my master");
		return;
	}

	if (ch->carry_number + get_obj_number(obj) > can_carry_n(ch)) {
		char_puts("Your hands are full.\n", ch);
		return;
	}

	if (ch->carry_weight + get_obj_weight(obj) > ch_max_carry_weight(ch)) {
		char_puts("You can't carry that much weight.\n", ch);
		return;
	}

	if (!can_see_obj(ch, obj)) {
		act("You don't see that.", ch, NULL, victim, TO_CHAR);
		return;
	}

	obj_from_char(obj);
	obj_to_char(obj, ch);
	act("$n demands $p from $N.", ch, obj, victim, TO_NOTVICT);
	act("You demand $p from $N.",	ch, obj, victim, TO_CHAR  );
	act("$n demands $p from you.", ch, obj, victim, TO_VICT  );

	oprog_call(OPROG_GIVE, obj, ch, victim);
	char_puts("Your power makes all around the world shivering.\n",ch);
}

void do_control(CHAR_DATA *ch, const char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int chance;
	int sn;
	race_t *r;

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

	if ((sn = sn_lookup("control animal")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (arg[0] == '\0') {
		char_puts("Charm what?\n", ch);
		return;
	}

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

	if ((r = race_lookup(ORG_RACE(victim))) && r->pcdata) {
		char_puts("You should try this on monsters?\n", ch);
		return;
	}

	if (count_charmed(ch))
		return;

	if (is_safe(ch, victim))
		return;

	WAIT_STATE(ch, SKILL(sn)->beats);

	chance += get_curr_stat(ch,STAT_CHA);
	chance += (ch->level - victim->level) * 3;
	chance +=
	(get_curr_stat(ch,STAT_INT) - get_curr_stat(victim,STAT_INT));

	if (IS_AFFECTED(victim, AFF_CHARM)
	||  IS_AFFECTED(ch, AFF_CHARM)
	||  number_percent() > chance
	||  ch->level < (victim->level + 2)
	||  IS_SET(victim->imm_flags,IMM_CHARM)
	||  (IS_NPC(victim) && victim->pIndexData->pShop != NULL)) {
		check_improve(ch, sn, FALSE, 2);
		do_say(victim,"I'm not about to follow you!");
		do_murder(victim, ch->name);
		return;
	}

	check_improve(ch, sn, TRUE, 2);

	if (victim->master)
		stop_follower(victim);
	SET_BIT(victim->affected_by, AFF_CHARM);
	victim->master = victim->leader = ch;

	act("Isn't $n just so nice?", ch, NULL, victim, TO_VICT);
	if (ch != victim)
		act("$N looks at you with adoring eyes.",
		    ch, NULL, victim, TO_NOTVICT);
}

void do_make_arrow(CHAR_DATA *ch, const char *argument)
{
	OBJ_DATA *arrow;
	AFFECT_DATA af;
	OBJ_INDEX_DATA *pObjIndex;
	int count, mana, wait;
	char arg[MAX_INPUT_LENGTH];
	int chance;
	int color_chance = 100;
	int vnum = -1;
	int sn;
	int color = -1;

	if (IS_NPC(ch))
		return;

	if ((sn = sn_lookup("make arrow")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("You don't know how to make arrows.\n", ch);
		return;
	}

	if (ch->in_room->sector_type != SECT_FIELD
	&&  ch->in_room->sector_type != SECT_FOREST
	&&  ch->in_room->sector_type != SECT_HILLS) {
		char_puts("You couldn't find enough wood.\n", ch);
		return;
	}

	mana = SKILL(sn)->min_mana;
	wait = SKILL(sn)->beats;

	argument = one_argument(argument, arg, sizeof(arg));
	if (arg[0] == '\0')
		vnum = OBJ_VNUM_WOODEN_ARROW;
	else if (!str_prefix(arg, "green")) {
		color = sn_lookup("green arrow");
		vnum = OBJ_VNUM_GREEN_ARROW;
	}
	else if (!str_prefix(arg, "red")) {
		color = sn_lookup("red arrow");
		vnum = OBJ_VNUM_RED_ARROW;
	}
	else if (!str_prefix(arg, "white")) {
		color = sn_lookup("white arrow");
		vnum = OBJ_VNUM_WHITE_ARROW;
	}
	else if (!str_prefix(arg, "blue")) {
		color = sn_lookup("blue arrow");
		vnum = OBJ_VNUM_BLUE_ARROW;
	}

	if (vnum < 0) {
		char_puts("You don't know how to make "
			  "that kind of arrow.\n", ch);
		return;
	}

	if (color > 0) {
		color_chance = get_skill(ch, color);
		mana += SKILL(color)->min_mana;
		wait += SKILL(color)->beats;
	}

	if (ch->mana < mana) {
		char_puts("You don't have enough energy "
			  "to make that kind of arrows.\n", ch);
		return;
	}

	ch->mana -= mana;
	WAIT_STATE(ch, wait);

	char_puts("You start to make arrows!\n",ch);
	act("$n starts to make arrows!", ch, NULL, NULL, TO_ROOM);
	pObjIndex = get_obj_index(vnum);
	for(count = 0; count < ch->level / 5; count++) {
		if (number_percent() > chance * color_chance / 100) {
			char_puts("You failed to make the arrow, "
				  "and broke it.\n", ch);
			check_improve(ch, sn, FALSE, 3);
			if (color > 0)
				check_improve(ch, color, FALSE, 3);
			continue;
		}

		check_improve(ch, sn, TRUE, 3);
		if (color > 0)
			check_improve(ch, color, TRUE, 3);

		arrow = create_obj(pObjIndex, 0);
		arrow->level = ch->level;
		autoweapon(arrow, 100);

		arrow->owner = mlstr_dup(ch->short_descr);

		af.where	 = TO_OBJECT;
		af.type		 = sn;
		af.level	 = ch->level;
		af.duration	 = -1;
		af.location	 = APPLY_HITROLL;
		af.modifier	 = ch->level / 10;
		af.bitvector 	 = 0;
		affect_to_obj(arrow, &af);

		af.where	= TO_OBJECT;
		af.type		= sn;
		af.level	= ch->level;
		af.duration	= -1;
		af.location	= APPLY_DAMROLL;
		af.modifier	= ch->level / 10;
		af.bitvector	= 0;
		affect_to_obj(arrow, &af);

		obj_to_char(arrow, ch);
		act_puts("You successfully make $p.",
			 ch, arrow, NULL, TO_CHAR, POS_DEAD);
	}
}

void do_make_bow(CHAR_DATA *ch, const char *argument)
{
	OBJ_DATA *	bow;
	AFFECT_DATA	af;
	int		mana;
	int		sn;
	int		chance;

	if (IS_NPC(ch))
		return;

	if ((sn = sn_lookup("make bow")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("You don't know how to make bows.\n", ch);
		return;
	}

	if (ch->in_room->sector_type != SECT_FIELD
	&&  ch->in_room->sector_type != SECT_FOREST
	&&  ch->in_room->sector_type != SECT_HILLS) {
		char_puts("You couldn't find enough wood.\n", ch);
		return;
	}

	mana = SKILL(sn)->min_mana;
	if (ch->mana < mana) {
		char_puts("You don't have enough energy to make a bow.\n",
			     ch);
		return;
	}
	ch->mana -= mana;
	WAIT_STATE(ch, SKILL(sn)->beats);

	if (number_percent() > chance) {
		char_puts("You failed to make the bow, and broke it.\n",
			     ch);
		check_improve(ch, sn, FALSE, 1);
		return;
	}
	check_improve(ch, sn, TRUE, 1);

	bow = create_obj(get_obj_index(OBJ_VNUM_RANGER_BOW), 0);
	bow->level = ch->level;
	autoweapon(bow, 100);

	af.where	= TO_OBJECT;
	af.type		= sn;
	af.level	= ch->level;
	af.duration	= -1;
	af.location	= APPLY_HITROLL;
	af.modifier	= ch->level / 10;
	af.bitvector 	= 0;
	affect_to_obj(bow, &af);

	af.where	= TO_OBJECT;
	af.type		= sn;
	af.level	= ch->level;
	af.duration	= -1;
	af.location	= APPLY_DAMROLL;
	af.modifier	= ch->level / 10;
	af.bitvector 	= 0;
	affect_to_obj(bow, &af);

	obj_to_char(bow, ch);
	act_puts("You successfully make $p.", ch, bow, NULL, TO_CHAR, POS_DEAD);
}

void do_make_katana(CHAR_DATA *ch, const char *argument)
{
	OBJ_DATA *katana;
	AFFECT_DATA af;
	OBJ_DATA *part;
	char arg[MAX_INPUT_LENGTH];
	int chance;
	int mana;

	one_argument(argument, arg, sizeof(arg));
	
	if ((chance = get_skill(ch, gsn_make_katana)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}
	
	if (is_affected(ch, gsn_make_katana)) {
		char_puts("But you've already got one katana!\n", ch);
		return;
	}
	
	mana = SKILL(gsn_make_katana)->min_mana;
	if (ch->mana < mana) {
		char_puts("You feel too weak to concentrate on a katana.\n",
			  ch);
		return;
	}
	
	if (arg[0] == '\0') {
		char_puts("Make a katana from what?\n", ch);
		return;
	}
	
	if ((part = get_obj_carry(ch, arg)) == NULL) {
		char_puts("You do not have chunk of iron.\n", ch);
		return;
	}

	if (part->pIndexData->vnum != OBJ_VNUM_CHUNK_IRON) {
		char_puts("You do not have the right material.\n", ch);
		return;
	}

	if (number_percent() < chance / 3 * 2) {
		char_puts("You failed and destroyed it.\n", ch);
		extract_obj(part, 0);
		return;
	} 

	WAIT_STATE(ch, SKILL(gsn_make_katana)->beats);

	if (number_percent() < chance) {
		af.where	= TO_AFFECTS;
		af.type		= gsn_katana;
		af.level	= ch->level;
		af.duration	= ch->level;
		af.modifier	= 0;
		af.bitvector 	= 0;      
		af.location	= 0;
		affect_to_char(ch,&af);
	
		katana = create_obj(get_obj_index(OBJ_VNUM_KATANA_SWORD), 0);
		katana->level = ch->level;
		autoweapon(katana, 100);
		katana->owner = mlstr_dup(ch->short_descr);
		katana->cost  = 0;
		ch->mana -= mana;

		af.where	= TO_OBJECT;
		af.type 	= gsn_katana;
		af.level	= ch->level;
		af.duration	= -1;
		af.location	= APPLY_DAMROLL;
		af.modifier	= ch->level / 10;
		af.bitvector	= 0;
		affect_to_obj(katana, &af);

		af.location	= APPLY_HITROLL;
		affect_to_obj(katana, &af);

		katana->ed = ed_new2(katana->pIndexData->ed, ch->name);
			
		obj_to_char(katana, ch);
		check_improve(ch, gsn_make_katana, TRUE, 1);
			
		act("You make a katana from $p!",ch,part,NULL,TO_CHAR);
		act("$n makes a katana from $p!",ch,part,NULL,TO_ROOM);
			
		extract_obj(part, 0);
		return;
	}
	else {
		char_puts("You destroyed it.\n", ch);
		extract_obj(part, 0);
		ch->mana -= mana/2;
		check_improve(ch, gsn_make_katana, FALSE, 1);
	}
}

/*Added by Osya*/
void do_homepoint(CHAR_DATA *ch, const char *argument)
{
        AFFECT_DATA af;
        int sn;
        int chance;
        char arg[MAX_INPUT_LENGTH];

        if ((sn = sn_lookup("homepoint")) < 0
        ||  (chance = get_skill(ch, sn)) == 0) {
                char_puts("Huh?\n", ch);
                return;
        }

        if (is_affected(ch, sn)) {
                char_puts("You fatigue for searching new home.\n", ch) ;
                return;
        }

        if (IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_PEACE |
                                            ROOM_PRIVATE | ROOM_SOLITARY)
        ||  (ch->in_room->sector_type != SECT_FIELD
        &&   ch->in_room->sector_type != SECT_FOREST
        &&   ch->in_room->sector_type != SECT_MOUNTAIN
        &&   ch->in_room->sector_type != SECT_HILLS)) {
                char_puts("You are cannot set home here.\n",
                             ch);
                return;
        }

        if (ch->mana < ch->max_mana) {
                char_puts("You don't have strength to make a new home.\n",
                             ch);
                return;
        }

        ch->mana = 0 ;

        if (number_percent() > chance) {
                char_puts("You failed to make your homepoint.\n", ch);
                check_improve(ch, sn, FALSE, 4);
                return;
        }

        check_improve(ch, sn, TRUE, 4);
        WAIT_STATE(ch, SKILL(sn)->beats);

        char_puts("You succeeded to make your homepoint.\n", ch);
        act("$n succeeded to make $s homepoint. ", ch, NULL, NULL, TO_ROOM);

        af.where        = TO_AFFECTS;
        af.type         = sn;
        af.level        = ch->level;
        af.duration     = 100;
        af.bitvector    = 0;
        af.modifier     = 0;
        af.location     = APPLY_NONE;
        affect_to_char(ch, &af);

        argument = one_argument(argument, arg, sizeof(arg));
	if (arg[0] && !str_prefix(arg, "motherland"))
		ch->pcdata->homepoint = NULL;
        else 
		ch->pcdata->homepoint = ch->in_room; 
}

void do_make_shuriken(CHAR_DATA *ch, const char *argument)
{
        OBJ_DATA *shuriken;
        int mana;
        int chance;
        int sn;
        int count;

        if (IS_NPC(ch))
                return;

        if ((sn = sn_lookup("make shuriken")) < 0
        ||  (chance = get_skill(ch, sn)) == 0) {
                char_puts("You do not know the art of creating shurikens.\n", ch);
                return;
        }

        mana = SKILL(sn)->min_mana;

        if (ch->mana < mana) {
                char_puts("You don't have enough energy "
                          "to make a shuriken.\n", ch);
                return;
        }

        ch->mana -= mana;
        WAIT_STATE(ch, SKILL(sn)->beats);

        char_puts("You settle down to create shurikens.\n",ch);
        act("$n begins creating shurikens.", ch, NULL, NULL, TO_ROOM);
        for(count = 0; count < ch->level / 15; count++) {
                if (number_percent() > chance) {
                        char_puts("You cut the shuriken too small and it broke.\n", ch);
                        check_improve(ch, sn, FALSE, 3);
                        continue;
                }

                check_improve(ch, sn, TRUE, 3);

                shuriken = create_obj(get_obj_index(OBJ_VNUM_SHURIKEN), 0);
                shuriken->level = ch->level;
		autoweapon(shuriken, 100);
                obj_to_char(shuriken, ch);
                act_puts("You successfully create $p.",
                         ch, shuriken, NULL, TO_CHAR, POS_DEAD);
        }
}

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

	argument = one_argument(argument, arg, sizeof(arg));
	if (arg[0] == '\0') {
		char_puts("What should you make?\n",ch);
		return;
	}

	if (!str_prefix(arg, "arrow"))
		do_make_arrow(ch, argument);
	else if (!str_prefix(arg, "bow"))
		do_make_bow(ch, argument);
	else if(!str_prefix(arg, "shuriken"))
		do_make_shuriken(ch, argument);
	else if(!str_prefix(arg, "katana"))
		do_make_katana(ch, argument);
	else
		do_make(ch, str_empty);
}

void do_detect_hidden(CHAR_DATA *ch, const char *argument)
{
	AFFECT_DATA	af;
	int		chance;
	int		sn;

	if ((sn = sn_lookup("detect hide")) < 0
	||  (chance = get_skill(ch, sn)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (IS_AFFECTED(ch, AFF_DETECT_HIDDEN)) {
		char_puts("You are already as alert as you can be. \n",ch);
		return;
	}

	if (number_percent() > chance) {
		char_puts("You peer intently at the shadows "
			     "but they are unrevealing.\n", ch);
		check_improve(ch, sn, FALSE, 1);
		return;
	}

	af.where     = TO_AFFECTS;
	af.type      = sn;
	af.level     = ch->level;
	af.duration  = ch->level;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_DETECT_HIDDEN;
	affect_to_char(ch, &af);
	char_puts("Your awareness improves.\n", ch);
	check_improve(ch, sn, TRUE, 1);
}

void do_resistance(CHAR_DATA *ch, const char *argument)
{
	int chance;
	int mana;
	pcskill_t* ps;
	
	if (IS_NPC(ch)) 
		return;
	if ((ps = pcskill_lookup(ch, gsn_resistance)) == NULL
	||  skill_level(ch, gsn_resistance) > ch->level)
		chance = 0;
	else
		chance = ps->percent;

	if (chance == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (is_affected(ch, gsn_resistance)) {
		char_puts("You are as resistant as you will get.\n", ch);
		return;
	}

	mana = SKILL(gsn_resistance)->min_mana;
	if (ch->mana < mana) {
		char_puts("You cannot muster up the energy.\n", ch);
		return;
	}

	WAIT_STATE(ch, SKILL(gsn_resistance)->beats);

	if (number_percent() < chance) {
		AFFECT_DATA af;
		
		af.where	= TO_AFFECTS;
		af.type 	= gsn_resistance;
		af.level 	= ch->level;
		af.duration	= ch->level / 6;
		af.location	= APPLY_NONE;
		af.modifier	= 0;
		af.bitvector	= 0;

		affect_to_char(ch, &af);
		ch->mana -= mana;

		act("You feel tough!", ch, NULL, NULL, TO_CHAR);
		act("$n looks tougher.", ch, NULL, NULL, TO_ROOM);
		check_improve(ch, gsn_resistance, TRUE, 1);
	}
	else {
		ch->mana -= mana/2;

		char_puts("You flex your muscles, "
			  "but you don't feel tougher.\n", ch);
		act("$n flexes $s muscles, trying to look tough.",
		    ch, NULL, NULL, TO_ROOM);
		check_improve(ch, gsn_resistance, FALSE, 1);
	}
}

void do_trophy(CHAR_DATA *ch, const char *argument)
{
	int trophy_vnum;
	OBJ_DATA *trophy;
	AFFECT_DATA af;
	OBJ_DATA *part;
	char arg[MAX_INPUT_LENGTH];
	int level;
	int chance;
	int mana;
	
	if ((chance = get_skill(ch, gsn_trophy)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}
	
	if (is_affected(ch, gsn_trophy)) {
		char_puts("But you've already got one trophy!\n", ch);
		return;
	}
	
	mana = SKILL(gsn_trophy)->min_mana;
	if (ch->mana < mana) {
		char_puts("You feel too weak to concentrate on a trophy.\n",
			  ch);
		return;
	}
	
	one_argument(argument, arg, sizeof(arg));
	if (arg[0] == '\0') {
		char_puts("Make a trophy of what?\n", ch);
		return;
	}
	
	if ((part = get_obj_carry(ch, arg)) == NULL) {
		char_puts("You do not have that body part.\n", ch);
		return;
	}

	WAIT_STATE(ch, SKILL(gsn_trophy)->beats);

	if (part->pIndexData->vnum == OBJ_VNUM_SLICED_ARM
	||  part->pIndexData->vnum == OBJ_VNUM_SLICED_LEG
	||  part->pIndexData->vnum == OBJ_VNUM_SEVERED_HEAD
	||  part->pIndexData->vnum == OBJ_VNUM_TORN_HEART
	||  part->pIndexData->vnum == OBJ_VNUM_GUTS)
		trophy_vnum = OBJ_VNUM_BATTLE_PONCHO;
	else if (part->pIndexData->vnum == OBJ_VNUM_BRAINS) {
		char_puts("Why don't you just eat those instead?\n", ch);
		return;
	}
	else {
		char_puts("You can't make a trophy out of that!\n", ch);
		return;
	}

	if (mlstr_null(part->owner)) {
		char_puts("Invalid body part.\n", ch);
		return;
	}

	if (!IS_NPC(ch) && number_percent() < chance) {
		af.where  = TO_AFFECTS;
		af.type	= gsn_trophy;
		af.level	= ch->level;
		af.duration	= ch->level/2;
		af.modifier	= 0;
		af.bitvector 	= 0;
		
		af.location	= 0;
		affect_to_char(ch,&af);
	
		if (trophy_vnum != 0) {
			level = UMIN(part->level + 5, MAX_LEVEL);
 
			trophy = create_obj_of(get_obj_index(trophy_vnum),
					       part->owner);
			trophy->level = ch->level;
			trophy->timer = ch->level * 2;
			trophy->cost  = 0;
			ch->mana -= mana;
			af.where	= TO_OBJECT;
			af.type 	= gsn_trophy;
			af.level	= level;
			af.duration	= -1;
			af.location	= APPLY_DAMROLL;
			af.modifier	= ch->level / 10 + number_range(2,4);
			af.bitvector	= 0;
			affect_to_obj(trophy, &af);

			af.location	= APPLY_HITROLL;
			af.modifier	= ch->level / 10 + number_range(2,4);
			affect_to_obj(trophy, &af);

			af.location	= APPLY_INT;
			af.modifier	= level>20?-2:-1;
			affect_to_obj(trophy, &af);

			af.location	= APPLY_STR;
			af.modifier	= level>20?2:1;
			affect_to_obj(trophy, &af);

			trophy->value[ITEM_ARMOR_AC_PIERCE] = ch->level / 3;
			trophy->value[ITEM_ARMOR_AC_BASH] = ch->level / 3;
			trophy->value[ITEM_ARMOR_AC_SLASH] = ch->level / 3;
			trophy->value[ITEM_ARMOR_AC_EXOTIC] = ch->level / 3;

			obj_to_char(trophy, ch);
			  check_improve(ch, gsn_trophy, TRUE, 1);
			
			act("You make a poncho from $p!",
			    ch, part, NULL, TO_CHAR);
			act("$n makes a poncho from $p!",
			    ch, part, NULL, TO_ROOM);
			
			extract_obj(part, 0);
			return;
		}
	}
	else {
		char_puts("You destroyed it.\n", ch);
		extract_obj(part, 0);
		ch->mana -= mana/2;
		check_improve(ch, gsn_trophy, FALSE, 1);
	}
}
	
void do_truesight(CHAR_DATA *ch, const char *argument)
{
	int chance;

	if ((chance = get_skill(ch, gsn_truesight)) == 0) {
		char_puts("Huh?\n", ch);
		return;
	}

	if (is_affected(ch, gsn_truesight)) {
		char_puts("Your eyes are as sharp as they can get.\n", ch);
		return;
	}

	WAIT_STATE(ch, SKILL(gsn_truesight)->beats);

	if (number_percent() < chance) {
		AFFECT_DATA af;
		
		af.where    = TO_AFFECTS;
		af.type     = gsn_truesight;
		af.level    = ch->level;
		af.duration = ch->level/2 + 5;
		af.location = APPLY_NONE;
		af.modifier = 0;
			
		af.bitvector = AFF_DETECT_INVIS;
		affect_to_char(ch, &af);

/*		af.bitvector = AFF_DETECT_IMP_INVIS;
		affect_to_char(ch,&af);
*/
		
		af.bitvector = AFF_DETECT_MAGIC;
		affect_to_char(ch,&af);

		act("You look around sharply!",ch,NULL,NULL,TO_CHAR);
		act("$n looks more enlightened.",ch,NULL,NULL,TO_ROOM);
		check_improve(ch,gsn_truesight,TRUE,1);
	}
	else {
		char_puts("You look about sharply, but you don't see "
			     "anything new.\n" ,ch);
		act("$n looks around sharply but doesn't seem enlightened.",
			ch,NULL,NULL,TO_ROOM);
		check_improve(ch, gsn_truesight, FALSE, 1);
	}
}