asgard/
asgard/.settings/
asgard/area/
asgard/data/clans/
asgard/data/clans/history/
asgard/data/rosters/
asgard/src/notice/
/***************************************************************************
 *  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			   *
 ***************************************************************************/
/*************************************************************************** 
 *       ROT 1.4 is copyright 1996-1997 by Russ Walsh                       *
 *       By using this code, you have agreed to follow the terms of the     *
 *       ROT license, in the file doc/rot.license                           *
 ***************************************************************************/
#if defined(macintosh)
#include <types.h>
#include <time.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "recycle.h"
#include "magic.h"
/* command procedures needed */
DECLARE_DO_FUN(do_help );
DECLARE_DO_FUN(do_say );
DECLARE_DO_FUN(do_handle );
DECLARE_DO_FUN(do_side_kick );
DECLARE_DO_FUN(do_spin_kick );
DECLARE_DO_FUN(do_blindness_dust);
DECLARE_DO_FUN(do_will_of_iron );
//DECLARE_DO_FUN(do_spinkick      );
DECLARE_DO_FUN(do_purify_body );
DECLARE_DO_FUN(do_healing_trance );
DECLARE_DO_FUN(do_yell );
DECLARE_DO_FUN(do_rest );
DECLARE_DO_FUN(do_sleep );

int handling_improve(CHAR_DATA *ch, sh_int sn);
void check_ground_stomp(CHAR_DATA *ch,CHAR_DATA *victim,int chance,int dam);
void check_follow_through(CHAR_DATA *ch, CHAR_DATA *victim, int dam);
bool check_dispel( int dis_level, CHAR_DATA *victim, int sn);
bool is_safe_quiet(CHAR_DATA * ch, CHAR_DATA * victim);
void improve_toughness(CHAR_DATA *ch);

char *magtype_name(int id) {
	switch (id) {
	case MAGIC_WHITE:
		return "white";
	case MAGIC_RED:
		return "red";
	case MAGIC_BLUE:
		return "blue";
	case MAGIC_GREEN:
		return "green";
	case MAGIC_BLACK:
		return "black";
	case MAGIC_ORANGE:
		return "orange";
	default:
		return "unknown";
	}
}


/* used to get new skills */
void do_gain(CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	char arg[MAX_INPUT_LENGTH];
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	CHAR_DATA *trainer;
	int sn = 0;

	if (IS_NPC(ch))
		return;

	/* find a trainer */
	for (trainer = ch->in_room->people; trainer != NULL; trainer
			= trainer->next_in_room)
		if (IS_NPC(trainer) && IS_SET(trainer->act,ACT_GAIN))
			break;

	if (trainer == NULL || !can_see(ch, trainer))
	{
		send_to_char("You can't do that here.\n\r", ch);
		return;
	}

	strcpy(arg2, argument);
	argument = one_argument(argument, arg);
	strcpy(arg1, argument);

	if (arg[0] == '\0')
	{
		do_say(trainer, "{_Pardon me?{x");
		return;
	}

	if (!str_prefix(arg, "list"))
	{
		int col;

		col = 0;

		sprintf(buf, "%-18s %-5s %-18s %-5s %-18s %-5s\n\r", "skill", "cost",
				"skill", "cost", "skill", "cost");
		send_to_char(buf, ch);

		for (sn = 0; sn < MAX_SKILL; sn++)
		{
			if (skill_table[sn].name == NULL)
				break;

			if (!ch->pcdata->learned[sn]
					&& skill_table[sn].skill_level[ch->class] <= LEVEL_HERO)
			{
				sprintf(buf, "{&%-18s {8%-5d{x ", skill_table[sn].name,
						skill_table[sn].rating[ch->class]);
				send_to_char(buf, ch);
				if (++col % 3 == 0)
					send_to_char("\n\r", ch);
			}
		}
		if (col % 3 != 0)
			send_to_char("\n\r", ch);
		return;
	}

	if (!str_prefix(arg, "convert"))
	{
		if (ch->practice < 6)
		{
			act("$N tells you 'You are not yet ready.{x'", ch, NULL, trainer,
					TO_CHAR);
			return;
		}
		if (!str_cmp(arg1, "all"))
		{
			act("$N converts all your practices to trains.", ch, NULL, trainer,
					TO_CHAR);
			while (ch->practice >= 6)
			{ //Do it.  All your practice are belong to train.
				ch->practice -= 6;
				ch->train += 1;
			}
			return;
		}
		else
		{
			act("$N helps you apply your practice to training", ch, NULL,
					trainer, TO_CHAR);
			ch->practice -= 6;
			ch->train += 1;
			return;
		}
	}

	if (!str_prefix(arg, "study"))
	{
		if (ch->train < 1)
		{
			act("$N tells you 'You are not yet ready.{x'", ch, NULL, trainer,
					TO_CHAR);
			return;
		}
		if (!str_cmp(arg1, "all"))
		{
			act("$N converts all your trains to practices.", ch, NULL, trainer,
					TO_CHAR);
			while (ch->train > 0)
			{ //Do it.  All your trains are belong to practice.
				ch->practice += 6;
				ch->train -= 1;
			}
			return;
		}
		else
		{
			act("$N helps you apply your training to practice", ch, NULL,
					trainer, TO_CHAR);
			ch->train -= 1;
			ch->practice += 6;
			return;
		}
	}

	if (!str_prefix(arg, "points"))
	{
		if (ch->train < 2)
		{
			act("$N tells you '{_You are not yet ready.{x'", ch, NULL, trainer,
					TO_CHAR);
			return;
		}

		if (ch->pcdata->points <= 40)
		{
			act("$N tells you '{_There would be no point in that.{x'", ch,
					NULL, trainer, TO_CHAR);
			return;
		}

		act("$N trains you, and you feel more at ease with your skills.", ch,
				NULL, trainer, TO_CHAR);

		ch->train -= 2;
		ch->pcdata->points -= 1;
		ch->exp = (long) exp_per_level(ch, ch->pcdata->points) * ch->level;
		return;
	}

	/* else add a group/skill */

	sn = skill_lookup(arg2);

	if (sn == skill_lookup("conceal"))
	{
		send_to_char("You cannot gain that.\n\r", ch);
		return;
	}

	if (sn > -1)
	{

		if (ch->pcdata->learned[sn])
		{
			act("$N tells you '{_You already know that skill!{x'", ch, NULL,
					trainer, TO_CHAR);
			return;
		}

		if (skill_table[sn].skill_level[ch->class] > LEVEL_HERO)
		{
			act("$N tells you '{_That skill is beyond your powers.{x'", ch,
					NULL, trainer, TO_CHAR);
			return;
		}

		if (ch->train < skill_table[sn].rating[ch->class])
		{
			act("$N tells you '{_You are not yet ready for that skill.{x'", ch,
					NULL, trainer, TO_CHAR);
			return;
		}

		/* add the skill */
		ch->pcdata->learned[sn] = 1;
		ch->pcdata->learnlvl[sn] = skill_table[sn].skill_level[ch->class];
		act("$N trains you in the art of $t", ch, skill_table[sn].name,
				trainer, TO_CHAR);
		ch->train -= skill_table[sn].rating[ch->class];
		return;
	}

	act("$N tells you '{_I do not understand...{x'", ch, NULL, trainer, TO_CHAR);
}

/* RT spells and skills show the players spells (or skills) */
void do_garrote(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int chance;

	one_argument(argument, arg);

	if ((chance = get_skill(ch, gsn_garrote)) == 0 || (!IS_NPC(ch) && ch->level
			< skill_table[gsn_garrote].skill_level[ch->class]))
	{
		send_to_char("Garrote? What's that?{x\n\r", ch);
		return;
	}

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

	if (ch->fighting != NULL)
	{
		send_to_char("{hYou're facing the wrong end.{x\n\r", ch);
		return;
	}

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

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

	if (is_safe(ch, victim))
		return;

	if (IS_NPC(victim) && victim->fighting != NULL && !is_same_group(ch,
			victim->fighting)
			&& !IS_SET(victim->in_room->room_flags, ROOM_ARENA))
	{
		send_to_char("Kill stealing is not permitted.\n\r", ch);
		return;
	}
	if (victim->hit < victim->max_hit / 4)
	{
		act("$N is hurt and suspicious ... you can't sneak up.", ch, NULL,
				victim, TO_CHAR );
		return;
	}

	if ((ch->fighting == NULL) && (!IS_NPC( ch )) && (!IS_NPC( victim )))
	{
		ch->attacker = TRUE;
		victim->attacker = FALSE;
	}

	/* dexterity */
	chance += get_curr_stat(ch, STAT_DEX);
	chance -= get_curr_stat(victim, STAT_DEX) / 2;

	/* speed */
	if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))
		chance += 25;
	if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))
		chance -= 10;

	/* level */
	chance += (ch->level - victim->level) * 4;

	/* sloppy hack to prevent false zeroes */
	if (chance % 5 == 0)
		chance += 1;

	/* now the attack */
	if (number_percent() * 2 < chance)
	{
		AFFECT_DATA af;
		act("{k$n is choked by a wire around the neck!{x", victim, NULL, NULL,
				TO_ROOM);
		act("{i$n slips a wire around your neck!{x", ch, NULL, victim, TO_VICT);
		multi_hit(ch, victim, gsn_garrote);
		send_to_char("{7You choke and gag!{x\n\r", victim);
		check_improve(ch, gsn_garrote, TRUE, 2);
		WAIT_STATE(ch,skill_table[gsn_garrote].beats)
;
		/* Leave the garrote on the choke the shit out of em */

		af.where = TO_AFFECTS2;
		af.type = gsn_garrote;
		af.level = ch->level;
		af.duration = 3;
		af.location = APPLY_HITROLL;
		af.modifier = -150;
		af.bitvector = AFF2_GARROTE;

		affect_to_char(victim,&af);
	}
	else
	{
		damage(ch,victim,0,gsn_garrote,DAM_NONE,TRUE, 0);
		check_improve(ch,gsn_garrote,FALSE,2);
		WAIT_STATE(ch,skill_table[gsn_garrote].beats);
	}
}

void do_spells(CHAR_DATA *ch, char *argument)
{
	char spell_list[LEVEL_HERO][MAX_STRING_LENGTH];
	char spell_columns[LEVEL_HERO];
	int sn, lev, mana;
	bool found = FALSE;
	char buf[MAX_STRING_LENGTH];
	char arg[MAX_STRING_LENGTH];
	bool ShowColors = TRUE;
	bool fWhite = FALSE;
	bool fRed = FALSE;
	bool fBlue = FALSE;
	bool fGreen = FALSE;
	bool fOrange = FALSE;
	bool fBlack = FALSE;

	if (IS_NPC(ch))
		return;

	argument = one_argument(argument, arg);

	if (arg[0] != '\0')
	{
		if (!str_cmp(arg, "white"))
		{
			fWhite = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {7White{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_WHITE]);
		}
		if (!str_cmp(arg, "red"))
		{
			fRed = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {!Red{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_RED]);
		}
		if (!str_cmp(arg, "blue"))
		{
			fBlue = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {$Blue{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_BLUE]);
		}
		if (!str_cmp(arg, "green"))
		{
			fGreen = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {@Green{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_GREEN]);
		}
		if (!str_cmp(arg, "black"))
		{
			fBlack = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {8Black{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_BLACK]);
		}
		if (!str_cmp(arg, "orange"))
		{
			fOrange = TRUE;
			ShowColors = FALSE;
			printf_to_char(ch, "Proficiecy in {3Orange{x Magic: {&%d{x.\n\r",
					ch->magic[MAGIC_ORANGE]);
		}
	}

	/* initilize data */
	for (lev = 0; lev < LEVEL_HERO; lev++)
	{
		spell_columns[lev] = 0;
		spell_list[lev][0] = '\0';
	}

	for (sn = 0; sn < MAX_SKILL; sn++)
	{
		if (skill_table[sn].name == NULL)
			break;

		/*      if (skill_table[sn].skill_level[ch->class] < LEVEL_HERO &&
		 skill_table[sn].spell_fun != spell_null &&
		 ch->pcdata->learned[sn] > 0)
		 {
		 found = TRUE;
		 lev = skill_table[sn].skill_level[ch->class]; */

		lev = ch->pcdata->learnlvl[sn];

		if (lev < LEVEL_HERO && skill_table[sn].spell_fun != spell_null
				&& ch->pcdata->learned[sn] > 0)
		{
			found = TRUE;

			if (ch->level < lev)
			{

				if (!ShowColors)
				{
					if (fWhite && !IS_SPELL_WHITE(sn))
						continue;
					else if (fRed && !IS_SPELL_RED(sn))
						continue;
					else if (fBlue && !IS_SPELL_BLUE(sn))
						continue;
					else if (fGreen && !IS_SPELL_GREEN(sn))
						continue;
					else if (fOrange && !IS_SPELL_ORANGE(sn))
						continue;
					else if (fBlack && !IS_SPELL_BLACK(sn))
						continue;
				}

				if (IS_SPELL_WHITE(sn))
					sprintf(buf, "{&%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else if (IS_SPELL_RED(sn))
					sprintf(buf, "{!%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else if (IS_SPELL_BLUE(sn))
					sprintf(buf, "{$%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else if (IS_SPELL_GREEN(sn))
					sprintf(buf, "{@%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else if (IS_SPELL_ORANGE(sn))
					sprintf(buf, "{3%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else if (IS_SPELL_BLACK(sn))
					sprintf(buf, "{8%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
				else
					sprintf(buf, "{C%-18s{x  {#n/a{x      ",
							skill_table[sn].name);
			}
			else
			{

				if (!ShowColors)
				{
					if (fWhite && !IS_SPELL_WHITE(sn))
						continue;
					else if (fRed && !IS_SPELL_RED(sn))
						continue;
					else if (fBlue && !IS_SPELL_BLUE(sn))
						continue;
					else if (fGreen && !IS_SPELL_GREEN(sn))
						continue;
					else if (fOrange && !IS_SPELL_ORANGE(sn))
						continue;
					else if (fBlack && !IS_SPELL_BLACK(sn))
						continue;
				}

				mana = UMAX(skill_table[sn].min_mana,
						100/(2 + ch->level - lev));
				if (IS_SPELL_WHITE(sn))//maybe put * 3 or 2 after [sn] --bree learned
					sprintf(buf, "{&%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else if (IS_SPELL_BLUE(sn))
					sprintf(buf, "{$%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else if (IS_SPELL_RED(sn))
					sprintf(buf, "{!%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else if (IS_SPELL_GREEN(sn))
					sprintf(buf, "{@%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else if (IS_SPELL_ORANGE(sn))
					sprintf(buf, "{3%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else if (IS_SPELL_BLACK(sn))
					sprintf(buf, "{8%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);
				else
					sprintf(buf, "{C%-18s  {#%3d{x mana {@({&%d{@){x ",
							skill_table[sn].name, mana, ch->pcdata->learned[sn]);

			}

			if (spell_list[lev][0] == '\0')
				sprintf(spell_list[lev], "\n\r{BLevel{x {&%2d{x: %s", lev, buf);
			else /* append */
			{
				if (++spell_columns[lev] % 2 == 0)
					strcat(spell_list[lev], "\n\r          ");
				strcat(spell_list[lev], buf);
			}
		}
	}

	/* return results */

	if (!found)
	{
		send_to_char("You know no spells.\n\r", ch);
		return;
	}

	for (lev = 0; lev < LEVEL_HERO; lev++)
		if (spell_list[lev][0] != '\0')
			send_to_char(spell_list[lev], ch);
	send_to_char("\n\r", ch);
}

void do_skills(CHAR_DATA *ch, char *argument)
{
	char skill_list[LEVEL_HERO][MAX_STRING_LENGTH];
	char skill_columns[LEVEL_HERO];
	int sn, lev;
	bool found = FALSE;
	char buf[MAX_STRING_LENGTH];

	if (IS_NPC(ch))
		return;

	/* initilize data */
	for (lev = 0; lev < LEVEL_HERO; lev++)
	{
		skill_columns[lev] = 0;
		skill_list[lev][0] = '\0';
	}

	for (sn = 0; sn < MAX_SKILL; sn++)
	{
		if (skill_table[sn].name == NULL)
			break;

		lev = ch->pcdata->learnlvl[sn];

		/*      if (skill_table[sn].skill_level[ch->class] < LEVEL_HERO && */

		if (lev < LEVEL_HERO && skill_table[sn].spell_fun == spell_null
				&& ch->pcdata->learned[sn] > 0)
		{
			found = TRUE;
			//      lev = skill_table[sn].skill_level[ch->class];

			if (ch->level < lev)
				sprintf(buf, "{R%-18s{x {@n/a{x      ", skill_table[sn].name);
			else
				sprintf(buf, "{R%-18s{x {@%3d%%{x      ", skill_table[sn].name,
						ch->pcdata->learned[sn]);

			if (skill_list[lev][0] == '\0')
				sprintf(skill_list[lev], "\n\r{yLevel {&%2d{x: %s", lev, buf);
			else /* append */
			{
				if (++skill_columns[lev] % 2 == 0)
					strcat(skill_list[lev], "\n\r          ");
				strcat(skill_list[lev], buf);
			}
		}
	}

	/* return results */

	if (!found)
	{
		send_to_char("You know no skills.\n\r", ch);
		return;
	}

	for (lev = 0; lev < LEVEL_HERO; lev++)
		if (skill_list[lev][0] != '\0')
			send_to_char(skill_list[lev], ch);
	send_to_char("\n\r", ch);
}

/* shows skills, groups and costs (only if not bought) */
void list_group_costs(CHAR_DATA *ch)
{
	char buf[100];
	int sn, col;

	if (IS_NPC(ch))
		return;

	col = 0;

	sprintf(buf, "%-18s %-5s %-18s %-5s %-18s %-5s\n\r", "skill", "cp",
			"skill", "cp", "skill", "cp");
	send_to_char(buf, ch);

	for (sn = 0; sn < MAX_SKILL; sn++)
	{
		if (skill_table[sn].name == NULL)
			break;

		if (!ch->gen_data->skill_chosen[sn] && ch->pcdata->learned[sn] < 1
				&& skill_table[sn].skill_level[ch->class] < LEVEL_HERO)
		{
			sprintf(buf, "%-18s %-5d ", skill_table[sn].name,
					skill_table[sn].rating[ch->class]);
			send_to_char(buf, ch);
			if (++col % 3 == 0)
				send_to_char("\n\r", ch);
			/* Bad Hack but should work
			 * Sets class gainable skills to 0
			 * leaves ungainables at -1
			 */
			ch->pcdata->learned[sn] = 0;
		}
	}
	if (col % 3 != 0)
		send_to_char("\n\r", ch);
	send_to_char("\n\r", ch);

	sprintf(buf, "Creation points: %d\n\r", ch->pcdata->points);
	send_to_char(buf, ch);
	sprintf(buf, "Experience per level: %ld\n\r", exp_per_level(ch,
			ch->gen_data->points_chosen));
	send_to_char(buf, ch);
	return;
}

void list_group_chosen(CHAR_DATA *ch)
{
	char buf[100];
	int sn, col;

	if (IS_NPC(ch))
		return;

	col = 0;

	sprintf(buf, "%-18s %-5s %-18s %-5s %-18s %-5s", "skill", "cp", "skill",
			"cp", "skill", "cp\n\r");
	send_to_char(buf, ch);

	for (sn = 0; sn < MAX_SKILL; sn++)
	{
		if (skill_table[sn].name == NULL)
			break;

		if (ch->gen_data->skill_chosen[sn]
				&& skill_table[sn].skill_level[ch->class] <= LEVEL_HERO)
		{
			sprintf(buf, "%-18s %-5d ", skill_table[sn].name,
					skill_table[sn].rating[ch->class]);
			send_to_char(buf, ch);
			if (++col % 3 == 0)
				send_to_char("\n\r", ch);
		}
	}
	if (col % 3 != 0)
		send_to_char("\n\r", ch);
	send_to_char("\n\r", ch);

	sprintf(buf, "Creation points: %d\n\r", ch->gen_data->points_chosen);
	send_to_char(buf, ch);
	sprintf(buf, "Experience per level: %ld\n\r", exp_per_level(ch,
			ch->gen_data->points_chosen));
	send_to_char(buf, ch);
	return;
}

long exp_per_level(CHAR_DATA *ch, int points)
{
	long expl, inc, epl;

	if (IS_NPC(ch))
		return 1000;

	expl = 1000;
	inc = 500;

	if (points < 40)
		return 1000 * pc_race_table[ch->race].class_mult[ch->class] / 100;

	/* processing */
	points -= 40;

	while (points > 9)
	{
		expl += (long) inc;
		points -= 10;
		if (points > 9)
		{
			expl += (long) inc;
			inc *= 2;
			points -= 10;
		}
	}

	expl += (long) points * (long) inc / 10;

	epl = (long) expl * (long) pc_race_table[ch->race].class_mult[ch->class]
			/ 100;

	if (ch->pcdata->tier > 2)
	{
		/* Temporary check */
		if (epl < 3000)
			epl += (long) (epl * 8 / 100);
		else if (epl < 6000)
			epl += (long) (epl * 4 / 100);
		else
			epl += (long) (epl * 2 / 200);
	}
	else if (ch->pcdata->tier > 1)
	{
		epl += (long) (epl * 4 / 100);
	}

	return epl;
}

/* this procedure handles the input parsing for the skill generator */
bool parse_gen_groups(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char buf[100];
	int sn;

	if (argument[0] == '\0')
		return FALSE;

	argument = one_argument(argument, arg);

	if (!str_prefix(arg, "help"))
	{
		if (argument[0] == '\0')
		{
			do_help(ch, "group help");
			return TRUE;
		}

		do_help(ch, argument);
		return TRUE;
	}

	if (!str_prefix(arg, "add"))
	{
		if (argument[0] == '\0')
		{
			send_to_char("You must provide a skill name.\n\r", ch);
			return TRUE;
		}

		sn = skill_lookup(argument);
		if (sn != -1)
		{
			if (ch->gen_data->skill_chosen[sn] || ch->pcdata->learned[sn] > 0)
			{
				send_to_char("You already know that skill!\n\r", ch);
				return TRUE;
			}

			if (skill_table[sn].skill_level[ch->class] > LEVEL_HERO)
			{
				send_to_char("That skill is not available.\n\r", ch);
				return TRUE;
			}
			sprintf(buf, "%s skill added\n\r", skill_table[sn].name);
			send_to_char(buf, ch);
			ch->gen_data->skill_chosen[sn] = TRUE;
			ch->gen_data->points_chosen += skill_table[sn].rating[ch->class];
			ch->pcdata->learned[sn] = 1;
			ch->pcdata->points += skill_table[sn].rating[ch->class];
			return TRUE;
		}

		send_to_char("No skills or groups by that name...\n\r", ch);
		return TRUE;
	}

	if (!strcmp(arg, "drop"))
	{
		if (argument[0] == '\0')
		{
			send_to_char("You must provide a skill to drop.\n\r", ch);
			return TRUE;
		}

		sn = skill_lookup(argument);
		if (sn != -1 && ch->gen_data->skill_chosen[sn])
		{
			send_to_char("Skill dropped.\n\r", ch);
			ch->gen_data->skill_chosen[sn] = FALSE;
			ch->gen_data->points_chosen -= skill_table[sn].rating[ch->class];
			ch->pcdata->learned[sn] = 0;
			ch->pcdata->points -= skill_table[sn].rating[ch->class];
			return TRUE;
		}

		send_to_char("You haven't bought any such skill or group.\n\r", ch);
		return TRUE;
	}

	if (!str_prefix(arg, "premise"))
	{
		do_help(ch, "premise");
		return TRUE;
	}

	if (!str_prefix(arg, "list"))
	{
		list_group_costs(ch);
		return TRUE;
	}

	if (!str_prefix(arg, "learned"))
	{
		list_group_chosen(ch);
		return TRUE;
	}
	return FALSE;
}

int spell_avail(CHAR_DATA *ch, const char *name)
{
	/* checks to see if a spell is available to a class */
	int sn, found = -1;

	if (IS_NPC(ch))
		return skill_lookup(name);

	for (sn = 0; sn < MAX_SKILL; sn++)
	{
		if (skill_table[sn].name == NULL)
			break;
		if (LOWER(name[0]) == LOWER(skill_table[sn].name[0]) && !str_prefix(
				name, skill_table[sn].name))
		{
			if (skill_table[sn].skill_level[ch->class] <= LEVEL_HERO)
				return sn;
		}
	}
	return found;
}

/* checks for skill improvement */
void check_improve(CHAR_DATA *ch, int sn, bool success, int multiplier)
{
	int chance;
	char buf[100];

	if (IS_NPC(ch))
		return;

	sn = handling_improve(ch, sn);

	if (ch->level < skill_table[sn].skill_level[ch->class]
			|| skill_table[sn].skill_level[ch->class] > LEVEL_HERO
			|| ch->pcdata->learned[sn] == 0 || ch->pcdata->learned[sn] == 100)
		return; /* skill is not known */

	/* check to see if the character has a chance to learn */
	chance = 10 * int_app[get_curr_stat(ch, STAT_INT)].learn;
	chance /= (multiplier * skill_table[sn].rating[ch->class] * 4) + 1;
	chance += ch->level;

	if (number_range(1, 1000) > chance)
		return;

	/* now that the character has a CHANCE to learn, see if they really have */

	if (success)
	{
		chance = URANGE(5,100 - ch->pcdata->learned[sn], 95);
		if (number_percent() < chance)
		{
			ch->pcdata->learned[sn]++;
			sprintf(buf,
					"{GYou have become better at {R%s{G! ({R%d{G%%){x\n\r",
					skill_table[sn].name, ch->pcdata->learned[sn]);
			send_to_char(buf, ch);
			gain_exp(ch, 2 * skill_table[sn].rating[ch->class], FALSE, TRUE);
		}
	}

	else
	{
		chance = URANGE(5,ch->pcdata->learned[sn]/2,30);
		if (number_percent() < chance)
		{
			ch->pcdata->learned[sn] += number_range(1, 3);
			ch->pcdata->learned[sn] = UMIN(ch->pcdata->learned[sn],100);
			sprintf(
					buf,
					"{GYou learn from your mistakes, and your {R%s {Gskill improves. ({R%d{G%%){x\n\r",
					skill_table[sn].name, ch->pcdata->learned[sn]);
			send_to_char(buf, ch);
			gain_exp(ch, 2 * skill_table[sn].rating[ch->class], FALSE, TRUE);
		}
	}
}

/* use for processing a skill or group for addition  */
void group_add(CHAR_DATA *ch, const char *name, bool deduct)
{
	int sn;

	if (IS_NPC(ch)) /* NPCs do not have skills */
		return;

	sn = skill_lookup(name);

	if (sn != -1)
	{
		if (ch->pcdata->learned[sn] == 0) /* i.e. not known */
		{
			ch->pcdata->learned[sn] = 1;
			if (deduct)
				ch->pcdata->points += skill_table[sn].rating[ch->class];
		}
		return;
	}

}

/* used for processing a skill or group for deletion -- no points back! */

void group_remove(CHAR_DATA *ch, const char *name)
{
	int sn;

	sn = skill_lookup(name);

	if (sn != -1)
	{
		ch->pcdata->learned[sn] = 0;
		return;
	}

}

void do_showclass(CHAR_DATA *ch, char *argument) {
	BUFFER *buffer;
	char buf[MAX_STRING_LENGTH];
	int classID;

	if ((classID = class_lookup(argument)) == -1) {
		send_to_char("That's not a valid class", ch);
		return;
	}
	
	buffer = new_buf();
	sprintf(buf, "Level [ Type ] Name                     (CP) [ Type ] Name                     (CP)");
	add_buf(buffer, buf);

	int sn, level, column;
	for (level = 1; level < LEVEL_HERO; level++) {
		for (column = 0, sn = 0; sn < MAX_SKILL; sn++) {
			if (skill_table[sn].skill_level[classID] == level) {
				if (column % 2 == 0) {
					if (column == 0)
						sprintf(buf, "\r\n[%3d] ", level);
					else
						strcpy(buf, "\r\n      ");
					add_buf(buffer, buf);
				}
				++column;
				sprintf(buf, "[%-6s] %-24s (%-2d) ",
					skill_table[sn].spell_fun != spell_null ? magtype_name(magic_table[sn]) : "skill",
					skill_table[sn].name, skill_table[sn].rating[classID]);
				add_buf(buffer, buf);
			}
		}
	}
	add_buf(buffer, "\r\n");
	page_to_char(buffer->string, ch);
	free_buf(buffer);
}

void do_showskill(CHAR_DATA *ch, char *argument) {
	BUFFER *buffer;
	char buf[MAX_STRING_LENGTH];
	int classID, sn;

	if ((sn = skill_lookup(argument)) == -1) {
		send_to_char("Thats not a skill or spell.\r\n", ch);
		return;
	}
	
	buffer = new_buf();
	sprintf(buf, "The following classes get '%s':\r\n", skill_table[sn].name);
	add_buf(buffer, buf);
	sprintf(buf, "[Level] [CP] Class        [Level] [CP] Class        [Level] [CP] Class        ");
	add_buf(buffer, buf);
	int column = 0;
	for (classID = 0; classID < MAX_CLASS; classID++) {
		if (skill_table[sn].skill_level[classID] < LEVEL_HERO) {
			if (column % 3 == 0)
				add_buf(buffer, "\r\n");
			++column;
			sprintf(buf, "[ %3d ] [%2d] %-13s",
				skill_table[sn].skill_level[classID],
				skill_table[sn].rating[classID],
				class_table[classID].name);
			add_buf(buffer, buf);
		}
	}
	add_buf(buffer, "\r\n");
	page_to_char(buffer->string, ch);
	free_buf(buffer);
}

/* Monk Stuff -- Skyntil */
void do_open_palming(CHAR_DATA *ch, char *argument)
{
	AFFECT_DATA af;
	int chance;

	if ((chance = get_skill(ch, gsn_palm)) == 0
			|| ch->pcdata->learned[gsn_palm] < 1)
	{
		send_to_char(
				"You don't have the ability to use open palm striking martial arts.\n\r",
				ch);
		return;
	}

	if (IS_NPC(ch) && IS_AFFECTED(ch,AFF_CHARM))
		return;

	if (is_affected(ch, gsn_palm))
	{
		send_to_char("Your palms are already tense.\n\r", ch);
		return;
	}

	if (get_eq_char(ch, WEAR_WIELD) != NULL || get_eq_char(ch, WEAR_SECONDARY)
			!= NULL)
	{
		send_to_char(
				"You can't start using open palm striking while using weapons.\n\r",
				ch);
		return;
	}

	if (number_percent() >= chance)
	{
		send_to_char(
				"Your try to tense the nerves in your hands, but fail.\n\r", ch);
		check_improve(ch, gsn_palm, FALSE, 2);
		return;
	}

	act("$n goes into a trance and $s hands become deadly weapons.", ch, 0, 0,
			TO_ROOM);
	send_to_char(
			"You feel your mind relax as the nerves in your hands tense.\n\r",
			ch);
	af.where = TO_AFFECTS;
	af.type = gsn_palm;
	af.location = 0;
	af.modifier = 0;
	af.duration = (ch->level / 4);
	af.level = ch->level;
	af.bitvector = 0;
	affect_to_char(ch, &af);
	check_improve(ch, gsn_palm, TRUE, 2);
	WAIT_STATE(ch,6)
;	return;
}

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

	if ((chance = get_skill(ch, gsn_martial_arts)) == 0
			|| ch->pcdata->learned[gsn_martial_arts] < 1)
	{
		send_to_char("You don't know any martial arts.\n\r", ch);
		return;
	}

	if (ch->class == CLASS_MONK)
	{
		if (is_affected(ch, gsn_martial_arts))
		{
			if (ch->fighting == NULL)
			{
				send_to_char(
						"You stop focusing on the art of combat and find inner peace.\n\r",
						ch);
				affect_strip(ch, gsn_martial_arts);
				WAIT_STATE(ch,18)
;				return;
			}
			else
			{
				send_to_char("You are too busy fighting to do that!\n\r",ch);
				return;
			}
		}
	}
	else if (is_affected(ch,gsn_martial_arts))
	{
		send_to_char("You are already focused on combat.\n\r",ch);
		return;
	}

	if ((get_eq_char(ch,WEAR_WIELD) != NULL
					|| get_eq_char(ch,WEAR_SECONDARY) != NULL) && ch->class == CLASS_MONK)
	{
		send_to_char("You cannot practice this skill using weapons.\n\r",ch);
		return;
	}

	if (number_percent() >= chance)
	{
		send_to_char("You build up intense focus but lose concentration.\n\r",ch);
		check_improve(ch,gsn_martial_arts,FALSE,2);
		return;
	}

	act("$n's face clouds with a look of deadly concentration.",ch,0,0,TO_ROOM);
	send_to_char("You feel your body's focus increase toward mastery.\n\r",ch);
	af.where = TO_AFFECTS;
	af.type = gsn_martial_arts;
	af.location = 0;
	af.modifier = 0;
	if (ch->class == CLASS_MONK)
	{
		af.duration = -1;
	}
	else
	{
		af.duration = ch->level/5;
	}
	af.level = ch->level;
	af.bitvector = 0;
	affect_to_char(ch,&af);
	WAIT_STATE(ch,6);

	return;
}

void lose_skill(CHAR_DATA *ch, int skill)
{
	int gain = 0; /* Gain from losing */
	int prac_gain = 0;

	// If your class loses a skill
	if (!IS_IMMORTAL(ch) && !class_has_skill(ch->class, skill))
	{
		gain = skill_table[skill].rating[ch->class];
		if (ch->pcdata->learned[skill] >= 75)
			prac_gain = 3;
		else if (ch->pcdata->learned[skill] >= 50)
			prac_gain = 2;
		else if (ch->pcdata->learned[skill] >= 25)
			prac_gain = 1;
		else
			prac_gain = 0;
		ch->train += gain;
		ch->practice += prac_gain;
		printf_to_char(ch, "You lose the %s skill and gain %d trains.\n\r",
				skill_table[skill].name, gain);
		ch->pcdata->learned[skill] = -1;
		ch->pcdata->learnlvl[skill] = 102;
		printf_debug("%s has lost the %s skill.", ch->name, skill_table[skill].name);
	}
	return;
}

void gain_skill(CHAR_DATA *ch, int skill)
{
	// You figure it out
	if (class_has_skill(ch->class, skill) && ch->pcdata->learned[skill] < 1)
	{
		if (ch->level > skill_table[skill].skill_level[ch->class])
		{
			ch->pcdata->learned[skill] = 75;
			ch->pcdata->learnlvl[skill]
					= skill_table[skill].skill_level[ch->class];
		}
		else
		{
			ch->pcdata->learned[skill] = 1;
			ch->pcdata->learnlvl[skill]
					= skill_table[skill].skill_level[ch->class];
		}
		printf_to_char(ch, "You gain the %s skill at %d percent.\n\r",
				skill_table[skill].name, ch->pcdata->learned[skill]);
		printf_debug("%s has gained the %s skill.", ch->name, skill_table[skill].name);
	}
	return;
}

/* Gain a skill into the gain list */
void gain_skill_gain(CHAR_DATA *ch, int skill)
{
	if (class_has_skill(ch->class, skill) && ch->pcdata->learned[skill] < 0)
	{
		ch->pcdata->learned[skill] = 0;
		printf_to_char(ch, "You are now able to gain the %s skill.\n\r",
				skill_table[skill].name);
		printf_debug("%s can now gain the %s skill.", ch->name, skill_table[skill].name);
	}
	return;
}

bool has_skill(CHAR_DATA *ch, int skill)
{
	return IS_NPC(ch) ? TRUE : (ch->level >= ch->pcdata->learnlvl[skill]);
}

bool class_has_skill(int class, int skill)
{
	return (skill_table[skill].skill_level[class] < 102);
}

bool has_learned_skill(CHAR_DATA *ch, int skill)
{
	return IS_NPC(ch) ? TRUE : (ch->pcdata->learned[skill] > 0);
}

bool has_gain(CHAR_DATA *ch, int skill)
{
	if (ch->pcdata->learned[skill] == 0)
		return TRUE;
	else
		return FALSE;
}

int handling_improve(CHAR_DATA *ch, sh_int sn)
{
	sh_int wsn = -1;

	if (ch->pcdata->learned[sn] < 100)
		return sn;

	if (sn == gsn_sword)
		wsn = gsn_sword2;
	else if (sn == gsn_axe)
		wsn = gsn_axe2;
	else if (sn == gsn_hand_to_hand)
		wsn = gsn_hand2;
	else if (sn == gsn_dagger)
		wsn = gsn_dagger2;
	else if (sn == gsn_polearm)
		wsn = gsn_polearm2;
	else if (sn == gsn_whip)
		wsn = gsn_whip2;
	else if (sn == gsn_spear)
		wsn = gsn_spear2;
	else if (sn == gsn_mace)
		wsn = gsn_mace2;
	else if (sn == gsn_flail)
		wsn = gsn_flail2;
	else if (sn == gsn_dual_wield)
		wsn = gsn_dual_wield2;

	if (wsn == -1)
		return sn;

	return wsn;

}

void do_handle(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *trainer;
	sh_int sn, wsn = -1;

	if (IS_NPC(ch))
		return;

	/* find a trainer */
	for (trainer = ch->in_room->people; trainer != NULL; trainer
			= trainer->next_in_room)
		if (IS_NPC(trainer) && (IS_SET(trainer->act,ACT_GAIN)
				|| IS_SET(trainer->act,ACT_TRAIN)))
			break;

	if (trainer == NULL || !can_see(ch, trainer))
	{
		send_to_char("You can't do that here.\n\r", ch);
		return;
	}

	one_argument(argument, arg);

	if (arg[0] == '\0')
	{
		do_say(trainer, "What do you wish to learn?");
		do_say(trainer,
				"I can teach you how to handle your weapon better perhaps?");
		return;
	}

	if (str_cmp(arg, "sword") && str_cmp(arg, "dagger") && str_cmp(arg,
			"polearm") && str_cmp(arg, "spear") && str_cmp(arg, "flail")
			&& str_cmp(arg, "mace") && str_cmp(arg, "whip") && str_cmp(arg,
			"axe") && str_cmp(arg, "dual wield"))
	{
		do_say(trainer, "Pardon me?");
		return;
	}

	sn = skill_lookup(arg);

	if (ch->pcdata->learned[sn] < 100 && sn != gsn_dual_wield)
	{
		act("$N tells you 'You are not yet ready to learn with that weapon.'",
				ch, NULL, trainer, TO_CHAR);
		return;
	}
	else if (ch->pcdata->learned[sn] < 100 && sn == gsn_dual_wield)
	{
		act(
				"$N tells you 'You are not yet ready to learn dual weapon mastery.'",
				ch, NULL, trainer, TO_CHAR);
		return;
	}

	if (sn == gsn_sword)
		wsn = gsn_sword2;
	else if (sn == gsn_axe)
		wsn = gsn_axe2;
	else if (sn == gsn_dagger)
		wsn = gsn_dagger2;
	else if (sn == gsn_polearm)
		wsn = gsn_polearm2;
	else if (sn == gsn_whip)
		wsn = gsn_whip2;
	else if (sn == gsn_spear)
		wsn = gsn_spear2;
	else if (sn == gsn_mace)
		wsn = gsn_mace2;
	else if (sn == gsn_flail)
		wsn = gsn_flail2;
	else if (sn == gsn_dual_wield)
		wsn = gsn_dual_wield2;

	if (wsn == -1)
		return;

	if (wsn == gsn_dual_wield2)
	{
		ch->pcdata->learned[wsn] = 1;
		ch->pcdata->learnlvl[wsn] = skill_table[wsn].skill_level[ch->class];
		act("$N teaches how to better handle your weapon!", ch, NULL, trainer,
				TO_CHAR);
		return;
	}

	if (ch->class == CLASS_ASSASSIN && !IS_IMMORTAL(ch) && wsn == gsn_dagger2)
	{
		ch->pcdata->learned[wsn] = 1;
		act("$N teaches how to better handle your weapon!", ch, NULL, trainer,
				TO_CHAR);
		return;
	}

	if (ch->class != CLASS_CRUSADER && !IS_IMMORTAL(ch))
	{
		do_say(trainer, "You cannot learn to better handle that weapon.");
		return;
	}
	ch->pcdata->learned[wsn] = 1;

	act("$N teaches how to better handle your weapon!", ch, NULL, trainer,
			TO_CHAR);

	/*if(ch->level == LEVEL_HERO)
	 ch->practice += 2;*/

	return;
}

// New Stuff 01/2005 -- Skyn.

// Ground Stomp
void check_ground_stomp(CHAR_DATA *ch, CHAR_DATA *victim, int chance, int dam)
{
	if (chance < 10)
		return;
	if (dam == 0)
		return;

	chance = get_skill(ch, gsn_ground_stomp);
	chance /= 2;

	chance -= number_range(5, 15);
	chance = URANGE(5,chance,50);

	if (!has_skill(ch, gsn_ground_stomp))
		return;

	if (number_percent() > chance)
	{
		check_improve(ch, gsn_ground_stomp, FALSE, 3);
		return;
	}

	act("You land your foot hard on $N's body.", ch, 0, victim, TO_CHAR);
	act("$n stomps $N's body with brutal force.", ch, 0, victim, TO_NOTVICT);
	act("$n lands his foot hard against your body.", ch, 0, victim, TO_VICT);

	check_improve(ch, gsn_ground_stomp, TRUE, 2);

	dam = dam * 4;
	dam = dam / 5;

	if (number_percent() < 10)
	{
		act("You hit $N critically!", ch, 0, victim, TO_CHAR);
		dam *= 3 / 2;
	}

	damage(ch, victim, dam, gsn_ground_stomp, DAM_BASH, TRUE, 0);
	return;
}

// Side Kick
void do_side_kick(CHAR_DATA *ch, char *argument)
{
	int dam;
	CHAR_DATA *victim;

	if (IS_NPC(ch))
		return;

	if (!IS_NPC(ch) && !has_skill(ch, gsn_sidekick))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}

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

	if (ch->stunned)
	{
		send_to_char("You're still a bit woozy.\n\r", ch);
		return;
	}

	if (get_skill(ch, gsn_sidekick) > number_percent())
	{
		dam = number_range(1, ch->level);
		dam += number_range(0, (ch->level) / 3);
		dam += number_range(0, (ch->level) / 3);
		dam += number_range(0, (ch->level) / 3);
		dam += number_range(0, (ch->level) / 4);
		dam += number_range(0, (ch->level) / 4);
		dam += number_range(0, (ch->level) / 4);
		dam += number_range(0, (ch->level) / 4);
		dam += number_range(ch->level / 3, ch->level / 2);

		act("You kick $N brutally in the side!", ch, 0, victim, TO_CHAR);
		act("$n kicks you brutally in the side!", ch, 0, victim, TO_VICT);

		if (has_skill(ch, gsn_vital_hit))
		{
			if ((get_skill(ch, gsn_vital_hit) / 12) > number_percent())
			{
				check_improve(ch, gsn_vital_hit, TRUE, 3);
				dam = (dam * 8) / 5;
			}
		}

		damage(ch, victim, dam, gsn_sidekick, DAM_BASH, TRUE, 0);
		check_improve(ch, gsn_sidekick, TRUE, 1);
		check_follow_through(ch, victim, dam);
	}
	else
	{
		damage(ch, victim, 0, gsn_sidekick, DAM_BASH, TRUE, 0);
		check_improve(ch, gsn_sidekick, FALSE, 1);
	}

	WAIT_STATE( ch, skill_table[gsn_sidekick].beats )
;
	return;
}

// Spin Kick
void do_spin_kick(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim;
	int dam;
	int skill;

	if (((get_skill(ch, gsn_spin_kick)) <= 0) || !has_skill(ch, gsn_spin_kick))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}

	if (!is_affected(ch, gsn_martial_arts))
	{
		send_to_char(
				"You must be focused on the martial arts to use this skill.\n\r",
				ch);
		return;
	}

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

	if (ch->stunned)
	{
		send_to_char("You're still a bit woozy.\n\r", ch);
		return;
	}

	if (number_percent() > get_skill(ch, gsn_spin_kick))
	{
		send_to_char("You slip and fail your kick.\n\r", ch);
		check_improve(ch, gsn_spin_kick, FALSE, 1);
		WAIT_STATE(ch, skill_table[gsn_spin_kick].beats)
;		return;
	}

	act("You deftly spin around and kick $N in the chest!",ch,NULL,victim,TO_CHAR);
	act("$n spins around and kicks you in the chest!",ch,NULL,victim,TO_VICT);
	act("$n spins around deftly and kicks $N hard!",ch,NULL,victim,TO_NOTVICT);

	skill = get_skill(ch,gsn_spin_kick);

	if(ch->level <= 80)
	dam = ch->level * 2 + (number_range(0, skill)) * 3 / 2;
	else if(ch->level <= 90)
	dam = ch->level * 3 + (number_range((skill/3), skill)) * 3 / 2;
	else if(ch->level <= 100)
	dam = ch->level * 3 + (number_range((skill/2), skill)) * 9 / 5;
	else
	dam = ch->level * 3 + (number_range((skill*3/4), skill)) * 9 / 4;

	dam += -2*(dex_app[get_curr_stat(ch,STAT_DEX)].defensive);

	if (number_percent() < get_skill(ch,gsn_spin_kick) / 8)
	{
		act("Your kick knocks $N's breath away!",ch,NULL,victim,TO_CHAR);
		act("$n's kick knocks your breath away!",ch,NULL,victim,TO_VICT);
		act("$n's kick sends $N sprawling!",ch,NULL,victim,TO_NOTVICT);
		WAIT_STATE(victim,2*PULSE_VIOLENCE);
	}

	if(has_skill(ch,gsn_vital_hit))
	{
		if( (get_skill(ch,gsn_vital_hit) / 12) > number_percent( ))
		{
			check_improve(ch,gsn_vital_hit,TRUE, 3);
			dam = (dam * 8) / 5;
		}
	}

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

	damage(ch,victim,dam, gsn_spin_kick,DAM_SLASH,TRUE, 0);
	check_improve(ch,gsn_spin_kick, TRUE,1);
	check_follow_through(ch,victim,dam);

	return;
}

// Follow through
void check_follow_through(CHAR_DATA *ch, CHAR_DATA *victim, int dam)
{
	int chance;
	OBJ_DATA *wield;
	wield = get_eq_char(ch, WEAR_WIELD);

	chance = get_skill(ch, gsn_follow_through);

	if (wield != NULL && IS_WEAPON_STAT(wield,WEAPON_TWO_HANDS))
	{
		chance = chance * (get_curr_stat(ch, STAT_DEX) / 12);
	}
	chance = chance / 2;
	chance -= number_range(0, 7);

	if (!has_skill(ch, gsn_follow_through))
		return;

	if (number_percent() < chance)
	{
		if (ch->class == CLASS_BARBARIAN)
		{
			if (wield != NULL && IS_WEAPON_STAT(wield,WEAPON_TWO_HANDS))
			{
				act(
						"The momentum of $n's weapon brings them around for another attack!",
						ch, 0, 0, TO_ROOM);
				act(
						"The momentum of your swing brings your two-handed weapon around for another attack!",
						ch, 0, 0, TO_CHAR);
				dam = dam * 7 / 4;
				damage(ch, victim, dam, gsn_follow_through, DAM_SLASH, TRUE, 0);
				check_improve(ch, gsn_follow_through, TRUE, 2);
			}
			else
			{
				act(
						"The momentum of $n's weapon brings them around for another attack!",
						ch, 0, 0, TO_ROOM);
				act(
						"The momentum of your swing brings your weapon around for another attack!",
						ch, 0, 0, TO_CHAR);
				dam = dam * 2 / 3;
				damage(ch, victim, dam, gsn_follow_through, DAM_SLASH, TRUE, 0);
				check_improve(ch, gsn_follow_through, TRUE, 2);
			}
		}
		else if (is_affected(ch, gsn_martial_arts))
		{
			act("$n's leg sweeps around and strikes with a follow through!",
					ch, 0, 0, TO_ROOM);
			act("Your leg sweeps around to land a follow through kick!", ch, 0,
					0, TO_CHAR);
			dam = dam * 4;
			dam = dam / 5;
			damage(ch, victim, dam, gsn_follow_through, DAM_BASH, TRUE, 0);
			check_improve(ch, gsn_follow_through, TRUE, 2);
		}
	}
	else
		check_improve(ch, gsn_follow_through, FALSE, 3);

	return;
}

// Blindness dust  
void do_blindness_dust(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *vch;
	CHAR_DATA *vch_next;
	AFFECT_DATA af;
	int chance;
	bool fighting = FALSE;
	char buf[MAX_STRING_LENGTH];

	if ((chance = get_skill(ch, gsn_blindness_dust)) == 0 || !has_skill(ch,
			gsn_blindness_dust))
	{
		send_to_char("You don't know how to make blindness dust to throw.\n\r",
				ch);
		return;
	}

	if (ch->stunned)
	{
		send_to_char("You're still a bit woozy.\n\r", ch);
		return;
	}

	if (ch->mana < 36)
	{
		send_to_char("You don't have the mana.\n\r", ch);
		return;
	}

	if (number_percent() + 10 > chance)
	{
		act("$n hurls some dust into the air but it is blown away.", ch, 0, 0,
				TO_ROOM);
		send_to_char("You throw out some dust but it is blown away.\n\r", ch);
		ch->mana -= 18;
		check_improve(ch, gsn_blindness_dust, FALSE, 2);
		WAIT_STATE(ch,12)
;		return;
	}

	act("$n hurls a handful of dust into the room!",ch,0,0,TO_ROOM);
	send_to_char("You throw a handful of blindness dust into the room!\n\r",ch);
	check_improve(ch,gsn_blindness_dust,TRUE,2);
	if (ch->fighting != NULL)
	fighting = TRUE;

	af.where = TO_AFFECTS;
	af.type = gsn_blindness_dust;
	af.level = ch->level;
	af.duration = (ch->level)/25;
	af.bitvector = AFF_BLIND;
	af.location = APPLY_HITROLL;
	af.modifier = -4;
	ch->mana -= 36;
	WAIT_STATE(ch,12);

	for (vch = ch->in_room->people; vch != NULL; vch = vch_next)
	{
		vch_next = vch->next_in_room;
		if (is_safe_quiet(ch,vch))
		continue;
		if (is_same_group(ch,vch))
		continue;
		if (!IS_AFFECTED(vch,AFF_BLIND) && !saves_spell( ch->level,vch,DAM_OTHER))
		{
			act("$n appears blinded.",vch,0,0,TO_ROOM);
			send_to_char("You get dust in your eyes.\n\r",vch);
			affect_to_char(vch,&af);
		}

		if (!IS_NPC(vch) && !IS_NPC(ch) && (vch->fighting == NULL || (!fighting)))
		{
			sprintf(buf,"Help! %s just threw dust in my eyes!",PERS(ch,vch));
			do_yell(vch,buf);
		}

		if (vch->fighting == NULL)
		multi_hit(vch,ch,TYPE_UNDEFINED);
	}

	return;
}

void do_will_of_iron(CHAR_DATA *ch, char *argument)
{
	AFFECT_DATA af;
	// int counter;

	if (((get_skill(ch, gsn_will_of_iron)) <= 0) || !has_skill(ch,
			gsn_will_of_iron) || IS_NPC(ch))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}

	if (is_affected(ch, gsn_will_of_iron))
	{
		send_to_char("You are already focusing your will!\n\r", ch);
		return;
	}

	send_to_char(
			"You focus your energy, and your will becomes strong as steel.\n\r",
			ch);

	//check_improve(ch,gsn_will_of_iron,TRUE,1);

	af.where = TO_AFFECTS;
	af.type = gsn_will_of_iron;
	af.level = ch->level;
	af.duration = ch->level / 5 + 5;
	af.location = APPLY_AC;
	af.modifier = -1 * (ch->level * 5 / 8);
	af.bitvector = 0;
	affect_to_char(ch, &af);
	af.modifier = -25;
	af.location = APPLY_HITROLL;
	affect_to_char(ch, &af);
	af.location = APPLY_REGEN;
	af.modifier = 100;
	affect_to_char(ch, &af);
	check_improve(ch, gsn_will_of_iron, TRUE, 1);
	return;
}

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

	if (((get_skill(ch, gsn_healing_trance)) <= 0) || !has_skill(ch,
			gsn_healing_trance) || IS_NPC(ch))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}

	if (ch->fighting != NULL)
	{
		send_to_char("You are too busy fighting to meditate.\n\r", ch);
		return;
	}

	if (is_affected(ch, gsn_healing_trance))
	{
		send_to_char("You are already at an inner peace.\n\r", ch);
		return;
	}

	do_rest(ch, "");

	send_to_char("You relax and concentrate on healing your wounds.\n\r", ch);

	check_improve(ch, gsn_healing_trance, TRUE, 1);

	af.where = TO_AFFECTS;
	af.level = ch->level;
	af.type = gsn_healing_trance;
	af.location = APPLY_REGEN;
	af.modifier = (ch->level - 1) * 2.0;
	af.bitvector = 0;
	af.duration = 4;
	affect_to_char(ch, &af);
	af.location = APPLY_MANA_REGEN;
	af.modifier = (ch->level - 1) * .1;
	affect_to_char(ch, &af);
	ch->stunned = 4;

	return;
}

void do_trance(CHAR_DATA *ch, char *argument)
{

	AFFECT_DATA af;

	if (((get_skill(ch, gsn_meditation)) <= 0)
			|| !has_skill(ch, gsn_meditation) || IS_NPC(ch))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}

	if (ch->fighting != NULL)
	{
		send_to_char("You are too busy fighting to meditate.\n\r", ch);
		return;
	}

	if (is_affected(ch, gsn_meditation))
	{
		send_to_char("You are already meditating.\n\r", ch);
		return;
	}

	do_rest(ch, "");

	send_to_char("You relax and focus your mind within.\n\r", ch);

	check_improve(ch, gsn_meditation, TRUE, 1);

	af.where = TO_AFFECTS;
	af.level = ch->level;
	af.type = gsn_meditation;
	af.location = APPLY_REGEN;
	af.modifier = (ch->level - 1) * 1;
	af.bitvector = 0;
	af.duration = 10;
	affect_to_char(ch, &af);
	af.location = APPLY_MANA_REGEN;
	af.modifier = (ch->level - 1) * 2.5;
	affect_to_char(ch, &af);
	//ch->stunned = 4;
	WAIT_STATE(ch,24);

	return;
}

void do_purify_body(CHAR_DATA *ch, char *argument)
{
	AFFECT_DATA *af;
	sh_int af_type;
	sh_int sn;

	sn = gsn_purify_body;

	if (((get_skill(ch, gsn_purify_body)) <= 0) || !has_skill(ch,
			gsn_purify_body) || IS_NPC(ch))
	{
		send_to_char("Huh?\n\r", ch);
		return;
	}
	if (is_affected(ch, gsn_martial_arts))
	{
		send_to_char("Not while your mind focuses on the art of war.\n\r", ch);
		return;
	}

	send_to_char("You go into a deep trance and purify your body.\n\r", ch);

	check_improve(ch, gsn_purify_body, TRUE, 1);

	for (af = ch->affected; af != NULL; af = af->next)
	{
		af_type = af->type;

		if (af_type < 0 || af_type > MAX_SKILL)
		{
			printf_debug("Problem: Monk :: Purify Body :: Affect remove");
			return;
		}

		if (af_type != gsn_healing_trance && skill_table[af_type].slot != 999)
			check_dispel(ch->level + 35, ch, af->type);
	}

	do_sleep(ch, "");
	ch->stunned = 2;
	WAIT_STATE(ch,24)
;
	return;
}

/*void do_spinkick(CHAR_DATA *ch, char *argument)
 {
 ROOM_INDEX_DATA *was_in;
 CHAR_DATA *victim,*vch,*vch_next;
 int attempt, chance, dam, level;
 char arg1[MAX_INPUT_LENGTH];
 char buf[MAX_INPUT_LENGTH];

 one_argument(argument,arg1);

 if(IS_NPC(ch))
 return;

 if ( (chance = get_skill(ch,gsn_spinkick)) == 0
 || !has_skill(ch,gsn_spinkick))
 {
 send_to_char("Huh?\n\r",ch);
 return;
 }

 if(ch->fighting != NULL)
 victim = ch->fighting;
 else
 {
 if( (victim = get_char_room(ch,arg1)) == NULL )
 {
 send_to_char("They're not here.\n\r",ch);
 return;
 }
 }

 if(victim == ch)
 {
 send_to_char("Kicking yourself? get real.\n\r",ch);
 return;
 }
 if (!IS_NPC(victim) && !can_pkill(ch,victim)) {
 send_to_char("You can't seem to kick them.",ch);
 return;
 }

 if (IS_AFFECTED(ch,AFF_FEAR) && (number_percent() <= 25)) {
 act("You attempt to spin kick, but begin crying instead.",ch,NULL,NULL,TO_CHAR);
 act("$n attempts to spin kick, but begins crying instead.",ch,NULL,NULL,TO_ROOM);
 WAIT_STATE(ch,DEF_FEAR_WAIT);
 return; }

 if(ch->stunned)
 {
 send_to_char("You are still a bit woozy.\n\r",ch);
 return;
 }

 level = ch->level + 5;
 // chance = (ch->level - victim->level) * 2;
 chance += number_range(20,50);
 chance -= get_curr_stat(victim,STAT_DEX)/2;
 chance -= get_curr_stat(victim,STAT_STR)/3;
 chance += get_curr_stat(ch,STAT_STR)/3;
 chance += get_curr_stat(ch,STAT_DEX);

 if (IS_AFFECTED(victim,AFF_HASTE))
 chance -= 30;
 if (IS_AFFECTED(ch,AFF_HASTE))
 chance += 25;
 if (IS_AFFECTED(victim,AFF_SLOW))
 chance += 20;
 if (IS_AFFECTED(ch,AFF_SLOW))
 chance -= 30;
 if (IS_AFFECTED(victim,AFF_FLYING))
 chance += 5;
 chance += (ch->size - victim->size)*10;

 if (!IS_NPC(victim) && !IS_NPC(ch) && (victim->hit > 1))
 {
 sprintf(buf,"Help! %s just tried to kick me out of the room!",PERS(ch,victim));

 if(ch->fighting == NULL)
 {
 do_yell(victim,buf);
 }
 }


 if (number_percent() > chance)
 {
 act("You spin your leg around but miss $N.",ch,0,victim,TO_CHAR);
 act("$n spins his leg around but misses you.",ch,0,victim,TO_VICT);
 act("$n spins his leg visciously at $N but misses.",ch,0,victim,TO_NOTVICT);
 check_improve(ch,gsn_spinkick,FALSE,3);
 WAIT_STATE(ch,10);
 if(victim->fighting == NULL)
 multi_hit(victim,ch,TYPE_UNDEFINED);
 return;
 }

 was_in = victim->in_room;
 dam = dice(level,8);

 // Stance modifier
 if (!IS_NPC(ch) && ch->stance[0] > 0 && number_percent() < 3)
 {
 int stance = ch->stance[0];
 if (ch->stance[stance] >= 200)
 dam += dice(ch->stance[stance],2);
 else if(ch->stance[stance] > 0)
 dam += dice(ch->stance[stance],1);
 }

 if(number_percent() < 25)
 {

 for ( attempt = 0; attempt < 6; attempt++ )
 {
 EXIT_DATA *pexit;
 int door;
 char dir[MAX_STRING_LENGTH/4];

 door = number_door( );

 if (door == 0)
 (strcpy(dir,"north"));
 else if (door == 1)
 (strcpy(dir,"east"));
 else if (door == 2)
 (strcpy(dir,"south"));
 else if (door == 3)
 (strcpy(dir,"west"));
 else if (door == 4)
 (strcpy(dir,"up"));
 else if (door == 5)
 (strcpy(dir,"down"));
 else
 strcpy(dir,"none");

 if ( ( pexit = was_in->exit[door] ) == 0
 ||   pexit->u1.to_room == NULL
 ||  ( IS_SET(pexit->exit_info, EX_CLOSED) )
 || ( IS_NPC(victim)
 &&   IS_SET(pexit->u1.to_room->room_flags, ROOM_NO_MOB) ) )
 continue;

 if ( ( was_in->sector_type == SECT_AIR)
 ||  ( (pexit->u1.to_room->sector_type == SECT_AIR )
 &&  ( !IS_AFFECTED(victim, AFF_FLYING) ) ) )
 continue;

 if (IS_SET(pexit->exit_info,EX_CLOSED))
 {
 act("You spin around and kick $N through the door with incredible force!",ch,0,victim,TO_CHAR);
 act("$n's spin kick sends $N crashing through the door with incredible force!",ch,0,victim,TO_NOTVICT);
 act("$n spins around and kicks you through the door with incredible force!",ch,0,victim,TO_VICT);
 }
 else
 {
 act("You spin your leg visciously at $N and kick $M from the room!",ch,0,victim,TO_CHAR);
 act("$n spins his leg visciously at $N and kicks $M from the room!",ch,NULL,victim,TO_NOTVICT);
 act("$n spins his leg visciously at you and kicks you from the room!",ch,0,victim,TO_VICT);
 dam = dice(level,5);
 }

 for(vch = victim->in_room->people; vch != NULL; vch = vch_next)
 {
 vch_next = vch->next_in_room;

 if(IS_IMMORTAL(vch))
 {
 sprintf(buf,"\n\r%s is kicked %s.",victim->name,dir);
 send_to_char(buf,vch);
 }
 }

 char_from_room(victim);
 char_to_room(victim, pexit->u1.to_room);
 do_look(victim,"auto");

 if (IS_SET(pexit->exit_info,EX_CLOSED))
 {
 REMOVE_BIT(pexit->exit_info,EX_CLOSED);
 act("With a deafening crash the door explodes open and $n comes flying into the room!",victim,0,0,TO_ROOM);
 }
 else
 {
 act("$n comes flying into the room with incredible force!",victim,0,0,TO_ROOM);
 }

 if (saves_spell(ch->level,victim,DAM_BASH))
 dam /= 2;
 damage(ch,victim,dam,gsn_spinkick,DAM_BASH,TRUE,0);
 WAIT_STATE(victim,36);
 WAIT_STATE(ch,24);
 stop_fighting( ch, TRUE );
 return;
 }

 if( attempt == 6 )
 {
 dam += dice(level,4);
 act("You spin your leg viscously at $N and kick $M brutally into a wall!",ch,0,victim,TO_CHAR);
 act("$n spins his leg viscously at $N and kicks $M brutally into a wall!",ch,0,victim,TO_NOTVICT);
 act("$n spins his leg viscously at you and kicks you brutally into a wall!",ch,0,victim,TO_VICT);

 if (saves_spell(ch->level,victim,DAM_BASH))
 dam /= 2;
 damage(ch,victim,dam,gsn_spinkick,DAM_BASH,TRUE,0);
 WAIT_STATE(ch,24);
 WAIT_STATE(victim,24);
 }
 }
 else
 {
 act("You spin your leg viscously at $N and kick $M brutally!",ch,0,victim,TO_CHAR);
 act("$n spins his leg viscously at $N and kicks $M brutally!",ch,0,victim,TO_NOTVICT);
 act("$n spins his leg viscously at you and kicks you brutally!",ch,0,victim,TO_VICT);

 if (saves_spell(ch->level-4,victim,DAM_BASH))
 dam /= 2;
 damage(ch,victim,dam,gsn_spinkick,DAM_BASH,TRUE,0);

 if(number_range(1,2) == 2)
 WAIT_STATE(victim,24);
 else
 WAIT_STATE(victim,12);

 WAIT_STATE(ch,12);

 }
 return;
 }*/

/*void do_chop( CHAR_DATA *ch, char *argument) 
 {
 CHAR_DATA *victim;
 int chance, dam;
 char arg[MAX_INPUT_LENGTH];
 OBJ_DATA *wield,*second;
 int multiplier;
 bool DUAL = FALSE;

 dam = 0;
 one_argument(argument,arg);
 if ((chance = get_skill(ch,gsn_chop) ) == 0
 || !has_skill(ch,gsn_chop) )
 {
 send_to_char("Chopping? What's that?\n\r",ch);
 return;
 }
 if (arg[0] == '\0')
 {
 victim = ch->fighting;
 if (victim == NULL)
 {
 send_to_char("But you aren't fighting anyone!\n\r",ch);
 return;
 }
 }
 else if ( (victim = get_char_room(ch,arg)) == NULL )
 {
 send_to_char("They aren't here.\n\r",ch);
 return;
 }
 if (victim == ch)
 {
 send_to_char("You can't chop at yourself!\n\r",ch);
 return;
 }

 if (IS_AFFECTED(ch,AFF_FEAR) && (number_percent() <= 25)) {
 act("You attempt to chop, but begin crying instead.",ch,NULL,NULL,TO_CHAR);
 act("$n attempts to chop, but begins crying instead.",ch,NULL,NULL,TO_ROOM);
 WAIT_STATE(ch,DEF_FEAR_WAIT);
 return; }

 if(ch->stunned)
 {
 send_to_char("You are still a bit woozy.\n\r",ch);
 return;
 }

 wield = get_eq_char(ch,WEAR_WIELD);
 second = get_eq_char(ch,WEAR_SECONDARY);
 
 if ((wield == NULL)
 || (( wield->value[0] != WEAPON_SWORD)
 && ( wield->value[0] != WEAPON_AXE)
 && ( wield->value[0] != WEAPON_DAGGER) ))
 {
 if ((second == NULL)
 || (( second->value[0] != WEAPON_SWORD)
 && ( second->value[0] != WEAPON_AXE)
 && ( second->value[0] != WEAPON_DAGGER) ))
 {
 send_to_char("You must be wielding a sword or axe to chop.\n\r",ch);
 return;
 }
 else
 {
 DUAL = TRUE;
 }
 }
 
 if (is_safe(ch,victim) )
 return;
 
 chance += ch->carry_weight/25;
 chance -= victim->carry_weight/20;
 chance += (ch->size - victim->size)*20;
 chance -= get_curr_stat(victim,STAT_DEX);
 chance += get_curr_stat(ch,STAT_STR)/3;
 chance += get_curr_stat(ch,STAT_DEX)/2;
 if (IS_AFFECTED(ch,AFF_HASTE) )
 chance += 10;
 if (IS_AFFECTED(victim,AFF_HASTE) )
 chance -= 10;
 chance += (ch->level - victim->level);

 act("$n attempts to split open $N with a quick chop!",ch,0,victim,TO_NOTVICT);
 act("You attempt to split open $N with a quick chop!",ch,0,victim,TO_CHAR);
 act("$n attempts to split you open with a quick chop!",ch,0,victim,TO_VICT);
 
 if (number_percent() < chance)
 {
 check_improve(ch,gsn_lunge,TRUE,1);
 WAIT_STATE(ch,skill_table[gsn_chop].beats);
 
 if(DUAL)
 wield = second;
 
 if (wield->pIndexData->new_format)
 dam = dice(wield->value[1],wield->value[2]);
 else
 dam = number_range(wield->value[1],wield->value[2]);
 
 dam += GET_DAMROLL(ch);
 dam *= ch->pcdata->learned[gsn_chop];
 dam /= 100;
 multiplier = number_range(ch->level/8, ch->level/4);
 multiplier /= 10;
 multiplier += 5/4;
 dam *= multiplier;
 if(!DUAL && IS_WEAPON_STAT(wield,WEAPON_TWO_HANDS))
 dam *= 1.5;
 
 if (dam <= 0)
 dam = 1;
 damage(ch,victim,dam,gsn_chop,DAM_PIERCE,TRUE,0);
 }
 else
 {
 damage(ch,victim,dam,gsn_chop,DAM_PIERCE,TRUE,0);
 check_improve(ch,gsn_chop,FALSE,1);
 WAIT_STATE(ch,skill_table[gsn_chop].beats);
 }
 return;
 }
 */